diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/.gitignore b/sdk/ESP-IDF/esp_fastbee_aliyun/.gitignore new file mode 100644 index 00000000..636bdedf --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/.gitignore @@ -0,0 +1,2 @@ +build/ +.idea diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/.vscode/c_cpp_properties.json b/sdk/ESP-IDF/esp_fastbee_aliyun/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..fddb9c2e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/.vscode/c_cpp_properties.json @@ -0,0 +1,23 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**", + "D:/soft/esp-idf/Espressif/frameworks/esp-idf-v4.4.7/components/**", + "./esp-aliyun/**", + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "windowsSdkVersion": "10.0.22621.0", + "compilerPath": "cl.exe", + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "windows-msvc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/.vscode/launch.json b/sdk/ESP-IDF/esp_fastbee_aliyun/.vscode/launch.json new file mode 100644 index 00000000..eb835b10 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "ESP-IDF Debug: Launch", + "type": "espidf", + "request": "launch" + }, + { + "name": "GDB", + "type": "cppdbg", + "request": "launch", + "MIMode": "gdb", + "miDebuggerPath": "${command:espIdf.getXtensaGdb}", + "program": "${workspaceFolder}/build/${command:espIdf.getProjectName}.elf", + "windows": { + "program": "${workspaceFolder}\\build\\${command:espIdf.getProjectName}.elf" + }, + "cwd": "${workspaceFolder}", + "environment": [{ "name": "PATH", "value": "${config:idf.customExtraPaths}" }], + "setupCommands": [ + { "text": "set remotetimeout 100" }, + { "text": "target extended-remote :3333" }, + { "text": "set remote hardware-watchpoint-limit 2"}, + { "text": "mon reset halt" }, + { "text": "thb app_main" }, + { "text": "flushregs" } + ], + "externalConsole": false, + "logging": { + "engineLogging": true + } + } + ] +} \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/.vscode/settings.json b/sdk/ESP-IDF/esp_fastbee_aliyun/.vscode/settings.json new file mode 100644 index 00000000..a3bc1af0 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "idf.portWin": "COM6", + "idf.adapterTargetName": "esp32s3", + "idf.openOcdConfigs": [ + "board/esp32s3-builtin.cfg" + ], + "idf.flashType": "UART", + "files.associations": { + "infra_config.h": "c", + "cjson.h": "c", + "dm_wrapper.h": "c", + "infra_defs.h": "c", + "freertos.h": "c", + "stddef.h": "c", + "string.h": "c", + "esp_log.h": "c", + "mqtt_client.h": "c" + } +} \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/CMakeLists.txt b/sdk/ESP-IDF/esp_fastbee_aliyun/CMakeLists.txt new file mode 100644 index 00000000..163a6c23 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/CMakeLists.txt @@ -0,0 +1,12 @@ + +# (Automatically converted from project Makefile by convert_to_cmake.py.) + +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set (EXTRA_COMPONENT_DIRS "./esp-aliyun") + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +project(esp_fastbee_aliyun) diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/Makefile b/sdk/ESP-IDF/esp_fastbee_aliyun/Makefile new file mode 100644 index 00000000..7454f9b7 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/Makefile @@ -0,0 +1,11 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# +PROJECT_NAME := esp_fastbee_aliyun + +EXTRA_COMPONENT_DIRS := $(realpath ./esp-aliyun) + +SDKCONFIG_DEFAULTS := sdkconfig_$(chip).defaults + +include $(IDF_PATH)/make/project.mk \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/README.md b/sdk/ESP-IDF/esp_fastbee_aliyun/README.md new file mode 100644 index 00000000..492041ad --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/README.md @@ -0,0 +1,152 @@ +# ESP 设备对接Fastbee物联网云平台指南 +# 目录 + +- [1.目的](#aim) +- [2.硬件准备](#hardwareprepare) +- [3.云平台准备](#fastbeeprepare) +- [4.环境搭建](#compileprepare) +- [5.SDK 准备](#sdkprepare) +- [6.编译&烧写&运行](#makeflash) + + +# 1.目的 +本项目基于esp-aliyun SDK进行修改,介绍 ESP 设备对接Fastbee物联网云平台,阿里云平台的具体流程。 +主要实现的功能: +- 支持 配网&接入&控制 +- 支持 <云智能> APP 一键配网 +- 支持 <云智能> APP 控制设备 +- 支持 <天猫精灵智能音箱> 控制设备 +- 支持 <天猫精灵智能音箱> 配网并控制设备 +- 支持 LED 控制(开关,颜色等) +- 支持 OTA 升级 + +# 2.硬件准备 +- **linux 环境** +用来编译 & 烧写 & 运行等操作的必须环境。 +> windows 用户可安装虚拟机,在虚拟机中安装 linux。 + +- **ESP 设备** +ESP 设备包括 [ESP芯片](https://www.espressif.com/zh-hans/products/hardware/socs),[ESP模组](https://www.espressif.com/zh-hans/products/hardware/modules),[ESP开发板](https://www.espressif.com/zh-hans/products/hardware/development-boards)等。 + +- **USB 线** +连接 PC 和 ESP 设备,用来烧写/下载程序,查看 log 等。 + +# 3.云平台准备 + +# 4.环境搭建 +**如果您熟悉 ESP 开发环境,可以很顺利理解下面步骤; 如果您不熟悉某个部分,比如编译,烧录,需要您结合官方的相关文档来理解。如您需阅读 [ESP-IDF 编程指南](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/index.html)文档等。** + +## 4.1 编译器环境搭建 +- ESP8266 平台: 根据[官方链接](https://github.com/espressif/ESP8266_RTOS_SDK)中 **Get toolchain**,获取 toolchain +- ESP32 & ESP32S2 平台:根据[官方链接](https://github.com/espressif/esp-idf/blob/master/docs/zh_CN/get-started/linux-setup.rst)中 **工具链的设置**,下载 toolchain + +toolchain 设置参考 [ESP-IDF 编程指南](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/get-started/index.html#get-started-setup-toolchain)。 +## 4.2 烧录工具/下载工具获取 +- ESP8266 平台:烧录工具位于 [ESP8266_RTOS_SDK](https://github.com/espressif/ESP8266_RTOS_SDK) 下 `./components/esptool_py/esptool/esptool.py` +- ESP32 & ESP32S2 平台:烧录工具位于 [esp-idf](https://github.com/espressif/esp-idf) 下 `./components/esptool_py/esptool/esptool.py` + +esptool 功能参考: + +``` +$ ./components/esptool_py/esptool/esptool.py --help +``` + +# 5.SDK 准备 +- [esp-aliyun SDK](https://github.com/espressif/esp-aliyun), 通过该 SDK 可实现使用 MQTT 协议,连接 ESP 设备到阿里云。 +- Espressif SDK + - ESP32 & ESP32S2 平台: [ESP-IDF](https://github.com/espressif/esp-idf) + - ESP8266 平台: [ESP8266_RTOS_SDK](https://github.com/espressif/ESP8266_RTOS_SDK) + +> Espressif SDK 下载好后: +> ESP-IDF: 请切换到 v4.2 分支: `git checkout v4.2` +如果需要使用 ESP32S2 模组,请切换到 v4.2 版本: `git checkout v4.2` +> ESP8266_RTOS_SDK: 请切换到 v3.3 分支: `git checkout v3.3` + +# 6.编译 & 烧写 & 运行 +## 6.1 编译 + +### 6.1.1 导出编译器 +参考 [工具链的设置](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/get-started/linux-setup.html) + +### 6.1.2 编译 demo 示例 +**由于 esp32 和 esp8266 将会采用不同的 sdkconfig.defaults 和对应的 partitions.csv,在对应的 make 命令中加入了对应的芯片选项,如 chip=esp32 或 chip=esp8266。** + +当 chip=esp32 时将默认使用 sdkconfig_esp32.defaults 以及 partitions_esp32.csv。 + +当 chip=esp8266 时将默认使用 sdkconfig_esp8266.defaults 以及 partitions_esp8266.csv。 + +当使用 esp32s2 时,将默认使用 sdkconfig.defaults ,sdkconfig.defaults.esp32s2 以及 partitions_esp32s2.csv,编译方式与 8266 & 32 都不一样,需要使用 cmake 进行编译。 + +以上需要特别注意。 + +在 esp-aliyun 目录下执行: + +``` +cd fastbee\sdk\ESP-IDF\esp-aliyun +make chip=esp32 defconfig +make menuconfig +``` + +如果需要编译esp32s2版本, 请按照如下步骤编译: + +在 esp-aliyun 目录下执行: + +``` +cd fastbee\sdk\ESP-IDF\esp-aliyun +idf.py set-target esp32s2 +idf.py menuconfig +``` + +- 配置烧写串口 +- 配置 `WIFI_SSID`, `WIFI_PASSWORD` + +如果需要编译esp32s3版本, 请按照如下步骤编译: + +在 esp-aliyun 目录下执行: + +``` +cd fastbee\sdk\ESP-IDF\esp-aliyun +idf.py set-target esp32s3 +idf.py menuconfig +``` + +2.生成最终 bin + +``` +make -j8 +``` +使用 esp32s2/esp32s3 生成 bin + +``` +idf.py build +``` + +## 6.2 擦除 & 编译烧写 & 下载固件 & 查看 log +将 USB 线连接好 ESP 设备和 PC,确保烧写端口正确。 + +### 6.2.1[可选] 擦除 flash +``` +make erase_flash +``` +> 注:无需每次擦除,擦除后需要重做 6.2.3。 + +### 6.2.2 烧录程序 +``` +make flash +``` + +使用 esp32s2/esp32s3 擦除 flash +``` +idf.py -p (PORT) erase_flash +``` + +### 6.2.3 烧录三元组信息 +参考 [量产说明](./aliyunsdk/config/mass_mfg/README.md) 文档烧录三元组 NVS 分区。 + +## 6.2.4 运行 + +``` +make monitor +``` + +> 也可执行 `make flash monitor` 来编译烧写和查看 log。 diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/README_examples.md b/sdk/ESP-IDF/esp_fastbee_aliyun/README_examples.md new file mode 100644 index 00000000..aeceab57 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/README_examples.md @@ -0,0 +1,127 @@ +# Smart Light 解决方案 + +### 解决方案部署 +#### 1.参考 [README](./README.md) 文档进行硬件准备、环境搭建、SDK 准备 + +#### 2.阿里云平台部署 +在阿里云 [生活物联网平台](https://living.aliyun.com/#/) 创建产品, 参考[创建产品文档](https://living.aliyun.com/doc#readygo.html). +> 配置较多, 如果不太懂, 也不用纠结, 后续都可以修改. + +部署自己的产品, 可参考如下: +新增 RGB 调色功能: +![](_static/p1.png) + +新增测试设备, 此处即可以获得`三元组`, 后续需要烧录到 NVS 分区. +![](_static/p2.png) +![](_static/p3.png) + +选择面板, 手机 APP 上会显示同样界面; `配网二维码`是贴在产品包装上, 终端客户给设备配网中需扫描此二维码. +![](_static/p4.png) + +选择面板时, 主题面板在手机上仅能显示标准界面, 没有 RGB 调色功能. 可以自定义面板, 增加 RGB 调色. +![](_static/p5.png) + +![](_static/p6.png) + +配网方案选择: +![](_static/p7.png) + +完成 +![](_static/p8.png) + +#### 3.下载本工程 + ``` + git clone https://github.com/espressif/esp-aliyun.git + cd esp-aliyun + ``` + +#### 4.烧录三元组信息 +- 参考 [量产说明](../../../config/mass_mfg/README.md) 文档烧录三元组 NVS 分区. + +> 如果执行了 `make erase_flash`, 需要重新烧录三元组. + +#### 5.配置 `smart light example` +- RGB 灯分别接 ESP32/ESP8266 开发板上 `GPIO0`, `GPIO2`, `GPIO4` (可在 `lightbulb.c` 中修改) + +#### 6.编译 `smart light` 并烧录运行 +``` +cd examples/solutions/smart_light +make chip=esp32 defconfig 或者 make chip=esp8266 defconfig +make -j8 flash monitor +``` +使用 esp32s2 请参考根目录 README。 + +> 在测试配网中, 请先执行 `make erase_flash` . + +#### 7.设备第一次运行时, 会进入配网 + +![](_static/p9.png) + +#### 8.手机从[阿里云官网](https://living.aliyun.com/doc#muti-app.html) 下载 `云智能` 公版 APP, 国内用户版. + +#### 9.注册好账号后,进入 APP, 右上角扫描, 扫描第二步的二维码配网. +设备端配网成功后会保存 `ssid` 和 `password` : +![](_static/p10.png) + +设备与手机绑定成功后, APP 上会弹出灯的配置页面. 返回主页显示灯 `在线`. +![](_static/p11.png) +![](_static/p12.png) + +#### 10.控制智能灯 + +在 APP 上打开灯, 设备端收到消息: +![](_static/p13.png) + +在 APP 上设置 RGB 调色: +![](_static/p14.png) + +设备端即解析 RGB 颜色, 并设置到具体的灯产品上. +![](_static/p15.png) + +#### 11.重新配网 +快速重启设备 5 次, 设备会擦除配置信息, 重新进入配网状态. + +可以配置快速重启的次数和超时时间. +``` +cd examples/solutions/smart_light +make menuconfig +``` +![](_static/p20.png) +![](_static/p21.png) + +#### 12.OTA 支持 +参考 examples/ota/ota_example_mqtt 示例下的 [README](../../ota/ota_example_mqtt/README.md) , 向管理控制台上传固件, 验证固件后, 下发升级指令. +设备端收到升级指令后, 即开始 OTA: +![](_static/p16.png) + +升级完成后, 会检查固件的有效性, 下图说明固件有效. +![](_static/p17.png) + +iotkit-embedded 目前没有设置软重启操作, 可以手动按模组重启键运行新固件: +![](_static/p18.png) + +#### 13.天猫精灵 +##### 13.1 天猫精灵控制设备 +针对使用公版 APP 的产品,用户可以一键开通天猫精灵,实现天猫精灵音箱对设备的控制. 使用步骤参照[阿里云文档](https://living.aliyun.com/doc#TmallGenie.html). +- 在阿里云 [生活物联网平台](https://living.aliyun.com/#/)上一键开通天猫精灵, 查看功能映射. +- 在 `云智能` [公版 APP]((https://living.aliyun.com/doc#muti-app.html))上绑定天猫精灵账号(即淘宝账号). + +注意最后步骤, 否则天猫精灵无法找到设备: +> 在天猫精灵 APP 找到 "阿里智能" 技能, 手动进行 "尝试" 或 "设备同步"(后期会进行自动同步) +> 即可在 "我家" 的设备列表中看到您的设备 + +完成以上步骤后,您可以通过天猫精灵音箱控制您的设备了. 您可以对天猫精灵说 "天猫精灵,开灯", "天猫精灵, 关灯", "天猫精灵, 把灯调成红色" 或者其他您希望设置的颜色, 设备即响应相应的命令. + +##### 13.2 天猫精灵配网并控制设备 +阿里云设备支持 `零配` 的配网方式. +使设备进入配网状态, 对天猫精灵说 "天猫精灵,发现设备" +天猫精灵回复 "正在为您扫描, 发现了智能灯, 现在连接吗" +对天猫精灵说 "连接" 或者 "是的" +天猫精灵回复 "好的, 设备连接中, 稍等一下下哦" +设备收到天猫精灵发送的管理帧配网信息, 进行联网: +![](_static/p19.png) + +等待联网成功, 天猫精灵说 "智能设备联网成功, 现在用语音控制它试试", 这时您可以通过天猫精灵音箱控制您的设备了. + +如果您之前通过云智能 APP 配网, 天猫精灵配网成功后, 云智能 APP 将不再显示设备. 如果继续通过云智能 APP 配网, APP 会配网失败, 显示 "设备添加失败, 设备已被管理员绑定, 请联系管理员解绑或将设备分享给您". +> 在天猫精灵 APP 删除设备, 云智能 APP 再进行配网可以配置成功并显示设备. \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-redirect.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-redirect.png new file mode 100644 index 00000000..f4e5db53 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-redirect.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-se.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-se.png new file mode 100644 index 00000000..dbce5aa1 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-se.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-sub.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-sub.png new file mode 100644 index 00000000..a84a4158 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-sub.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-us.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-us.png new file mode 100644 index 00000000..5fcf7075 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p-us.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p1.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p1.png new file mode 100644 index 00000000..a2a2b36f Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p1.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p10.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p10.png new file mode 100644 index 00000000..7c538988 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p10.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p11.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p11.png new file mode 100644 index 00000000..ab8a48c3 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p11.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p12.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p12.png new file mode 100644 index 00000000..ca802ae3 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p12.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p13.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p13.png new file mode 100644 index 00000000..538ebfcc Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p13.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p14.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p14.png new file mode 100644 index 00000000..a0fbe21f Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p14.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p15.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p15.png new file mode 100644 index 00000000..1803e23a Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p15.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p16.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p16.png new file mode 100644 index 00000000..70842f54 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p16.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p17.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p17.png new file mode 100644 index 00000000..b0ab72dd Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p17.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p18.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p18.png new file mode 100644 index 00000000..3086b3d4 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p18.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p19.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p19.png new file mode 100644 index 00000000..798e3064 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p19.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p2.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p2.png new file mode 100644 index 00000000..80dcc095 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p2.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p20.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p20.png new file mode 100644 index 00000000..f542d286 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p20.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p21.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p21.png new file mode 100644 index 00000000..7bceee55 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p21.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p22.jpg b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p22.jpg new file mode 100644 index 00000000..076fb035 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p22.jpg differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p23.jpg b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p23.jpg new file mode 100644 index 00000000..3d6e577c Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p23.jpg differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p24.jpg b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p24.jpg new file mode 100644 index 00000000..51c7ccbf Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p24.jpg differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p3.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p3.png new file mode 100644 index 00000000..d036d4a6 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p3.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p4.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p4.png new file mode 100644 index 00000000..c5c8212b Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p4.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p5.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p5.png new file mode 100644 index 00000000..371e345e Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p5.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p6.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p6.png new file mode 100644 index 00000000..06f135e4 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p6.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p7.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p7.png new file mode 100644 index 00000000..e716b2b2 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p7.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p8.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p8.png new file mode 100644 index 00000000..46705e9b Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p8.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p9.png b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p9.png new file mode 100644 index 00000000..d93f2312 Binary files /dev/null and b/sdk/ESP-IDF/esp_fastbee_aliyun/_static/p9.png differ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/CMakeLists.txt b/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/CMakeLists.txt new file mode 100644 index 00000000..415fe200 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/CMakeLists.txt @@ -0,0 +1,7 @@ +set(COMPONENT_ADD_INCLUDEDIRS .) + +set(COMPONENT_SRCS "factory_restore.c") + +set(COMPONENT_REQUIRES "esp-aliyun") + +register_component() diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/Kconfig.projbuild b/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/Kconfig.projbuild new file mode 100644 index 00000000..1a456afe --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/Kconfig.projbuild @@ -0,0 +1,15 @@ +menu "[Aliyun]Factory restore" + + config FACTORY_QUICK_REBOOT_TIMEOUT + int "Quick reboot timeout, unit second" + default 6 + help + Timeout for exiting quick reboot timer, users should reboot device before this timeout. + + config FACTORY_QUICK_REBOOT_MAX_TIMES + int "Quick reboot times max record" + default 5 + help + If quick reboot times reach this max value, device will do factory restore. + +endmenu diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/component.mk b/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/component.mk new file mode 100644 index 00000000..a82220a1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS := ./ +COMPONENT_SRCDIRS := ./ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/factory_restore.c b/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/factory_restore.c new file mode 100644 index 00000000..78b7dcfb --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/factory_restore.c @@ -0,0 +1,103 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/timers.h" +#include "esp_sleep.h" +#include "dm_wrapper.h" +#include "conn_mgr.h" + +#define FACTORY_QUICK_REBOOT_TIMEOUT (CONFIG_FACTORY_QUICK_REBOOT_TIMEOUT * 1000) +#define FACTORY_QUICK_REBOOT_MAX_TIMES CONFIG_FACTORY_QUICK_REBOOT_MAX_TIMES +#define FACTORY_QUICK_REBOOT_TIMES "q_rt" + +#define AWSS_KV_RST "awss.rst" + +static const char *TAG = "factory_rst"; + +static esp_err_t factory_restore_handle(void) +{ + esp_err_t ret = ESP_OK; + int quick_reboot_times = 0; + + /**< If the device restarts within the instruction time, the event_mdoe value will be incremented by one */ + int length = sizeof(int); + ret = HAL_Kv_Get(FACTORY_QUICK_REBOOT_TIMES, &quick_reboot_times, &length); + + quick_reboot_times++; + + ret = HAL_Kv_Set(FACTORY_QUICK_REBOOT_TIMES, &quick_reboot_times, sizeof(int), 0); + + if (quick_reboot_times >= FACTORY_QUICK_REBOOT_MAX_TIMES) { + char rst = 0x01; + + /* since we cannot report reset status to cloud in this stage, just set the reset flag. + when connects to cloud, awss will do the reset report. */ + ret = HAL_Kv_Set(AWSS_KV_RST, &rst, sizeof(rst), 0); + ret = HAL_Kv_Del(FACTORY_QUICK_REBOOT_TIMES); + + ESP_LOGW(TAG, "factory restore"); + conn_mgr_reset_wifi_config(); + } else { + ESP_LOGI(TAG, "quick reboot times %d, don't need to restore", quick_reboot_times); + } + + return ret; +} + +static void factory_restore_timer_handler(void *timer) +{ + if (!xTimerStop(timer, 0)) { + ESP_LOGE(TAG, "xTimerStop timer %p", timer); + } + + if (!xTimerDelete(timer, 0)) { + ESP_LOGE(TAG, "xTimerDelete timer %p", timer); + } + + /* erase reboot times record */ + HAL_Kv_Del(FACTORY_QUICK_REBOOT_TIMES); + + ESP_LOGI(TAG, "Quick reboot timeout, clear reboot times"); +} + +esp_err_t factory_restore_init(void) +{ +#ifndef CONFIG_IDF_TARGET_ESP8266 + if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_UNDEFINED) { + HAL_Kv_Del(FACTORY_QUICK_REBOOT_TIMES); + return ESP_OK; + } +#endif + + TimerHandle_t timer = xTimerCreate("factory_clear", FACTORY_QUICK_REBOOT_TIMEOUT / portTICK_RATE_MS, + false, NULL, factory_restore_timer_handler); + + xTimerStart(timer, portMAX_DELAY); + + return factory_restore_handle(); +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/factory_restore.h b/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/factory_restore.h new file mode 100644 index 00000000..bde37521 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/factory_restore/factory_restore.h @@ -0,0 +1,50 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2018 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#pragma once + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize factory restore + * + * @note For some devices which don't have a physical restore key or button, such as light, we use + * a quick reboot method to record the reboot times, if users quickly reboot the device within + * a specific time, configured by FACTORY_QUICK_REBOOT_TIMEOUT, and reboot several times, + * configured by FACTORY_QUICK_REBOOT_MAX_TIMES, the device will do a factory restore, clear + * stored ssid and password. + * + * @return + * - ESP_OK : OK + * - others : fail + */ +esp_err_t factory_restore_init(void); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/CMakeLists.txt b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/CMakeLists.txt new file mode 100644 index 00000000..9a944f71 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/CMakeLists.txt @@ -0,0 +1,7 @@ +set(COMPONENT_ADD_INCLUDEDIRS "./include") + +set(COMPONENT_SRCS "fastbee.c" "Config.c" "Mqtt.c") + +set(COMPONENT_REQUIRES "esp-aliyun" "mqtt" "json") + +register_component() diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/Config.c b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/Config.c new file mode 100644 index 00000000..d847beed --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/Config.c @@ -0,0 +1,174 @@ +/********************************************************************* + * function: 设备交互 + * board: esp8266,esp32,esp32s2,esp32s3 core for esp-idf v4.4.7 + * source: https://gitee.com/zhuangpengli/IOTDeviceSDK + * copyright: zhuangpeng.li all rights reserved. + ********************************************************************/ +#include "Config.h" +#include "esp_err.h" +#include "esp_log.h" + +#include "nvs_flash.h" +#include "nvs.h" +#include "dm_wrapper.h" + +// 设备信息配置 +char g_userId[USER_ID_LEN + 1] = {0}; +char g_productId[PRODUCT_ID_LEN + 1] = {0}; +char g_deviceSN[DEVICE_SN_LEN + 1] = {0}; + +// Mqtt配置 +char g_mqtt_url[MQTT_URL_LEN + 1] = {0}; +char g_mqtt_username[MQTT_USERNAME_LEN + 1] = {0}; +char g_mqtt_password[MQTT_PASSWORD_LEN + 1] = {0}; +char g_mqtt_clientid[MQTT_CLIENTID_LEN + 1] = {0}; +char g_mqtt_prefix[MQTT_PREFIX_LEN + 1] = {0}; + +float rssi = 0; +char wumei_iv[17] = "wumei-smart-open"; +int monitorCount = 0; +long monitorInterval = 1000; +bool isApMode = false; +/********************************** begin 可配置的项 **********************************/ +// wifi信息 +char *wifiSsid = ""; +char *wifiPwd = ""; +// 产品启用授权码,则授权码不能为空 +char *authCode = ""; +// 设备信息配置 +float firmwareVersion = 1.0; +// 经度和纬度可选,如果产品使用设备定位,则必须传 +float latitude = 0; +float longitude = 0; +// Mqtt配置 +char mqttSecret[17] = "KV52PPZ813EFCQD8"; +// NTP地址(用于获取时间,修改为自己部署项目的接口地址) +char *ntpServer = "http://fastbee.cn:8080/iot/tool/ntp?deviceSendTime="; +/********************************** end 可配置的项 **********************************/ + +static const char *TAG = "FASTBEE_CONFIG"; +static bool s_part_init_flag; + +static esp_err_t HAL_ProductParam_init(void) +{ + esp_err_t ret = ESP_OK; + + do { + if (s_part_init_flag == false) { + if ((ret = nvs_flash_init_partition(MFG_FASTBEE_PARTITION_NAME)) != ESP_OK) { + ESP_LOGE(TAG, "NVS Flash init %s failed, Please check that you have flashed fctry partition!!!", MFG_FASTBEE_PARTITION_NAME); + break; + } + + s_part_init_flag = true; + } + } while (0); + + return ret; +} + +static int HAL_GetProductParam(char *param_name, const char *param_name_str) +{ + esp_err_t ret; + size_t read_len = 0; + nvs_handle handle; + + do { + if (HAL_ProductParam_init() != ESP_OK) { + break; + } + + if (param_name == NULL) { + ESP_LOGE(TAG, "%s param %s NULL", __func__, param_name); + break; + } + + ret = nvs_open_from_partition(MFG_FASTBEE_PARTITION_NAME, NVS_FASTBEE_PRODUCT, NVS_READONLY, &handle); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "%s nvs_open failed with %x", __func__, ret); + break; + } + + ret = nvs_get_str(handle, param_name_str, NULL, (size_t *)&read_len); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "%s nvs_get_str get %s failed with %x", __func__, param_name_str, ret); + break; + } + + ret = nvs_get_str(handle, param_name_str, param_name, (size_t *)&read_len); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "%s nvs_get_str get %s failed with %x", __func__, param_name_str, ret); + } else { + ESP_LOGV(TAG, "%s %s %s", __func__, param_name_str, param_name); + } + + nvs_close(handle); + } while (0); + + return read_len; +} + +int HAL_GetMqttUrl(char mqtt_url[MQTT_URL_LEN + 1]) +{ + return HAL_GetProductParam(mqtt_url, "MQTTUrl"); +} +int HAL_GetMqttUsername(char mqtt_username[MQTT_USERNAME_LEN + 1]) +{ + return HAL_GetProductParam(mqtt_username, "MQTTUsername"); +} +int HAL_GetMqttPassword(char mqtt_password[MQTT_PASSWORD_LEN + 1]) +{ + return HAL_GetProductParam(mqtt_password, "MQTTPassword"); +} +int HAL_GetMqttClientId(char mqtt_clientid[MQTT_CLIENTID_LEN + 1]) +{ + return HAL_GetProductParam(mqtt_clientid, "MQTTClientId"); +} +int HAL_GetUserId(char userid[USER_ID_LEN + 1]) +{ + return HAL_GetProductParam(userid, "UserId"); +} +int HAL_GetDeviceSN(char deviceSN[DEVICE_SN_LEN + 1]) +{ + return HAL_GetProductParam(deviceSN, "DeviceSN"); +} +int HAL_GetProductId(char productId[PRODUCT_ID_LEN + 1]) +{ + return HAL_GetProductParam(productId, "ProductId"); +} + +void loadConfig() { + HAL_GetMqttUrl(g_mqtt_url); + if (strlen(g_mqtt_url) == 0) { + //加载默认配置 + memcpy(g_mqtt_url, CONFIG_ESP_MQTT_PLATFORM_FASTBEE_URL, strlen(CONFIG_ESP_MQTT_PLATFORM_FASTBEE_URL)); + } + HAL_GetMqttUsername(g_mqtt_username); + if (strlen(g_mqtt_username) == 0) { + memcpy(g_mqtt_username, CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERNAME, strlen(CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERNAME)); + } + HAL_GetMqttPassword(g_mqtt_password); + if (strlen(g_mqtt_password) == 0) { + memcpy(g_mqtt_password, CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PASSWORD, strlen(CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PASSWORD)); + } + HAL_GetMqttClientId(g_mqtt_clientid); + if (strlen(g_mqtt_clientid) == 0) { + HAL_Snprintf(g_mqtt_clientid, sizeof(g_mqtt_clientid), "S&%s&%s&%s", CONFIG_ESP_MQTT_PLATFORM_FASTBEE_DEVICESN,CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PRODICTID,CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERID); + } + HAL_GetUserId(g_userId); + if (strlen(g_userId) == 0) { + memcpy(g_userId, CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERID, strlen(CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERID)); + } + HAL_GetDeviceSN(g_productId); + if (strlen(g_productId) == 0) { + memcpy(g_productId, CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PRODICTID, strlen(CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PRODICTID)); + } + HAL_GetProductId(g_deviceSN); + if (strlen(g_deviceSN) == 0) { + memcpy(g_deviceSN, CONFIG_ESP_MQTT_PLATFORM_FASTBEE_DEVICESN, strlen(CONFIG_ESP_MQTT_PLATFORM_FASTBEE_DEVICESN)); + } + HAL_Snprintf(g_mqtt_prefix, sizeof(g_mqtt_prefix), "/%s/%s", g_productId,g_deviceSN); +} \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/Mqtt.c b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/Mqtt.c new file mode 100644 index 00000000..8c8fedc0 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/Mqtt.c @@ -0,0 +1,158 @@ +/********************************************************************* + * function: 设备交互 + * board: esp8266,esp32,esp32s2,esp32s3 core for esp-idf v4.4.7 + * source: https://gitee.com/zhuangpengli/IOTDeviceSDK + * copyright: zhuangpeng.li all rights reserved. + ********************************************************************/ +#include "Mqtt.h" +#include "Config.h" +#include "cJSON.h" +#include "esp_log.h" +#include "dm_wrapper.h" + +char *sInfoTopic = "/info/get"; +char *sOtaTopic = "/ota/get"; +char *sNtpTopic = "/ntp/get"; +char *sPropertyTopic = "/property/get"; +char *sFunctionTopic = "/function/get"; +char *sPropertyOnline = "/property-online/get"; +char *sFunctionOnline = "/function-online/get"; +char *sMonitorTopic = "/monitor/get"; +// Mqtt发布的主题 +char *pInfoTopic = "/info/post"; +char *pNtpTopic = "/ntp/post"; +char *pPropertyTopic = "/property/post"; +char *pFunctionTopic = "/function/post"; +char *pMonitorTopic = "/monitor/post"; +char *pEventTopic = "/event/post"; + +static const char *TAG = "FASTBEE_MQTT"; +// 订阅系统主题 +void subscribeTopic(esp_mqtt_client_handle_t client) { + char topic[128] = {0}; + int msg_id; + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sInfoTopic); + msg_id = esp_mqtt_client_subscribe(client, topic, 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + memset(topic, 0, sizeof(topic)); + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sOtaTopic); + msg_id = esp_mqtt_client_subscribe(client, topic, 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + memset(topic, 0, sizeof(topic)); + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sNtpTopic); + msg_id = esp_mqtt_client_subscribe(client, topic, 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + memset(topic, 0, sizeof(topic)); + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sPropertyTopic); + msg_id = esp_mqtt_client_subscribe(client, topic, 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + memset(topic, 0, sizeof(topic)); + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sFunctionTopic); + msg_id = esp_mqtt_client_subscribe(client, topic, 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + memset(topic, 0, sizeof(topic)); + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sPropertyOnline); + msg_id = esp_mqtt_client_subscribe(client, topic, 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + memset(topic, 0, sizeof(topic)); + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sFunctionOnline); + msg_id = esp_mqtt_client_subscribe(client, topic, 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + memset(topic, 0, sizeof(topic)); + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, sMonitorTopic); + msg_id = esp_mqtt_client_subscribe(client, topic, 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); +} + +// 1.发布设备信息 +void publishInfo(esp_mqtt_client_handle_t client) { + char topic[128] = {0}; + int msg_id; + cJSON *json = cJSON_CreateObject(); + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, pInfoTopic); + // 向JSON对象中添加数据 + cJSON_AddNumberToObject(json, "rssi", 3); + cJSON_AddNumberToObject(json, "firmwareVersion", firmwareVersion); + cJSON_AddNumberToObject(json, "status", 3); + cJSON_AddStringToObject(json, "userId", g_userId); + cJSON_AddNumberToObject(json, "longitude", longitude); + cJSON_AddNumberToObject(json, "latitude", latitude); + + cJSON *summary = cJSON_CreateObject(); + cJSON_AddStringToObject(summary, "name", "fastbee"); + cJSON_AddStringToObject(summary, "chip", "esp32"); + cJSON_AddStringToObject(summary, "author", "zhuangpeng.li"); + cJSON_AddNumberToObject(summary, "version", 1.6); + cJSON_AddStringToObject(summary, "create", "2024-07-07"); + + cJSON_AddItemToObject(json, "summary", summary); + char *json_string = cJSON_Print(json); + msg_id = esp_mqtt_client_publish(client, topic, json_string, 0, 0, 0); + ESP_LOGI(TAG, "sent publish %s, msg_id= %d, msg: %s", topic, msg_id, json_string); + + cJSON_Delete(json); + free(json_string); +} + +// 2.发布时钟同步信,用于获取当前时间(可选) +void publishNtp(esp_mqtt_client_handle_t client) { + char topic[128] = {0}; + int msg_id; + cJSON *json = cJSON_CreateObject(); + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, pNtpTopic); + cJSON_AddStringToObject(json, "deviceSendTime", "test"); + char *json_string = cJSON_Print(json); + msg_id = esp_mqtt_client_publish(client, topic, json_string, 0, 0, 0); + ESP_LOGI(TAG, "sent publish %s, msg_id= %d, msg: %s", topic, msg_id, json_string); + + cJSON_Delete(json); + free(json_string); +} + +// 3.发布属性 +void publishProperty(esp_mqtt_client_handle_t client, const char *msg) { + char topic[128] = {0}; + int msg_id; + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, pPropertyTopic); + msg_id = esp_mqtt_client_publish(client, topic, msg, 0, 0, 0); + ESP_LOGI(TAG, "发布属性主题: %s", topic); + ESP_LOGI(TAG, "消息id= %d, 消息: %s", msg_id, msg); +} + +// 4.发布功能 +void publishFunction(esp_mqtt_client_handle_t client, const char *msg) { + char topic[128] = {0}; + int msg_id; + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, pFunctionTopic); + msg_id = esp_mqtt_client_publish(client, topic, msg, 0, 0, 0); + ESP_LOGI(TAG, "发布功能主题: %s", topic); + ESP_LOGI(TAG, "消息id= %d, 消息: %s", msg_id, msg); +} + +// 5.发布事件 +void publishEvent(esp_mqtt_client_handle_t client, const char *msg) { + char topic[128] = {0}; + int msg_id; + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, pEventTopic); + msg_id = esp_mqtt_client_publish(client, topic, msg, 0, 0, 0); + ESP_LOGI(TAG, "发布事件主题: %s", topic); + ESP_LOGI(TAG, "消息id= %d, 消息: %s", msg_id, msg); +} + +// 6.发布实时监测数据 +void publishMonitor(esp_mqtt_client_handle_t client, const char *msg) { + char topic[128] = {0}; + int msg_id; + HAL_Snprintf(topic, sizeof(topic), "%s%s", g_mqtt_prefix, pMonitorTopic); + // 发布实时监测数据(不会存储,需要实时存储则发布为属性) + msg_id = esp_mqtt_client_publish(client, topic, msg, 0, 0, 0); + ESP_LOGI(TAG, "发布实时监测主题: %s", topic); + ESP_LOGI(TAG, "消息id= %d, 消息: %s", msg_id, msg); +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/component.mk b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/component.mk new file mode 100644 index 00000000..da8d8132 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS := ./include +COMPONENT_SRCDIRS := ./ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/config/multipule_mfg_config.csv b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/config/multipule_mfg_config.csv new file mode 100644 index 00000000..399f4a45 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/config/multipule_mfg_config.csv @@ -0,0 +1,8 @@ +fastbee-key,namespace, +MQTTUrl,data,string +MQTTUsername,data,string +MQTTPassword,data,string +MQTTClientId,data,string +UserId,data,string +DeviceSN,data,string +ProductId,data,string \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/config/multipule_mfg_values.csv b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/config/multipule_mfg_values.csv new file mode 100644 index 00000000..895cb576 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/config/multipule_mfg_values.csv @@ -0,0 +1,4 @@ +id,MQTTUrl,MQTTUsername,MQTTPassword,MQTTClientId,UserId,DeviceSN,ProductId +1,fastbee.cn:1883,FastBee,P63653937TRQ8F27,S&DCDA0C11FEBC&588&1,1,DCDA0C11FEBC,588 +2,fastbee.cn:1883,FastBee,P63653937TRQ8F27,S&DCDA0C11FEBC&588&1,1,DCDA0C11FEBC,588 +3,fastbee.cn:1883,FastBee,P63653937TRQ8F27,S&DCDA0C11FEBC&588&1,1,DCDA0C11FEBC,588 \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/config/single_mfg_config.csv b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/config/single_mfg_config.csv new file mode 100644 index 00000000..033f7eac --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/config/single_mfg_config.csv @@ -0,0 +1,9 @@ +key,type,encoding,value +fastbee-key,namespace,, +MQTTUrl,data,string,fastbee.cn:1883 +MQTTUsername,data,string,FastBee +MQTTPassword,data,string,P63653937TRQ8F27 +MQTTClientId,data,string,S&DCDA0C11FEBC&588&1 +UserId,data,string,1 +DeviceSN,data,string,DCDA0C11FEBC +ProductId,data,string,588 diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/fastbee.c b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/fastbee.c new file mode 100644 index 00000000..bd6a370c --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/fastbee.c @@ -0,0 +1,98 @@ +/********************************************************************* + * function: 设备交互 + * board: esp8266,esp32,esp32s2,esp32s3 core for esp-idf v4.4.7 + * source: https://gitee.com/zhuangpengli/IOTDeviceSDK + * copyright: zhuangpeng.li all rights reserved. + ********************************************************************/ +#include "fastbee.h" +#include "config.h" +#include "mqtt.h" + +#include "esp_log.h" +#include "dm_wrapper.h" + +static const char *TAG = "FASTBEE"; + +static void log_error_if_nonzero(const char *message, int error_code) +{ + if (error_code != 0) { + ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code); + } +} +/* + * @brief Event handler registered to receive MQTT events + * + * This function is called by the MQTT client event loop. + * + * @param handler_args user data registered to the event. + * @param base Event base for the handler(always MQTT Base in this example). + * @param event_id The id for the received event. + * @param event_data The data for the event, esp_mqtt_event_handle_t. + */ +static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) +{ + ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id); + esp_mqtt_event_handle_t event = event_data; + esp_mqtt_client_handle_t client = event->client; + int msg_id; + switch ((esp_mqtt_event_id_t)event_id) { + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); + subscribeTopic(client); + publishInfo(client); + break; + case MQTT_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); + break; + case MQTT_EVENT_SUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); + msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); + break; + case MQTT_EVENT_UNSUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_PUBLISHED: + ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_DATA: + ESP_LOGI(TAG, "MQTT_EVENT_DATA"); + printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); + printf("DATA=%.*s\r\n", event->data_len, event->data); + break; + case MQTT_EVENT_ERROR: + ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); + if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) { + log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err); + log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err); + log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno); + ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno)); + } + break; + default: + ESP_LOGI(TAG, "Other event id:%d", event->event_id); + break; + } +} + +static int fastbee_thread(void *paras){ + loadConfig(); + esp_mqtt_client_config_t mqtt_cfg = { + .uri = g_mqtt_url, + .client_id = g_mqtt_clientid, + .username = g_mqtt_username, + .password = g_mqtt_password, + }; + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); + /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */ + esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL); + esp_mqtt_client_start(client); + return 0; +} + +void fastbee_main(void *paras) +{ + while (1) { + fastbee_thread(NULL); + } +} \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/include/Config.h b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/include/Config.h new file mode 100644 index 00000000..00f7ce55 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/include/Config.h @@ -0,0 +1,58 @@ +/********************************************************************* + * function: 设备交互 + * board: esp8266,esp32,esp32s2,esp32s3 core for esp-idf v4.4.7 + * source: https://gitee.com/zhuangpengli/IOTDeviceSDK + * copyright: zhuangpeng.li all rights reserved. + ********************************************************************/ +#ifndef _CONFIG_H +#define _CONFIG_H +#include +#include +#include + +#define MQTT_URL_LEN (64) +#define MQTT_USERNAME_LEN (64) +#define MQTT_PASSWORD_LEN (64) +#define MQTT_CLIENTID_LEN (64) +#define USER_ID_LEN (16) +#define DEVICE_SN_LEN (64) +#define PRODUCT_ID_LEN (16) +#define MQTT_PREFIX_LEN (128) + +#define MFG_FASTBEE_PARTITION_NAME "fctry" +#define NVS_FASTBEE_PRODUCT "fastbee-key" + +extern char g_userId[USER_ID_LEN + 1]; // 用户ID +extern char g_productId[PRODUCT_ID_LEN + 1]; // 产品ID +extern char g_deviceSN[DEVICE_SN_LEN + 1]; // 设备编号(重要,同时是Mqtt的clientId) + +// Mqtt配置 +extern char g_mqtt_url[MQTT_URL_LEN + 1]; +extern char g_mqtt_username[MQTT_USERNAME_LEN + 1]; +extern char g_mqtt_password[MQTT_PASSWORD_LEN + 1]; +extern char g_mqtt_clientid[MQTT_CLIENTID_LEN + 1]; +extern char g_mqtt_prefix[MQTT_PREFIX_LEN + 1]; + +extern float rssi; // 信号强度(信号极好4格[-55— 0],信号好3格[-70— -55],信号一般2格[-85— -70],信号差1格[-100— -85]) +extern char wumei_iv[17]; // AES加密偏移量,固定值16位 +extern int monitorCount; // 发布监测数据的最大次数 +extern long monitorInterval; // 发布监测数据的间隔,默认1000毫秒 +extern bool isApMode; // 是否进入AP配网模式 + +/********************************** begin 可配置的项 **********************************/ +extern char *wifiSsid; // WIFI的SSID +extern char *wifiPwd; // WIFI的密码 + +extern char *authCode; // 产品授权码,产品未启用时为空字符串 + +extern float firmwareVersion; // 固件版本 +extern float latitude; // 设备精度 +extern float longitude; // 设备维度 + +extern char mqttSecret[17]; // Mqtt秘钥,16位 +extern char *ntpServer; // NTP服务地址,用于获取当前时间 +/********************************** end 可配置的项 **********************************/ + +// 加载配置 +void loadConfig(); +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/include/Mqtt.h b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/include/Mqtt.h new file mode 100644 index 00000000..43c6f33a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/include/Mqtt.h @@ -0,0 +1,43 @@ +/********************************************************************* + * function: 设备交互 + * board: esp8266,esp32,esp32s2,esp32s3 core for esp-idf v4.4.7 + * source: https://gitee.com/zhuangpengli/IOTDeviceSDK + * copyright: zhuangpeng.li all rights reserved. + ********************************************************************/ +#ifndef _FASTBEE_MQTT_H +#define _FASTBEE_MQTT_H + +#include "mqtt_client.h" +// 订阅的主题 +extern char *sInfoTopic; // 订阅设备信息 +extern char *sOtaTopic; // 订阅OTA升级 +extern char *sNtpTopic; // 订阅NTP时间 +extern char *sPropertyTopic; // 订阅属性 +extern char *sFunctionTopic; // 订阅功能 +extern char *sPropertyOnline; // 订阅属性-在线模式 +extern char *sFunctionOnline; // 订阅功能-在线模式 +extern char *sMonitorTopic; // 订阅实时监测 +// 发布的主题 +extern char *pInfoTopic; // 发布设备信息 +extern char *pNtpTopic; // 发布NTP时间 +extern char *pPropertyTopic; // 发布属性 +extern char *pFunctionTopic; // 发布功能 +extern char *pMonitorTopic; // 发布实时监测数据 +extern char *pEventTopic; // 发布事件 + +// 订阅系统主题 +void subscribeTopic(esp_mqtt_client_handle_t client); +// 发布设备信息 +void publishInfo(esp_mqtt_client_handle_t client); +// 发布时钟同步信息 +void publishNtp(esp_mqtt_client_handle_t client); +// 发布事件 +void publishEvent(esp_mqtt_client_handle_t client, const char *msg); +// 发布实时监测数据(不会存储,需要实时存储则发布属性) +void publishMonitor(esp_mqtt_client_handle_t client, const char *msg); +// 发布属性 +void publishProperty(esp_mqtt_client_handle_t client, const char *msg); +// 发布功能 +void publishFunction(esp_mqtt_client_handle_t client, const char *msg); + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/include/fastbee.h b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/include/fastbee.h new file mode 100644 index 00000000..f9783525 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/fastbee/include/fastbee.h @@ -0,0 +1,12 @@ +/********************************************************************* + * function: 设备交互 + * board: esp8266,esp32,esp32s2,esp32s3 core for esp-idf v4.4.7 + * source: https://gitee.com/zhuangpengli/IOTDeviceSDK + * copyright: zhuangpeng.li all rights reserved. + ********************************************************************/ +#ifndef _FASTBEE_H +#define _FASTBEE_H + +void fastbee_main(void *paras); + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/CMakeLists.txt b/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/CMakeLists.txt new file mode 100644 index 00000000..f6119229 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/CMakeLists.txt @@ -0,0 +1,7 @@ +set(COMPONENT_ADD_INCLUDEDIRS .) + +set(COMPONENT_SRCS "lightbulb.c") + +set(COMPONENT_REQUIRES) + +register_component() diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/component.mk b/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/component.mk new file mode 100644 index 00000000..a82220a1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS := ./ +COMPONENT_SRCDIRS := ./ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/lightbulb.c b/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/lightbulb.c new file mode 100644 index 00000000..59a15d9f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/lightbulb.c @@ -0,0 +1,327 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include +#include + +#ifdef CONFIG_IDF_TARGET_ESP8266 +#include "driver/pwm.h" +#else +#include "driver/ledc.h" +#endif +#include "esp_log.h" + +typedef struct rgb { + uint8_t r; // 0-100 % + uint8_t g; // 0-100 % + uint8_t b; // 0-100 % +} rgb_t; + + +typedef struct hsp { + uint16_t h; // 0-360 + uint16_t s; // 0-100 + uint16_t b; // 0-100 +} hsp_t; + +/* LED numbers below are for ESP-WROVER-KIT */ +/* Red LED */ +#define LEDC_IO_0 (0) +/* Green LED */ +#define LEDC_IO_1 (2) +/* Blued LED */ +#define LEDC_IO_2 (4) + +#define PWM_DEPTH (1023) +#define PWM_TARGET_DUTY 8192 + +static hsp_t s_hsb_val; +static uint16_t s_brightness; +static bool s_on = false; + +static const char *TAG = "lightbulb"; + +#ifdef CONFIG_IDF_TARGET_ESP8266 +#define PWM_PERIOD (500) +#define PWM_IO_NUM 3 + +// pwm pin number +const uint32_t pin_num[PWM_IO_NUM] = { + LEDC_IO_0, + LEDC_IO_1, + LEDC_IO_2 +}; + +// dutys table, (duty/PERIOD)*depth +uint32_t duties[PWM_IO_NUM] = { + 250, 250, 250, +}; + +// phase table, (phase/180)*depth +int16_t phase[PWM_IO_NUM] = { + 0, 0, 50, +}; + +#define LEDC_CHANNEL_0 0 +#define LEDC_CHANNEL_1 1 +#define LEDC_CHANNEL_2 2 + +#endif + +/** + * @brief transform lightbulb's "RGB" and other parameter + */ +static void lightbulb_set_aim(uint32_t r, uint32_t g, uint32_t b, uint32_t cw, uint32_t ww, uint32_t period) +{ +#ifdef CONFIG_IDF_TARGET_ESP8266 + pwm_stop(0x3); + pwm_set_duty(LEDC_CHANNEL_0, r); + pwm_set_duty(LEDC_CHANNEL_1, g); + pwm_set_duty(LEDC_CHANNEL_2, b); + pwm_start(); +#else + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, r); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, g); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, b); + ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); + ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1); + ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2); +#endif +} + +/** + * @brief transform lightbulb's "HSV" to "RGB" + */ +static bool lightbulb_set_hsb2rgb(uint16_t h, uint16_t s, uint16_t v, rgb_t *rgb) +{ + bool res = true; + uint16_t hi, F, P, Q, T; + + if (!rgb) + return false; + + if (h > 360) return false; + if (s > 100) return false; + if (v > 100) return false; + + hi = (h / 60) % 6; + F = 100 * h / 60 - 100 * hi; + P = v * (100 - s) / 100; + Q = v * (10000 - F * s) / 10000; + T = v * (10000 - s * (100 - F)) / 10000; + + switch (hi) { + case 0: + rgb->r = v; + rgb->g = T; + rgb->b = P; + break; + case 1: + rgb->r = Q; + rgb->g = v; + rgb->b = P; + break; + case 2: + rgb->r = P; + rgb->g = v; + rgb->b = T; + break; + case 3: + rgb->r = P; + rgb->g = Q; + rgb->b = v; + break; + case 4: + rgb->r = T; + rgb->g = P; + rgb->b = v; + break; + case 5: + rgb->r = v; + rgb->g = P; + rgb->b = Q; + break; + default: + return false; + } + return res; +} + +/** + * @brief set the lightbulb's "HSV" + */ +static bool lightbulb_set_aim_hsv(uint16_t h, uint16_t s, uint16_t v) +{ + rgb_t rgb_tmp; + bool ret = lightbulb_set_hsb2rgb(h, s, v, &rgb_tmp); + + if (ret == false) + return false; + + lightbulb_set_aim(rgb_tmp.r * PWM_TARGET_DUTY / 100, rgb_tmp.g * PWM_TARGET_DUTY / 100, + rgb_tmp.b * PWM_TARGET_DUTY / 100, (100 - s) * 5000 / 100, v * 2000 / 100, 1000); + + return true; +} + +/** + * @brief update the lightbulb's state + */ +static void lightbulb_update() +{ + lightbulb_set_aim_hsv(s_hsb_val.h, s_hsb_val.s, s_hsb_val.b); +} + + +/** + * @brief initialize the lightbulb lowlevel module + */ +void lightbulb_init(void) +{ +#ifdef CONFIG_IDF_TARGET_ESP8266 + pwm_init(PWM_PERIOD, duties, PWM_IO_NUM, pin_num); + pwm_set_channel_invert(0x1 << 0); + pwm_set_phases(phase); + pwm_start(); +#else + // enable ledc module + periph_module_enable(PERIPH_LEDC_MODULE); + + // config the timer + ledc_timer_config_t ledc_timer = { + //set timer counter bit number + .bit_num = LEDC_TIMER_13_BIT, + //set frequency of pwm + .freq_hz = 5000, + //timer mode, + .speed_mode = LEDC_LOW_SPEED_MODE, + //timer index + .timer_num = LEDC_TIMER_0 + }; + ledc_timer_config(&ledc_timer); + + //config the channel + ledc_channel_config_t ledc_channel = { + //set LEDC channel 0 + .channel = LEDC_CHANNEL_0, + //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1) + .duty = 100, + //GPIO number + .gpio_num = LEDC_IO_0, + //GPIO INTR TYPE, as an example, we enable fade_end interrupt here. + .intr_type = LEDC_INTR_FADE_END, + //set LEDC mode, from ledc_mode_t + .speed_mode = LEDC_LOW_SPEED_MODE, + //set LEDC timer source, if different channel use one timer, + //the frequency and bit_num of these channels should be the same + .timer_sel = LEDC_TIMER_0 + }; + //set the configuration + ledc_channel_config(&ledc_channel); + + //config ledc channel1 + ledc_channel.channel = LEDC_CHANNEL_1; + ledc_channel.gpio_num = LEDC_IO_1; + ledc_channel_config(&ledc_channel); + //config ledc channel2 + ledc_channel.channel = LEDC_CHANNEL_2; + ledc_channel.gpio_num = LEDC_IO_2; + ledc_channel_config(&ledc_channel); +#endif +} + +/** + * @brief deinitialize the lightbulb's lowlevel module + */ +void lightbulb_deinit(void) +{ +#ifdef CONFIG_IDF_TARGET_ESP8266 +#else + ledc_stop(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0); + ledc_stop(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0); + ledc_stop(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 0); +#endif +} + +/** + * @brief turn on/off the lowlevel lightbulb + */ +int lightbulb_set_on(bool value) +{ + ESP_LOGI(TAG, "lightbulb_set_on : %s", value == true ? "true" : "false"); + + if (value == true) { + s_hsb_val.b = s_brightness; + s_on = true; + } else { + s_brightness = s_hsb_val.b; + s_hsb_val.b = 0; + s_on = false; + } + lightbulb_update(); + + return 0; +} + +/** + * @brief set the saturation of the lowlevel lightbulb + */ +int lightbulb_set_saturation(float value) +{ + ESP_LOGI(TAG, "lightbulb_set_saturation : %f", value); + + s_hsb_val.s = value; + if (true == s_on) + lightbulb_update(); + + return 0; +} + +/** + * @brief set the hue of the lowlevel lightbulb + */ +int lightbulb_set_hue(float value) +{ + ESP_LOGI(TAG, "lightbulb_set_hue : %f", value); + + s_hsb_val.h = value; + if (true == s_on) + lightbulb_update(); + + return 0; +} + +/** + * @brief set the brightness of the lowlevel lightbulb + */ +int lightbulb_set_brightness(int value) +{ + ESP_LOGI(TAG, "lightbulb_set_brightness : %d", value); + + s_hsb_val.b = value; + s_brightness = s_hsb_val.b; + if (true == s_on) + lightbulb_update(); + + return 0; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/lightbulb.h b/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/lightbulb.h new file mode 100644 index 00000000..700b0c15 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/lightbulb.h @@ -0,0 +1,89 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef _LIGHTBULB_H_ +#define _LIGHTBULB_H_ + +#include + +/** + * @brief initialize the lightbulb lowlevel module + * + * @param none + * + * @return none + */ +void lightbulb_init(void); + +/** + * @brief deinitialize the lightbulb's lowlevel module + * + * @param none + * + * @return none + */ +void lightbulb_deinit(void); + +/** + * @brief turn on/off the lowlevel lightbulb + * + * @param value The "On" value + * + * @return none + */ +int lightbulb_set_on(bool value); + +/** + * @brief set the saturation of the lowlevel lightbulb + * + * @param value The Saturation value + * + * @return + * - 0 : OK + * - others : fail + */ +int lightbulb_set_saturation(float value); + +/** + * @brief set the hue of the lowlevel lightbulb + * + * @param value The Hue value + * + * @return + * - 0 : OK + * - others : fail + */ +int lightbulb_set_hue(float value); + +/** + * @brief set the brightness of the lowlevel lightbulb + * + * @param value The Brightness value + * + * @return + * - 0 : OK + * - others : fail + */ +int lightbulb_set_brightness(int value); + +#endif /* _LIGHTBULB_H_ */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/linkkit_handle/CMakeLists.txt b/sdk/ESP-IDF/esp_fastbee_aliyun/components/linkkit_handle/CMakeLists.txt new file mode 100644 index 00000000..52977f03 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/linkkit_handle/CMakeLists.txt @@ -0,0 +1,7 @@ +set(COMPONENT_ADD_INCLUDEDIRS .) + +set(COMPONENT_SRCS "linkkit_solo.c") + +set(COMPONENT_REQUIRES "esp-aliyun" "json" "lightbulb") + +register_component() diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/linkkit_handle/component.mk b/sdk/ESP-IDF/esp_fastbee_aliyun/components/linkkit_handle/component.mk new file mode 100644 index 00000000..a82220a1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/linkkit_handle/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS := ./ +COMPONENT_SRCDIRS := ./ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/linkkit_handle/linkkit_solo.c b/sdk/ESP-IDF/esp_fastbee_aliyun/components/linkkit_handle/linkkit_solo.c new file mode 100644 index 00000000..cf5a1912 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/linkkit_handle/linkkit_solo.c @@ -0,0 +1,468 @@ + +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "infra_config.h" + +void HAL_Printf(const char *fmt, ...); +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); + +#ifdef DEPRECATED_LINKKIT +#include "solo.c" +#else +#include +#include +#include +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_compat.h" +#include "infra_compat.h" +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" +#endif +#include "dev_model_api.h" +#include "dm_wrapper.h" +#include "cJSON.h" +#ifdef ATM_ENABLED + #include "at_api.h" +#endif + +#include "lightbulb.h" +#include "esp_log.h" + +static const char* TAG = "linkkit_example_solo"; + +#define EXAMPLE_TRACE(...) \ + do { \ + HAL_Printf("\033[1;32;40m%s.%d: ", __func__, __LINE__); \ + HAL_Printf(__VA_ARGS__); \ + HAL_Printf("\033[0m\r\n"); \ + } while (0) + +#define EXAMPLE_MASTER_DEVID (0) +#define EXAMPLE_YIELD_TIMEOUT_MS (200) + +typedef struct { + int master_devid; + int cloud_connected; + int master_initialized; +} user_example_ctx_t; + +/** + * These PRODUCT_KEY|PRODUCT_SECRET|DEVICE_NAME|DEVICE_SECRET are listed for demo only + * + * When you created your own devices on iot.console.com, you SHOULD replace them with what you got from console + * + */ + +char PRODUCT_KEY[IOTX_PRODUCT_KEY_LEN + 1] = {0}; +char PRODUCT_SECRET[IOTX_PRODUCT_SECRET_LEN + 1] = {0}; +char DEVICE_NAME[IOTX_DEVICE_NAME_LEN + 1] = {0}; +char DEVICE_SECRET[IOTX_DEVICE_SECRET_LEN + 1] = {0}; + +static user_example_ctx_t g_user_example_ctx; + +/** Awss Status event callback */ +static int user_awss_status_event_handler(int status) +{ + EXAMPLE_TRACE("Awss Status %d", status); + + return SUCCESS_RETURN; +} + +/** cloud connected event callback */ +static int user_connected_event_handler(void) +{ + EXAMPLE_TRACE("Cloud Connected"); + g_user_example_ctx.cloud_connected = 1; + + return 0; +} + +/** cloud connect fail event callback */ +static int user_connect_fail_event_handler(void) +{ + EXAMPLE_TRACE("Cloud Connect Fail"); + + return SUCCESS_RETURN; +} + +/** cloud disconnected event callback */ +static int user_disconnected_event_handler(void) +{ + EXAMPLE_TRACE("Cloud Disconnected"); + g_user_example_ctx.cloud_connected = 0; + + return 0; +} + +/** cloud raw_data arrived event callback */ +static int user_rawdata_arrived_event_handler(const int devid, const unsigned char *request, const int request_len) +{ + EXAMPLE_TRACE("Cloud Rawdata Arrived"); + + return 0; +} + +/* device initialized event callback */ +static int user_initialized(const int devid) +{ + EXAMPLE_TRACE("Device Initialized"); + g_user_example_ctx.master_initialized = 1; + + return 0; +} + +/** recv property post response message from cloud **/ +static int user_report_reply_event_handler(const int devid, const int msgid, const int code, const char *reply, + const int reply_len) +{ + EXAMPLE_TRACE("Message Post Reply Received, Message ID: %d, Code: %d, Reply: %.*s", msgid, code, + reply_len, + (reply == NULL)? ("NULL") : (reply)); + return 0; +} + +/** recv event post response message from cloud **/ +static int user_trigger_event_reply_event_handler(const int devid, const int msgid, const int code, const char *eventid, + const int eventid_len, const char *message, const int message_len) +{ + EXAMPLE_TRACE("Trigger Event Reply Received, Message ID: %d, Code: %d, EventID: %.*s, Message: %.*s", + msgid, code, + eventid_len, + eventid, message_len, message); + + return 0; +} + +static int user_property_set_event_handler(const int devid, const char *request, const int request_len) +{ + int res = 0; + cJSON *root = NULL, *LightSwitch = NULL, *LightColor = NULL; + ESP_LOGI(TAG,"Property Set Received, Devid: %d, Request: %s", devid, request); + + lightbulb_set_brightness(78); + lightbulb_set_saturation(100); + + if (!request) { + return NULL_VALUE_ERROR; + } + + /* Parse Root */ + root = cJSON_Parse(request); + if (!root) { + ESP_LOGI(TAG,"JSON Parse Error"); + return FAIL_RETURN; + } + + /** Switch Lightbulb On/Off */ + LightSwitch = cJSON_GetObjectItem(root, "LightSwitch"); + if (LightSwitch) { + lightbulb_set_on(LightSwitch->valueint); + } + + /** Switch Lightbulb Hue */ + LightSwitch = cJSON_GetObjectItem(root, "RGBColor"); + if (LightSwitch) { + LightColor = cJSON_GetObjectItem(LightSwitch, "Red"); + lightbulb_set_hue(LightColor ? LightColor->valueint : 0); + LightColor = cJSON_GetObjectItem(LightSwitch, "Green"); + lightbulb_set_hue(LightColor ? LightColor->valueint : 120); + LightColor = cJSON_GetObjectItem(LightSwitch, "Blue"); + lightbulb_set_hue(LightColor ? LightColor->valueint : 240); + } + + cJSON_Delete(root); + + res = IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID, ITM_MSG_POST_PROPERTY, + (unsigned char *)request, request_len); + ESP_LOGI(TAG,"Post Property Message ID: %d", res); + + return SUCCESS_RETURN; +} + +static int user_property_desired_get_reply_event_handler(const char *serviceid, const int serviceid_len) +{ + ESP_LOGI(TAG, "ITE_PROPERTY_DESIRED_GET_REPLY"); + + return SUCCESS_RETURN; +} + +static int user_property_get_event_handler(const int devid, const char *serviceid, const int serviceid_len, char **response, int *response_len) +{ + ESP_LOGI(TAG,"Get Property Message ID: %d", devid); + + return SUCCESS_RETURN; +} + + +static int user_service_request_event_handler(const int devid, const char *serviceid, const int serviceid_len, + const char *request, const int request_len, + char **response, int *response_len) +{ + int contrastratio = 0, to_cloud = 0; + cJSON *root = NULL, *item_transparency = NULL, *item_from_cloud = NULL; + ESP_LOGI(TAG,"Service Request Received, Devid: %d, Service ID: %.*s, Payload: %s", devid, serviceid_len, + serviceid, + request); + + /* Parse Root */ + root = cJSON_Parse(request); + if (root == NULL || !cJSON_IsObject(root)) { + ESP_LOGI(TAG,"JSON Parse Error"); + return -1; + } + + if (strlen("Custom") == serviceid_len && memcmp("Custom", serviceid, serviceid_len) == 0) { + /* Parse Item */ + const char *response_fmt = "{\"Contrastratio\":%d}"; + item_transparency = cJSON_GetObjectItem(root, "transparency"); + if (item_transparency == NULL || !cJSON_IsNumber(item_transparency)) { + cJSON_Delete(root); + return -1; + } + ESP_LOGI(TAG,"transparency: %d", item_transparency->valueint); + contrastratio = item_transparency->valueint + 1; + + /* Send Service Response To Cloud */ + *response_len = strlen(response_fmt) + 10 + 1; + *response = malloc(*response_len); + if (*response == NULL) { + ESP_LOGW(TAG,"Memory Not Enough"); + return -1; + } + memset(*response, 0, *response_len); + snprintf(*response, *response_len, response_fmt, contrastratio); + *response_len = strlen(*response); + } else if (strlen("SyncService") == serviceid_len && memcmp("SyncService", serviceid, serviceid_len) == 0) { + /* Parse Item */ + const char *response_fmt = "{\"ToCloud\":%d}"; + item_from_cloud = cJSON_GetObjectItem(root, "FromCloud"); + if (item_from_cloud == NULL || !cJSON_IsNumber(item_from_cloud)) { + cJSON_Delete(root); + return -1; + } + ESP_LOGI(TAG,"FromCloud: %d", item_from_cloud->valueint); + to_cloud = item_from_cloud->valueint + 1; + + /* Send Service Response To Cloud */ + *response_len = strlen(response_fmt) + 10 + 1; + *response = malloc(*response_len); + if (*response == NULL) { + ESP_LOGW(TAG,"Memory Not Enough"); + return -1; + } + memset(*response, 0, *response_len); + snprintf(*response, *response_len, response_fmt, to_cloud); + *response_len = strlen(*response); + } + cJSON_Delete(root); + + return 0; +} + +static int user_timestamp_reply_event_handler(const char *timestamp) +{ + EXAMPLE_TRACE("Current Timestamp: %s", timestamp); + + return SUCCESS_RETURN; +} + +static int user_toplist_reply_event_handler(const int devid, const int msgid, const int code, const char *eventid, const int eventid_len) +{ + EXAMPLE_TRACE("ITE_TOPOLIST_REPLY"); + + return SUCCESS_RETURN; +} + +static int user_permit_join_event_handler(const int devid, const int msgid, const int code, const char *eventid, const int eventid_len) +{ + EXAMPLE_TRACE("ITE_PERMIT_JOIN"); + + return SUCCESS_RETURN; +} + +/** fota event handler **/ +static int user_fota_event_handler(int type, const char *version) +{ + char buffer[1024] = {0}; + int buffer_length = 1024; + + /* 0 - new firmware exist, query the new firmware */ + if (type == 0) { + EXAMPLE_TRACE("New Firmware Version: %s", version); + + IOT_Linkkit_Query(EXAMPLE_MASTER_DEVID, ITM_MSG_QUERY_FOTA_DATA, (unsigned char *)buffer, buffer_length); + } + + return 0; +} + +/* cota event handler */ +static int user_cota_event_handler(int type, const char *config_id, int config_size, const char *get_type, + const char *sign, const char *sign_method, const char *url) +{ + char buffer[128] = {0}; + int buffer_length = 128; + + /* type = 0, new config exist, query the new config */ + if (type == 0) { + EXAMPLE_TRACE("New Config ID: %s", config_id); + EXAMPLE_TRACE("New Config Size: %d", config_size); + EXAMPLE_TRACE("New Config Type: %s", get_type); + EXAMPLE_TRACE("New Config Sign: %s", sign); + EXAMPLE_TRACE("New Config Sign Method: %s", sign_method); + EXAMPLE_TRACE("New Config URL: %s", url); + + IOT_Linkkit_Query(EXAMPLE_MASTER_DEVID, ITM_MSG_QUERY_COTA_DATA, (unsigned char *)buffer, buffer_length); + } + + return 0; +} + +static int user_mqtt_connect_succ_event_handler(void) +{ + EXAMPLE_TRACE("ITE_MQTT_CONNECT_SUCC"); + + return SUCCESS_RETURN; +} + +static void user_post_property(void) +{ + static int cnt = 0; + int res = 0; + + char property_payload[30] = {0}; + HAL_Snprintf(property_payload, sizeof(property_payload), "{\"Counter\": %d}", cnt++); + + res = IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID, ITM_MSG_POST_PROPERTY, + (unsigned char *)property_payload, strlen(property_payload)); + + EXAMPLE_TRACE("Post Property Message ID: %d", res); +} + +static void user_post_event(void) +{ + int res = 0; + char *event_id = "HardwareError"; + char *event_payload = "{\"ErrorCode\": 0}"; + + res = IOT_Linkkit_TriggerEvent(EXAMPLE_MASTER_DEVID, event_id, strlen(event_id), + event_payload, strlen(event_payload)); + EXAMPLE_TRACE("Post Event Message ID: %d", res); +} + +static void user_deviceinfo_update(void) +{ + int res = 0; + char *device_info_update = "[{\"attrKey\":\"abc\",\"attrValue\":\"hello,world\"}]"; + + res = IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID, ITM_MSG_DEVICEINFO_UPDATE, + (unsigned char *)device_info_update, strlen(device_info_update)); + EXAMPLE_TRACE("Device Info Update Message ID: %d", res); +} + +static void user_deviceinfo_delete(void) +{ + int res = 0; + char *device_info_delete = "[{\"attrKey\":\"abc\"}]"; + + res = IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID, ITM_MSG_DEVICEINFO_DELETE, + (unsigned char *)device_info_delete, strlen(device_info_delete)); + EXAMPLE_TRACE("Device Info Delete Message ID: %d", res); +} + +static int linkkit_thread(void *paras) +{ + int res = 0; + iotx_linkkit_dev_meta_info_t master_meta_info; + int domain_type = 0, dynamic_register = 0, post_reply_need = 0; + +#ifdef ATM_ENABLED + if (IOT_ATM_Init() < 0) { + EXAMPLE_TRACE("IOT ATM init failed!\n"); + return -1; + } +#endif + + memset(&g_user_example_ctx, 0, sizeof(user_example_ctx_t)); + + HAL_GetProductKey(PRODUCT_KEY); + HAL_GetProductSecret(PRODUCT_SECRET); + HAL_GetDeviceName(DEVICE_NAME); + HAL_GetDeviceSecret(DEVICE_SECRET); + memset(&master_meta_info, 0, sizeof(iotx_linkkit_dev_meta_info_t)); + memcpy(master_meta_info.product_key, PRODUCT_KEY, strlen(PRODUCT_KEY)); + memcpy(master_meta_info.product_secret, PRODUCT_SECRET, strlen(PRODUCT_SECRET)); + memcpy(master_meta_info.device_name, DEVICE_NAME, strlen(DEVICE_NAME)); + memcpy(master_meta_info.device_secret, DEVICE_SECRET, strlen(DEVICE_SECRET)); + + /* Register Callback */ + IOT_RegisterCallback(ITE_AWSS_STATUS, user_awss_status_event_handler); + IOT_RegisterCallback(ITE_CONNECT_SUCC, user_connected_event_handler); + IOT_RegisterCallback(ITE_CONNECT_FAIL, user_connect_fail_event_handler); + IOT_RegisterCallback(ITE_DISCONNECTED, user_disconnected_event_handler); + IOT_RegisterCallback(ITE_RAWDATA_ARRIVED, user_rawdata_arrived_event_handler); + IOT_RegisterCallback(ITE_SERVICE_REQUEST, user_service_request_event_handler); + IOT_RegisterCallback(ITE_PROPERTY_SET, user_property_set_event_handler); + IOT_RegisterCallback(ITE_PROPERTY_GET, user_property_get_event_handler); + IOT_RegisterCallback(ITE_PROPERTY_DESIRED_GET_REPLY, user_property_desired_get_reply_event_handler); + IOT_RegisterCallback(ITE_REPORT_REPLY, user_report_reply_event_handler); + IOT_RegisterCallback(ITE_TRIGGER_EVENT_REPLY, user_trigger_event_reply_event_handler); + IOT_RegisterCallback(ITE_TIMESTAMP_REPLY, user_timestamp_reply_event_handler); + IOT_RegisterCallback(ITE_TOPOLIST_REPLY, user_toplist_reply_event_handler); + IOT_RegisterCallback(ITE_PERMIT_JOIN, user_permit_join_event_handler); + IOT_RegisterCallback(ITE_INITIALIZE_COMPLETED, user_initialized); + IOT_RegisterCallback(ITE_FOTA, user_fota_event_handler); + IOT_RegisterCallback(ITE_COTA, user_cota_event_handler); + IOT_RegisterCallback(ITE_MQTT_CONNECT_SUCC, user_mqtt_connect_succ_event_handler); + +#if CONFIG_MQTT_DIRECT + domain_type = IOTX_CLOUD_REGION_SHANGHAI; +#else + domain_type = IOTX_CLOUD_REGION_SINGAPORE; +#endif + + IOT_Ioctl(IOTX_IOCTL_SET_DOMAIN, (void *)&domain_type); + + /* Choose Login Method */ + dynamic_register = 0; + IOT_Ioctl(IOTX_IOCTL_SET_DYNAMIC_REGISTER, (void *)&dynamic_register); + + /* post reply doesn't need */ + post_reply_need = 1; + IOT_Ioctl(IOTX_IOCTL_RECV_EVENT_REPLY, (void *)&post_reply_need); + + /* Create Master Device Resources */ + g_user_example_ctx.master_devid = IOT_Linkkit_Open(IOTX_LINKKIT_DEV_TYPE_MASTER, &master_meta_info); + if (g_user_example_ctx.master_devid < 0) { + EXAMPLE_TRACE("IOT_Linkkit_Open Failed\n"); + return -1; + } + + /* Start Connect Aliyun Server */ + res = IOT_Linkkit_Connect(g_user_example_ctx.master_devid); + if (res < 0) { + EXAMPLE_TRACE("IOT_Linkkit_Connect Failed\n"); + IOT_Linkkit_Close(g_user_example_ctx.master_devid); + return -1; + } + + while (1) { + IOT_Linkkit_Yield(EXAMPLE_YIELD_TIMEOUT_MS); + } + + IOT_Linkkit_Close(g_user_example_ctx.master_devid); + + IOT_DumpMemoryStats(IOT_LOG_DEBUG); + IOT_SetLogLevel(IOT_LOG_NONE); + return 0; +} + +void linkkit_main(void *paras) +{ + while (1) { + linkkit_thread(NULL); + } +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/components/linkkit_handle/linkkit_solo.h b/sdk/ESP-IDF/esp_fastbee_aliyun/components/linkkit_handle/linkkit_solo.h new file mode 100644 index 00000000..eafc8fc9 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/components/linkkit_handle/linkkit_solo.h @@ -0,0 +1,29 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef _LINKKIT_SOLO_H__ +#define _LINKKIT_SOLO_H__ + +void linkkit_main(void *paras); + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/CMakeLists.txt b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/CMakeLists.txt new file mode 100644 index 00000000..4f9ae6c6 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/CMakeLists.txt @@ -0,0 +1,66 @@ +set(COMPONENT_PRIV_INCLUDEDIRS + iotkit-embedded/coap_server/CoAPPacket + iotkit-embedded/coap_server/server + iotkit-embedded/dev_bind/impl + iotkit-embedded/dev_bind/impl/os + iotkit-embedded/dev_bind/impl/awss_reset + iotkit-embedded/wifi_provision/dev_ap + iotkit-embedded/wifi_provision/frameworks + iotkit-embedded/wifi_provision/frameworks/aplist + iotkit-embedded/wifi_provision/frameworks/ieee80211 + iotkit-embedded/wifi_provision/frameworks/statics + iotkit-embedded/wifi_provision/frameworks/utils + iotkit-embedded/wifi_provision/p2p + iotkit-embedded/wifi_provision/phone_ap + iotkit-embedded/wifi_provision/router_ap + iotkit-embedded/wifi_provision/smartconfig + iotkit-embedded/wifi_provision/zero_config) + +set(COMPONENT_ADD_INCLUDEDIRS + conn_mgr + iotkit-embedded/coap_server + iotkit-embedded/dev_bind + iotkit-embedded/dev_model + iotkit-embedded/dev_sign + iotkit-embedded/dynamic_register + iotkit-embedded/mqtt + iotkit-embedded/ota + iotkit-embedded/infra + iotkit-embedded/wifi_provision + iotkit-embedded + wrappers) + +# Edit following two lines to set component requirements (see docs) +set(COMPONENT_REQUIRES "nvs_flash" "app_update" "esp-tls") +set(COMPONENT_PRIV_REQUIRES ) + +set(COMPONENT_SRCDIRS + conn_mgr + iotkit-embedded/certs + iotkit-embedded/dev_bind/impl + iotkit-embedded/dev_bind/impl/os + iotkit-embedded/dev_bind/impl/awss_reset + iotkit-embedded/dev_model + iotkit-embedded/dev_reset + iotkit-embedded/dev_sign + iotkit-embedded/dynamic_register + iotkit-embedded/infra + iotkit-embedded/mqtt + iotkit-embedded/ota + iotkit-embedded/wifi_provision/dev_ap + iotkit-embedded/wifi_provision/frameworks + iotkit-embedded/wifi_provision/frameworks/aplist + iotkit-embedded/wifi_provision/frameworks/ieee80211 + iotkit-embedded/wifi_provision/frameworks/statics + iotkit-embedded/wifi_provision/frameworks/utils + iotkit-embedded/wifi_provision/p2p + iotkit-embedded/wifi_provision/phone_ap + iotkit-embedded/wifi_provision/router_ap + iotkit-embedded/wifi_provision/smartconfig + iotkit-embedded/wifi_provision/zero_config + iotkit-embedded/coap_server/CoAPPacket + iotkit-embedded/coap_server/server + wrappers) + +register_component() +component_compile_options(-DAUTH_MODE_CERT) diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/Kconfig b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/Kconfig new file mode 100644 index 00000000..7599f3e2 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/Kconfig @@ -0,0 +1,143 @@ +menu "iotkit embedded" + + menu "Aliyun linkkit device version" + + config LINKKIT_FIRMWARE_VERSION + string "Device version" + default "0.0.1" + help + aliyun linkkit device version + endmenu + + menu "Aliyun linkkit awss config" + config AWSS_ENCRYPT_TYPE + int "Get the security level of the `smartconfig` service" + range 1 5 + default 3 + help + Get the security level of the `smartconfig` service + + config AWSS_CONN_ENCRYPT_TYPE + int "Get Security level for wifi configuration with connection.Used for AP solution of router and App" + range 3 5 + default 4 + help + Get Security level for wifi configuration with connection.Used for AP solution of router and App + + config AWSS_TIMEOUT_INTERVAL_MS + int "Get the timeout period of the distribution service (`AWSS`), in milliseconds" + range 0 1800000 + default 180000 + help + Get the timeout period of the distribution service (`AWSS`), in milliseconds + + config AWSS_CHANNELSCAN_INTERVAL_MS + int "Get the length of time scanned on each channel (`channel`), in milliseconds" + range 0 1000 + default 200 + help + Get the length of time scanned on each channel (`channel`), in milliseconds + endmenu + + menu "Aliyun linkkit network config" + config SUPPORT_TCP + bool "Enable tcp connection" + default n + help + Select this option to enable tcp connection + + config TCP_ESTABLISH_TIMEOUT_MS + int "Device tcp connection timeout wait time milliseconds" + range 0 100000 + default 10000 + help + Device tcp connection timeout wait time milliseconds + + config TLS_ESTABLISH_TIMEOUT_MS + int "Device tls connection timeout wait time milliseconds" + range 0 100000 + default 10000 + help + Device tls connection timeout wait time milliseconds + endmenu + + menu "Aliyun linkkit device model config" + config DEVICE_MODEL_GATEWAY + bool "Enable device model gateway" + default n + help + Select this option to enable device model gateway + endmenu + + menu "Aliyun linkkit local control" + config DEVICE_ALCS_ENABLE + bool "Enable device local control" + default n + help + Select this option to enable device local control + endmenu + + menu "Aliyun linkkit security OTA" + config SUPPORT_SECURITY_OTA + bool "Enable Security OTA" + default n + help + Select this option to enable security ota + endmenu + + menu "Aliyun linkkit dynamic register" + config DYNAMIC_REGISTER + bool "Enable dynamic register" + default y + help + Select this option to enable dynamic register + endmenu + + menu "Aliyun linkkit mqtt config" + config MQTT_DIRECT + bool "MQTT DIRECT" + default y + help + Directly connect MQTT server without perform HTTP authenticate to another HTTP server ahead + + Switching to "y" leads to connect MQTT server directly and MQTT_DIRECT included into CFLAGS + Switching to "n" leads to legacy authenticate mode: connnect HTTP server first, then connect MQTT server afterwards + endmenu + +config HAL_SEM_MAX_COUNT + int "The maximum count value that can be reached of the semaphore" + default 255 + range 0 255 + help + The recommended value of maximum count of the semaphore is 255 + +config HAL_SEM_INIT_COUNT + int "The count value assigned to the semaphore when it is created" + default 0 + range 0 10 + help + The recommended value of count of the semaphore is 0 +config HAL_TLS_HANDSHAKE_TIMEOUT + int "TLS Handsake Timeout" + default 180 + range 0 65535 + help + Default TLS handshake timeout to host in seconds +config HAL_USE_CUSTOMER_AP_SSID + bool "Enable use customer softap SSID" + default n + help + Select this option to enable use customer softap SSID +config AP_SSID_KEY + string "AP SSID KV Key value" + default "apssid" + help + The KV key value which store AP SSID + +config USE_SOFTAP_CONFIG + bool "Use softap config in smart light example" + default n + help + smart light example will use softap config when enable this option. Otherwise use smartconfig. + +endmenu diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/component.mk b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/component.mk new file mode 100644 index 00000000..ce30a408 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/component.mk @@ -0,0 +1,65 @@ +# Makefile +COMPONENT_ADD_LDFLAGS += -u ota_pubn_buf +COMPONENT_PRIV_INCLUDEDIRS := \ +iotkit-embedded/coap_server/CoAPPacket \ +iotkit-embedded/coap_server/server \ +iotkit-embedded/dev_bind/impl \ +iotkit-embedded/dev_bind/impl/os \ +iotkit-embedded/dev_bind/impl/awss_reset \ +iotkit-embedded/wifi_provision/dev_ap \ +iotkit-embedded/wifi_provision/frameworks \ +iotkit-embedded/wifi_provision/frameworks/aplist \ +iotkit-embedded/wifi_provision/frameworks/ieee80211 \ +iotkit-embedded/wifi_provision/frameworks/statics \ +iotkit-embedded/wifi_provision/frameworks/utils \ +iotkit-embedded/wifi_provision/p2p \ +iotkit-embedded/wifi_provision/phone_ap \ +iotkit-embedded/wifi_provision/router_ap \ +iotkit-embedded/wifi_provision/smartconfig \ +iotkit-embedded/wifi_provision/zero_config + +COMPONENT_ADD_INCLUDEDIRS := \ +conn_mgr \ +iotkit-embedded/atm \ +iotkit-embedded/coap_server \ +iotkit-embedded/dev_bind \ +iotkit-embedded/dev_model \ +iotkit-embedded/dev_sign \ +iotkit-embedded/dynamic_register \ +iotkit-embedded/mqtt \ +iotkit-embedded/ota \ +iotkit-embedded/infra \ +iotkit-embedded/wifi_provision \ +iotkit-embedded \ +wrappers + +COMPONENT_SRCDIRS := \ +conn_mgr \ +iotkit-embedded/atm \ +iotkit-embedded/certs \ +iotkit-embedded/dev_bind/impl \ +iotkit-embedded/dev_bind/impl/os \ +iotkit-embedded/dev_bind/impl/awss_reset \ +iotkit-embedded/dev_model \ +iotkit-embedded/dev_reset \ +iotkit-embedded/dev_sign \ +iotkit-embedded/dynamic_register \ +iotkit-embedded/infra \ +iotkit-embedded/mqtt \ +iotkit-embedded/ota \ +iotkit-embedded/wifi_provision/dev_ap \ +iotkit-embedded/wifi_provision/frameworks \ +iotkit-embedded/wifi_provision/frameworks/aplist \ +iotkit-embedded/wifi_provision/frameworks/ieee80211 \ +iotkit-embedded/wifi_provision/frameworks/statics \ +iotkit-embedded/wifi_provision/frameworks/utils \ +iotkit-embedded/wifi_provision/p2p \ +iotkit-embedded/wifi_provision/phone_ap \ +iotkit-embedded/wifi_provision/router_ap \ +iotkit-embedded/wifi_provision/smartconfig \ +iotkit-embedded/wifi_provision/zero_config \ +iotkit-embedded/coap_server/CoAPPacket \ +iotkit-embedded/coap_server/server \ +wrappers + +CFLAGS += -Wno-char-subscripts diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/config/mass_mfg/README.md b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/config/mass_mfg/README.md new file mode 100644 index 00000000..bcc92e14 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/config/mass_mfg/README.md @@ -0,0 +1,87 @@ +# 量产说明 +aliyun 在使用一机一密的情况下,需要在每个设备上烧写与设备对应的 ProductKey、ProductSecret、DeviceName、DeviceSecret。 + +为了使烧录和软件读取流程尽量简化,我们将使用 IDF 的 NVS 分区功能,将 ProductKey、ProductSecret、DeviceName、DeviceSecret 信息通过 NVS 分区生成工具或量产工具生成对应的 NVS 分区,该分区中利用 NVS 结构保存了 ProductKey、ProductSecret、DeviceName、DeviceSecret 的键值对。生成后的 NVS 分区 bin 可以通过 esptool 或其他烧写工具直接烧录到 NVS 分区对应的起始扇区,partition 分区表中指明了该 NVS 分区的起始地址。软件可以通过 NVS 相关接口读取到 ProductKey、ProductSecret、DeviceName、DeviceSecret 的具体值。 + +请参照 partitions_esp32.csv 和 partitions_esp8266.csv 中 fctry 的起始地址进行烧录,也可根据实际项目对 partitions 进行调整,但一定要保证 partitons 中 fctry 的实际地址与烧录地址保持吻合。 + +关于 NVS、NVS 分区生成工具、量产工具,请参考: +- [NVS](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/nvs_flash.html) +- [NVS 分区生成工具](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/nvs_partition_gen.html) +- [量产工具](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/mass_mfg.html) + +## 单个 bin 生成 +在调试过程中,建议使用该方式。 + +mass_mfg 目录中有一参考配置:single_mfg_config.csv,请拷贝成自己的配置文件,如 my_single_mfg_config.csv。 +``` +cp single_mfg_config.csv my_single_mfg_config.csv +``` + +使用自己的 ProductKey、ProductSecret、DeviceName、DeviceSecret 对 my_single_mfg_config.csv 进行修改: +``` +key,type,encoding,value +aliyun-key,namespace,, +DeviceName,data,string,config +DeviceSecret,data,string,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh +ProductKey,data,string,a10BnLLzGv4 +ProductSecret,data,string,pVfLpS1u3A9JM0go +``` + +将 config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go 修改为你对应的值。 + +修改完成后,使用如下命令生成对应的 NVS 分区: +``` +$IDF_PATH/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py --input single_mfg_config.csv --output single_mfg.bin --size 0x4000 +python nvs_partition_gen.py generate single_mfg_config.csv single_mfg.bin 0x4000 +``` +如针对 esp8266 平台,请使用如下命令: +``` +$IDF_PATH/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py --input my_single_mfg_config.csv --output my_single_mfg.bin --size 0x4000 +``` +> 说明:esp8266 的 NVS 格式当前为 v1, 默认已设置。 + +可以使用 esptool 工具将生成的包含秘钥的 NVS 分区烧入对应的 sector,针对 example 中默认提供的 partitions,esp32 和 esp8266 将烧写到不同的分区,其中 esp32 的默认烧录地址为 0x210000,esp8266 的默认烧录地址为 0x100000。 + +针对 esp32: +``` +$IDF_PATH/components/esptool_py/esptool/esptool.py write_flash 0x210000 my_single_mfg.bin +``` + +针对 esp8266: +``` +$IDF_PATH/components/esptool_py/esptool/esptool.py --port /dev/ttyUSB0 write_flash 0x100000 my_single_mfg.bin +``` + +> 注,当前 esp32 默认使用 4MB 的模组,esp8266 默认使用 2MB 的模组,如使用其他大小的 Flash,请适当调整 partitions 分区表,并确认烧写地址。 + +## 多个 bin 批量生成 +量产过程中如采用以上方法单个生成对应的 NVS 分区会很繁琐,因此采用 IDF 中的量产工具,该量产工具也是基于 NVS 分区生成工具的扩充。 + +mass_mfg 目录中提供了一套参考的配置,其中 multipule_mfg_config.csv 为参数区配置文件,已做好针对 aliyun 的配置,用户无需修改,multipule_mfg_values.csv 中可以包含所有需要生成 NVS 分区的 ProductKey、ProductSecret、DeviceName、DeviceSecret 信息,请将 multipule_mfg_values.csv 复制为 my_multipule_mfg_values.csv 并对该文件进行修改,包含所有希望用于量产的 ProductKey、ProductSecret、DeviceName、DeviceSecret 信息。 + +my_multipule_mfg_values.csv 中内容如下: +``` +id,DeviceName,DeviceSecret,ProductKey,ProductSecret +1,config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go +2,config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go +3,config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go +``` + +每一行代表了一组秘钥信息,第一列的为 id 信息,不会生成到对应的 NVS 分区中,仅用作标号。 + +采用如下命令批量生成 NVS 分区。 + +针对 esp32: +``` +$IDF_PATH/tools/mass_mfg/mfg_gen.py --conf multipule_mfg_config.csv --values my_multipule_mfg_values.csv --prefix Fan --size 0x4000 +``` + +针对 esp8266: +``` +$IDF_PATH/tools/mass_mfg/mfg_gen.py --conf multipule_mfg_config.csv --values my_multipule_mfg_values.csv --prefix Fan --size 0x4000 --version v1 +``` + +其中 --prefix 为生成的批量文件的前缀名称,可以修改为所需要的产品名称。执行完成后,会在当前目录下生成一 bin 目录,里面保持了所有可用于量产的 NVS 分区 bin。 + +> 注,当前不知道 aliyun 能否批量导出 ProductKey、ProductSecret、DeviceName、DeviceSecret,如有需要,可以编写特定脚本来生成 my_multipule_mfg_values.csv。 \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/config/mass_mfg/multipule_mfg_config.csv b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/config/mass_mfg/multipule_mfg_config.csv new file mode 100644 index 00000000..95fc4c2f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/config/mass_mfg/multipule_mfg_config.csv @@ -0,0 +1,5 @@ +aliyun-key,namespace, +DeviceName,data,string +DeviceSecret,data,string +ProductKey,data,string +ProductSecret,data,string \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/config/mass_mfg/multipule_mfg_values.csv b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/config/mass_mfg/multipule_mfg_values.csv new file mode 100644 index 00000000..1aa970b6 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/config/mass_mfg/multipule_mfg_values.csv @@ -0,0 +1,4 @@ +id,DeviceName,DeviceSecret,ProductKey,ProductSecret +1,config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go +2,config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go +3,config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/config/mass_mfg/single_mfg_config.csv b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/config/mass_mfg/single_mfg_config.csv new file mode 100644 index 00000000..d81b3660 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/config/mass_mfg/single_mfg_config.csv @@ -0,0 +1,6 @@ +key,type,encoding,value +aliyun-key,namespace,, +DeviceName,data,string,DCDA0C11FEBC +DeviceSecret,data,string,8eb157145f057600459e9b7245beb59f +ProductKey,data,string,a1LCAxGhf7h +ProductSecret,data,string,c119juI2ruCDg3A7 \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/conn_mgr/conn_mgr.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/conn_mgr/conn_mgr.c new file mode 100644 index 00000000..d58492e4 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/conn_mgr/conn_mgr.c @@ -0,0 +1,415 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + +#include "esp_err.h" +#include "esp_event_loop.h" +#include "esp_log.h" +#include "esp_wifi.h" + +#include "lwip/apps/sntp.h" + +#include "wifi_provision_api.h" +#include "dm_wrapper.h" + +#include "conn_mgr.h" + +static const char *TAG = "conn_mgr"; + +static system_event_cb_t hal_wifi_system_cb; + +static esp_err_t conn_mgr_wifi_connect(void) +{ + wifi_config_t wifi_config = {0}; + int ssid_len = sizeof(wifi_config.sta.ssid); + int password_len = sizeof(wifi_config.sta.password); + + int ret = HAL_Kv_Get(STA_SSID_KEY, wifi_config.sta.ssid, &ssid_len); + ESP_LOGI(TAG, "HAL_Kv_Get STA_SSID_KEY: %s ", wifi_config.sta.ssid); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to get stored SSID"); + return ESP_FAIL; + } + + /* Even if the password is not found, it is not an error, as it could be an open network */ + ret = HAL_Kv_Get(STA_PASSWORD_KEY, wifi_config.sta.password, &password_len); + ESP_LOGI(TAG, "HAL_Kv_Get STA_PASSWORD_KEY: %s ", wifi_config.sta.password); + if (ret != ESP_OK) { + ESP_LOGW(TAG, "Failed to get stored Password"); + password_len = 0; + } + + esp_wifi_set_mode(WIFI_MODE_STA); + esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config); + esp_wifi_start(); + esp_wifi_connect(); + + return ESP_OK; +} + +static esp_err_t conn_mgr_save_wifi_config(void) +{ + wifi_config_t wifi_config = {0}; + + esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_config); + + /* Do not save hotspot or router APs. */ + if (strcmp((char *)(wifi_config.sta.ssid), HOTSPOT_AP) == 0 || + strcmp((char *)(wifi_config.sta.ssid), ROUTER_AP) == 0) { + ESP_LOGI(TAG, "Do not save hotspot or router APs: %s", wifi_config.sta.ssid); + return ESP_FAIL; + } + + int ret = HAL_Kv_Set(STA_SSID_KEY, wifi_config.sta.ssid, sizeof(wifi_config.sta.ssid), 0); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "%s key store failed with %d", STA_SSID_KEY, ret); + return ESP_FAIL; + } + + /* Password may be NULL. Save, only if it is given */ + if (wifi_config.sta.password[0] != 0) { + ret = HAL_Kv_Set(STA_PASSWORD_KEY, wifi_config.sta.password, sizeof(wifi_config.sta.password), 0); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "%s key store failed with %d", STA_PASSWORD_KEY, ret); + return ESP_FAIL; + } + } + + return ESP_OK; +} + +static esp_err_t conn_mgr_obtain_time(void) +{ + static bool get_time_flag = false; + if (get_time_flag) { + return ESP_OK; + } + + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_setservername(0, "ntp1.aliyun.com"); + sntp_setservername(1, "ntp2.aliyun.com"); + sntp_setservername(2, "ntp3.aliyun.com"); + sntp_init(); + + time_t now = 0; + struct tm timeinfo = { 0 }; + int sntp_retry_cnt = 0; + int sntp_retry_time = 0; + while (1) { + for (int32_t i = 0; (i < (SNTP_RECV_TIMEOUT / 100)) && timeinfo.tm_year < (2019 - 1900); i ++) { + vTaskDelay(100 / portTICK_RATE_MS); + time(&now); + localtime_r(&now, &timeinfo); + } + + if (timeinfo.tm_year < (2019 - 1900) && sntp_retry_cnt < (SNTP_RECV_TIMEOUT / 100)) { + sntp_retry_time = SNTP_RECV_TIMEOUT << sntp_retry_cnt; + + if (SNTP_RECV_TIMEOUT << (sntp_retry_cnt + 1) < SNTP_RETRY_TIMEOUT_MAX) { + sntp_retry_cnt ++; + } + + ESP_LOGI(TAG,"SNTP get time failed, retry after %d ms\n", sntp_retry_time); + vTaskDelay(sntp_retry_time / portTICK_RATE_MS); + } else { + ESP_LOGI(TAG,"SNTP get time success\n"); + break; + } + } + + get_time_flag = true; + + return ESP_OK; +} + +static esp_err_t conn_mgr_wifi_event_loop_handler(void *ctx, system_event_t *event) +{ + system_event_info_t *info = &event->event_info; + switch (event->event_id) { + case SYSTEM_EVENT_STA_GOT_IP: + conn_mgr_save_wifi_config(); +#ifdef CONFIG_ESP_TLS_USING_WOLFSSL + conn_mgr_obtain_time(); +#endif + break; + + case SYSTEM_EVENT_STA_DISCONNECTED: + ESP_LOGE(TAG, "Disconnect reason : %d", info->disconnected.reason); +#ifdef CONFIG_IDF_TARGET_ESP8266 + if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) { + /*Switch to 802.11 bgn mode */ + esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N); + } +#endif + esp_wifi_connect(); + break; + + default: + break; + } + + /** The application loop event handle */ + if (hal_wifi_system_cb) { + hal_wifi_system_cb(ctx, event); + } + + return ESP_OK; +} + +void conn_mgr_register_wifi_event(system_event_cb_t cb) +{ + hal_wifi_system_cb = cb; +} + +esp_err_t conn_mgr_reset_wifi_config(void) +{ + HAL_Kv_Del(STA_SSID_KEY); + HAL_Kv_Del(STA_PASSWORD_KEY); + + return ESP_OK; +} + +esp_err_t conn_mgr_init_wifi_config(void) +{ + wifi_config_t wifi_config = { + .sta = { + .ssid = CONFIG_ESP_WIFI_SSID, + .password = CONFIG_ESP_WIFI_PASSWORD, + }, + }; + int ret = HAL_Kv_Set(STA_SSID_KEY, wifi_config.sta.ssid, sizeof(wifi_config.sta.ssid), 0); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "%s key store failed with %d", STA_SSID_KEY, ret); + return ESP_FAIL; + } + + ret = HAL_Kv_Set(STA_PASSWORD_KEY, wifi_config.sta.password, sizeof(wifi_config.sta.password), 0); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "%s key store failed with %d", STA_PASSWORD_KEY, ret); + return ESP_FAIL; + } + return ESP_OK; +} + +static esp_err_t conn_mgr_is_configured(bool *configured) +{ + if (!configured) { + return ESP_ERR_INVALID_ARG; + } + + *configured = false; + + int ssid_len = 32; + uint8_t ssid[32]; + + int ret = HAL_Kv_Get(STA_SSID_KEY, ssid, &ssid_len); + + if (ret == ESP_OK && ssid_len) { + *configured = true; + ESP_LOGI(TAG, "Found ssid %s", ssid); + } + + return ESP_OK; +} + +esp_err_t conn_mgr_set_wifi_config_ext(const uint8_t *ssid, size_t ssid_len, const uint8_t *password, size_t password_len) +{ + wifi_config_t wifi_config = {0}; + + if (!ssid || ssid_len > sizeof(wifi_config.sta.ssid) || password_len > sizeof(wifi_config.sta.password)) + return ESP_ERR_INVALID_ARG; + + memcpy(wifi_config.sta.ssid, ssid, ssid_len); + if (password) { + memcpy(wifi_config.sta.password, password, password_len); + } + esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config); + + conn_mgr_save_wifi_config(); + + return ESP_OK; +} + +esp_err_t conn_mgr_get_wifi_config(wifi_config_t *wifi_cfg) +{ + return esp_wifi_get_config(ESP_IF_WIFI_STA, wifi_cfg); +} + +esp_err_t conn_mgr_init(void) +{ + extern esp_err_t HAL_Kv_Init(void); + HAL_Kv_Init(); + + tcpip_adapter_init(); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_event_loop_init(conn_mgr_wifi_event_loop_handler, NULL)); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_start()); + + return ESP_OK; +} + +esp_err_t conn_mgr_start(void) +{ + bool ret = true; + bool configured = false; + uint8_t mode = 0; + int mode_len = sizeof(uint8_t); + conn_sc_mode_t awss_mode = CONN_SC_ZERO_MODE; + + // Let's find out if the device is configured. + if (conn_mgr_is_configured(&configured) != ESP_OK) { + return ESP_FAIL; + } + + // Get SC mode and decide to start which awss service + HAL_Kv_Get(SC_MODE, &mode, &mode_len); + if (mode_len && mode == CONN_SOFTAP_MODE) { + ESP_LOGI(TAG, "CONN_SOFTAP_MODE"); + awss_mode = CONN_SOFTAP_MODE; + } else { + ESP_LOGI(TAG, "mode: %d ", mode); + } + + // If the device is not yet configured, start awss service. + if (!configured) { + do { + if (awss_config_press() != 0) { + ret = false; + break; + } + if (awss_mode == CONN_SOFTAP_MODE) { + if (awss_dev_ap_start() != 0) { + ret = false; + break; + } + } else { + if (awss_start() != 0) { + ret = false; + break; + } + } + } while (0); + } else { + if (conn_mgr_wifi_connect() != ESP_OK) { + ret = false; + } + } + + return ret == true ? ESP_OK : ESP_FAIL; +} + +esp_err_t conn_mgr_stop(void) +{ + bool ret = true; + bool configured = false; + uint8_t mode = 0; + int mode_len = sizeof(uint8_t); + conn_sc_mode_t awss_mode = CONN_SC_ZERO_MODE; + + // Let's find out if the device is configured. + if (conn_mgr_is_configured(&configured) != ESP_OK) { + return ESP_FAIL; + } + + // Get SC mode and decide to start which awss service + HAL_Kv_Get(SC_MODE, &mode, &mode_len); + if (mode_len && mode == CONN_SOFTAP_MODE) { + awss_mode = CONN_SOFTAP_MODE; + } + + // If the device is not yet configured, stop awss service. + if (!configured) { + if (awss_mode == CONN_SOFTAP_MODE) { + if (awss_dev_ap_stop() != 0) { + ret = false; + } + } else { + if (awss_stop() != 0) { + ret = false; + } + } + } + + return ret == true ? ESP_OK : ESP_FAIL; +} + +esp_err_t conn_mgr_set_ap_ssid(uint8_t *ssid, int len) +{ + int ret = ESP_FAIL; + uint8_t ssid_kv[32] = {0}; + int len_kv = 32; + + if (!ssid || !len) { + ESP_LOGI(TAG, "input ssid and len error"); + return ret; + } + ret = HAL_Kv_Get(AP_SSID_KEY, ssid_kv, &len_kv); + if (ret == ESP_OK && len_kv == len) { + if (!memcmp(ssid, ssid_kv, len)) { + return ESP_OK; + } + } + + ret = HAL_Kv_Set(AP_SSID_KEY, ssid, len, 0); + ESP_LOGI(TAG, "%s %s", __FUNCTION__, (ret == ESP_OK) ? "success" : "fail"); + + return ret; +} + +esp_err_t conn_mgr_set_sc_mode(uint8_t mode) +{ + int ret = ESP_FAIL; + uint8_t mode_kv = 0; + int len_kv = sizeof(uint8_t); + + ret = HAL_Kv_Get(SC_MODE, &mode_kv, &len_kv); + if (ret == ESP_OK) { + if (mode == mode_kv) { + return ESP_OK; + } + } + + ret = HAL_Kv_Set(SC_MODE, &mode, sizeof(uint8_t), 0); + ESP_LOGI(TAG, "%s %s", __FUNCTION__, (ret == ESP_OK) ? "success" : "fail"); + + return ret; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/conn_mgr/conn_mgr.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/conn_mgr/conn_mgr.h new file mode 100644 index 00000000..c78ebc2c --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/conn_mgr/conn_mgr.h @@ -0,0 +1,149 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#pragma once + +#include "esp_err.h" +#include "esp_event_loop.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HOTSPOT_AP "aha" +#define ROUTER_AP "adha" +#define STA_SSID_KEY "stassid" +#define STA_PASSWORD_KEY "pswd" +#define AP_SSID_KEY CONFIG_AP_SSID_KEY +#define SC_MODE "scmode" + +typedef enum { + CONN_SC_ZERO_MODE = 1, + CONN_SOFTAP_MODE = 2, +} conn_sc_mode_t; + +/** + * @brief register wifi event handler + * + * @param cb wifi event handler + * + * @return none + */ +void conn_mgr_register_wifi_event(system_event_cb_t cb); + +/** + * @brief reset the stored router info, include ssid & password + * + * @return + * - ESP_OK : OK + * - others : fail + */ +esp_err_t conn_mgr_reset_wifi_config(void); +esp_err_t conn_mgr_init_wifi_config(void); + +/** + * @brief connect wifi with configure information + * + * This will initiate connection to the given Wi-Fi configure information + * + * @param ssid Pointer to the target network SSID string + * @param ssid_len Length of the above SSID + * @param password Pointer to the targer network Password string. Can be NULL for open networks. + * @param password_len Length of the password + * + * @return + * - ESP_OK : OK + * - others : fail + */ +esp_err_t conn_mgr_set_wifi_config_ext(const uint8_t *ssid, size_t ssid_len, const uint8_t *password, size_t password_len); + +/** + * @brief get wifi configure information + * + * @return + * - ESP_OK : OK + * - others : fail + */ +esp_err_t conn_mgr_get_wifi_config(wifi_config_t *wifi_cfg); + +/** + * @brief init the connection management module + * + * @return + * - ESP_OK : OK + * - others : fail + */ +esp_err_t conn_mgr_init(void); + +/** + * @brief start the connection management module + * + * If the device is configured, the device will connect to the router which is configured. + * If the device is not configured, the device will start awss service. + * + * @return + * - ESP_OK : OK + * - others : fail + */ +esp_err_t conn_mgr_start(void); + +/** + * @brief stop the connection management module + * + * If the device is configured, the device keep connect to the router which is configured. + * If the device is not configured, the device will stop awss service. + * + * @return + * - ESP_OK : OK + * - others : fail + */ +esp_err_t conn_mgr_stop(void); + +/** + * @brief set softap ssid to KV + * + * @param ssid Pointer to the softap SSID string + * @param len Length of the above SSID + * + * @return + * - ESP_OK : OK + * - others : fail + */ +esp_err_t conn_mgr_set_ap_ssid(uint8_t *ssid, int len); + +/** + * @brief set wifi distribution network mode to KV + * + * If mode is 1, means support smartconfig and zero-config + * If mode is 2, means support softap config + * @param mode Value of the sc mode + * + * @return + * - ESP_OK : OK + * - others : fail + */ +esp_err_t conn_mgr_set_sc_mode(uint8_t mode); +#ifdef __cplusplus +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/certs/root_ca.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/certs/root_ca.c new file mode 100644 index 00000000..4881a944 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/certs/root_ca.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include + +const char *iotx_ca_crt = \ +{ + \ + "-----BEGIN CERTIFICATE-----\r\n" + "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n" \ + "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" \ + "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n" \ + "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" \ + "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n" \ + "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n" \ + "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n" \ + "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n" \ + "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n" \ + "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n" \ + "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n" \ + "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n" \ + "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n" \ + "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n" \ + "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n" \ + "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n" \ + "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n" \ + "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n" \ + "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n" \ + "-----END CERTIFICATE-----" +}; diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/Cloud_CoAPExport.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/Cloud_CoAPExport.h new file mode 100644 index 00000000..5e0016cd --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/Cloud_CoAPExport.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "Cloud_CoAPNetwork.h" +#include "iotx_coap_internal.h" + +#ifndef CLOUD__COAP_EXPORT_H__ +#define CLOUD__COAP_EXPORT_H__ + +/* #define COAP_DTLS_SUPPORT */ +typedef CoAPMsgOption Cloud_CoAPMsgOption; +typedef CoAPMessageCode Cloud_CoAPMessageCode; +typedef CoAPMessage Cloud_CoAPMessage ; +#define COAP_OPTION_SEQ 2089 + +typedef void (*Cloud_CoAPRespMsgHandler)(void *data, void *message); + +typedef struct { + void *user; + unsigned short msgid; + char acked; + unsigned char tokenlen; + unsigned char token[8]; + unsigned char retrans_count; + unsigned short timeout; + unsigned short timeout_val; + unsigned char *message; + unsigned int msglen; + Cloud_CoAPRespMsgHandler resp; + struct list_head sendlist; +} Cloud_CoAPSendNode; + + +typedef struct { + unsigned char count; + unsigned char maxcount; + struct list_head sendlist; +} Cloud_CoAPSendList; + + +typedef void (*Cloud_CoAPEventNotifier)(unsigned int event, void *p_message); +typedef struct { + char *url; + unsigned char maxcount; /*list maximal count*/ + unsigned int waittime; + Cloud_CoAPEventNotifier notifier; +} Cloud_CoAPInitParam; + +typedef struct { + unsigned short message_id; + coap_network_t network; + Cloud_CoAPEventNotifier notifier; + unsigned char *sendbuf; + unsigned char *recvbuf; + Cloud_CoAPSendList list; + unsigned int waittime; +} Cloud_CoAPContext; + +#define COAP_TRC(...) log_debug("coap_cloud", __VA_ARGS__) +#define COAP_DUMP(...) log_debug("coap_cloud", __VA_ARGS__) +#define COAP_DEBUG(...) log_debug("coap_cloud", __VA_ARGS__) +#define COAP_INFO(...) log_info("coap_cloud", __VA_ARGS__) +#define COAP_WRN(...) log_warning("coap_cloud", __VA_ARGS__) +#define COAP_ERR(...) log_err("coap_cloud", __VA_ARGS__) + +Cloud_CoAPContext *Cloud_CoAPContext_create(Cloud_CoAPInitParam *param); +void Cloud_CoAPContext_free(Cloud_CoAPContext *p_ctx); + + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/Cloud_CoAPMessage.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/Cloud_CoAPMessage.h new file mode 100644 index 00000000..5899698b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/Cloud_CoAPMessage.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#include "Cloud_CoAPExport.h" + +#ifndef __COAP_HANDLE_MSG_H__ +#define __COAP_HANDLE_MSG_H__ + +int Cloud_CoAPStrOption_add(Cloud_CoAPMessage *message, unsigned short optnum, + unsigned char *data, unsigned short datalen); + + +int Cloud_CoAPUintOption_add(Cloud_CoAPMessage *message, unsigned short optnum, + unsigned int data); + +unsigned short Cloud_CoAPMessageId_gen(Cloud_CoAPContext *context); + +int Cloud_CoAPMessageId_set(Cloud_CoAPMessage *message, unsigned short msgid); + +int Cloud_CoAPMessageType_set(Cloud_CoAPMessage *message, unsigned char type); + +int Cloud_CoAPMessageCode_set(Cloud_CoAPMessage *message, Cloud_CoAPMessageCode code); + +int Cloud_CoAPMessageToken_set(Cloud_CoAPMessage *message, unsigned char *token, + unsigned char tokenlen); + +int Cloud_CoAPMessageUserData_set(Cloud_CoAPMessage *message, void *userdata); + +int Cloud_CoAPMessagePayload_set(Cloud_CoAPMessage *message, unsigned char *payload, + unsigned short payloadlen); + +int Cloud_CoAPMessageHandler_set(Cloud_CoAPMessage *message, Cloud_CoAPRespMsgHandler handler); + +int Cloud_CoAPMessage_init(Cloud_CoAPMessage *message); + +int Cloud_CoAPMessage_destory(Cloud_CoAPMessage *message); + +int Cloud_CoAPMessage_send(Cloud_CoAPContext *context, Cloud_CoAPMessage *message); + +int Cloud_CoAPMessage_recv(Cloud_CoAPContext *context, unsigned int timeout, int readcount); + +int Cloud_CoAPMessage_cycle(Cloud_CoAPContext *context); + + + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/Cloud_CoAPNetwork.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/Cloud_CoAPNetwork.h new file mode 100644 index 00000000..43ec5b1e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/Cloud_CoAPNetwork.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include + +#ifndef COAP_TRANSPORT_H__ +#define COAP_TRANSPORT_H__ + +typedef enum { + COAP_ENDPOINT_NOSEC = 0, + COAP_ENDPOINT_DTLS, + COAP_ENDPOINT_PSK, +} coap_endpoint_type; + + +typedef struct { + DTLSContext *context; +} coap_remote_session_t; + + +typedef struct { + int socket_id; + coap_endpoint_type ep_type; + void *context; +} coap_network_t; + + +typedef struct { + coap_endpoint_type ep_type; + unsigned char *p_ca_cert_pem; + char *p_host; + unsigned short port; +} coap_network_init_t; + + +unsigned int Cloud_CoAPNetwork_init(const coap_network_init_t *p_param, coap_network_t *p_network); + + +unsigned int Cloud_CoAPNetwork_write(coap_network_t *p_network, + const unsigned char *p_data, + unsigned int datalen); + +int Cloud_CoAPNetwork_read(coap_network_t *network, unsigned char *data, + unsigned int datalen, unsigned int timeout); + +unsigned int Cloud_CoAPNetwork_deinit(coap_network_t *p_network); + + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/Cloud_CoAPPlatform.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/Cloud_CoAPPlatform.h new file mode 100644 index 00000000..8e8da178 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/Cloud_CoAPPlatform.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __COAP_PLATFORM_OS_H__ +#define __COAP_PLATFORM_OS_H__ +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define coap_malloc(size) LITE_malloc(size, MEM_MAGIC, "coap.cloud") + #define coap_free(ptr) LITE_free(ptr) +#else + #define coap_malloc(size) HAL_Malloc(size) + #define coap_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPDeserialize.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPDeserialize.h new file mode 100644 index 00000000..8d0cef68 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPDeserialize.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef __COAP_DESERIALIZE_H__ +#define __COAP_DESERIALIZE_H__ +#include +#include "iotx_coap_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int CoAPDeserialize_Message(CoAPMessage *msg, unsigned char *buf, int buflen); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPDeserialize_common.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPDeserialize_common.c new file mode 100644 index 00000000..c034a795 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPDeserialize_common.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#include +#include +#include "iotx_coap_internal.h" + +int CoAPDeserialize_Header(CoAPMessage *msg, unsigned char *buf) +{ + msg->header.version = ((buf[0] >> 6) & 0x03); + msg->header.type = ((buf[0] >> 4) & 0x03); + msg->header.tokenlen = (buf[0] & 0x0F); + msg->header.code = buf[1]; + msg->header.msgid = buf[2] << 8; + msg->header.msgid += buf[3]; + + return 4; +} + +int CoAPDeserialize_Token(CoAPMessage *msg, unsigned char *buf) +{ + memcpy(msg->token, buf, msg->header.tokenlen); + return msg->header.tokenlen; +} + +static int CoAPDeserialize_Option(CoAPMsgOption *option, unsigned char *buf, unsigned short *predeltas) +{ + unsigned char *ptr = buf; + unsigned short optdelta = 0; + unsigned short optlen = 0; + unsigned short predelta = 0; + + optdelta = (*ptr & 0xF0) >> 4; + optlen = (*ptr & 0x0F); + ptr++; + + predelta = *predeltas; + if (13 == optdelta) { + predelta += 13 + *ptr; + ptr ++; + + } else if (14 == optdelta) { + predelta += 269; + predelta += (*ptr << 8); + predelta += *(ptr + 1); + ptr += 2; + } else { + predelta += optdelta; + } + option->num = predelta; + + if (13 == optlen) { + optlen = 13 + *ptr; + ptr ++; + } else if (14 == optlen) { + optlen = 269; + optlen += (*ptr << 8); + optlen += *(ptr + 1); + ptr += 2; + } + option->len = optlen; + + option->val = ptr; + *predeltas = option->num; + + return (ptr - buf + option->len); +} + +int CoAPDeserialize_Options(CoAPMessage *msg, unsigned char *buf, int buflen) +{ + int index = 0; + int count = 0; + unsigned char *ptr = buf; + unsigned short len = 0; + unsigned short optdeltas = 0; + + msg->optcount = 0; + while ((count < buflen) && (0xFF != *ptr)) { + len = CoAPDeserialize_Option(&msg->options[index], ptr, &optdeltas); + msg->optcount += 1; + ptr += len; + index ++; + count += len; + } + + return (int)(ptr - buf); +} + +int CoAPDeserialize_Payload(CoAPMessage *msg, unsigned char *buf, int buflen) +{ + unsigned char *ptr = buf; + + if (0xFF == *ptr) { + ptr ++; + } else { + return 0; + } + msg->payloadlen = buflen - 1; + msg->payload = (unsigned char *)ptr; + + return buflen; +} + +int CoAPDeserialize_Message(CoAPMessage *msg, unsigned char *buf, int buflen) +{ + int count = 0; + int remlen = buflen; + unsigned char *ptr = buf; + + if (NULL == buf || NULL == msg) { + return COAP_ERROR_INVALID_PARAM; + } + + if (buflen < 4) { + return COAP_ERROR_INVALID_LENGTH; + } + + /* Deserialize CoAP header. */ + count = CoAPDeserialize_Header(msg, ptr); + ptr += count; + remlen -= count; + + /* Deserialize the token, if any. */ + count = CoAPDeserialize_Token(msg, ptr); + ptr += count; + remlen -= count; + + count = CoAPDeserialize_Options(msg, ptr, remlen); + ptr += count; + remlen -= count; + + CoAPDeserialize_Payload(msg, ptr, remlen); + + return COAP_SUCCESS; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPExport.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPExport.c new file mode 100644 index 00000000..5c9a6dea --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPExport.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include +#include +#include +#include "iotx_coap_internal.h" +#include "ctype.h" +#include "Cloud_CoAPPlatform.h" +#include "Cloud_CoAPNetwork.h" +#include "Cloud_CoAPExport.h" + +#define COAP_DEFAULT_PORT 5683 /* CoAP default UDP port */ +#define COAPS_DEFAULT_PORT 5684 /* CoAP default UDP port for secure transmission */ + +#define COAP_DEFAULT_SCHEME "coap" /* the default scheme for CoAP URIs */ +#define COAP_DEFAULT_HOST_LEN 128 +#define COAP_DEFAULT_WAIT_TIME_MS 2000 + +unsigned int Cloud_CoAPUri_parse(char *p_uri, coap_endpoint_type *p_endpoint_type, + char host[COAP_DEFAULT_HOST_LEN], unsigned short *port) +{ + int len = 0; + char *p = NULL, *q = NULL; + if (NULL == p_uri || NULL == p_endpoint_type) { + return COAP_ERROR_INVALID_PARAM; + } + + COAP_DEBUG("The uri is %s", p_uri); + len = strlen(p_uri); + p = p_uri; + q = (char *)COAP_DEFAULT_SCHEME; + while (len && *q && tolower(*p) == *q) { + ++p; + ++q; + --len; + } + + if (*q) { + return COAP_ERROR_INVALID_URI; + } + if (tolower(*p) == 's') { + ++p; + --len; + *p_endpoint_type = COAP_ENDPOINT_DTLS; + *port = COAPS_DEFAULT_PORT; + } else if (*p == '-') { + ++p; + --len; + q = (char *)"psk"; + while (len && *q && tolower(*p) == *q) { + ++p; + ++q; + --len; + } + if (*q) { + return COAP_ERROR_INVALID_URI; + } + *p_endpoint_type = COAP_ENDPOINT_PSK; + *port = COAP_DEFAULT_PORT; + } else { + *p_endpoint_type = COAP_ENDPOINT_NOSEC; + *port = COAP_DEFAULT_PORT; + } + COAP_DEBUG("The endpoint type is: %d", *p_endpoint_type); + + q = (char *)"://"; + while (len && *q && tolower(*p) == *q) { + ++p; + ++q; + --len; + } + + if (*q) { + return COAP_ERROR_INVALID_URI; + } + + q = p; + while (len && *q != ':') { + ++q; + --len; + } + if (p == q) { + return COAP_ERROR_INVALID_URI; + } + + if (COAP_DEFAULT_HOST_LEN - 1 < (q - p)) { + return COAP_ERROR_INVALID_URI; + } else { + memset(host, 0x00, COAP_DEFAULT_HOST_LEN); + strncpy(host, p, q - p); + } + COAP_DEBUG("The host name is: %s", host); + if (len && *q == ':') { + p = ++q; + --len; + + while (len && isdigit(*q)) { + ++q; + --len; + } + + if (p < q) { + int uri_port = 0; + + while (p < q) { + uri_port = uri_port * 10 + (*p++ - '0'); + } + + if (uri_port > 65535) { + return COAP_ERROR_INVALID_URI; + } + *port = uri_port; + } + } + COAP_DEBUG("The port is: %d", *port); + + return COAP_SUCCESS; +} + + +Cloud_CoAPContext *Cloud_CoAPContext_create(Cloud_CoAPInitParam *param) +{ + unsigned int ret = COAP_SUCCESS; + Cloud_CoAPContext *p_ctx = NULL; + coap_network_init_t network_param; + char host[COAP_DEFAULT_HOST_LEN] = {0}; + + memset(&network_param, 0x00, sizeof(coap_network_init_t)); + p_ctx = coap_malloc(sizeof(Cloud_CoAPContext)); + if (NULL == p_ctx) { + COAP_ERR("malloc for coap context failed"); + goto err; + } + + memset(p_ctx, 0, sizeof(Cloud_CoAPContext)); + p_ctx->message_id = 1; + p_ctx->notifier = param->notifier; + p_ctx->sendbuf = coap_malloc(COAP_MSG_MAX_PDU_LEN); + if (NULL == p_ctx->sendbuf) { + COAP_ERR("not enough memory"); + goto err; + } + + p_ctx->recvbuf = coap_malloc(COAP_MSG_MAX_PDU_LEN); + if (NULL == p_ctx->recvbuf) { + COAP_ERR("not enough memory"); + goto err; + } + + if (0 == param->waittime) { + p_ctx->waittime = COAP_DEFAULT_WAIT_TIME_MS; + } else { + p_ctx->waittime = param->waittime; + } + + /*CoAP message send list*/ + INIT_LIST_HEAD(&p_ctx->list.sendlist); + p_ctx->list.count = 0; + p_ctx->list.maxcount = param->maxcount; + + /*set the endpoint type by uri schema*/ + if (NULL != param->url) { + ret = Cloud_CoAPUri_parse(param->url, &network_param.ep_type, host, &network_param.port); + } + + if (COAP_SUCCESS != ret) { + goto err; + } + +#ifdef COAP_DTLS_SUPPORT + if (COAP_ENDPOINT_DTLS == network_param.ep_type) { + extern const char *iotx_ca_crt; + network_param.p_ca_cert_pem = (unsigned char *)iotx_ca_crt; + } +#endif + if (COAP_ENDPOINT_NOSEC == network_param.ep_type + || COAP_ENDPOINT_PSK == network_param.ep_type) { + network_param.p_ca_cert_pem = NULL; + } + network_param.p_host = host; + + /*CoAP network init*/ + ret = Cloud_CoAPNetwork_init(&network_param, &p_ctx->network); + + if (COAP_SUCCESS != ret) { + goto err; + } + + return p_ctx; +err: + if (NULL == p_ctx) { + return p_ctx; + } + + if (NULL != p_ctx->recvbuf) { + coap_free(p_ctx->recvbuf); + p_ctx->recvbuf = NULL; + } + + if (NULL != p_ctx->sendbuf) { + coap_free(p_ctx->sendbuf); + p_ctx->sendbuf = NULL; + } + + coap_free(p_ctx); + p_ctx = NULL; + + return p_ctx; +} + +void Cloud_CoAPContext_free(Cloud_CoAPContext *p_ctx) +{ + Cloud_CoAPSendNode *cur, *next; + + if (NULL == p_ctx) { + return; + } + + Cloud_CoAPNetwork_deinit(&p_ctx->network); + + list_for_each_entry_safe(cur, next, &p_ctx->list.sendlist, sendlist, Cloud_CoAPSendNode) { + if (NULL != cur) { + if (NULL != cur->message) { + coap_free(cur->message); + cur->message = NULL; + } + coap_free(cur); + cur = NULL; + } + } + + if (NULL != p_ctx->recvbuf) { + coap_free(p_ctx->recvbuf); + p_ctx->recvbuf = NULL; + } + + if (NULL != p_ctx->sendbuf) { + coap_free(p_ctx->sendbuf); + p_ctx->sendbuf = NULL; + } + + + if (NULL != p_ctx) { + coap_free(p_ctx); + p_ctx = NULL; + } +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPMessage.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPMessage.c new file mode 100644 index 00000000..4214d880 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPMessage.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "iotx_coap_internal.h" +#include "Cloud_CoAPExport.h" +#include "CoAPSerialize.h" +#include "CoAPDeserialize.h" +#include "Cloud_CoAPPlatform.h" + + +#define COAPAckMsg(header) \ + ((header.code == COAP_MSG_CODE_EMPTY_MESSAGE) \ + &&(header.type == COAP_MESSAGE_TYPE_ACK)) + +#define Cloud_CoAPRespMsg(header)\ + ((header.code >= 0x40) && (header.code < 0xc0)) + +#define Cloud_CoAPPingMsg(header)\ + ((header.code == COAP_MSG_CODE_EMPTY_MESSAGE)\ + && (header.type == COAP_MESSAGE_TYPE_CON)) + +#define Cloud_CoAPRstMsg(header)\ + (header.type == COAP_MESSAGE_TYPE_RST) + +#define Cloud_CoAPCONRespMsg(header)\ + ((header.code == COAP_MSG_CODE_205_CONTENT) \ + && (header.type == COAP_MESSAGE_TYPE_CON)) + +#define Cloud_CoAPReqMsg(header)\ + ((1 <= header.code) && (32 > header.code)) + + +#define COAP_CUR_VERSION 1 +#define COAP_WAIT_TIME_MS 2000 +#define COAP_MAX_MESSAGE_ID 65535 +#define COAP_MAX_RETRY_COUNT 4 +#define COAP_ACK_TIMEOUT 2 +#define COAP_ACK_RANDOM_FACTOR 1 +#define COAP_MAX_TRANSMISSION_SPAN 10 + +unsigned short Cloud_CoAPMessageId_gen(Cloud_CoAPContext *context) +{ + unsigned short msg_id = 0; + msg_id = ((COAP_MAX_MESSAGE_ID == context->message_id) ? 1 : context->message_id++); + return msg_id; +} + +int Cloud_CoAPMessageHandler_set(Cloud_CoAPMessage *message, Cloud_CoAPRespMsgHandler resp) +{ + if (NULL == message) { + return COAP_ERROR_NULL; + } + message->resp = resp; + return COAP_SUCCESS; +} + +static int Cloud_CoAPMessageList_add(Cloud_CoAPContext *context, Cloud_CoAPMessage *message, int len) +{ + Cloud_CoAPSendNode *node = NULL; + node = coap_malloc(sizeof(Cloud_CoAPSendNode)); + + if (NULL != node) { + node->acked = 0; + node->user = message->user; + node->msgid = message->header.msgid; + node->resp = message->resp; + node->msglen = len; + node->timeout_val = COAP_ACK_TIMEOUT * COAP_ACK_RANDOM_FACTOR; + + if (COAP_MESSAGE_TYPE_CON == message->header.type) { + node->timeout = node->timeout_val; + node->retrans_count = 0; + } else { + node->timeout = COAP_MAX_TRANSMISSION_SPAN; + node->retrans_count = COAP_MAX_RETRY_COUNT; + } + node->tokenlen = message->header.tokenlen; + memcpy(node->token, message->token, message->header.tokenlen); + node->message = (unsigned char *)coap_malloc(len); + if (NULL != node->message) { + memcpy(node->message, context->sendbuf, len); + } + + if (&context->list.count >= &context->list.maxcount) { + coap_free(node); + return -1; + } else { + list_add_tail(&node->sendlist, &context->list.sendlist); + context->list.count ++; + return 0; + } + } else { + return -1; + } +} + +int Cloud_CoAPMessage_send(Cloud_CoAPContext *context, Cloud_CoAPMessage *message) +{ + unsigned int ret = COAP_SUCCESS; + unsigned short msglen = 0; + + if (NULL == message || NULL == context) { + return (COAP_ERROR_INVALID_PARAM); + } + + /* TODO: get the message length */ + /* msglen = CoAPSerialize_MessageLength(message); */ + msglen = CoAPSerialize_MessageLength(message); + if (COAP_MSG_MAX_PDU_LEN < msglen) { + COAP_INFO("The message length %d is too loog", msglen); + return COAP_ERROR_DATA_SIZE; + } + + memset(context->sendbuf, 0x00, COAP_MSG_MAX_PDU_LEN); + msglen = CoAPSerialize_Message(message, context->sendbuf, COAP_MSG_MAX_PDU_LEN); + COAP_DEBUG("----The message length %d-----", msglen); + + + ret = Cloud_CoAPNetwork_write(&context->network, context->sendbuf, (unsigned int)msglen); + if (COAP_SUCCESS == ret) { + if (Cloud_CoAPReqMsg(message->header) || Cloud_CoAPCONRespMsg(message->header)) { + COAP_DEBUG("Add message id %d len %d to the list", + message->header.msgid, msglen); + Cloud_CoAPMessageList_add(context, message, msglen); + } else { + COAP_DEBUG("The message doesn't need to be retransmitted"); + } + } else { + COAP_ERR("CoAP transport write failed, return %d", ret); + } + + return ret; +} + + +static int Cloud_CoAPAckMessage_handle(Cloud_CoAPContext *context, Cloud_CoAPMessage *message) +{ + Cloud_CoAPSendNode *node = NULL; + + list_for_each_entry(node, &context->list.sendlist, sendlist, Cloud_CoAPSendNode) { + if (node->msgid == message->header.msgid) { + node->acked = 1; + return COAP_SUCCESS; + } + } + + return COAP_SUCCESS; +} + +static int Cloud_CoAPAckMessage_send(Cloud_CoAPContext *context, unsigned short msgid) +{ + Cloud_CoAPMessage message; + CoAPMessage_init(&message); + CoAPMessageId_set(&message, msgid); + return Cloud_CoAPMessage_send(context, &message); +} + +static int Cloud_CoAPRespMessage_handle(Cloud_CoAPContext *context, Cloud_CoAPMessage *message) +{ + Cloud_CoAPSendNode *node = NULL; + + if (COAP_MESSAGE_TYPE_CON == message->header.type) { + Cloud_CoAPAckMessage_send(context, message->header.msgid); + } + + + list_for_each_entry(node, &context->list.sendlist, sendlist, Cloud_CoAPSendNode) { + if (0 != node->tokenlen && node->tokenlen == message->header.tokenlen + && 0 == memcmp(node->token, message->token, message->header.tokenlen)) { + +#ifdef INFRA_LOG_NETWORK_PAYLOAD + COAP_DEBUG("Find the node by token"); + COAP_INFO("Downstream Payload:"); + iotx_facility_json_print((const char *)message->payload, LOG_INFO_LEVEL, '<'); +#endif + message->user = node->user; + if (COAP_MSG_CODE_400_BAD_REQUEST <= message->header.code) { + /* TODO:i */ + if (NULL != context->notifier) { + /* context->notifier(message->header.code, message); */ + } + } + + if (NULL != node->resp) { + node->resp(node->user, message); + } + COAP_DEBUG("Remove the message id %d from list", node->msgid); + list_del_init(&node->sendlist); + context->list.count--; + if (NULL != node->message) { + coap_free(node->message); + } + coap_free(node); + node = NULL; + return COAP_SUCCESS; + } + } + return COAP_ERROR_NOT_FOUND; +} + +static void Cloud_CoAPMessage_handle(Cloud_CoAPContext *context, + unsigned char *buf, + unsigned short datalen) +{ + int ret = COAP_SUCCESS; + Cloud_CoAPMessage message; + unsigned char code, msgclass, detail; + memset(&message, 0x00, sizeof(Cloud_CoAPMessage)); + + ret = CoAPDeserialize_Message(&message, buf, datalen); + code = (unsigned char)message.header.code; + msgclass = code >> 5; + detail = code & 0x1F; + + COAP_DEBUG("Version : %d", message.header.version); + COAP_DEBUG("Code : %d.%02d(0x%x)", msgclass, detail, code); + COAP_DEBUG("Type : 0x%x", message.header.type); + COAP_DEBUG("Msgid : %d", message.header.msgid); + COAP_DEBUG("Option : %d", message.optcount); + COAP_DEBUG("Payload Len : %d", message.payloadlen); + + msgclass = msgclass; + detail = detail; + + if (COAP_SUCCESS != ret) { + if (NULL != context->notifier) { + /* TODO: */ + /* context->notifier(context, event); */ + } + } + + if (COAPAckMsg(message.header)) { + COAP_DEBUG("Receive CoAP ACK Message,ID %d", message.header.msgid); + Cloud_CoAPAckMessage_handle(context, &message); + + } else if (Cloud_CoAPRespMsg(message.header)) { + COAP_DEBUG("Receive CoAP Response Message,ID %d", message.header.msgid); + Cloud_CoAPRespMessage_handle(context, &message); + } +} + +int Cloud_CoAPMessage_recv(Cloud_CoAPContext *context, unsigned int timeout, int readcount) +{ + int len = 0; + int count = readcount; + + while (1) { + len = Cloud_CoAPNetwork_read(&context->network, context->recvbuf, + COAP_MSG_MAX_PDU_LEN, timeout); + if (len > 0) { + if (0 == readcount) { + Cloud_CoAPMessage_handle(context, context->recvbuf, len); + } else { + count--; + Cloud_CoAPMessage_handle(context, context->recvbuf, len); + if (0 == count) { + return len; + } + } + } else { + return 0; + } + } +} + +int Cloud_CoAPMessage_cycle(Cloud_CoAPContext *context) +{ + unsigned int ret = 0; + Cloud_CoAPSendNode *node = NULL, *next = NULL; + Cloud_CoAPMessage_recv(context, context->waittime, 0); + + list_for_each_entry_safe(node, next, &context->list.sendlist, sendlist, Cloud_CoAPSendNode) { + if (NULL != node) { + if (node->timeout == 0) { + if (node->retrans_count < COAP_MAX_RETRY_COUNT && (0 == node->acked)) { + node->timeout = node->timeout_val * 2; + node->timeout_val = node->timeout; + node->retrans_count++; + COAP_DEBUG("Retansmit the message id %d len %d", node->msgid, node->msglen); + ret = Cloud_CoAPNetwork_write(&context->network, node->message, node->msglen); + if (ret != COAP_SUCCESS) { + if (NULL != context->notifier) { + /* TODO: */ + /* context->notifier(context, event); */ + } + } + } + + if ((node->timeout > COAP_MAX_TRANSMISSION_SPAN) || + (node->retrans_count >= COAP_MAX_RETRY_COUNT)) { + if (NULL != context->notifier) { + /* TODO: */ + /* context->notifier(context, event); */ + } + + /*Remove the node from the list*/ + list_del_init(&node->sendlist); + context->list.count--; + COAP_INFO("Retransmit timeout,remove the message id %d count %d", + node->msgid, context->list.count); + coap_free(node->message); + coap_free(node); + } + } else { + node->timeout--; + } + } + } + return COAP_SUCCESS; +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPMessage_common.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPMessage_common.c new file mode 100644 index 00000000..47e6104f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPMessage_common.c @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + + +#include +#include "iotx_coap_internal.h" +#include "CoAPSerialize.h" +#include "CoAPDeserialize.h" +#if 0 +#include "CoAPResource.h" +#include "CoAPObserve.h" +#include "CoAPInternal.h" +#endif +#include "CoAPPlatform.h" + +#define COAPAckMsg(header) \ + ((header.code == COAP_MSG_CODE_EMPTY_MESSAGE) \ + &&(header.type == COAP_MESSAGE_TYPE_ACK)) + +#define CoAPRespMsg(header)\ + ((header.code >= 0x40) && (header.code < 0xc0)) + +#define CoAPPingMsg(header)\ + ((header.code == COAP_MSG_CODE_EMPTY_MESSAGE)\ + && (header.type == COAP_MESSAGE_TYPE_CON)) + +#define CoAPResetMsg(header)\ + (header.type == COAP_MESSAGE_TYPE_RST) + +#define CoAPCONRespMsg(header)\ + ((header.code == COAP_MSG_CODE_205_CONTENT) \ + && (header.type == COAP_MESSAGE_TYPE_CON)) + +#define CoAPReqMsg(header)\ + ((1 <= header.code) && (32 > header.code)) + + +#define COAP_CUR_VERSION 1 +#define COAP_WAIT_TIME_MS 2000 +#define COAP_MAX_MESSAGE_ID 65535 +#define COAP_MAX_RETRY_COUNT 4 +#define COAP_ACK_TIMEOUT 2 +#define COAP_ACK_RANDOM_FACTOR 1 +#define COAP_MAX_TRANSMISSION_SPAN 10 + +int CoAPStrOption_add(CoAPMessage *message, unsigned short optnum, unsigned char *data, unsigned short datalen) +{ + unsigned char *ptr = NULL; + if (COAP_MSG_MAX_OPTION_NUM <= message->optcount) { + return COAP_ERROR_INVALID_PARAM; + } + + message->options[message->optcount].num = optnum - message->optdelta; + message->options[message->optcount].len = datalen; + ptr = (unsigned char *)coap_malloc(datalen); + if (NULL == ptr) { + return COAP_ERROR_MALLOC; + } + memset(ptr, 0x00, datalen); + memcpy(ptr, data, datalen); + message->options[message->optcount].val = ptr; + message->optdelta = optnum; + message->optcount ++; + + return COAP_SUCCESS; + +} + +int CoAPStrOption_get(CoAPMessage *message, unsigned short optnum, unsigned char *data, unsigned short *datalen) +{ + unsigned char index = 0; + + for (index = 0; index < message->optcount; index++) { + if (message->options[index].num == optnum) { + if (*datalen >= message->options[index].len) { + memcpy(data, message->options[index].val, message->options[index].len); + *datalen = message->options[index].len; + return COAP_SUCCESS; + } else { + return COAP_ERROR_INVALID_LENGTH; + } + } + } + + return COAP_ERROR_NOT_FOUND; + +} + + +int CoAPUintOption_add(CoAPMessage *message, unsigned short optnum, unsigned int data) +{ + unsigned char *ptr = NULL; + if (COAP_MSG_MAX_OPTION_NUM <= message->optcount) { + return COAP_ERROR_INVALID_PARAM; + } + message->options[message->optcount].num = optnum - message->optdelta; + + if (0 == data) { + message->options[message->optcount].len = 0; + } else if (255 >= data) { + message->options[message->optcount].len = 1; + ptr = (unsigned char *)coap_malloc(1); + if (NULL != ptr) { + *ptr = (unsigned char)data; + } + } else if (65535 >= data) { + message->options[message->optcount].len = 2; + ptr = (unsigned char *)coap_malloc(2); + if (NULL != ptr) { + *ptr = (unsigned char)((data & 0xFF00) >> 8); + *(ptr + 1) = (unsigned char)(data & 0x00FF); + } + } else { + message->options[message->optcount].len = 4; + ptr = (unsigned char *)coap_malloc(4); + if (NULL != ptr) { + *ptr = (unsigned char)((data & 0xFF000000) >> 24); + *(ptr + 1) = (unsigned char)((data & 0x00FF0000) >> 16); + *(ptr + 2) = (unsigned char)((data & 0x0000FF00) >> 8); + *(ptr + 3) = (unsigned char)(data & 0x000000FF); + } + } + message->options[message->optcount].val = ptr; + message->optdelta = optnum; + message->optcount += 1; + + return COAP_SUCCESS; +} + +int CoAPUintOption_get(CoAPMessage *message, + unsigned short optnum, + unsigned int *data) +{ + + unsigned char index = 0; + + for (index = 0; index < message->optcount; index++) { + if (message->options[index].num == optnum) { + int byte = 0; + switch (message->options[index].len) { + case 1: + *data |= message->options[index].val[byte++]; + break; + case 2: + *data |= (message->options[index].val[byte++] << 8); + *data |= message->options[index].val[byte++]; + break; + case 3: + *data |= (message->options[index].val[byte++] << 16); + *data |= (message->options[index].val[byte++] << 8); + *data |= message->options[index].val[byte++]; + break; + case 4: + *data |= (message->options[index].val[byte++] << 24); + *data |= (message->options[index].val[byte++] << 16); + *data |= (message->options[index].val[byte++] << 8); + *data |= message->options[index].val[byte++]; + break; + default: + *data = 0; + break; + } + return COAP_SUCCESS; + } + } + + return COAP_ERROR_NOT_FOUND; +} + + +int CoAPOption_present(CoAPMessage *message, unsigned short option) +{ + unsigned char index = 0; + + + for (index = 0; index < message->optcount; index++) { + if (message->options[index].num == option) { + return COAP_SUCCESS; + } + } + return COAP_ERROR_NOT_FOUND; +} + +int CoAPMessageId_set(CoAPMessage *message, unsigned short msgid) +{ + if (NULL == message) { + return COAP_ERROR_NULL; + } + message->header.msgid = msgid; + return COAP_SUCCESS; +} + +int CoAPMessageType_set(CoAPMessage *message, unsigned char type) +{ + if (NULL == message) { + return COAP_ERROR_NULL; + } + if (COAP_MESSAGE_TYPE_CON != type && COAP_MESSAGE_TYPE_NON != type + && COAP_MESSAGE_TYPE_ACK != type && COAP_MESSAGE_TYPE_RST != type) { + return COAP_ERROR_INVALID_PARAM; + } + + message->header.type = type; + return COAP_SUCCESS; +} + +int CoAPMessageCode_set(CoAPMessage *message, CoAPMessageCode code) +{ + if (NULL == message) { + return COAP_ERROR_NULL; + } + message->header.code = code; + return COAP_SUCCESS; +} + +int CoAPMessageCode_get(CoAPMessage *message, CoAPMessageCode *code) +{ + if (NULL == message || NULL == code) { + return COAP_ERROR_NULL; + } + *code = message->header.code; + return COAP_SUCCESS; +} + +int CoAPMessageToken_set(CoAPMessage *message, unsigned char *token, + unsigned char tokenlen) +{ + if (NULL == message || NULL == token) { + return COAP_ERROR_NULL; + } + if (COAP_MSG_MAX_TOKEN_LEN < tokenlen) { + return COAP_ERROR_INVALID_LENGTH; + } + memcpy(message->token, token, tokenlen); + message->header.tokenlen = tokenlen; + + return COAP_SUCCESS; +} + +int CoAPMessageUserData_set(CoAPMessage *message, void *userdata) +{ + if (NULL == message || NULL == userdata) { + return COAP_ERROR_NULL; + } + message->user = userdata; + return COAP_SUCCESS; +} + +int CoAPMessageKeep_Set(CoAPMessage *message, int keep) +{ + if (NULL == message || keep < 0) { + return COAP_ERROR_NULL; + } + message->keep = keep; + return COAP_SUCCESS; +} + +int CoAPMessagePayload_set(CoAPMessage *message, unsigned char *payload, + unsigned short payloadlen) +{ + if (NULL == message || (0 < payloadlen && NULL == payload)) { + return COAP_ERROR_NULL; + } + message->payload = payload; + message->payloadlen = payloadlen; + + return COAP_SUCCESS; +} + +int CoAPMessage_init(CoAPMessage *message) +{ + int count = 0; + + if (NULL == message) { + return COAP_ERROR_NULL; + } + memset(message, 0x00, sizeof(CoAPMessage)); + message->header.version = COAP_CUR_VERSION; + message->header.type = COAP_MESSAGE_TYPE_ACK; + message->header.tokenlen = 0; + message->header.code = COAP_MSG_CODE_EMPTY_MESSAGE; + message->header.msgid = 0; + message->payload = NULL; + message->payloadlen = 0; + message->optcount = 0; + message->optdelta = 0; + message->handler = NULL; + message->keep = 0; + for (count = 0; count < COAP_MSG_MAX_OPTION_NUM; count++) { + message->options[count].len = 0; + message->options[count].num = 0; + message->options[count].val = NULL; + } + + return COAP_SUCCESS; +} + +int CoAPMessage_destory(CoAPMessage *message) +{ + int count = 0; + if (NULL == message) { + return COAP_ERROR_NULL; + } + + for (count = 0; count < COAP_MSG_MAX_OPTION_NUM; count++) { + if (NULL != message->options[count].val) { + coap_free(message->options[count].val); + message->options[count].val = NULL; + } + } + + return COAP_SUCCESS; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPNetwork.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPNetwork.c new file mode 100644 index 00000000..68847070 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPNetwork.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#include +#include +#include +#include + +#include "iotx_coap_internal.h" +#include "Cloud_CoAPExport.h" +#include "Cloud_CoAPNetwork.h" + +#ifdef COAP_DTLS_SUPPORT +static void *Cloud_CoAPDTLS_Malloc(uint32_t size) +{ +#ifdef INFRA_MEM_STATS + return LITE_malloc(size, MEM_MAGIC, "dtls"); +#else + return HAL_Malloc(size); +#endif +} +static void Cloud_CoAPDTLS_Free(void *ptr) +{ +#ifdef INFRA_MEM_STATS + LITE_free(ptr); +#else + HAL_Free((void *)ptr); +#endif +} + +static void Cloud_CoAPNetworkDTLS_freeSession(void *p_session); + +unsigned int Cloud_CoAPNetworkDTLS_read(void *p_session, + unsigned char *p_data, + unsigned int *p_datalen, + unsigned int timeout) +{ + unsigned int err_code = DTLS_SUCCESS; + const unsigned int read_len = *p_datalen; + DTLSContext *context = NULL; + + COAP_TRC("<< secure_datagram_read, read buffer len %d, timeout %d", read_len, timeout); + (void)read_len; + if (NULL != p_session) { + /* read dtls application data*/ + context = (DTLSContext *)p_session; + err_code = HAL_DTLSSession_read(context, p_data, p_datalen, timeout); + if (DTLS_PEER_CLOSE_NOTIFY == err_code + || DTLS_FATAL_ALERT_MESSAGE == err_code) { + COAP_INFO("dtls session read failed, return (0x%04x)", err_code); + Cloud_CoAPNetworkDTLS_freeSession(context); + } + if (DTLS_SUCCESS == err_code) { + return COAP_SUCCESS; + } else { + return COAP_ERROR_READ_FAILED; + } + } + + return COAP_ERROR_INVALID_PARAM; +} + +unsigned int Cloud_CoAPNetworkDTLS_write(void *p_session, + const unsigned char *p_data, + unsigned int *p_datalen) +{ + unsigned int err_code = DTLS_SUCCESS; + if (NULL != p_session) { + err_code = HAL_DTLSSession_write((DTLSContext *)p_session, p_data, p_datalen); + if (DTLS_SUCCESS == err_code) { + return COAP_SUCCESS; + } else { + return COAP_ERROR_WRITE_FAILED; + } + } + return COAP_ERROR_INVALID_PARAM; +} + +static void Cloud_CoAPNetworkDTLS_freeSession(void *p_session) +{ + /* Free the session.*/ + HAL_DTLSSession_free((DTLSContext *)p_session); +} + +void *Cloud_CoAPNetworkDTLS_createSession(char *p_host, + unsigned short port, + unsigned char *p_ca_cert_pem) +{ + DTLSContext *context = NULL; + dtls_hooks_t dtls_hooks; + coap_dtls_options_t dtls_options; + + memset(&dtls_hooks, 0, sizeof(dtls_hooks_t)); + dtls_hooks.malloc = Cloud_CoAPDTLS_Malloc; + dtls_hooks.free = Cloud_CoAPDTLS_Free; + + HAL_DTLSHooks_set(&dtls_hooks); + + memset(&dtls_options, 0x00, sizeof(coap_dtls_options_t)); + dtls_options.p_ca_cert_pem = p_ca_cert_pem; + dtls_options.p_host = p_host; + dtls_options.port = port; + + context = HAL_DTLSSession_create(&dtls_options); + return (void *)context; +} + +#endif + +unsigned int Cloud_CoAPNetwork_write(coap_network_t *p_network, + const unsigned char *p_data, + unsigned int datalen) +{ + int rc = COAP_ERROR_WRITE_FAILED; + +#ifdef COAP_DTLS_SUPPORT + if (COAP_ENDPOINT_DTLS == p_network->ep_type) { + rc = Cloud_CoAPNetworkDTLS_write(p_network->context, p_data, &datalen); + } else { +#endif + rc = HAL_UDP_write((intptr_t)p_network->context, p_data, datalen); + COAP_DEBUG("[CoAP-NWK]: Network write return %d", rc); + + if (-1 == rc) { + rc = COAP_ERROR_WRITE_FAILED; + } else { + rc = COAP_SUCCESS; + } +#ifdef COAP_DTLS_SUPPORT + } +#endif + return (unsigned int)rc; +} + +int Cloud_CoAPNetwork_read(coap_network_t *network, unsigned char *data, + unsigned int datalen, unsigned int timeout) +{ + int len = 0; + +#ifdef COAP_DTLS_SUPPORT + if (COAP_ENDPOINT_DTLS == network->ep_type) { + len = datalen; + memset(data, 0x00, datalen); + Cloud_CoAPNetworkDTLS_read(network->context, data, (unsigned int *)&len, timeout); + } else { +#endif + memset(data, 0x00, datalen); + len = HAL_UDP_readTimeout((intptr_t)network->context, + data, COAP_MSG_MAX_PDU_LEN, timeout); +#ifdef COAP_DTLS_SUPPORT + } +#endif + if (len > 0) { + COAP_TRC("<< CoAP recv %d bytes data", len); + } + return len; +} + +unsigned int Cloud_CoAPNetwork_init(const coap_network_init_t *p_param, coap_network_t *p_network) +{ + unsigned int err_code = COAP_SUCCESS; + + if (NULL == p_param || NULL == p_network) { + return COAP_ERROR_INVALID_PARAM; + } + + /* TODO : Parse the url here */ + p_network->ep_type = p_param->ep_type; + +#ifdef COAP_DTLS_SUPPORT + if (COAP_ENDPOINT_DTLS == p_param->ep_type) { + p_network->context = Cloud_CoAPNetworkDTLS_createSession(p_param->p_host, + p_param->port, p_param->p_ca_cert_pem); + if (NULL == p_network->context) { + return COAP_ERROR_NET_INIT_FAILED; + } + } +#endif + if (COAP_ENDPOINT_NOSEC == p_param->ep_type + || COAP_ENDPOINT_PSK == p_param->ep_type) { + /*Create udp socket*/ + p_network->context = (void *)HAL_UDP_create(p_param->p_host, p_param->port); + if ((void *) - 1 == p_network->context) { + return COAP_ERROR_NET_INIT_FAILED; + } + } + return err_code; +} + + +unsigned int Cloud_CoAPNetwork_deinit(coap_network_t *p_network) +{ + unsigned int err_code = COAP_SUCCESS; + +#ifdef COAP_DTLS_SUPPORT + if (COAP_ENDPOINT_DTLS == p_network->ep_type) { + Cloud_CoAPNetworkDTLS_freeSession(p_network->context); + p_network->context = NULL; + } +#endif + if (COAP_ENDPOINT_NOSEC == p_network->ep_type + || COAP_ENDPOINT_PSK == p_network->ep_type) { + HAL_UDP_close_without_connect((intptr_t)p_network->context); + } + + return err_code; +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPPlatform.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPPlatform.h new file mode 100644 index 00000000..02f6eca0 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPPlatform.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __COAP_PLATFORM_OS_H__ +#define __COAP_PLATFORM_OS_H__ + +#include +#include "iotx_coap_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define coap_malloc(size) LITE_malloc(size, MEM_MAGIC, "coap.local") + #define coap_free(ptr) LITE_free(ptr) +#else + #define coap_malloc(size) HAL_Malloc(size) + #define coap_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#ifdef INFRA_LOG + #include "infra_log.h" + #define COAP_ERR(...) log_err("coap_local", __VA_ARGS__) + #define COAP_WRN(...) log_warning("coap_local", __VA_ARGS__) + #define COAP_INFO(...) log_info("coap_local", __VA_ARGS__) + #define COAP_TRC(...) log_debug("coap_local", __VA_ARGS__) + #define COAP_DUMP(...) log_debug("coap_local", __VA_ARGS__) + #define COAP_DEBUG(...) log_debug("coap_local", __VA_ARGS__) + #define COAP_FLOW(...) log_flow("coap_local", __VA_ARGS__) +#else + #define COAP_ERR(...) + #define COAP_WRN(...) + #define COAP_INFO(...) + #define COAP_TRC(...) + #define COAP_DUMP(...) + #define COAP_DEBUG(...) + #define COAP_FLOW(...) +#endif + +int platform_is_multicast(const char *ip_str); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPSerialize.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPSerialize.h new file mode 100644 index 00000000..4a8177d1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPSerialize.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef __COAP_SERIALIZE_H__ +#define __COAP_SERIALIZE_H__ +#include "iotx_coap_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +unsigned short CoAPSerialize_MessageLength(CoAPMessage *msg); + +int CoAPSerialize_Message(CoAPMessage *msg, unsigned char *buf, unsigned short buflen); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPSerialize_common.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPSerialize_common.c new file mode 100644 index 00000000..ae2f0d89 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/CoAPSerialize_common.c @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#include +#include +#include "CoAPSerialize.h" +#include "iotx_coap_internal.h" + +int CoAPSerialize_Header(CoAPMessage *msg, unsigned char *buf, unsigned short buflen) +{ + if(4 > buflen){ + return 0; + } + buf[0] = (((msg->header.version & 0x3) << 6) | ((msg->header.type & 0x3) << 4)) + | (msg->header.tokenlen & 0x0F); + + buf[1] = msg->header.code; + buf[2] = (msg->header.msgid & 0xFF00) >> 8; + buf[3] = (msg->header.msgid & 0x00FF); + + return 4; +} + +int CoAPSerialize_Token(CoAPMessage *msg, unsigned char * buf, unsigned short buflen) +{ + int i = 0; + + if(buflen < msg->header.tokenlen){ + return 0; + } + for (i = 0; i < msg->header.tokenlen; i++){ + buf[i] = msg->token[i]; + } + return msg->header.tokenlen; +} + +static unsigned short CoAPSerialize_Option(CoAPMsgOption *option, unsigned char *buf) +{ + unsigned char *ptr = buf; + + if(269 <= option->num){ + *ptr = ((14 & 0x0F) << 4); + } + else if(13 <= option->num){ + *ptr = ((13 & 0x0F) << 4); + } + else{ + *ptr = option->num << 4; + } + + if (269 <= option->len){ + *ptr |= (14 & 0x0F); + } + else if(13 <= option->len){ + *ptr |= (13 & 0x0F); + } + else{ + *ptr |= (option->len & 0x0F); + } + ptr ++; + + if (269 <= option->num){ + *ptr = (unsigned char)(((option->num - 269) & 0xFF00) >> 8); + *(ptr+1) = (unsigned char)(((option->num - 269) & 0x00FF)); + ptr += 2; + } + else if(13 <= option->num){ + *ptr = (unsigned char)(option->num - 13); + ptr ++; + } + + + if (269 <= option->len){ + *ptr = (unsigned char)(((option->len - 269) & 0xFF00) >> 8); + *(ptr+1) = (unsigned char)(((option->len - 269) & 0x00FF)); + ptr += 2; + } + else if(13 <= option->len){ + *ptr = (unsigned char)(option->len - 13); + ptr ++; + } + + + memcpy(ptr, option->val, option->len); + ptr += option->len; + + return (int)(ptr - buf); +} + +unsigned short CoAPSerialize_Options(CoAPMessage *msg, unsigned char * buf, unsigned short buflen) +{ + int i = 0; + unsigned short count = 0; + + for (i = 0; i < msg->optcount; i++) + { + unsigned short len = 0; + len = CoAPSerialize_Option(&msg->options[i], &buf[count]); + if (0 < len){ + count += len; + } + else{ + return 0; + } + } + + return count; +} + +static unsigned short CoAPSerialize_OptionLen(CoAPMsgOption *option) +{ + unsigned short len = 1; + + if(269 <= option->num){ + len += 2; + } + else if(13 <= option->num){ + len += 1; + } + else{ + } + + if (269 <= option->len){ + len += 2; + } + else if(13 <= option->len){ + len += 1; + } + else{ + } + + len += option->len; + return len; +} + + +unsigned short CoAPSerialize_OptionsLen(CoAPMessage *msg) +{ + int i = 0; + unsigned short count = 0; + + for (i = 0; i < msg->optcount; i++) + { + unsigned short len = 0; + len = CoAPSerialize_OptionLen(&msg->options[i]); + if (0 < len){ + count += len; + } + else{ + return 0; + } + } + + return count; +} + + +int CoAPSerialize_Payload(CoAPMessage *msg, unsigned char *buf, int buflen) +{ + if(msg->payloadlen + 1 > buflen){ + return 0; + } + if(msg->payloadlen > 0 && NULL != msg->payload) + { + *buf = 0xFF; + buf ++; + memcpy(buf, msg->payload, msg->payloadlen); + return msg->payloadlen + 1; + } + else{ + return 0; + } +} + + +unsigned short CoAPSerialize_MessageLength(CoAPMessage *msg) +{ + unsigned short msglen = 4; + + msglen += msg->header.tokenlen; + msglen += CoAPSerialize_OptionsLen(msg); + + if(0 < msg->payloadlen){ + msglen += msg->payloadlen; + msglen += 1; /*CoAP payload marker*/ + } + + return msglen; +} + +int CoAPSerialize_Message(CoAPMessage *msg, unsigned char *buf, unsigned short buflen) +{ + unsigned char *ptr = buf; + unsigned short count = 0; + unsigned short remlen = buflen; + + if(NULL == buf || NULL == msg){ + return COAP_ERROR_INVALID_PARAM; + } + + count = CoAPSerialize_Header(msg, ptr, remlen); + ptr += count; + remlen -= count; + + count = CoAPSerialize_Token(msg, ptr, remlen); + ptr += count; + remlen -= count; + + count = CoAPSerialize_Options(msg, ptr, remlen); + ptr += count; + remlen -= count; + + count = CoAPSerialize_Payload(msg, ptr, remlen); + ptr += count; + remlen -= count; + + return (buflen-remlen); +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/coap_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/coap_api.h new file mode 100644 index 00000000..127990dc --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/coap_api.h @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __IOTX_COAP_API_H__ +#define __IOTX_COAP_API_H__ + +#if defined(__cplusplus) +extern "C" { +#endif + +#include "infra_defs.h" + +/*iotx return code definition*/ +typedef enum { + IOTX_ERR_RECV_MSG_TIMEOUT = -9, /*Receive message timeout */ + IOTX_ERR_SEND_MSG_FAILED = -8, /* Send message failed*/ + IOTX_ERR_MSG_TOO_LOOG = -7, /* The payload too loog */ + IOTX_ERR_URI_TOO_LOOG = -6, /* URI length too long */ + IOTX_ERR_NOT_AUTHED = -5, /* Client isn't authed */ + IOTX_ERR_AUTH_FAILED = -4, /* Client authed failed */ + IOTX_ERR_BUFF_TOO_SHORT = -3, /* Buffer too short */ + IOTX_ERR_NO_MEM = -2, /* Malloc failed */ + IOTX_ERR_INVALID_PARAM = -1, /* Invalid parameter */ + IOTX_SUCCESS = 0, /* Success */ +} iotx_ret_code_t; + +/* The message payload encode format */ +typedef enum { + IOTX_CONTENT_TYPE_JSON, + IOTX_CONTENT_TYPE_CBOR, +} iotx_content_type_t; + +/* The message type */ +typedef enum { + IOTX_MESSAGE_CON = 0, /* confirmable message */ + IOTX_MESSAGE_NON = 1, /* non-confirmable message */ + IOTX_MESSAGE_ACK = 2, /* acknowledgement message */ + IOTX_MESSAGE_RST = 3, /* reset message */ +} iotx_msg_type_t; + +/* IoTx events to notify application */ +typedef enum { + IOTX_COAP_EVENT_SEND_FAILED = 0, + IOTX_COAP_EVENT_RECV_FAILED = 1, + IOTX_COAP_EVENT_AUTH_FAILED = 2, +} iotx_coap_event_t; + +typedef enum { + IOTX_COAP_RESP_CODE_CONTENT = 0x45, /* Mapping to 2.05, Content*/ + IOTX_COAP_RESP_CODE_BAD_REQUEST = 0x80, /* Mapping to 4.00, Bad Request*/ + IOTX_COAP_RESP_CODE_UNAUTHORIZED = 0x81, /* Mapping to 4.01, Token is invalid or expire*/ + IOTX_COAP_RESP_CODE_NOT_FOUND = 0x84, /* Mapping to 4.04, Path or uri is not found*/ + IOTX_COAP_RESP_CODE_URL_TOO_LONG = 0x8E, /* Mapping to 4.14, The request url is too long*/ + IOTX_COAP_RESP_CODE_INTERNAL_SERVER_ERROR = 0xA0,/* Mapping to 5.00, Internal server error*/ + +} iotx_coap_resp_code_t; + +/* Callback function to notify the application events.*/ +typedef void (*iotx_event_handle_t)(void *context, iotx_coap_event_t event, void *p_data); + +/*IoTx device*/ +typedef struct { + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + char device_id[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 2]; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1]; +} iotx_deviceinfo_t; + +typedef struct { + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + char device_id[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 2]; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1]; + char module_vendor_id[IOTX_PARTNER_ID_LEN + 1]; +} iotx_device_info_t; + +/* IoTx initializa parameters */ +typedef struct { + char *p_url; /*Can be NULL*/ + int wait_time_ms; /*unit is micro second*/ + iotx_device_info_t *p_devinfo; /*Device info*/ + iotx_event_handle_t event_handle; /*TODO, not supported now*/ +} iotx_coap_config_t; + +/* Callback function to handle the response message.*/ +typedef void (*iotx_response_callback_t)(void *p_arg, void *p_message); + +/* IoTx message definition */ +typedef struct { + unsigned char *p_payload; + unsigned short payload_len; + iotx_content_type_t content_type; + iotx_msg_type_t msg_type; + void *user_data; + iotx_response_callback_t resp_callback; +} iotx_message_t; + + +/*iotx coap context definition*/ +typedef void iotx_coap_context_t; + + +/** @defgroup group_api api + * @{ + */ + +/** @defgroup group_api_coap coap + * @{ + */ + +/** + * @brief Initialize the CoAP client. + * This function initialize the data structures and network, + * and create the DTLS session. + * + * @param [in] p_config: Specify the CoAP client parameter. + * + * @retval NULL : Initialize failed. + * @retval NOT_NULL : The contex of CoAP client. + * @see None. + */ +iotx_coap_context_t *IOT_CoAP_Init(iotx_coap_config_t *p_config); + +/** + * @brief De-initialize the CoAP client. + * This function release CoAP DTLS session. + * and release the related resource. + * + * @param [in] p_context: Pointer of contex, specify the CoAP client. + * + * @return None. + * @see None. + */ +DLL_IOT_API void IOT_CoAP_Deinit(iotx_coap_context_t **p_context); + + +/** + * @brief Handle device name authentication with remote server. + * + * @param [in] p_context: Pointer of contex, specify the CoAP client. + * + * @retval IOTX_SUCCESS : Authenticate success. + * @retval IOTX_ERR_SEND_MSG_FAILED : Send authentication message failed. + * @retval IOTX_ERR_AUTH_FAILED : Authenticate failed or timeout. + * @see iotx_ret_code_t. + */ +DLL_IOT_API int IOT_CoAP_DeviceNameAuth(iotx_coap_context_t *p_context); + + +/** + * @brief Handle CoAP response packet from remote server, + * and process timeout request etc.. + * + * @param [in] p_context : Pointer of contex, specify the CoAP client. + * + * @return status. + * @see iotx_ret_code_t. + */ +DLL_IOT_API int IOT_CoAP_Yield(iotx_coap_context_t *p_context); + + +/** + * @brief Send a message with specific path to server. + * Client must authentication with server before send message. + * + * @param [in] p_context : Pointer of contex, specify the CoAP client. + * @param [in] p_path: Specify the path name. + * @param [in] p_message: Message to be sent. + * + * @retval IOTX_SUCCESS : Send the message success. + * @retval IOTX_ERR_MSG_TOO_LOOG : The message length is too long. + * @retval IOTX_ERR_NOT_AUTHED : The client hasn't authenticated with server + * @see iotx_ret_code_t. + */ +DLL_IOT_API int IOT_CoAP_SendMessage(iotx_coap_context_t *p_context, char *p_path, iotx_message_t *p_message); + +/** +* @brief Retrieves the length and payload pointer of specified message. +* +* @param [in] p_message: Pointer to the message to get the payload. Should not be NULL. +* @param [out] pp_payload: Pointer to the payload. +* @param [out] p_len: Size of the payload. +* +* @retval IOTX_SUCCESS : Get the payload success. +* @retval IOTX_ERR_INVALID_PARAM : Can't get the payload due to invalid parameter. +* @see iotx_ret_code_t. +**/ +DLL_IOT_API int IOT_CoAP_GetMessagePayload(void *p_message, unsigned char **pp_payload, int *p_len); + +/** +* @brief Get the response code from a CoAP message. +* +* @param [in] p_message: Pointer to the message to add the address information to. +* Should not be NULL. +* @param [out] p_resp_code: The response code. +* +* @retval IOTX_SUCCESS : When get the response code to message success. +* @retval IOTX_ERR_INVALID_PARAM : Pointer to the message is NULL. +* @see iotx_ret_code_t. +**/ +DLL_IOT_API int IOT_CoAP_GetMessageCode(void *p_message, iotx_coap_resp_code_t *p_resp_code); + +/** @} */ /* end of api_coap */ +/** @} */ /* end of api */ + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/coap_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/coap_wrapper.h new file mode 100644 index 00000000..d11faa30 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/coap_wrapper.h @@ -0,0 +1,90 @@ +#ifndef _COAP_WRAPPER_H_ +#define _COAP_WRAPPER_H_ + +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_compat.h" +#include "wrappers_defs.h" + +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); +void HAL_SleepMs(uint32_t ms); +uint64_t HAL_UptimeMs(void); +void HAL_Srandom(uint32_t seed); +uint32_t HAL_Random(uint32_t region); +void HAL_Printf(const char *fmt, ...); +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); + +int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN]); +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN]); +int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN]); + +int HAL_SetProductKey(char *product_key); +int HAL_SetProductSecret(char *product_secret); +int HAL_SetDeviceName(char *device_name); +int HAL_SetDeviceSecret(char *device_secret); + +DLL_HAL_API int HAL_DTLSHooks_set(dtls_hooks_t *hooks); +DLL_HAL_API DTLSContext *HAL_DTLSSession_create(coap_dtls_options_t *p_options); +DLL_HAL_API unsigned int HAL_DTLSSession_write(DTLSContext *context, + const unsigned char *p_data, + unsigned int *p_datalen); +DLL_HAL_API unsigned int HAL_DTLSSession_read(DTLSContext *context, + unsigned char *p_data, + unsigned int *p_datalen, + unsigned int timeout_ms); +DLL_HAL_API unsigned int HAL_DTLSSession_free(DTLSContext *context); +intptr_t HAL_UDP_create(char *host, unsigned short port); +intptr_t HAL_UDP_create_without_connect(const char *host, unsigned short port); +int HAL_UDP_write(intptr_t p_socket, + const unsigned char *p_data, + unsigned int datalen); +int HAL_UDP_readTimeout(intptr_t p_socket, + unsigned char *p_data, + unsigned int datalen, + unsigned int timeout); +int HAL_UDP_close_without_connect(intptr_t sockfd); +int HAL_UDP_recvfrom(intptr_t sockfd, + NetworkAddr *p_remote, + unsigned char *p_data, + unsigned int datalen, + unsigned int timeout_ms); +int HAL_UDP_sendto(intptr_t sockfd, + const NetworkAddr *p_remote, + const unsigned char *p_data, + unsigned int datalen, + unsigned int timeout_ms); +int HAL_UDP_joinmulticast(intptr_t sockfd, + char *p_group); +uint32_t HAL_Wifi_Get_IP(char ip_str[NETWORK_ADDR_LEN], const char *ifname); +p_HAL_Aes128_t HAL_Aes128_Init( + const uint8_t *key, + const uint8_t *iv, + AES_DIR_t dir); +int HAL_Aes128_Destroy(p_HAL_Aes128_t aes); +int HAL_Aes128_Cbc_Encrypt( + p_HAL_Aes128_t aes, + const void *src, + size_t blockNum, + void *dst); +int HAL_Aes128_Cbc_Decrypt( + p_HAL_Aes128_t aes, + const void *src, + size_t blockNum, + void *dst); +void *HAL_MutexCreate(void); +void HAL_MutexDestroy(void *mutex); +void HAL_MutexLock(void *mutex); +void HAL_MutexUnlock(void *mutex); +void *HAL_SemaphoreCreate(void); +void HAL_SemaphoreDestroy(void *sem); +int HAL_SemaphoreWait(void *sem, uint32_t timeout_ms); +void HAL_SemaphorePost(void *sem); +int HAL_ThreadCreate( + void **thread_handle, + void *(*work_routine)(void *), + void *arg, + hal_os_thread_param_t *hal_os_thread_param, + int *stack_used); +void HAL_ThreadDelete(void *thread_handle); +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/iotx_coap.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/iotx_coap.h new file mode 100644 index 00000000..e557ef7a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/iotx_coap.h @@ -0,0 +1,2 @@ +#include "CoAPServer.h" +#include "iotx_coap_internal.h" diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/iotx_coap_api.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/iotx_coap_api.c new file mode 100644 index 00000000..2aa5cd4e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/iotx_coap_api.c @@ -0,0 +1,950 @@ +/* +* Copyright (C) 2015-2018 Alibaba Group Holding Limited +*/ + +#include + +#include "coap_api.h" +#include "iotx_coap_internal.h" +#include "Cloud_CoAPPlatform.h" +#include "Cloud_CoAPPlatform.h" +#include "Cloud_CoAPMessage.h" +#include "Cloud_CoAPExport.h" + +#define IOTX_SIGN_LENGTH (40+1) +#define IOTX_SIGN_SOURCE_LEN (256) +#define IOTX_AUTH_TOKEN_LEN (192+1) +#define IOTX_COAP_INIT_TOKEN (0x01020304) +#define IOTX_LIST_MAX_ITEM (10) + +#ifndef INFRA_LOG + #undef HEXDUMP_DEBUG + #undef HEXDUMP_INFO + + #define HEXDUMP_DEBUG(...) + #define HEXDUMP_INFO(...) +#endif + +#define IOTX_AUTH_STR "auth" +#define IOTX_SIGN_SRC_STR "clientId%sdeviceName%sproductKey%s" +#define IOTX_SIGN_SRC_STR_WITH_SEQ "clientId%sdeviceName%sproductKey%sseq%d" + +#define IOTX_AUTH_DEVICENAME_STR "{\"productKey\":\"%s\",\"deviceName\":\"%s\",\"clientId\":\"%s\",\"sign\":\"%s\"}" +#define IOTX_AUTH_DEVICENAME_STR_WITH_SEQ "{\"productKey\":\"%s\",\"deviceName\":\"%s\",\"clientId\":\"%s\",\"sign\":\"%s\",\"seq\":\"%d\"}" + +#define IOTX_COAP_ONLINE_DTLS_SERVER_URL "coaps://%s.coap.cn-shanghai.link.aliyuncs.com:5684" +#define IOTX_COAP_ONLINE_PSK_SERVER_URL "coap-psk://%s.coap.cn-shanghai.link.aliyuncs.com:5682" + +iotx_coap_context_t *g_coap_context = NULL; + +typedef struct { + char *p_auth_token; + int auth_token_len; + char is_authed; + iotx_deviceinfo_t *p_devinfo; + Cloud_CoAPContext *p_coap_ctx; + unsigned int coap_token; + unsigned int seq; + unsigned char key[32]; + iotx_event_handle_t event_handle; +} iotx_coap_t; + + +int iotx_calc_sign(const char *p_device_secret, const char *p_client_id, + const char *p_device_name, const char *p_product_key, char sign[IOTX_SIGN_LENGTH]) +{ + char *p_msg = NULL; + + p_msg = (char *)coap_malloc(IOTX_SIGN_SOURCE_LEN); + if (NULL == p_msg) { + return IOTX_ERR_NO_MEM; + } + memset(sign, 0x00, IOTX_SIGN_LENGTH); + memset(p_msg, 0x00, IOTX_SIGN_SOURCE_LEN); + + HAL_Snprintf(p_msg, IOTX_SIGN_SOURCE_LEN, + IOTX_SIGN_SRC_STR, + p_client_id, + p_device_name, + p_product_key); + utils_hmac_md5(p_msg, strlen(p_msg), sign, p_device_secret, strlen(p_device_secret)); + + coap_free(p_msg); + COAP_DEBUG("The device name sign: %s", sign); + return IOTX_SUCCESS; +} + +int iotx_calc_sign_with_seq(const char *p_device_secret, const char *p_client_id, + const char *p_device_name, const char *p_product_key, unsigned int seq, char sign[IOTX_SIGN_LENGTH]) +{ + char *p_msg = NULL; + + p_msg = (char *)coap_malloc(IOTX_SIGN_SOURCE_LEN); + if (NULL == p_msg) { + return IOTX_ERR_NO_MEM; + } + memset(sign, 0x00, IOTX_SIGN_LENGTH); + memset(p_msg, 0x00, IOTX_SIGN_SOURCE_LEN); + + HAL_Snprintf(p_msg, IOTX_SIGN_SOURCE_LEN, + IOTX_SIGN_SRC_STR_WITH_SEQ, + p_client_id, + p_device_name, + p_product_key, seq); + COAP_DEBUG("The source string: %s", p_msg); + utils_hmac_md5(p_msg, strlen(p_msg), sign, p_device_secret, strlen(p_device_secret)); + + coap_free(p_msg); + COAP_DEBUG("The device name sign with seq: %s", sign); + return IOTX_SUCCESS; +} + + +static int iotx_get_token_from_json(char *p_str, char *p_token, int len) +{ + char *p_value = NULL; + if (NULL == p_str || NULL == p_token) { + COAP_ERR("Invalid paramter p_str %p, p_token %p", p_str, p_token); + return IOTX_ERR_INVALID_PARAM; + } + + p_value = LITE_json_value_of("token", p_str, 0x1234, "coap.cloud"); + if (NULL != p_value) { + if (len - 1 < strlen(p_value)) { + return IOTX_ERR_BUFF_TOO_SHORT; + } + memset(p_token, 0x00, len); + strncpy(p_token, p_value, strlen(p_value)); +#ifdef INFRA_MEM_STATS + LITE_free(p_value); +#else + HAL_Free((void *)p_value); +#endif + return IOTX_SUCCESS; + } + + return IOTX_ERR_AUTH_FAILED; +} + +static int iotx_parse_auth_from_json(char *p_str, iotx_coap_t *p_iotx_coap) +{ + int ret = -1; + lite_cjson_t root; + lite_cjson_t node; + unsigned char key[32] = {0}; + unsigned char buff[128] = {0}; + unsigned char random[32] = {0}; + + if (NULL == p_str || NULL == p_iotx_coap) { + return IOTX_ERR_INVALID_PARAM; + } + + memset(&root, 0x00, sizeof(lite_cjson_t)); + memset(&node, 0x00, sizeof(lite_cjson_t)); + ret = lite_cjson_parse(p_str, strlen(p_str), &root); + if (-1 == ret) { + return IOTX_ERR_AUTH_FAILED; + } + + ret = lite_cjson_object_item(&root, "token", strlen("token"), &node); + if (-1 == ret) { + return IOTX_ERR_AUTH_FAILED; + } + if (p_iotx_coap->auth_token_len - 1 < node.value_length) { + return IOTX_ERR_BUFF_TOO_SHORT; + } + memset(p_iotx_coap->p_auth_token, 0x00, node.value_length); + strncpy(p_iotx_coap->p_auth_token, node.value, node.value_length); + + memset(&node, 0x00, sizeof(lite_cjson_t)); + ret = lite_cjson_object_item(&root, "seqOffset", strlen("seqOffset"), &node); + if (-1 == ret) { + return IOTX_ERR_AUTH_FAILED; + } + p_iotx_coap->seq = node.value_int; + + memset(&node, 0x00, sizeof(lite_cjson_t)); + ret = lite_cjson_object_item(&root, "random", strlen("random"), &node); + if (-1 == ret) { + return IOTX_ERR_AUTH_FAILED; + } + + memcpy(random, node.value, node.value_length); + HAL_Snprintf((char *)buff, sizeof(buff), "%s,%s", + p_iotx_coap->p_devinfo->device_secret, random); + COAP_DEBUG("The src:%s", buff); + utils_sha256(buff, strlen((char *)buff), key); + memcpy(p_iotx_coap->key, key + 8, 16); + COAP_DEBUG("The key is:"); + HEXDUMP_DEBUG(key, 32); + COAP_DEBUG("The short key:"); + HEXDUMP_DEBUG(p_iotx_coap->key, 16); + + return IOTX_SUCCESS; +} + +static void iotx_device_name_auth_callback(void *user, void *p_message) +{ + int ret_code = IOTX_SUCCESS; + iotx_coap_t *p_iotx_coap = NULL; + Cloud_CoAPMessage *message = (Cloud_CoAPMessage *)p_message; + + if (NULL == user) { + COAP_ERR("Invalid paramter, p_arg %p", user); + return ; + } + p_iotx_coap = (iotx_coap_t *)user; + + if (NULL == message) { + COAP_ERR("Invalid paramter, message %p", message); + return; + } + COAP_DEBUG("Receive response message:"); + COAP_DEBUG("* Response Code : 0x%x", message->header.code); + COAP_DEBUG("* Payload: %s", message->payload); + + switch (message->header.code) { + case COAP_MSG_CODE_205_CONTENT: { + if (COAP_ENDPOINT_PSK == p_iotx_coap->p_coap_ctx->network.ep_type) { + ret_code = iotx_parse_auth_from_json((char *)message->payload, p_iotx_coap); + } else { + ret_code = iotx_get_token_from_json((char *)message->payload, p_iotx_coap->p_auth_token, p_iotx_coap->auth_token_len); + } + + if (IOTX_SUCCESS == ret_code) { + p_iotx_coap->is_authed = IOT_TRUE; + COAP_INFO("CoAP authenticate success!!!"); + } + break; + } + case COAP_MSG_CODE_500_INTERNAL_SERVER_ERROR: { + COAP_INFO("CoAP internal server error, authenticate failed, will retry it"); + HAL_SleepMs(1000); + IOT_CoAP_DeviceNameAuth((iotx_coap_context_t *)p_iotx_coap); + break; + } + default: + break; + } + +} + +static unsigned int iotx_get_coap_token(iotx_coap_t *p_iotx_coap, unsigned char *p_encoded_data) +{ + unsigned int value = p_iotx_coap->coap_token; + p_encoded_data[0] = (unsigned char)((value & 0x00FF) >> 0); + p_encoded_data[1] = (unsigned char)((value & 0xFF00) >> 8); + p_encoded_data[2] = (unsigned char)((value & 0xFF0000) >> 16); + p_encoded_data[3] = (unsigned char)((value & 0xFF000000) >> 24); + p_iotx_coap->coap_token++; + return sizeof(unsigned int); +} + +void iotx_event_notifyer(unsigned int code, Cloud_CoAPMessage *message) +{ + if (NULL == message) { + COAP_ERR("Invalid paramter, message %p", message); + return ; + } + + COAP_DEBUG("Error code: 0x%x, payload: %s", code, message->payload); + switch (code) { + case COAP_MSG_CODE_402_BAD_OPTION: + case COAP_MSG_CODE_401_UNAUTHORIZED: { + iotx_coap_t *p_context = NULL; + if (NULL != message->user) { + p_context = (iotx_coap_t *)message->user; + p_context->is_authed = IOT_FALSE; + IOT_CoAP_DeviceNameAuth(p_context); + COAP_INFO("IoTx token expired, will reauthenticate"); + } + /* TODO: call event handle to notify application */ + /* p_context->event_handle(); */ + break; + } + + default: + break; + } +} + +static void iotx_get_well_known_handler(void *arg, void *p_response) +{ + + int len = 0; + unsigned char *p_payload = NULL; + iotx_coap_resp_code_t resp_code; + IOT_CoAP_GetMessageCode(p_response, &resp_code); + IOT_CoAP_GetMessagePayload(p_response, &p_payload, &len); + COAP_INFO("[APPL]: Message response code: %d", resp_code); + COAP_INFO("[APPL]: Len: %d, Payload: %s, ", len, p_payload); +} + + +int iotx_get_well_known(iotx_coap_context_t *p_context) +{ + int len = 0; + Cloud_CoAPContext *p_coap_ctx = NULL; + iotx_coap_t *p_iotx_coap = NULL; + Cloud_CoAPMessage message; + unsigned char token[8] = {0}; + + p_iotx_coap = (iotx_coap_t *)p_context; + p_coap_ctx = (Cloud_CoAPContext *)p_iotx_coap->p_coap_ctx; + + + CoAPMessage_init(&message); + CoAPMessageType_set(&message, COAP_MESSAGE_TYPE_CON); + CoAPMessageCode_set(&message, COAP_MSG_CODE_GET); + CoAPMessageId_set(&message, Cloud_CoAPMessageId_gen(p_coap_ctx)); + len = iotx_get_coap_token(p_iotx_coap, token); + CoAPMessageToken_set(&message, token, len); + Cloud_CoAPMessageHandler_set(&message, iotx_get_well_known_handler); + CoAPStrOption_add(&message, COAP_OPTION_URI_PATH, (unsigned char *)".well-known", strlen(".well-known")); + CoAPStrOption_add(&message, COAP_OPTION_URI_PATH, (unsigned char *)"core", strlen("core")); + CoAPUintOption_add(&message, COAP_OPTION_ACCEPT, COAP_CT_APP_LINK_FORMAT); + CoAPMessageUserData_set(&message, (void *)p_iotx_coap); + Cloud_CoAPMessage_send(p_coap_ctx, &message); + CoAPMessage_destory(&message); + return IOTX_SUCCESS; +} + +static void iotx_coap_report_rsphdl(void *arg, void *p_response) +{ + int p_payload_len = 0; + unsigned char *p_payload = NULL; + iotx_coap_resp_code_t resp_code; + + IOT_CoAP_GetMessageCode(p_response, &resp_code); + IOT_CoAP_GetMessagePayload(p_response, &p_payload, &p_payload_len); + COAP_DEBUG("Report response: CoAP response code = %d", resp_code); + COAP_DEBUG("Report response: CoAP msg_len = %d", p_payload_len); + if (p_payload_len > 0) { + COAP_DEBUG("Report response: CoAP msg = '%.*s'", p_payload_len, p_payload); + } else { + COAP_WRN("Report response: CoAP response payload_len = 0"); + } +} + +static int coap_report_func(void *handle, const char *topic_name, int req_ack, void *data, int len) +{ + iotx_message_t message; + char coap_topic[100] = {0}; + (void)req_ack; + + memset(&message, 0, sizeof(iotx_message_t)); + message.p_payload = (unsigned char *)data; + message.payload_len = len; + message.resp_callback = iotx_coap_report_rsphdl; + message.msg_type = IOTX_MESSAGE_NON; + message.content_type = IOTX_CONTENT_TYPE_JSON; + HAL_Snprintf(coap_topic, 100, "/topic%s", topic_name); + return IOT_CoAP_SendMessage(handle, (char *)coap_topic, &message); +} + +int iotx_aes_cbc_encrypt(const unsigned char *src, int len, const unsigned char *key, void *out) +{ + char *iv = "543yhjy97ae7fyfg"; + + int len1 = len & 0xfffffff0; + int len2 = len1 + 16; + int pad = len2 - len; + int ret = 0; + + p_HAL_Aes128_t aes_e_h = HAL_Aes128_Init((unsigned char *)key, (unsigned char *)iv, HAL_AES_ENCRYPTION); + if (len1) { + ret = HAL_Aes128_Cbc_Encrypt(aes_e_h, src, len1 >> 4, out); + } + if (!ret && pad) { + char buf[16] = {0}; + memcpy(buf, src + len1, len - len1); + memset(buf + len - len1, pad, pad); + ret = HAL_Aes128_Cbc_Encrypt(aes_e_h, buf, 1, (unsigned char *)out + len1); + + } + + HAL_Aes128_Destroy(aes_e_h); + + COAP_DEBUG("to encrypt src: %s, len: %d", src, len2); + return ret == 0 ? len2 : 0; +} + +int iotx_aes_cbc_decrypt(const unsigned char *src, int len, const unsigned char *key, void *out) +{ + char *iv = "543yhjy97ae7fyfg"; + + p_HAL_Aes128_t aes_d_h; + int ret = 0; + int n = len >> 4; + + aes_d_h = HAL_Aes128_Init((uint8_t *)key, (uint8_t *)iv, HAL_AES_DECRYPTION); + if (!aes_d_h) { + COAP_INFO("fail to decrypt"); + return 0; + } + if (n > 1) { + ret = HAL_Aes128_Cbc_Decrypt(aes_d_h, src, n - 1, out); + } + + if (ret == 0) { + char *out_c = (char *)out; + int offset = n > 0 ? ((n - 1) << 4) : 0; + out_c[offset] = 0; + + if (aes_d_h) { + ret = HAL_Aes128_Cbc_Decrypt(aes_d_h, src + offset, 1, out_c + offset); + } else { + COAP_ERR("fail to decrypt remain data"); + } + + if (ret == 0) { + char pad = out_c[len - 1]; + out_c[len - pad] = 0; + /* + COAP_DEBUG("decrypt data:%s, len:%d", out_c, len - pad); + */ + HAL_Aes128_Destroy(aes_d_h); + return len - pad; + } + } + HAL_Aes128_Destroy(aes_d_h); + + return 0; +} + + +#if AES_CFB_NOPADDING +static int iotx_aes_cfb_encrypt(const unsigned char *src, int len, const unsigned char *key, void *out) +{ + int ret = -1; + char *iv = "543yhjy97ae7fyfg"; + + p_HAL_Aes128_t aes_e_h = HAL_Aes128_Init((unsigned char *)key, (unsigned char *)iv, HAL_AES_ENCRYPTION); + ret = HAL_Aes128_Cfb_Encrypt(aes_e_h, src, len, out); + HAL_Aes128_Destroy(aes_e_h); + + COAP_DEBUG("to encrypt src:%s, len:%d", src, len); + return len; +} + +int iotx_aes_cfb_decrypt(const unsigned char *src, int len, const unsigned char *key, void *out) +{ + int ret = -1; + char *iv = "543yhjy97ae7fyfg"; + + p_HAL_Aes128_t aes_d_h = HAL_Aes128_Init((unsigned char *)key, (unsigned char *)iv, HAL_AES_ENCRYPTION); + ret = HAL_Aes128_Cfb_Decrypt(aes_d_h, src, len, out); + HAL_Aes128_Destroy(aes_d_h); + + return ret; +} +#endif + +int IOT_CoAP_DeviceNameAuth(iotx_coap_context_t *p_context) +{ + int len = 0; + int ret = COAP_SUCCESS; + Cloud_CoAPContext *p_coap_ctx = NULL; + iotx_coap_t *p_iotx_coap = NULL; + Cloud_CoAPMessage message; + unsigned char *p_payload = NULL; + unsigned char token[8] = {0}; + char sign[IOTX_SIGN_LENGTH] = {0}; + + p_iotx_coap = (iotx_coap_t *)p_context; + if (NULL == p_iotx_coap || + (NULL != p_iotx_coap && + (NULL == p_iotx_coap->p_auth_token || NULL == p_iotx_coap->p_coap_ctx || 0 == p_iotx_coap->auth_token_len))) { + COAP_DEBUG("Invalid paramter"); + return IOTX_ERR_INVALID_PARAM; + } + + p_coap_ctx = (Cloud_CoAPContext *)p_iotx_coap->p_coap_ctx; + + CoAPMessage_init(&message); + CoAPMessageType_set(&message, COAP_MESSAGE_TYPE_CON); + CoAPMessageCode_set(&message, COAP_MSG_CODE_POST); + CoAPMessageId_set(&message, Cloud_CoAPMessageId_gen(p_coap_ctx)); + len = iotx_get_coap_token(p_iotx_coap, token); + CoAPMessageToken_set(&message, token, len); + Cloud_CoAPMessageHandler_set(&message, iotx_device_name_auth_callback); + + CoAPStrOption_add(&message, COAP_OPTION_URI_PATH, (unsigned char *)IOTX_AUTH_STR, strlen(IOTX_AUTH_STR)); + CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT, COAP_CT_APP_JSON); + CoAPUintOption_add(&message, COAP_OPTION_ACCEPT, COAP_CT_APP_JSON); + + CoAPMessageUserData_set(&message, (void *)p_iotx_coap); + + p_payload = coap_malloc(COAP_MSG_MAX_PDU_LEN); + if (NULL == p_payload) { + CoAPMessage_destory(&message); + return IOTX_ERR_NO_MEM; + } + memset(p_payload, 0x00, COAP_MSG_MAX_PDU_LEN); + + if (COAP_ENDPOINT_PSK == p_iotx_coap->p_coap_ctx->network.ep_type) { + iotx_calc_sign_with_seq(p_iotx_coap->p_devinfo->device_secret, p_iotx_coap->p_devinfo->device_id, + p_iotx_coap->p_devinfo->device_name, p_iotx_coap->p_devinfo->product_key, p_iotx_coap->seq, sign); + HAL_Snprintf((char *)p_payload, COAP_MSG_MAX_PDU_LEN, + IOTX_AUTH_DEVICENAME_STR_WITH_SEQ, + p_iotx_coap->p_devinfo->product_key, + p_iotx_coap->p_devinfo->device_name, + p_iotx_coap->p_devinfo->device_id, + sign, p_iotx_coap->seq); + + } else { + iotx_calc_sign(p_iotx_coap->p_devinfo->device_secret, p_iotx_coap->p_devinfo->device_id, + p_iotx_coap->p_devinfo->device_name, p_iotx_coap->p_devinfo->product_key, sign); + HAL_Snprintf((char *)p_payload, COAP_MSG_MAX_PDU_LEN, + IOTX_AUTH_DEVICENAME_STR, + p_iotx_coap->p_devinfo->product_key, + p_iotx_coap->p_devinfo->device_name, + p_iotx_coap->p_devinfo->device_id, + sign); + } + CoAPMessagePayload_set(&message, p_payload, strlen((char *)p_payload)); + COAP_DEBUG("The payload is: %s", message.payload); + COAP_DEBUG("Send authentication message to server"); + ret = Cloud_CoAPMessage_send(p_coap_ctx, &message); + coap_free(p_payload); + CoAPMessage_destory(&message); + + if (COAP_SUCCESS != ret) { + COAP_DEBUG("Send authentication message to server failed, ret = %d", ret); + return IOTX_ERR_SEND_MSG_FAILED; + } + + ret = Cloud_CoAPMessage_recv(p_coap_ctx, CONFIG_COAP_AUTH_TIMEOUT, 2); + if (0 < ret && !p_iotx_coap->is_authed) { + COAP_INFO("CoAP authenticate failed"); + return IOTX_ERR_AUTH_FAILED; + } + + + iotx_set_report_func(coap_report_func); + /* report module id */ + ret = iotx_report_mid(p_context); + if (SUCCESS_RETURN != ret) { + COAP_WRN("Send ModuleId message to server(CoAP) failed, ret = %d", ret); + } + /* report device information */ + ret = iotx_report_devinfo(p_context); + if (SUCCESS_RETURN != ret) { + COAP_WRN("Send devinfo message to server(CoAP) failed, ret = %d", ret); + } + +#if 0 + /* report firmware version */ + ret = iotx_report_firmware_version(p_context); + if (SUCCESS_RETURN != ret) { + COAP_DEBUG("Send firmware message to server(CoAP) failed, ret = %d", ret); + return IOTX_ERR_SEND_MSG_FAILED; + } +#endif + + return IOTX_SUCCESS; +} + +static int iotx_split_path_2_option(char *uri, Cloud_CoAPMessage *message) +{ + char *ptr = NULL; + char *pstr = NULL; + char path[COAP_MSG_MAX_PATH_LEN] = {0}; + + if (NULL == uri || NULL == message) { + COAP_ERR("Invalid paramter p_path %p, p_message %p", uri, message); + return IOTX_ERR_INVALID_PARAM; + } + if (IOTX_URI_MAX_LEN < strlen(uri)) { + COAP_ERR("The uri length is too loog,len = %d", (int)strlen(uri)); + return IOTX_ERR_URI_TOO_LOOG; + } + COAP_DEBUG("The uri is %s", uri); + ptr = pstr = uri; + while ('\0' != *ptr) { + if ('/' == *ptr) { + if (ptr != pstr) { + memset(path, 0x00, sizeof(path)); + strncpy(path, pstr, ptr - pstr); + COAP_DEBUG("path: %s,len=%d", path, (int)(ptr - pstr)); + CoAPStrOption_add(message, COAP_OPTION_URI_PATH, + (unsigned char *)path, (int)strlen(path)); + } + pstr = ptr + 1; + + } + if ('\0' == *(ptr + 1) && '\0' != *pstr) { + memset(path, 0x00, sizeof(path)); + strncpy(path, pstr, sizeof(path) - 1); + COAP_DEBUG("path: %s,len=%d", path, (int)strlen(path)); + CoAPStrOption_add(message, COAP_OPTION_URI_PATH, + (unsigned char *)path, (int)strlen(path)); + } + ptr ++; + } + return IOTX_SUCCESS; +} + +uint32_t IOT_CoAP_GetCurToken(iotx_coap_context_t *p_context) +{ + iotx_coap_t *p_iotx_coap = NULL; + + if (p_context == NULL) { + return IOTX_ERR_INVALID_PARAM; + } + p_iotx_coap = (iotx_coap_t *)p_context; + + return p_iotx_coap->coap_token; +} + +int IOT_CoAP_SendMessage(iotx_coap_context_t *p_context, char *p_path, iotx_message_t *p_message) +{ + + int len = 0; + int ret = IOTX_SUCCESS; + Cloud_CoAPContext *p_coap_ctx = NULL; + iotx_coap_t *p_iotx_coap = NULL; + Cloud_CoAPMessage message; + unsigned char token[8] = {0}; + unsigned char *payload = NULL; + + p_iotx_coap = (iotx_coap_t *)p_context; + + if (NULL == p_context || NULL == p_path || NULL == p_message || + (NULL != p_iotx_coap && NULL == p_iotx_coap->p_coap_ctx)) { + COAP_ERR("Invalid paramter p_context %p, p_uri %p, p_message %p", + p_context, p_path, p_message); + return IOTX_ERR_INVALID_PARAM; + } + +#ifdef INFRA_LOG_NETWORK_PAYLOAD + COAP_INFO("Upstream Topic: '%s'", p_path); + COAP_INFO("Upstream Payload:"); + iotx_facility_json_print((const char *)p_message->p_payload, LOG_INFO_LEVEL, '>'); +#endif + + /* as this function only support POST request message, type ACK and RST shall be considered error parameters */ + if (p_message->msg_type != IOTX_MESSAGE_CON && p_message->msg_type != IOTX_MESSAGE_NON) { + return IOTX_ERR_INVALID_PARAM; + } + + if (p_message->payload_len >= COAP_MSG_MAX_PDU_LEN) { + COAP_ERR("The payload length %d is too loog", p_message->payload_len); + return IOTX_ERR_MSG_TOO_LOOG; + } + + p_coap_ctx = (Cloud_CoAPContext *)p_iotx_coap->p_coap_ctx; + if (p_iotx_coap->is_authed) { + + /* CoAPMessage_init(&message); */ + CoAPMessage_init(&message); + CoAPMessageType_set(&message, p_message->msg_type); + CoAPMessageCode_set(&message, COAP_MSG_CODE_POST); + CoAPMessageId_set(&message, Cloud_CoAPMessageId_gen(p_coap_ctx)); + len = iotx_get_coap_token(p_iotx_coap, token); + CoAPMessageToken_set(&message, token, len); + CoAPMessageUserData_set(&message, (void *)p_message->user_data); + Cloud_CoAPMessageHandler_set(&message, p_message->resp_callback); + + ret = iotx_split_path_2_option(p_path, &message); + if (IOTX_SUCCESS != ret) { + return ret; + } + + if (IOTX_CONTENT_TYPE_CBOR == p_message->content_type) { + CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT, COAP_CT_APP_CBOR); + CoAPUintOption_add(&message, COAP_OPTION_ACCEPT, COAP_CT_APP_OCTET_STREAM); + } else { + CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT, COAP_CT_APP_JSON); + CoAPUintOption_add(&message, COAP_OPTION_ACCEPT, COAP_CT_APP_OCTET_STREAM); + } + CoAPStrOption_add(&message, COAP_OPTION_AUTH_TOKEN, + (unsigned char *)p_iotx_coap->p_auth_token, strlen(p_iotx_coap->p_auth_token)); + if (COAP_ENDPOINT_PSK == p_iotx_coap->p_coap_ctx->network.ep_type) { + unsigned char buff[32] = {0}; + unsigned char seq[33] = {0}; + HAL_Snprintf((char *)buff, sizeof(buff) - 1, "%d", p_iotx_coap->seq++); + len = iotx_aes_cbc_encrypt(buff, strlen((char *)buff), p_iotx_coap->key, seq); + if (0 < len) { + CoAPStrOption_add(&message, COAP_OPTION_SEQ, (unsigned char *)seq, len); + } else { + COAP_INFO("Encrypt seq failed"); + } + HEXDUMP_DEBUG(seq, len); + + payload = (unsigned char *)coap_malloc(COAP_MSG_MAX_PDU_LEN); + if (NULL == payload) { + return IOTX_ERR_NO_MEM; + } + memset(payload, 0x00, COAP_MSG_MAX_PDU_LEN); + len = iotx_aes_cbc_encrypt(p_message->p_payload, p_message->payload_len, p_iotx_coap->key, payload); + if (0 == len) { + coap_free(payload); + payload = NULL; + return IOTX_ERR_INVALID_PARAM; + } + + HEXDUMP_DEBUG(payload, len); + CoAPMessagePayload_set(&message, payload, len); + } else { + CoAPMessagePayload_set(&message, p_message->p_payload, p_message->payload_len); + } + ret = Cloud_CoAPMessage_send(p_coap_ctx, &message); + CoAPMessage_destory(&message); + if (NULL != payload) { + coap_free(payload); + payload = NULL; + } + + if (COAP_ERROR_DATA_SIZE == ret) { + return IOTX_ERR_MSG_TOO_LOOG; + } + + return IOTX_SUCCESS; + } else { + COAP_ERR("The client [%s/%s] still un-authorized yet, return %d", + p_iotx_coap->p_devinfo->product_key, + p_iotx_coap->p_devinfo->device_name, + IOTX_ERR_NOT_AUTHED + ); + return IOTX_ERR_NOT_AUTHED; + } +} + + +int IOT_CoAP_GetMessagePayload(void *p_message, unsigned char **pp_payload, int *p_len) +{ + Cloud_CoAPMessage *message = NULL; + iotx_coap_t *p_iotx_coap = NULL; + + if (NULL == p_message || NULL == pp_payload || NULL == p_len || NULL == g_coap_context) { + COAP_ERR("Invalid parameter: p_message=%p, pp_payload=%p, p_len=%p", + p_message, pp_payload, p_len); + return IOTX_ERR_INVALID_PARAM; + } + + p_iotx_coap = (iotx_coap_t *)g_coap_context; + message = (Cloud_CoAPMessage *)p_message; + + COAP_DEBUG("message->payload: %p", message->payload); + COAP_DEBUG("message->payloadlen: %d", message->payloadlen); + + if (message->payloadlen >= COAP_MSG_MAX_PDU_LEN) { + COAP_ERR("Invalid parameter: message->payloadlen(%d) out of [0, %d]", + message->payloadlen, COAP_MSG_MAX_PDU_LEN); + return IOTX_ERR_INVALID_PARAM; + } + + if (COAP_ENDPOINT_PSK == p_iotx_coap->p_coap_ctx->network.ep_type) { + int len = 0; + unsigned char *payload = NULL; + payload = coap_malloc(COAP_MSG_MAX_PDU_LEN); + if (NULL == payload) { + return IOTX_ERR_NO_MEM; + } + memset(payload, 0x00, COAP_MSG_MAX_PDU_LEN); + + HEXDUMP_DEBUG(message->payload, message->payloadlen); + + len = iotx_aes_cbc_decrypt(message->payload, message->payloadlen, p_iotx_coap->key, payload); + if (len > 0) { + COAP_DEBUG("payload: %.*s, len %d", len, payload, len); + } + if (len != 0) { + memcpy(message->payload, payload, len); + message->payloadlen = len; + HEXDUMP_DEBUG(payload, len); + } + + coap_free(payload); + } + + *pp_payload = message->payload; + *p_len = message->payloadlen; + + return IOTX_SUCCESS; +} + +int IOT_CoAP_GetMessageToken(void *p_message, unsigned int *token) +{ + + Cloud_CoAPMessage *message = NULL; + + if (NULL == p_message || NULL == token) { + COAP_ERR("Invalid paramter p_message %p, token= %p", p_message, token); + return -1; + } + message = (Cloud_CoAPMessage *)p_message; + + *token = ((unsigned int)(message->token[3]) & 0xff) << 24; + *token += ((unsigned int)(message->token[2]) & 0xff) << 16; + *token += ((unsigned int)(message->token[1]) & 0xff) << 8; + *token += ((unsigned int)(message->token[0]) & 0xff); + return 0; +} + +int IOT_CoAP_GetMessageCode(void *p_message, iotx_coap_resp_code_t *p_resp_code) +{ + Cloud_CoAPMessage *message = NULL; + + if (NULL == p_message || NULL == p_resp_code) { + COAP_ERR("Invalid paramter p_message %p, p_resp_code %p", + p_message, p_resp_code); + return IOTX_ERR_INVALID_PARAM; + } + message = (Cloud_CoAPMessage *)p_message; + *p_resp_code = (iotx_coap_resp_code_t) message->header.code; + + return IOTX_SUCCESS; +} + +static unsigned int iotx_get_seq(void) +{ + HAL_Srandom((unsigned int)HAL_UptimeMs()); + return HAL_Random(0xffffffff) % 10000; +} + +iotx_coap_context_t *IOT_CoAP_Init(iotx_coap_config_t *p_config) +{ + Cloud_CoAPInitParam param; + char url[128] = {0}; + iotx_coap_t *p_iotx_coap = NULL; + + if (NULL == p_config) { + COAP_ERR("Invalid paramter p_config %p", p_config); + return NULL; + } + if (NULL == p_config->p_devinfo) { + COAP_ERR("Invalid paramter p_devinfo %p", p_config->p_devinfo); + return NULL; + } + + p_iotx_coap = coap_malloc(sizeof(iotx_coap_t)); + if (NULL == p_iotx_coap) { + COAP_ERR(" Allocate memory for iotx_coap_context_t failed"); + return NULL; + } + memset(p_iotx_coap, 0x00, sizeof(iotx_coap_t)); + + p_iotx_coap->p_auth_token = coap_malloc(IOTX_AUTH_TOKEN_LEN); + if (NULL == p_iotx_coap->p_auth_token) { + COAP_ERR(" Allocate memory for auth token failed"); + goto err; + } + memset(p_iotx_coap->p_auth_token, 0x00, IOTX_AUTH_TOKEN_LEN); + + /*Set the client isn't authed*/ + p_iotx_coap->is_authed = IOT_FALSE; + p_iotx_coap->auth_token_len = IOTX_AUTH_TOKEN_LEN; + + /*Get deivce information*/ + p_iotx_coap->p_devinfo = coap_malloc(sizeof(iotx_deviceinfo_t)); + if (NULL == p_iotx_coap->p_devinfo) { + COAP_ERR(" Allocate memory for iotx_deviceinfo_t failed"); + goto err; + } + memset(p_iotx_coap->p_devinfo, 0x00, sizeof(iotx_deviceinfo_t)); + + /*It should be implement by the user*/ + if (NULL != p_config->p_devinfo) { + memset(p_iotx_coap->p_devinfo, 0x00, sizeof(iotx_deviceinfo_t)); + strncpy(p_iotx_coap->p_devinfo->device_id, p_config->p_devinfo->device_id, strlen(p_config->p_devinfo->device_id)); + strncpy(p_iotx_coap->p_devinfo->product_key, p_config->p_devinfo->product_key, + strlen(p_config->p_devinfo->product_key)); + strncpy(p_iotx_coap->p_devinfo->device_secret, p_config->p_devinfo->device_secret, + strlen(p_config->p_devinfo->device_secret)); + strncpy(p_iotx_coap->p_devinfo->device_name, p_config->p_devinfo->device_name, + strlen(p_config->p_devinfo->device_name)); + } + + /*Init coap token*/ + p_iotx_coap->coap_token = IOTX_COAP_INIT_TOKEN; + p_iotx_coap->seq = iotx_get_seq(); + memset(p_iotx_coap->key, 0x00, sizeof(p_iotx_coap->key)); + + /*Create coap context*/ + memset(¶m, 0x00, sizeof(Cloud_CoAPInitParam)); + + if (NULL != p_config->p_url) { + param.url = p_config->p_url; + } else { + HAL_Snprintf(url, sizeof(url), IOTX_COAP_ONLINE_PSK_SERVER_URL, p_iotx_coap->p_devinfo->product_key); + param.url = url; + COAP_INFO("Using default CoAP server: %s", url); + } + param.maxcount = IOTX_LIST_MAX_ITEM; + param.notifier = (Cloud_CoAPEventNotifier)iotx_event_notifyer; + param.waittime = p_config->wait_time_ms; + p_iotx_coap->p_coap_ctx = Cloud_CoAPContext_create(¶m); + if (NULL == p_iotx_coap->p_coap_ctx) { + COAP_ERR(" Create coap context failed"); + goto err; + } + + /*Register the event handle to notify the application */ + p_iotx_coap->event_handle = p_config->event_handle; + + g_coap_context = (iotx_coap_context_t *)p_iotx_coap; + return (iotx_coap_context_t *)p_iotx_coap; +err: + /* Error, release the memory */ + if (NULL != p_iotx_coap) { + if (NULL != p_iotx_coap->p_devinfo) { + coap_free(p_iotx_coap->p_devinfo); + } + if (NULL != p_iotx_coap->p_auth_token) { + coap_free(p_iotx_coap->p_auth_token); + } + if (NULL != p_iotx_coap->p_coap_ctx) { + Cloud_CoAPContext_free(p_iotx_coap->p_coap_ctx); + } + + p_iotx_coap->auth_token_len = 0; + p_iotx_coap->is_authed = IOT_FALSE; + coap_free(p_iotx_coap); + } + return NULL; +} + +void IOT_CoAP_Deinit(iotx_coap_context_t **pp_context) +{ + iotx_coap_t *p_iotx_coap = NULL; + + if (NULL != pp_context && NULL != *pp_context) { + p_iotx_coap = (iotx_coap_t *)*pp_context; + p_iotx_coap->is_authed = IOT_FALSE; + p_iotx_coap->auth_token_len = 0; + p_iotx_coap->coap_token = IOTX_COAP_INIT_TOKEN; + + if (NULL != p_iotx_coap->p_auth_token) { + coap_free(p_iotx_coap->p_auth_token); + p_iotx_coap->p_auth_token = NULL; + } + + if (NULL != p_iotx_coap->p_devinfo) { + coap_free(p_iotx_coap->p_devinfo); + p_iotx_coap->p_devinfo = NULL; + } + + if (NULL != p_iotx_coap->p_coap_ctx) { + Cloud_CoAPContext_free(p_iotx_coap->p_coap_ctx); + p_iotx_coap->p_coap_ctx = NULL; + } + coap_free(p_iotx_coap); + *pp_context = NULL; + g_coap_context = NULL; + } +} + +int IOT_CoAP_Yield(iotx_coap_context_t *p_context) +{ + iotx_coap_t *p_iotx_coap = NULL; + p_iotx_coap = (iotx_coap_t *)p_context; + if (NULL == p_iotx_coap || (NULL != p_iotx_coap && NULL == p_iotx_coap->p_coap_ctx)) { + COAP_ERR("Invalid paramter"); + return IOTX_ERR_INVALID_PARAM; + } + + return Cloud_CoAPMessage_cycle(p_iotx_coap->p_coap_ctx); +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/iotx_coap_config.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/iotx_coap_config.h new file mode 100644 index 00000000..489903e3 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/iotx_coap_config.h @@ -0,0 +1,17 @@ +#ifndef __IOTX_COAP_CONFIG__ +#define __IOTX_COAP_CONFIG__ + +#define COAP_MSG_MAX_TOKEN_LEN 8 +#define COAP_MSG_MAX_OPTION_NUM 12 +#define COAP_MSG_MAX_PATH_LEN 128 +#ifndef COAP_LARGE_MEMORY_SUPPORT +#define COAP_MSG_MAX_PDU_LEN 1280 +#else +#define COAP_MSG_MAX_PDU_LEN 4096 +#endif + +#ifndef CONFIG_COAP_AUTH_TIMEOUT + #define CONFIG_COAP_AUTH_TIMEOUT (3 * 1000) +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/iotx_coap_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/iotx_coap_internal.h new file mode 100644 index 00000000..364634e6 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_cloud/iotx_coap_internal.h @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef __IOTX_COAP_INTERNAL__ +#define __IOTX_COAP_INTERNAL__ + +#include +#include +#include "infra_string.h" +#include "infra_compat.h" +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_log.h" +#include "infra_json_parser.h" +#include "infra_cjson.h" +#include "infra_list.h" +#include "infra_md5.h" +#include "infra_sha256.h" +#include "infra_report.h" +#include "iotx_coap_config.h" +#include "coap_wrapper.h" +#include "iotx_coap_config.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*CoAP Content Type*/ +#define COAP_CT_TEXT_PLAIN 0 /* text/plain (UTF-8) */ +#define COAP_CT_APP_LINK_FORMAT 40 /* application/link-format */ +#define COAP_CT_APP_XML 41 /* application/xml */ +#define COAP_CT_APP_OCTET_STREAM 42 /* application/octet-stream */ +#define COAP_CT_APP_RDF_XML 43 /* application/rdf+xml */ +#define COAP_CT_APP_EXI 47 /* application/exi */ +#define COAP_CT_APP_JSON 50 /* application/json */ +#define COAP_CT_APP_CBOR 60 /* application/cbor */ + +/*CoAP option types. */ +#define COAP_OPTION_IF_MATCH 1 /* C, opaque, 0-8 B, (none) */ +#define COAP_OPTION_URI_HOST 3 /* C, String, 1-255 B, destination address */ +#define COAP_OPTION_ETAG 4 /* E, opaque, 1-8 B, (none) */ +#define COAP_OPTION_IF_NONE_MATCH 5 /* empty, 0 B, (none) */ +#define COAP_OPTION_OBSERVE 6 /* E, empty/uint, 0 B/0-3 B, (none)*/ +#define COAP_OPTION_URI_PORT 7 /* C, uint, 0-2 B, destination port */ +#define COAP_OPTION_LOCATION_PATH 8 /* E, String, 0-255 B, - */ +#define COAP_OPTION_URI_PATH 11 /* C, String, 0-255 B, (none) */ +#define COAP_OPTION_CONTENT_FORMAT 12 /* E, uint, 0-2 B, (none) */ +#define COAP_OPTION_MAXAGE 14 /* E, uint, 0--4 B, 60 Seconds */ +#define COAP_OPTION_URI_QUERY 15 /* C, String, 1-255 B, (none) */ +#define COAP_OPTION_ACCEPT 17 /* C, uint, 0-2 B, (none) */ +#define COAP_OPTION_LOCATION_QUERY 20 /* E, String, 0-255 B, (none) */ +#define COAP_OPTION_BLOCK2 23 /* C, uint, 0--3 B, (none) */ +#define COAP_OPTION_BLOCK1 27 /* C, uint, 0--3 B, (none) */ +#define COAP_OPTION_PROXY_URI 35 /* C, String, 1-1024 B, (none) */ +#define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */ +#define COAP_OPTION_SIZE1 60 /* E, uint, 0-4 B, (none) */ +#define COAP_OPTION_AUTH_TOKEN 61 /* C, String, 1-255B, (none)*/ + +#define COAP_PERM_NONE 0x0000 +#define COAP_PERM_GET 0x0001 +#define COAP_PERM_POST 0x0002 +#define COAP_PERM_PUT 0x0004 +#define COAP_PERM_DELETE 0x0008 +#define COAP_PERM_OBSERVE 0x0100 + +/*CoAP Message types*/ +#define COAP_MESSAGE_TYPE_CON 0 +#define COAP_MESSAGE_TYPE_NON 1 +#define COAP_MESSAGE_TYPE_ACK 2 +#define COAP_MESSAGE_TYPE_RST 3 + +/* CoAP module error code base */ +#define COAP_ERROR_BASE (1<<8) +#define COAP_ERROR_DTLS_BASE (1<<16) + +/* CoAP base error code */ +#define COAP_SUCCESS (0) /* Successful */ +#define COAP_ERROR_INVALID_PARAM (COAP_ERROR_BASE | 1) /* Invalid Parameter */ +#define COAP_ERROR_NULL (COAP_ERROR_BASE | 2) /* Null Pointer */ +#define COAP_ERROR_MALLOC (COAP_ERROR_BASE | 3) +#define COAP_ERROR_INVALID_LENGTH (COAP_ERROR_BASE | 4) /* Invalid Length */ +#define COAP_ERROR_DATA_SIZE (COAP_ERROR_BASE | 5) /* Data size exceeds limit */ +#define COAP_ERROR_INVALID_URI (COAP_ERROR_BASE | 6) +#define COAP_ERROR_NOT_FOUND (COAP_ERROR_BASE | 7) +#define COAP_ERROR_NET_INIT_FAILED (COAP_ERROR_BASE | 8) +#define COAP_ERROR_INTERNAL (COAP_ERROR_BASE | 9) /* Internal Error */ +#define COAP_ERROR_WRITE_FAILED (COAP_ERROR_BASE | 10) +#define COAP_ERROR_READ_FAILED (COAP_ERROR_BASE | 11) +#define COAP_ERROR_ENCRYPT_FAILED (COAP_ERROR_BASE | 12) +#define COAP_ERROR_UNSUPPORTED (COAP_ERROR_BASE | 13) +#define COAP_ERROR_OBJ_ALREADY_EXIST (COAP_ERROR_BASE | 14) + +#define COAP_MSG_CODE_DEF(N) (((N)/100 << 5) | (N)%100) + +/*CoAP Message codes*/ +typedef enum { + /* CoAP Empty Message */ + COAP_MSG_CODE_EMPTY_MESSAGE = COAP_MSG_CODE_DEF(0), /* Mapping to CoAP code 0.00 */ + + /* CoAP Method Codes */ + COAP_MSG_CODE_GET = COAP_MSG_CODE_DEF(1), /* CoAP Get method */ + COAP_MSG_CODE_POST = COAP_MSG_CODE_DEF(2), /* CoAP Post method */ + COAP_MSG_CODE_PUT = COAP_MSG_CODE_DEF(3), /* CoAP Put method */ + COAP_MSG_CODE_DELETE = COAP_MSG_CODE_DEF(4), /* CoAP Delete method */ + + /* CoAP Success Response Codes */ + COAP_MSG_CODE_201_CREATED = COAP_MSG_CODE_DEF(201), /* Mapping to CoAP code 2.01, Hex:0x41, Created */ + COAP_MSG_CODE_202_DELETED = COAP_MSG_CODE_DEF(202), /* Mapping to CoAP code 2.02, Hex:0x42, Deleted*/ + COAP_MSG_CODE_203_VALID = COAP_MSG_CODE_DEF(203), /* Mapping to CoAP code 2.03, Hex:0x43, Valid*/ + COAP_MSG_CODE_204_CHANGED = COAP_MSG_CODE_DEF(204), /* Mapping to CoAP code 2.04, Hex:0x44, Changed*/ + COAP_MSG_CODE_205_CONTENT = COAP_MSG_CODE_DEF(205), /* Mapping to CoAP code 2.05, Hex:0x45, Content*/ + COAP_MSG_CODE_231_CONTINUE = COAP_MSG_CODE_DEF(231), /* Mapping to CoAP code 2.31, Hex:0x5F, Continue*/ + + /* CoAP Client Error Response Codes */ + COAP_MSG_CODE_400_BAD_REQUEST = COAP_MSG_CODE_DEF(400), /* Mapping to CoAP code 4.00, Hex:0x80, Bad Request */ + COAP_MSG_CODE_401_UNAUTHORIZED = COAP_MSG_CODE_DEF(401), /* Mapping to CoAP code 4.01, Hex:0x81, Unauthorized */ + COAP_MSG_CODE_402_BAD_OPTION = COAP_MSG_CODE_DEF(402), /* Mapping to CoAP code 4.02, Hex:0x82, Bad Option */ + COAP_MSG_CODE_403_FORBIDDEN = COAP_MSG_CODE_DEF(403), /* Mapping to CoAP code 4.03, Hex:0x83, Forbidden */ + COAP_MSG_CODE_404_NOT_FOUND = COAP_MSG_CODE_DEF(404), /* Mapping to CoAP code 4.04, Hex:0x84, Not Found */ + COAP_MSG_CODE_405_METHOD_NOT_ALLOWED = COAP_MSG_CODE_DEF(405), /* Mapping to CoAP code 4.05, Hex:0x85, Method Not Allowed */ + COAP_MSG_CODE_406_NOT_ACCEPTABLE = COAP_MSG_CODE_DEF(406), /* Mapping to CoAP code 4.06, Hex:0x86, Not Acceptable */ + COAP_MSG_CODE_408_REQUEST_ENTITY_INCOMPLETE = COAP_MSG_CODE_DEF(408), /* Mapping to CoAP code 4.08, Hex:0x88, Request Entity Incomplete */ + COAP_MSG_CODE_412_PRECONDITION_FAILED = COAP_MSG_CODE_DEF(412), /* Mapping to CoAP code 4.12, Hex:0x8C, Precondition Failed */ + COAP_MSG_CODE_413_REQUEST_ENTITY_TOO_LARGE = COAP_MSG_CODE_DEF(413), /* Mapping to CoAP code 4.13, Hex:0x8D, Request Entity Too Large */ + COAP_MSG_CODE_415_UNSUPPORTED_CONTENT_FORMAT = COAP_MSG_CODE_DEF(415), /* Mapping to CoAP code 4.15, Hex:0x8F, Unsupported Content-Format */ + + /* CoAP Server Error Response Codes */ + COAP_MSG_CODE_500_INTERNAL_SERVER_ERROR = COAP_MSG_CODE_DEF(500), /* Mapping to CoAP code 5.00, Hex:0xA0, Internal Server Error */ + COAP_MSG_CODE_501_NOT_IMPLEMENTED = COAP_MSG_CODE_DEF(501), /* Mapping to CoAP code 5.01, Hex:0xA1, Not Implemented */ + COAP_MSG_CODE_502_BAD_GATEWAY = COAP_MSG_CODE_DEF(502), /* Mapping to CoAP code 5.02, Hex:0xA2, Bad Gateway */ + COAP_MSG_CODE_503_SERVICE_UNAVAILABLE = COAP_MSG_CODE_DEF(503), /* Mapping to CoAP code 5.03, Hex:0xA3, Service Unavailable */ + COAP_MSG_CODE_504_GATEWAY_TIMEOUT = COAP_MSG_CODE_DEF(504), /* Mapping to CoAP code 5.04, Hex:0xA4, Gateway Timeout */ + COAP_MSG_CODE_505_PROXYING_NOT_SUPPORTED = COAP_MSG_CODE_DEF(505) /* Mapping to CoAP code 5.05, Hex:0xA5, Proxying Not Supported */ + +} CoAPMessageCode; + +typedef enum { + COAP_REQUEST_SUCCESS = 0, + COAP_RECV_RESP_TIMEOUT, + COAP_RECV_RESP_SUC, +} CoAPReqResult; + +typedef struct { + int len; + unsigned char *data; +} CoAPLenString; + +typedef struct { + unsigned char version : 2; + unsigned char type : 2; + unsigned char tokenlen : 4; + unsigned char code; + unsigned short msgid; +} CoAPMsgHeader; + + +typedef struct { + unsigned short num; + unsigned short len; + unsigned char *val; +} CoAPMsgOption; + +typedef void CoAPContext; +typedef struct CoAPMessage CoAPMessage; + +typedef void (*CoAPSendMsgHandler)(CoAPContext *context, CoAPReqResult result, void *userdata, NetworkAddr *remote, + CoAPMessage *message); + +typedef void (*CoAPEventNotifier)(unsigned int event, NetworkAddr *remote, void *message); + +typedef void (*CoAPRecvMsgHandler)(CoAPContext *context, const char *paths, NetworkAddr *remote, CoAPMessage *message); + +typedef int (*CoAPDataEncrypt)(CoAPContext *context, const char *paths, NetworkAddr *addr, CoAPMessage *message, + CoAPLenString *src, CoAPLenString *dest); +typedef void (*CoAPRespMsgHandler)(void *data, void *message); + +struct CoAPMessage { + CoAPMsgHeader header; + unsigned char token[COAP_MSG_MAX_TOKEN_LEN]; + CoAPMsgOption options[COAP_MSG_MAX_OPTION_NUM]; + unsigned char optcount; + unsigned char optdelta; + unsigned short payloadlen; + unsigned char *payload; + CoAPSendMsgHandler handler; + CoAPRespMsgHandler resp; + void *user; + int keep; +}; + + +/* CoAP message options APIs*/ +extern int CoAPStrOption_add(CoAPMessage *message, unsigned short optnum, + unsigned char *data, unsigned short datalen); + +extern int CoAPStrOption_get(CoAPMessage *message, unsigned short optnum, + unsigned char *data, unsigned short *datalen); + +extern int CoAPUintOption_add(CoAPMessage *message, unsigned short optnum, + unsigned int data); + +extern int CoAPUintOption_get(CoAPMessage *message, + unsigned short optnum, + unsigned int *data); + +extern int CoAPOption_present(CoAPMessage *message, unsigned short option); + + + +extern int CoAPMessageId_set(CoAPMessage *message, unsigned short msgid); + +extern int CoAPMessageType_set(CoAPMessage *message, unsigned char type); + +extern int CoAPMessageCode_set(CoAPMessage *message, CoAPMessageCode code); + +extern int CoAPMessageCode_get(CoAPMessage *message, CoAPMessageCode *code); + +extern int CoAPMessageToken_set(CoAPMessage *message, unsigned char *token, + unsigned char tokenlen); + +extern int CoAPMessageUserData_set(CoAPMessage *message, void *userdata); + +extern int CoAPMessageKeep_Set(CoAPMessage *message, int keep); + +extern int CoAPMessagePayload_set(CoAPMessage *message, unsigned char *payload, + unsigned short payloadlen); + +extern int CoAPMessageHandler_set(CoAPMessage *message, CoAPSendMsgHandler handler); + +extern int CoAPMessage_init(CoAPMessage *message); + +extern int CoAPMessage_destory(CoAPMessage *message); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPDeserialize.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPDeserialize.h new file mode 100644 index 00000000..8d0cef68 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPDeserialize.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef __COAP_DESERIALIZE_H__ +#define __COAP_DESERIALIZE_H__ +#include +#include "iotx_coap_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int CoAPDeserialize_Message(CoAPMessage *msg, unsigned char *buf, int buflen); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPDeserialize_common.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPDeserialize_common.c new file mode 100644 index 00000000..c034a795 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPDeserialize_common.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#include +#include +#include "iotx_coap_internal.h" + +int CoAPDeserialize_Header(CoAPMessage *msg, unsigned char *buf) +{ + msg->header.version = ((buf[0] >> 6) & 0x03); + msg->header.type = ((buf[0] >> 4) & 0x03); + msg->header.tokenlen = (buf[0] & 0x0F); + msg->header.code = buf[1]; + msg->header.msgid = buf[2] << 8; + msg->header.msgid += buf[3]; + + return 4; +} + +int CoAPDeserialize_Token(CoAPMessage *msg, unsigned char *buf) +{ + memcpy(msg->token, buf, msg->header.tokenlen); + return msg->header.tokenlen; +} + +static int CoAPDeserialize_Option(CoAPMsgOption *option, unsigned char *buf, unsigned short *predeltas) +{ + unsigned char *ptr = buf; + unsigned short optdelta = 0; + unsigned short optlen = 0; + unsigned short predelta = 0; + + optdelta = (*ptr & 0xF0) >> 4; + optlen = (*ptr & 0x0F); + ptr++; + + predelta = *predeltas; + if (13 == optdelta) { + predelta += 13 + *ptr; + ptr ++; + + } else if (14 == optdelta) { + predelta += 269; + predelta += (*ptr << 8); + predelta += *(ptr + 1); + ptr += 2; + } else { + predelta += optdelta; + } + option->num = predelta; + + if (13 == optlen) { + optlen = 13 + *ptr; + ptr ++; + } else if (14 == optlen) { + optlen = 269; + optlen += (*ptr << 8); + optlen += *(ptr + 1); + ptr += 2; + } + option->len = optlen; + + option->val = ptr; + *predeltas = option->num; + + return (ptr - buf + option->len); +} + +int CoAPDeserialize_Options(CoAPMessage *msg, unsigned char *buf, int buflen) +{ + int index = 0; + int count = 0; + unsigned char *ptr = buf; + unsigned short len = 0; + unsigned short optdeltas = 0; + + msg->optcount = 0; + while ((count < buflen) && (0xFF != *ptr)) { + len = CoAPDeserialize_Option(&msg->options[index], ptr, &optdeltas); + msg->optcount += 1; + ptr += len; + index ++; + count += len; + } + + return (int)(ptr - buf); +} + +int CoAPDeserialize_Payload(CoAPMessage *msg, unsigned char *buf, int buflen) +{ + unsigned char *ptr = buf; + + if (0xFF == *ptr) { + ptr ++; + } else { + return 0; + } + msg->payloadlen = buflen - 1; + msg->payload = (unsigned char *)ptr; + + return buflen; +} + +int CoAPDeserialize_Message(CoAPMessage *msg, unsigned char *buf, int buflen) +{ + int count = 0; + int remlen = buflen; + unsigned char *ptr = buf; + + if (NULL == buf || NULL == msg) { + return COAP_ERROR_INVALID_PARAM; + } + + if (buflen < 4) { + return COAP_ERROR_INVALID_LENGTH; + } + + /* Deserialize CoAP header. */ + count = CoAPDeserialize_Header(msg, ptr); + ptr += count; + remlen -= count; + + /* Deserialize the token, if any. */ + count = CoAPDeserialize_Token(msg, ptr); + ptr += count; + remlen -= count; + + count = CoAPDeserialize_Options(msg, ptr, remlen); + ptr += count; + remlen -= count; + + CoAPDeserialize_Payload(msg, ptr, remlen); + + return COAP_SUCCESS; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPMessage_common.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPMessage_common.c new file mode 100644 index 00000000..47e6104f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPMessage_common.c @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + + +#include +#include "iotx_coap_internal.h" +#include "CoAPSerialize.h" +#include "CoAPDeserialize.h" +#if 0 +#include "CoAPResource.h" +#include "CoAPObserve.h" +#include "CoAPInternal.h" +#endif +#include "CoAPPlatform.h" + +#define COAPAckMsg(header) \ + ((header.code == COAP_MSG_CODE_EMPTY_MESSAGE) \ + &&(header.type == COAP_MESSAGE_TYPE_ACK)) + +#define CoAPRespMsg(header)\ + ((header.code >= 0x40) && (header.code < 0xc0)) + +#define CoAPPingMsg(header)\ + ((header.code == COAP_MSG_CODE_EMPTY_MESSAGE)\ + && (header.type == COAP_MESSAGE_TYPE_CON)) + +#define CoAPResetMsg(header)\ + (header.type == COAP_MESSAGE_TYPE_RST) + +#define CoAPCONRespMsg(header)\ + ((header.code == COAP_MSG_CODE_205_CONTENT) \ + && (header.type == COAP_MESSAGE_TYPE_CON)) + +#define CoAPReqMsg(header)\ + ((1 <= header.code) && (32 > header.code)) + + +#define COAP_CUR_VERSION 1 +#define COAP_WAIT_TIME_MS 2000 +#define COAP_MAX_MESSAGE_ID 65535 +#define COAP_MAX_RETRY_COUNT 4 +#define COAP_ACK_TIMEOUT 2 +#define COAP_ACK_RANDOM_FACTOR 1 +#define COAP_MAX_TRANSMISSION_SPAN 10 + +int CoAPStrOption_add(CoAPMessage *message, unsigned short optnum, unsigned char *data, unsigned short datalen) +{ + unsigned char *ptr = NULL; + if (COAP_MSG_MAX_OPTION_NUM <= message->optcount) { + return COAP_ERROR_INVALID_PARAM; + } + + message->options[message->optcount].num = optnum - message->optdelta; + message->options[message->optcount].len = datalen; + ptr = (unsigned char *)coap_malloc(datalen); + if (NULL == ptr) { + return COAP_ERROR_MALLOC; + } + memset(ptr, 0x00, datalen); + memcpy(ptr, data, datalen); + message->options[message->optcount].val = ptr; + message->optdelta = optnum; + message->optcount ++; + + return COAP_SUCCESS; + +} + +int CoAPStrOption_get(CoAPMessage *message, unsigned short optnum, unsigned char *data, unsigned short *datalen) +{ + unsigned char index = 0; + + for (index = 0; index < message->optcount; index++) { + if (message->options[index].num == optnum) { + if (*datalen >= message->options[index].len) { + memcpy(data, message->options[index].val, message->options[index].len); + *datalen = message->options[index].len; + return COAP_SUCCESS; + } else { + return COAP_ERROR_INVALID_LENGTH; + } + } + } + + return COAP_ERROR_NOT_FOUND; + +} + + +int CoAPUintOption_add(CoAPMessage *message, unsigned short optnum, unsigned int data) +{ + unsigned char *ptr = NULL; + if (COAP_MSG_MAX_OPTION_NUM <= message->optcount) { + return COAP_ERROR_INVALID_PARAM; + } + message->options[message->optcount].num = optnum - message->optdelta; + + if (0 == data) { + message->options[message->optcount].len = 0; + } else if (255 >= data) { + message->options[message->optcount].len = 1; + ptr = (unsigned char *)coap_malloc(1); + if (NULL != ptr) { + *ptr = (unsigned char)data; + } + } else if (65535 >= data) { + message->options[message->optcount].len = 2; + ptr = (unsigned char *)coap_malloc(2); + if (NULL != ptr) { + *ptr = (unsigned char)((data & 0xFF00) >> 8); + *(ptr + 1) = (unsigned char)(data & 0x00FF); + } + } else { + message->options[message->optcount].len = 4; + ptr = (unsigned char *)coap_malloc(4); + if (NULL != ptr) { + *ptr = (unsigned char)((data & 0xFF000000) >> 24); + *(ptr + 1) = (unsigned char)((data & 0x00FF0000) >> 16); + *(ptr + 2) = (unsigned char)((data & 0x0000FF00) >> 8); + *(ptr + 3) = (unsigned char)(data & 0x000000FF); + } + } + message->options[message->optcount].val = ptr; + message->optdelta = optnum; + message->optcount += 1; + + return COAP_SUCCESS; +} + +int CoAPUintOption_get(CoAPMessage *message, + unsigned short optnum, + unsigned int *data) +{ + + unsigned char index = 0; + + for (index = 0; index < message->optcount; index++) { + if (message->options[index].num == optnum) { + int byte = 0; + switch (message->options[index].len) { + case 1: + *data |= message->options[index].val[byte++]; + break; + case 2: + *data |= (message->options[index].val[byte++] << 8); + *data |= message->options[index].val[byte++]; + break; + case 3: + *data |= (message->options[index].val[byte++] << 16); + *data |= (message->options[index].val[byte++] << 8); + *data |= message->options[index].val[byte++]; + break; + case 4: + *data |= (message->options[index].val[byte++] << 24); + *data |= (message->options[index].val[byte++] << 16); + *data |= (message->options[index].val[byte++] << 8); + *data |= message->options[index].val[byte++]; + break; + default: + *data = 0; + break; + } + return COAP_SUCCESS; + } + } + + return COAP_ERROR_NOT_FOUND; +} + + +int CoAPOption_present(CoAPMessage *message, unsigned short option) +{ + unsigned char index = 0; + + + for (index = 0; index < message->optcount; index++) { + if (message->options[index].num == option) { + return COAP_SUCCESS; + } + } + return COAP_ERROR_NOT_FOUND; +} + +int CoAPMessageId_set(CoAPMessage *message, unsigned short msgid) +{ + if (NULL == message) { + return COAP_ERROR_NULL; + } + message->header.msgid = msgid; + return COAP_SUCCESS; +} + +int CoAPMessageType_set(CoAPMessage *message, unsigned char type) +{ + if (NULL == message) { + return COAP_ERROR_NULL; + } + if (COAP_MESSAGE_TYPE_CON != type && COAP_MESSAGE_TYPE_NON != type + && COAP_MESSAGE_TYPE_ACK != type && COAP_MESSAGE_TYPE_RST != type) { + return COAP_ERROR_INVALID_PARAM; + } + + message->header.type = type; + return COAP_SUCCESS; +} + +int CoAPMessageCode_set(CoAPMessage *message, CoAPMessageCode code) +{ + if (NULL == message) { + return COAP_ERROR_NULL; + } + message->header.code = code; + return COAP_SUCCESS; +} + +int CoAPMessageCode_get(CoAPMessage *message, CoAPMessageCode *code) +{ + if (NULL == message || NULL == code) { + return COAP_ERROR_NULL; + } + *code = message->header.code; + return COAP_SUCCESS; +} + +int CoAPMessageToken_set(CoAPMessage *message, unsigned char *token, + unsigned char tokenlen) +{ + if (NULL == message || NULL == token) { + return COAP_ERROR_NULL; + } + if (COAP_MSG_MAX_TOKEN_LEN < tokenlen) { + return COAP_ERROR_INVALID_LENGTH; + } + memcpy(message->token, token, tokenlen); + message->header.tokenlen = tokenlen; + + return COAP_SUCCESS; +} + +int CoAPMessageUserData_set(CoAPMessage *message, void *userdata) +{ + if (NULL == message || NULL == userdata) { + return COAP_ERROR_NULL; + } + message->user = userdata; + return COAP_SUCCESS; +} + +int CoAPMessageKeep_Set(CoAPMessage *message, int keep) +{ + if (NULL == message || keep < 0) { + return COAP_ERROR_NULL; + } + message->keep = keep; + return COAP_SUCCESS; +} + +int CoAPMessagePayload_set(CoAPMessage *message, unsigned char *payload, + unsigned short payloadlen) +{ + if (NULL == message || (0 < payloadlen && NULL == payload)) { + return COAP_ERROR_NULL; + } + message->payload = payload; + message->payloadlen = payloadlen; + + return COAP_SUCCESS; +} + +int CoAPMessage_init(CoAPMessage *message) +{ + int count = 0; + + if (NULL == message) { + return COAP_ERROR_NULL; + } + memset(message, 0x00, sizeof(CoAPMessage)); + message->header.version = COAP_CUR_VERSION; + message->header.type = COAP_MESSAGE_TYPE_ACK; + message->header.tokenlen = 0; + message->header.code = COAP_MSG_CODE_EMPTY_MESSAGE; + message->header.msgid = 0; + message->payload = NULL; + message->payloadlen = 0; + message->optcount = 0; + message->optdelta = 0; + message->handler = NULL; + message->keep = 0; + for (count = 0; count < COAP_MSG_MAX_OPTION_NUM; count++) { + message->options[count].len = 0; + message->options[count].num = 0; + message->options[count].val = NULL; + } + + return COAP_SUCCESS; +} + +int CoAPMessage_destory(CoAPMessage *message) +{ + int count = 0; + if (NULL == message) { + return COAP_ERROR_NULL; + } + + for (count = 0; count < COAP_MSG_MAX_OPTION_NUM; count++) { + if (NULL != message->options[count].val) { + coap_free(message->options[count].val); + message->options[count].val = NULL; + } + } + + return COAP_SUCCESS; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPPlatform.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPPlatform.h new file mode 100644 index 00000000..02f6eca0 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPPlatform.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __COAP_PLATFORM_OS_H__ +#define __COAP_PLATFORM_OS_H__ + +#include +#include "iotx_coap_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define coap_malloc(size) LITE_malloc(size, MEM_MAGIC, "coap.local") + #define coap_free(ptr) LITE_free(ptr) +#else + #define coap_malloc(size) HAL_Malloc(size) + #define coap_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#ifdef INFRA_LOG + #include "infra_log.h" + #define COAP_ERR(...) log_err("coap_local", __VA_ARGS__) + #define COAP_WRN(...) log_warning("coap_local", __VA_ARGS__) + #define COAP_INFO(...) log_info("coap_local", __VA_ARGS__) + #define COAP_TRC(...) log_debug("coap_local", __VA_ARGS__) + #define COAP_DUMP(...) log_debug("coap_local", __VA_ARGS__) + #define COAP_DEBUG(...) log_debug("coap_local", __VA_ARGS__) + #define COAP_FLOW(...) log_flow("coap_local", __VA_ARGS__) +#else + #define COAP_ERR(...) + #define COAP_WRN(...) + #define COAP_INFO(...) + #define COAP_TRC(...) + #define COAP_DUMP(...) + #define COAP_DEBUG(...) + #define COAP_FLOW(...) +#endif + +int platform_is_multicast(const char *ip_str); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPSerialize.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPSerialize.h new file mode 100644 index 00000000..4a8177d1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPSerialize.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef __COAP_SERIALIZE_H__ +#define __COAP_SERIALIZE_H__ +#include "iotx_coap_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +unsigned short CoAPSerialize_MessageLength(CoAPMessage *msg); + +int CoAPSerialize_Message(CoAPMessage *msg, unsigned char *buf, unsigned short buflen); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPSerialize_common.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPSerialize_common.c new file mode 100644 index 00000000..ae2f0d89 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/CoAPPacket/CoAPSerialize_common.c @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#include +#include +#include "CoAPSerialize.h" +#include "iotx_coap_internal.h" + +int CoAPSerialize_Header(CoAPMessage *msg, unsigned char *buf, unsigned short buflen) +{ + if(4 > buflen){ + return 0; + } + buf[0] = (((msg->header.version & 0x3) << 6) | ((msg->header.type & 0x3) << 4)) + | (msg->header.tokenlen & 0x0F); + + buf[1] = msg->header.code; + buf[2] = (msg->header.msgid & 0xFF00) >> 8; + buf[3] = (msg->header.msgid & 0x00FF); + + return 4; +} + +int CoAPSerialize_Token(CoAPMessage *msg, unsigned char * buf, unsigned short buflen) +{ + int i = 0; + + if(buflen < msg->header.tokenlen){ + return 0; + } + for (i = 0; i < msg->header.tokenlen; i++){ + buf[i] = msg->token[i]; + } + return msg->header.tokenlen; +} + +static unsigned short CoAPSerialize_Option(CoAPMsgOption *option, unsigned char *buf) +{ + unsigned char *ptr = buf; + + if(269 <= option->num){ + *ptr = ((14 & 0x0F) << 4); + } + else if(13 <= option->num){ + *ptr = ((13 & 0x0F) << 4); + } + else{ + *ptr = option->num << 4; + } + + if (269 <= option->len){ + *ptr |= (14 & 0x0F); + } + else if(13 <= option->len){ + *ptr |= (13 & 0x0F); + } + else{ + *ptr |= (option->len & 0x0F); + } + ptr ++; + + if (269 <= option->num){ + *ptr = (unsigned char)(((option->num - 269) & 0xFF00) >> 8); + *(ptr+1) = (unsigned char)(((option->num - 269) & 0x00FF)); + ptr += 2; + } + else if(13 <= option->num){ + *ptr = (unsigned char)(option->num - 13); + ptr ++; + } + + + if (269 <= option->len){ + *ptr = (unsigned char)(((option->len - 269) & 0xFF00) >> 8); + *(ptr+1) = (unsigned char)(((option->len - 269) & 0x00FF)); + ptr += 2; + } + else if(13 <= option->len){ + *ptr = (unsigned char)(option->len - 13); + ptr ++; + } + + + memcpy(ptr, option->val, option->len); + ptr += option->len; + + return (int)(ptr - buf); +} + +unsigned short CoAPSerialize_Options(CoAPMessage *msg, unsigned char * buf, unsigned short buflen) +{ + int i = 0; + unsigned short count = 0; + + for (i = 0; i < msg->optcount; i++) + { + unsigned short len = 0; + len = CoAPSerialize_Option(&msg->options[i], &buf[count]); + if (0 < len){ + count += len; + } + else{ + return 0; + } + } + + return count; +} + +static unsigned short CoAPSerialize_OptionLen(CoAPMsgOption *option) +{ + unsigned short len = 1; + + if(269 <= option->num){ + len += 2; + } + else if(13 <= option->num){ + len += 1; + } + else{ + } + + if (269 <= option->len){ + len += 2; + } + else if(13 <= option->len){ + len += 1; + } + else{ + } + + len += option->len; + return len; +} + + +unsigned short CoAPSerialize_OptionsLen(CoAPMessage *msg) +{ + int i = 0; + unsigned short count = 0; + + for (i = 0; i < msg->optcount; i++) + { + unsigned short len = 0; + len = CoAPSerialize_OptionLen(&msg->options[i]); + if (0 < len){ + count += len; + } + else{ + return 0; + } + } + + return count; +} + + +int CoAPSerialize_Payload(CoAPMessage *msg, unsigned char *buf, int buflen) +{ + if(msg->payloadlen + 1 > buflen){ + return 0; + } + if(msg->payloadlen > 0 && NULL != msg->payload) + { + *buf = 0xFF; + buf ++; + memcpy(buf, msg->payload, msg->payloadlen); + return msg->payloadlen + 1; + } + else{ + return 0; + } +} + + +unsigned short CoAPSerialize_MessageLength(CoAPMessage *msg) +{ + unsigned short msglen = 4; + + msglen += msg->header.tokenlen; + msglen += CoAPSerialize_OptionsLen(msg); + + if(0 < msg->payloadlen){ + msglen += msg->payloadlen; + msglen += 1; /*CoAP payload marker*/ + } + + return msglen; +} + +int CoAPSerialize_Message(CoAPMessage *msg, unsigned char *buf, unsigned short buflen) +{ + unsigned char *ptr = buf; + unsigned short count = 0; + unsigned short remlen = buflen; + + if(NULL == buf || NULL == msg){ + return COAP_ERROR_INVALID_PARAM; + } + + count = CoAPSerialize_Header(msg, ptr, remlen); + ptr += count; + remlen -= count; + + count = CoAPSerialize_Token(msg, ptr, remlen); + ptr += count; + remlen -= count; + + count = CoAPSerialize_Options(msg, ptr, remlen); + ptr += count; + remlen -= count; + + count = CoAPSerialize_Payload(msg, ptr, remlen); + ptr += count; + remlen -= count; + + return (buflen-remlen); +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/coap_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/coap_api.h new file mode 100644 index 00000000..127990dc --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/coap_api.h @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __IOTX_COAP_API_H__ +#define __IOTX_COAP_API_H__ + +#if defined(__cplusplus) +extern "C" { +#endif + +#include "infra_defs.h" + +/*iotx return code definition*/ +typedef enum { + IOTX_ERR_RECV_MSG_TIMEOUT = -9, /*Receive message timeout */ + IOTX_ERR_SEND_MSG_FAILED = -8, /* Send message failed*/ + IOTX_ERR_MSG_TOO_LOOG = -7, /* The payload too loog */ + IOTX_ERR_URI_TOO_LOOG = -6, /* URI length too long */ + IOTX_ERR_NOT_AUTHED = -5, /* Client isn't authed */ + IOTX_ERR_AUTH_FAILED = -4, /* Client authed failed */ + IOTX_ERR_BUFF_TOO_SHORT = -3, /* Buffer too short */ + IOTX_ERR_NO_MEM = -2, /* Malloc failed */ + IOTX_ERR_INVALID_PARAM = -1, /* Invalid parameter */ + IOTX_SUCCESS = 0, /* Success */ +} iotx_ret_code_t; + +/* The message payload encode format */ +typedef enum { + IOTX_CONTENT_TYPE_JSON, + IOTX_CONTENT_TYPE_CBOR, +} iotx_content_type_t; + +/* The message type */ +typedef enum { + IOTX_MESSAGE_CON = 0, /* confirmable message */ + IOTX_MESSAGE_NON = 1, /* non-confirmable message */ + IOTX_MESSAGE_ACK = 2, /* acknowledgement message */ + IOTX_MESSAGE_RST = 3, /* reset message */ +} iotx_msg_type_t; + +/* IoTx events to notify application */ +typedef enum { + IOTX_COAP_EVENT_SEND_FAILED = 0, + IOTX_COAP_EVENT_RECV_FAILED = 1, + IOTX_COAP_EVENT_AUTH_FAILED = 2, +} iotx_coap_event_t; + +typedef enum { + IOTX_COAP_RESP_CODE_CONTENT = 0x45, /* Mapping to 2.05, Content*/ + IOTX_COAP_RESP_CODE_BAD_REQUEST = 0x80, /* Mapping to 4.00, Bad Request*/ + IOTX_COAP_RESP_CODE_UNAUTHORIZED = 0x81, /* Mapping to 4.01, Token is invalid or expire*/ + IOTX_COAP_RESP_CODE_NOT_FOUND = 0x84, /* Mapping to 4.04, Path or uri is not found*/ + IOTX_COAP_RESP_CODE_URL_TOO_LONG = 0x8E, /* Mapping to 4.14, The request url is too long*/ + IOTX_COAP_RESP_CODE_INTERNAL_SERVER_ERROR = 0xA0,/* Mapping to 5.00, Internal server error*/ + +} iotx_coap_resp_code_t; + +/* Callback function to notify the application events.*/ +typedef void (*iotx_event_handle_t)(void *context, iotx_coap_event_t event, void *p_data); + +/*IoTx device*/ +typedef struct { + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + char device_id[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 2]; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1]; +} iotx_deviceinfo_t; + +typedef struct { + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + char device_id[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 2]; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1]; + char module_vendor_id[IOTX_PARTNER_ID_LEN + 1]; +} iotx_device_info_t; + +/* IoTx initializa parameters */ +typedef struct { + char *p_url; /*Can be NULL*/ + int wait_time_ms; /*unit is micro second*/ + iotx_device_info_t *p_devinfo; /*Device info*/ + iotx_event_handle_t event_handle; /*TODO, not supported now*/ +} iotx_coap_config_t; + +/* Callback function to handle the response message.*/ +typedef void (*iotx_response_callback_t)(void *p_arg, void *p_message); + +/* IoTx message definition */ +typedef struct { + unsigned char *p_payload; + unsigned short payload_len; + iotx_content_type_t content_type; + iotx_msg_type_t msg_type; + void *user_data; + iotx_response_callback_t resp_callback; +} iotx_message_t; + + +/*iotx coap context definition*/ +typedef void iotx_coap_context_t; + + +/** @defgroup group_api api + * @{ + */ + +/** @defgroup group_api_coap coap + * @{ + */ + +/** + * @brief Initialize the CoAP client. + * This function initialize the data structures and network, + * and create the DTLS session. + * + * @param [in] p_config: Specify the CoAP client parameter. + * + * @retval NULL : Initialize failed. + * @retval NOT_NULL : The contex of CoAP client. + * @see None. + */ +iotx_coap_context_t *IOT_CoAP_Init(iotx_coap_config_t *p_config); + +/** + * @brief De-initialize the CoAP client. + * This function release CoAP DTLS session. + * and release the related resource. + * + * @param [in] p_context: Pointer of contex, specify the CoAP client. + * + * @return None. + * @see None. + */ +DLL_IOT_API void IOT_CoAP_Deinit(iotx_coap_context_t **p_context); + + +/** + * @brief Handle device name authentication with remote server. + * + * @param [in] p_context: Pointer of contex, specify the CoAP client. + * + * @retval IOTX_SUCCESS : Authenticate success. + * @retval IOTX_ERR_SEND_MSG_FAILED : Send authentication message failed. + * @retval IOTX_ERR_AUTH_FAILED : Authenticate failed or timeout. + * @see iotx_ret_code_t. + */ +DLL_IOT_API int IOT_CoAP_DeviceNameAuth(iotx_coap_context_t *p_context); + + +/** + * @brief Handle CoAP response packet from remote server, + * and process timeout request etc.. + * + * @param [in] p_context : Pointer of contex, specify the CoAP client. + * + * @return status. + * @see iotx_ret_code_t. + */ +DLL_IOT_API int IOT_CoAP_Yield(iotx_coap_context_t *p_context); + + +/** + * @brief Send a message with specific path to server. + * Client must authentication with server before send message. + * + * @param [in] p_context : Pointer of contex, specify the CoAP client. + * @param [in] p_path: Specify the path name. + * @param [in] p_message: Message to be sent. + * + * @retval IOTX_SUCCESS : Send the message success. + * @retval IOTX_ERR_MSG_TOO_LOOG : The message length is too long. + * @retval IOTX_ERR_NOT_AUTHED : The client hasn't authenticated with server + * @see iotx_ret_code_t. + */ +DLL_IOT_API int IOT_CoAP_SendMessage(iotx_coap_context_t *p_context, char *p_path, iotx_message_t *p_message); + +/** +* @brief Retrieves the length and payload pointer of specified message. +* +* @param [in] p_message: Pointer to the message to get the payload. Should not be NULL. +* @param [out] pp_payload: Pointer to the payload. +* @param [out] p_len: Size of the payload. +* +* @retval IOTX_SUCCESS : Get the payload success. +* @retval IOTX_ERR_INVALID_PARAM : Can't get the payload due to invalid parameter. +* @see iotx_ret_code_t. +**/ +DLL_IOT_API int IOT_CoAP_GetMessagePayload(void *p_message, unsigned char **pp_payload, int *p_len); + +/** +* @brief Get the response code from a CoAP message. +* +* @param [in] p_message: Pointer to the message to add the address information to. +* Should not be NULL. +* @param [out] p_resp_code: The response code. +* +* @retval IOTX_SUCCESS : When get the response code to message success. +* @retval IOTX_ERR_INVALID_PARAM : Pointer to the message is NULL. +* @see iotx_ret_code_t. +**/ +DLL_IOT_API int IOT_CoAP_GetMessageCode(void *p_message, iotx_coap_resp_code_t *p_resp_code); + +/** @} */ /* end of api_coap */ +/** @} */ /* end of api */ + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/coap_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/coap_wrapper.h new file mode 100644 index 00000000..d11faa30 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/coap_wrapper.h @@ -0,0 +1,90 @@ +#ifndef _COAP_WRAPPER_H_ +#define _COAP_WRAPPER_H_ + +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_compat.h" +#include "wrappers_defs.h" + +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); +void HAL_SleepMs(uint32_t ms); +uint64_t HAL_UptimeMs(void); +void HAL_Srandom(uint32_t seed); +uint32_t HAL_Random(uint32_t region); +void HAL_Printf(const char *fmt, ...); +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); + +int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN]); +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN]); +int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN]); + +int HAL_SetProductKey(char *product_key); +int HAL_SetProductSecret(char *product_secret); +int HAL_SetDeviceName(char *device_name); +int HAL_SetDeviceSecret(char *device_secret); + +DLL_HAL_API int HAL_DTLSHooks_set(dtls_hooks_t *hooks); +DLL_HAL_API DTLSContext *HAL_DTLSSession_create(coap_dtls_options_t *p_options); +DLL_HAL_API unsigned int HAL_DTLSSession_write(DTLSContext *context, + const unsigned char *p_data, + unsigned int *p_datalen); +DLL_HAL_API unsigned int HAL_DTLSSession_read(DTLSContext *context, + unsigned char *p_data, + unsigned int *p_datalen, + unsigned int timeout_ms); +DLL_HAL_API unsigned int HAL_DTLSSession_free(DTLSContext *context); +intptr_t HAL_UDP_create(char *host, unsigned short port); +intptr_t HAL_UDP_create_without_connect(const char *host, unsigned short port); +int HAL_UDP_write(intptr_t p_socket, + const unsigned char *p_data, + unsigned int datalen); +int HAL_UDP_readTimeout(intptr_t p_socket, + unsigned char *p_data, + unsigned int datalen, + unsigned int timeout); +int HAL_UDP_close_without_connect(intptr_t sockfd); +int HAL_UDP_recvfrom(intptr_t sockfd, + NetworkAddr *p_remote, + unsigned char *p_data, + unsigned int datalen, + unsigned int timeout_ms); +int HAL_UDP_sendto(intptr_t sockfd, + const NetworkAddr *p_remote, + const unsigned char *p_data, + unsigned int datalen, + unsigned int timeout_ms); +int HAL_UDP_joinmulticast(intptr_t sockfd, + char *p_group); +uint32_t HAL_Wifi_Get_IP(char ip_str[NETWORK_ADDR_LEN], const char *ifname); +p_HAL_Aes128_t HAL_Aes128_Init( + const uint8_t *key, + const uint8_t *iv, + AES_DIR_t dir); +int HAL_Aes128_Destroy(p_HAL_Aes128_t aes); +int HAL_Aes128_Cbc_Encrypt( + p_HAL_Aes128_t aes, + const void *src, + size_t blockNum, + void *dst); +int HAL_Aes128_Cbc_Decrypt( + p_HAL_Aes128_t aes, + const void *src, + size_t blockNum, + void *dst); +void *HAL_MutexCreate(void); +void HAL_MutexDestroy(void *mutex); +void HAL_MutexLock(void *mutex); +void HAL_MutexUnlock(void *mutex); +void *HAL_SemaphoreCreate(void); +void HAL_SemaphoreDestroy(void *sem); +int HAL_SemaphoreWait(void *sem, uint32_t timeout_ms); +void HAL_SemaphorePost(void *sem); +int HAL_ThreadCreate( + void **thread_handle, + void *(*work_routine)(void *), + void *arg, + hal_os_thread_param_t *hal_os_thread_param, + int *stack_used); +void HAL_ThreadDelete(void *thread_handle); +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/iotx_coap.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/iotx_coap.h new file mode 100644 index 00000000..e557ef7a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/iotx_coap.h @@ -0,0 +1,2 @@ +#include "CoAPServer.h" +#include "iotx_coap_internal.h" diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/iotx_coap_config.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/iotx_coap_config.h new file mode 100644 index 00000000..489903e3 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/iotx_coap_config.h @@ -0,0 +1,17 @@ +#ifndef __IOTX_COAP_CONFIG__ +#define __IOTX_COAP_CONFIG__ + +#define COAP_MSG_MAX_TOKEN_LEN 8 +#define COAP_MSG_MAX_OPTION_NUM 12 +#define COAP_MSG_MAX_PATH_LEN 128 +#ifndef COAP_LARGE_MEMORY_SUPPORT +#define COAP_MSG_MAX_PDU_LEN 1280 +#else +#define COAP_MSG_MAX_PDU_LEN 4096 +#endif + +#ifndef CONFIG_COAP_AUTH_TIMEOUT + #define CONFIG_COAP_AUTH_TIMEOUT (3 * 1000) +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/iotx_coap_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/iotx_coap_internal.h new file mode 100644 index 00000000..364634e6 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/iotx_coap_internal.h @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef __IOTX_COAP_INTERNAL__ +#define __IOTX_COAP_INTERNAL__ + +#include +#include +#include "infra_string.h" +#include "infra_compat.h" +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_log.h" +#include "infra_json_parser.h" +#include "infra_cjson.h" +#include "infra_list.h" +#include "infra_md5.h" +#include "infra_sha256.h" +#include "infra_report.h" +#include "iotx_coap_config.h" +#include "coap_wrapper.h" +#include "iotx_coap_config.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*CoAP Content Type*/ +#define COAP_CT_TEXT_PLAIN 0 /* text/plain (UTF-8) */ +#define COAP_CT_APP_LINK_FORMAT 40 /* application/link-format */ +#define COAP_CT_APP_XML 41 /* application/xml */ +#define COAP_CT_APP_OCTET_STREAM 42 /* application/octet-stream */ +#define COAP_CT_APP_RDF_XML 43 /* application/rdf+xml */ +#define COAP_CT_APP_EXI 47 /* application/exi */ +#define COAP_CT_APP_JSON 50 /* application/json */ +#define COAP_CT_APP_CBOR 60 /* application/cbor */ + +/*CoAP option types. */ +#define COAP_OPTION_IF_MATCH 1 /* C, opaque, 0-8 B, (none) */ +#define COAP_OPTION_URI_HOST 3 /* C, String, 1-255 B, destination address */ +#define COAP_OPTION_ETAG 4 /* E, opaque, 1-8 B, (none) */ +#define COAP_OPTION_IF_NONE_MATCH 5 /* empty, 0 B, (none) */ +#define COAP_OPTION_OBSERVE 6 /* E, empty/uint, 0 B/0-3 B, (none)*/ +#define COAP_OPTION_URI_PORT 7 /* C, uint, 0-2 B, destination port */ +#define COAP_OPTION_LOCATION_PATH 8 /* E, String, 0-255 B, - */ +#define COAP_OPTION_URI_PATH 11 /* C, String, 0-255 B, (none) */ +#define COAP_OPTION_CONTENT_FORMAT 12 /* E, uint, 0-2 B, (none) */ +#define COAP_OPTION_MAXAGE 14 /* E, uint, 0--4 B, 60 Seconds */ +#define COAP_OPTION_URI_QUERY 15 /* C, String, 1-255 B, (none) */ +#define COAP_OPTION_ACCEPT 17 /* C, uint, 0-2 B, (none) */ +#define COAP_OPTION_LOCATION_QUERY 20 /* E, String, 0-255 B, (none) */ +#define COAP_OPTION_BLOCK2 23 /* C, uint, 0--3 B, (none) */ +#define COAP_OPTION_BLOCK1 27 /* C, uint, 0--3 B, (none) */ +#define COAP_OPTION_PROXY_URI 35 /* C, String, 1-1024 B, (none) */ +#define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */ +#define COAP_OPTION_SIZE1 60 /* E, uint, 0-4 B, (none) */ +#define COAP_OPTION_AUTH_TOKEN 61 /* C, String, 1-255B, (none)*/ + +#define COAP_PERM_NONE 0x0000 +#define COAP_PERM_GET 0x0001 +#define COAP_PERM_POST 0x0002 +#define COAP_PERM_PUT 0x0004 +#define COAP_PERM_DELETE 0x0008 +#define COAP_PERM_OBSERVE 0x0100 + +/*CoAP Message types*/ +#define COAP_MESSAGE_TYPE_CON 0 +#define COAP_MESSAGE_TYPE_NON 1 +#define COAP_MESSAGE_TYPE_ACK 2 +#define COAP_MESSAGE_TYPE_RST 3 + +/* CoAP module error code base */ +#define COAP_ERROR_BASE (1<<8) +#define COAP_ERROR_DTLS_BASE (1<<16) + +/* CoAP base error code */ +#define COAP_SUCCESS (0) /* Successful */ +#define COAP_ERROR_INVALID_PARAM (COAP_ERROR_BASE | 1) /* Invalid Parameter */ +#define COAP_ERROR_NULL (COAP_ERROR_BASE | 2) /* Null Pointer */ +#define COAP_ERROR_MALLOC (COAP_ERROR_BASE | 3) +#define COAP_ERROR_INVALID_LENGTH (COAP_ERROR_BASE | 4) /* Invalid Length */ +#define COAP_ERROR_DATA_SIZE (COAP_ERROR_BASE | 5) /* Data size exceeds limit */ +#define COAP_ERROR_INVALID_URI (COAP_ERROR_BASE | 6) +#define COAP_ERROR_NOT_FOUND (COAP_ERROR_BASE | 7) +#define COAP_ERROR_NET_INIT_FAILED (COAP_ERROR_BASE | 8) +#define COAP_ERROR_INTERNAL (COAP_ERROR_BASE | 9) /* Internal Error */ +#define COAP_ERROR_WRITE_FAILED (COAP_ERROR_BASE | 10) +#define COAP_ERROR_READ_FAILED (COAP_ERROR_BASE | 11) +#define COAP_ERROR_ENCRYPT_FAILED (COAP_ERROR_BASE | 12) +#define COAP_ERROR_UNSUPPORTED (COAP_ERROR_BASE | 13) +#define COAP_ERROR_OBJ_ALREADY_EXIST (COAP_ERROR_BASE | 14) + +#define COAP_MSG_CODE_DEF(N) (((N)/100 << 5) | (N)%100) + +/*CoAP Message codes*/ +typedef enum { + /* CoAP Empty Message */ + COAP_MSG_CODE_EMPTY_MESSAGE = COAP_MSG_CODE_DEF(0), /* Mapping to CoAP code 0.00 */ + + /* CoAP Method Codes */ + COAP_MSG_CODE_GET = COAP_MSG_CODE_DEF(1), /* CoAP Get method */ + COAP_MSG_CODE_POST = COAP_MSG_CODE_DEF(2), /* CoAP Post method */ + COAP_MSG_CODE_PUT = COAP_MSG_CODE_DEF(3), /* CoAP Put method */ + COAP_MSG_CODE_DELETE = COAP_MSG_CODE_DEF(4), /* CoAP Delete method */ + + /* CoAP Success Response Codes */ + COAP_MSG_CODE_201_CREATED = COAP_MSG_CODE_DEF(201), /* Mapping to CoAP code 2.01, Hex:0x41, Created */ + COAP_MSG_CODE_202_DELETED = COAP_MSG_CODE_DEF(202), /* Mapping to CoAP code 2.02, Hex:0x42, Deleted*/ + COAP_MSG_CODE_203_VALID = COAP_MSG_CODE_DEF(203), /* Mapping to CoAP code 2.03, Hex:0x43, Valid*/ + COAP_MSG_CODE_204_CHANGED = COAP_MSG_CODE_DEF(204), /* Mapping to CoAP code 2.04, Hex:0x44, Changed*/ + COAP_MSG_CODE_205_CONTENT = COAP_MSG_CODE_DEF(205), /* Mapping to CoAP code 2.05, Hex:0x45, Content*/ + COAP_MSG_CODE_231_CONTINUE = COAP_MSG_CODE_DEF(231), /* Mapping to CoAP code 2.31, Hex:0x5F, Continue*/ + + /* CoAP Client Error Response Codes */ + COAP_MSG_CODE_400_BAD_REQUEST = COAP_MSG_CODE_DEF(400), /* Mapping to CoAP code 4.00, Hex:0x80, Bad Request */ + COAP_MSG_CODE_401_UNAUTHORIZED = COAP_MSG_CODE_DEF(401), /* Mapping to CoAP code 4.01, Hex:0x81, Unauthorized */ + COAP_MSG_CODE_402_BAD_OPTION = COAP_MSG_CODE_DEF(402), /* Mapping to CoAP code 4.02, Hex:0x82, Bad Option */ + COAP_MSG_CODE_403_FORBIDDEN = COAP_MSG_CODE_DEF(403), /* Mapping to CoAP code 4.03, Hex:0x83, Forbidden */ + COAP_MSG_CODE_404_NOT_FOUND = COAP_MSG_CODE_DEF(404), /* Mapping to CoAP code 4.04, Hex:0x84, Not Found */ + COAP_MSG_CODE_405_METHOD_NOT_ALLOWED = COAP_MSG_CODE_DEF(405), /* Mapping to CoAP code 4.05, Hex:0x85, Method Not Allowed */ + COAP_MSG_CODE_406_NOT_ACCEPTABLE = COAP_MSG_CODE_DEF(406), /* Mapping to CoAP code 4.06, Hex:0x86, Not Acceptable */ + COAP_MSG_CODE_408_REQUEST_ENTITY_INCOMPLETE = COAP_MSG_CODE_DEF(408), /* Mapping to CoAP code 4.08, Hex:0x88, Request Entity Incomplete */ + COAP_MSG_CODE_412_PRECONDITION_FAILED = COAP_MSG_CODE_DEF(412), /* Mapping to CoAP code 4.12, Hex:0x8C, Precondition Failed */ + COAP_MSG_CODE_413_REQUEST_ENTITY_TOO_LARGE = COAP_MSG_CODE_DEF(413), /* Mapping to CoAP code 4.13, Hex:0x8D, Request Entity Too Large */ + COAP_MSG_CODE_415_UNSUPPORTED_CONTENT_FORMAT = COAP_MSG_CODE_DEF(415), /* Mapping to CoAP code 4.15, Hex:0x8F, Unsupported Content-Format */ + + /* CoAP Server Error Response Codes */ + COAP_MSG_CODE_500_INTERNAL_SERVER_ERROR = COAP_MSG_CODE_DEF(500), /* Mapping to CoAP code 5.00, Hex:0xA0, Internal Server Error */ + COAP_MSG_CODE_501_NOT_IMPLEMENTED = COAP_MSG_CODE_DEF(501), /* Mapping to CoAP code 5.01, Hex:0xA1, Not Implemented */ + COAP_MSG_CODE_502_BAD_GATEWAY = COAP_MSG_CODE_DEF(502), /* Mapping to CoAP code 5.02, Hex:0xA2, Bad Gateway */ + COAP_MSG_CODE_503_SERVICE_UNAVAILABLE = COAP_MSG_CODE_DEF(503), /* Mapping to CoAP code 5.03, Hex:0xA3, Service Unavailable */ + COAP_MSG_CODE_504_GATEWAY_TIMEOUT = COAP_MSG_CODE_DEF(504), /* Mapping to CoAP code 5.04, Hex:0xA4, Gateway Timeout */ + COAP_MSG_CODE_505_PROXYING_NOT_SUPPORTED = COAP_MSG_CODE_DEF(505) /* Mapping to CoAP code 5.05, Hex:0xA5, Proxying Not Supported */ + +} CoAPMessageCode; + +typedef enum { + COAP_REQUEST_SUCCESS = 0, + COAP_RECV_RESP_TIMEOUT, + COAP_RECV_RESP_SUC, +} CoAPReqResult; + +typedef struct { + int len; + unsigned char *data; +} CoAPLenString; + +typedef struct { + unsigned char version : 2; + unsigned char type : 2; + unsigned char tokenlen : 4; + unsigned char code; + unsigned short msgid; +} CoAPMsgHeader; + + +typedef struct { + unsigned short num; + unsigned short len; + unsigned char *val; +} CoAPMsgOption; + +typedef void CoAPContext; +typedef struct CoAPMessage CoAPMessage; + +typedef void (*CoAPSendMsgHandler)(CoAPContext *context, CoAPReqResult result, void *userdata, NetworkAddr *remote, + CoAPMessage *message); + +typedef void (*CoAPEventNotifier)(unsigned int event, NetworkAddr *remote, void *message); + +typedef void (*CoAPRecvMsgHandler)(CoAPContext *context, const char *paths, NetworkAddr *remote, CoAPMessage *message); + +typedef int (*CoAPDataEncrypt)(CoAPContext *context, const char *paths, NetworkAddr *addr, CoAPMessage *message, + CoAPLenString *src, CoAPLenString *dest); +typedef void (*CoAPRespMsgHandler)(void *data, void *message); + +struct CoAPMessage { + CoAPMsgHeader header; + unsigned char token[COAP_MSG_MAX_TOKEN_LEN]; + CoAPMsgOption options[COAP_MSG_MAX_OPTION_NUM]; + unsigned char optcount; + unsigned char optdelta; + unsigned short payloadlen; + unsigned char *payload; + CoAPSendMsgHandler handler; + CoAPRespMsgHandler resp; + void *user; + int keep; +}; + + +/* CoAP message options APIs*/ +extern int CoAPStrOption_add(CoAPMessage *message, unsigned short optnum, + unsigned char *data, unsigned short datalen); + +extern int CoAPStrOption_get(CoAPMessage *message, unsigned short optnum, + unsigned char *data, unsigned short *datalen); + +extern int CoAPUintOption_add(CoAPMessage *message, unsigned short optnum, + unsigned int data); + +extern int CoAPUintOption_get(CoAPMessage *message, + unsigned short optnum, + unsigned int *data); + +extern int CoAPOption_present(CoAPMessage *message, unsigned short option); + + + +extern int CoAPMessageId_set(CoAPMessage *message, unsigned short msgid); + +extern int CoAPMessageType_set(CoAPMessage *message, unsigned char type); + +extern int CoAPMessageCode_set(CoAPMessage *message, CoAPMessageCode code); + +extern int CoAPMessageCode_get(CoAPMessage *message, CoAPMessageCode *code); + +extern int CoAPMessageToken_set(CoAPMessage *message, unsigned char *token, + unsigned char tokenlen); + +extern int CoAPMessageUserData_set(CoAPMessage *message, void *userdata); + +extern int CoAPMessageKeep_Set(CoAPMessage *message, int keep); + +extern int CoAPMessagePayload_set(CoAPMessage *message, unsigned char *payload, + unsigned short payloadlen); + +extern int CoAPMessageHandler_set(CoAPMessage *message, CoAPSendMsgHandler handler); + +extern int CoAPMessage_init(CoAPMessage *message); + +extern int CoAPMessage_destory(CoAPMessage *message); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPExport.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPExport.c new file mode 100644 index 00000000..d6e03973 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPExport.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#include +#include +#include +#include "ctype.h" +#include "iotx_coap_internal.h" +#include "CoAPPlatform.h" +#include "CoAPInternal.h" +#include "CoAPNetwork.h" +#include "CoAPExport.h" +#include "CoAPObserve.h" + +#define COAP_DEFAULT_PORT 5683 /* CoAP default UDP port */ +#define COAPS_DEFAULT_PORT 5684 /* CoAP default UDP port for secure transmission */ +#define COAP_DEFAULT_SENDLIST_MAXCOUNT 8 +#define COAP_DEFAULT_RES_MAXCOUNT 8 +#define COAP_DEFAULT_OBS_MAXCOUNT 8 + +#define COAP_DEFAULT_SCHEME "coap" /* the default scheme for CoAP URIs */ +#define COAP_DEFAULT_HOST_LEN 128 +#define COAP_DEFAULT_WAIT_TIME_MS 2000 + + +CoAPContext *CoAPContext_create(CoAPInitParam *param) +{ + CoAPIntContext *p_ctx = NULL; + NetworkInit network_param; + + memset(&network_param, 0x00, sizeof(NetworkInit)); + p_ctx = coap_malloc(sizeof(CoAPIntContext)); + if (NULL == p_ctx) { + COAP_ERR("malloc for coap context failed"); + goto err; + } + COAP_DEBUG("Send List Max-Count: %d", param->send_maxcount); + COAP_DEBUG("Observe Server Max-Count: %d", param->obs_maxcount); + COAP_DEBUG("Observe Client Max-Count: %d", param->obs_maxcount); + COAP_DEBUG("Resource Max-Count: %d", param->res_maxcount); + COAP_DEBUG("MultiCast Address: %s:%d", param->group, param->port); + COAP_DEBUG("Send/Recv Wait time: %dms", param->waittime); + + memset(p_ctx, 0, sizeof(CoAPIntContext)); + p_ctx->message_id = 1; + p_ctx->notifier = param->notifier; + p_ctx->appdata = param->appdata; + +#ifdef USE_SENDBUFF + p_ctx->sendbuf = coap_malloc(COAP_MSG_MAX_PDU_LEN); + if (NULL == p_ctx->sendbuf) { + COAP_ERR("not enough memory"); + goto err; + } + memset(p_ctx->sendbuf, 0x00, COAP_MSG_MAX_PDU_LEN); +#endif + + p_ctx->recvbuf = coap_malloc(COAP_MSG_MAX_PDU_LEN); + if (NULL == p_ctx->recvbuf) { + COAP_ERR("not enough memory"); + goto err; + } + memset(p_ctx->recvbuf, 0x00, COAP_MSG_MAX_PDU_LEN); + + if (0 == param->waittime) { + p_ctx->waittime = COAP_DEFAULT_WAIT_TIME_MS; + } else { + p_ctx->waittime = param->waittime; + } + p_ctx->mutex = HAL_MutexCreate(); + if (NULL == p_ctx->mutex) { + COAP_ERR("Mutex Create failed"); + goto err; + } + + /*Init message send list mutex*/ + p_ctx->sendlist.list_mutex = HAL_MutexCreate(); + HAL_MutexLock(p_ctx->sendlist.list_mutex); + /*CoAP message send list*/ + INIT_LIST_HEAD(&p_ctx->sendlist.list); + p_ctx->sendlist.count = 0; + HAL_MutexUnlock(p_ctx->sendlist.list_mutex); + + if (0 != param->send_maxcount) { + p_ctx->sendlist.maxcount = param->send_maxcount; + } else { + p_ctx->sendlist.maxcount = COAP_DEFAULT_SENDLIST_MAXCOUNT; + } + + if (0 == param->res_maxcount) { + param->res_maxcount = COAP_DEFAULT_RES_MAXCOUNT; + } + CoAPResource_init(p_ctx, param->res_maxcount); + +#ifndef COAP_OBSERVE_SERVER_DISABLE + if (0 == param->obs_maxcount) { + param->obs_maxcount = COAP_DEFAULT_OBS_MAXCOUNT; + } + CoAPObsServer_init(p_ctx, param->obs_maxcount); +#endif + +#ifndef COAP_OBSERVE_CLIENT_DISABLE + if (0 == param->obs_maxcount) { + param->obs_maxcount = COAP_DEFAULT_OBS_MAXCOUNT; + } + CoAPObsClient_init(p_ctx, param->obs_maxcount); +#endif + +#ifdef COAP_DTLS_SUPPORT + network_param.type = COAP_NETWORK_DTLS; + network_param.port = COAPS_DEFAULT_PORT; +#else + network_param.type = COAP_NETWORK_NOSEC; + network_param.port = param->port; + network_param.group = param->group; +#endif + + + /*CoAP network init*/ + p_ctx->p_network = CoAPNetwork_init(&network_param); + + if (NULL == p_ctx->p_network) { + COAP_ERR("CoAP Network init failed, exit"); + goto err; + } + + return p_ctx; +err: + if (NULL == p_ctx) { + return p_ctx; + } + + if (NULL != p_ctx->recvbuf) { + coap_free(p_ctx->recvbuf); + p_ctx->recvbuf = NULL; + } + +#ifdef USE_SENDBUFF + if (NULL != p_ctx->sendbuf) { + coap_free(p_ctx->sendbuf); + p_ctx->sendbuf = NULL; + } +#endif + +#ifndef COAP_OBSERVE_SERVER_DISABLE + CoAPObsServer_deinit(p_ctx); +#endif + +#ifndef COAP_OBSERVE_CLIENT_DISABLE + CoAPObsClient_deinit(p_ctx); +#endif + + CoAPResource_deinit(p_ctx); + + if (NULL != p_ctx->sendlist.list_mutex) { + HAL_MutexDestroy(p_ctx->sendlist.list_mutex); + p_ctx->sendlist.list_mutex = NULL; + } + + if (NULL != p_ctx->mutex) { + HAL_MutexDestroy(p_ctx->mutex); + p_ctx->mutex = NULL; + } + + coap_free(p_ctx); + p_ctx = NULL; + + /* TODO: release the resource */ + return (CoAPContext *)p_ctx; +} + +void *CoAPContextAppdata_get(CoAPContext *context) +{ + CoAPIntContext *p_ctx = (CoAPIntContext *)context; + if (NULL == p_ctx) { + return NULL; + } + + return (void *)p_ctx->appdata; +} + + +void CoAPContext_free(CoAPContext *context) +{ + CoAPIntContext *p_ctx = NULL; + CoAPSendNode *cur = NULL, *next = NULL; + if (NULL == context) { + return; + } + + p_ctx = (CoAPIntContext *)context; + + CoAPNetwork_deinit(p_ctx->p_network); + COAP_DEBUG("CoAP Network Deinit"); + + HAL_MutexLock(p_ctx->sendlist.list_mutex); + list_for_each_entry_safe(cur, next, &p_ctx->sendlist.list, sendlist, CoAPSendNode) { + if (NULL != cur) { + if (NULL != cur->message) { + coap_free(cur->message); + cur->message = NULL; + } + coap_free(cur); + cur = NULL; + } + } + INIT_LIST_HEAD(&p_ctx->sendlist.list); + HAL_MutexUnlock(p_ctx->sendlist.list_mutex); + HAL_MutexDestroy(p_ctx->sendlist.list_mutex); + p_ctx->sendlist.list_mutex = NULL; + HAL_MutexDestroy(p_ctx->mutex); + p_ctx->mutex = NULL; + COAP_DEBUG("Release Send List and Memory"); + +#ifndef COAP_OBSERVE_SERVER_DISABLE + CoAPObsServer_deinit(p_ctx); + COAP_DEBUG("CoAP Observe Server Deinit"); +#endif + + +#ifndef COAP_OBSERVE_CLIENT_DISABLE + CoAPObsClient_deinit(p_ctx); + COAP_DEBUG("CoAP Observe Client Deinit"); +#endif + + CoAPResource_deinit(p_ctx); + COAP_DEBUG("CoAP Resource unregister"); + + if (NULL != p_ctx->recvbuf) { + coap_free(p_ctx->recvbuf); + p_ctx->recvbuf = NULL; + COAP_DEBUG("Release The Recv Memory"); + } +#ifdef USE_SENDBUFF + if (NULL != p_ctx->sendbuf) { + coap_free(p_ctx->sendbuf); + p_ctx->sendbuf = NULL; + COAP_DEBUG("Release The Send Memory"); + } +#endif + + if (NULL != p_ctx) { + coap_free(p_ctx); + p_ctx = NULL; + COAP_DEBUG("Release The CoAP Context"); + } +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPExport.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPExport.h new file mode 100644 index 00000000..bf2b9aab --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPExport.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __COAP_EXPORT_H__ +#define __COAP_EXPORT_H__ + +#include "../iotx_coap_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct { + unsigned char send_maxcount; /*list maximal count*/ + unsigned char obs_maxcount; /*observe maximal count*/ + unsigned short port; /* Local port */ + char *group; /* Multicast address */ + unsigned int waittime; + CoAPEventNotifier notifier; + void *appdata; + unsigned char res_maxcount; +} CoAPInitParam; + +typedef enum { + PATH_NORMAL, + PATH_FILTER, +} path_type_t; + +CoAPContext *CoAPContext_create(CoAPInitParam *param); + +void CoAPContext_free(CoAPContext *context); + +void *CoAPContextAppdata_get(CoAPContext *context); + +/* CoAP message options APIs*/ +extern int CoAPStrOption_add(CoAPMessage *message, unsigned short optnum, + unsigned char *data, unsigned short datalen); + +extern int CoAPStrOption_get(CoAPMessage *message, unsigned short optnum, + unsigned char *data, unsigned short *datalen); + +extern int CoAPUintOption_add(CoAPMessage *message, unsigned short optnum, + unsigned int data); + +extern int CoAPUintOption_get(CoAPMessage *message, + unsigned short optnum, + unsigned int *data); + +extern int CoAPOption_present(CoAPMessage *message, unsigned short option); + + +/*CoAP Message APIs*/ +extern unsigned short CoAPMessageId_gen(CoAPContext *context); + +extern int CoAPMessageId_set(CoAPMessage *message, unsigned short msgid); + +extern int CoAPMessageType_set(CoAPMessage *message, unsigned char type); + +extern int CoAPMessageCode_set(CoAPMessage *message, CoAPMessageCode code); + +extern int CoAPMessageCode_get(CoAPMessage *message, CoAPMessageCode *code); + +extern int CoAPMessageToken_set(CoAPMessage *message, unsigned char *token, + unsigned char tokenlen); + +extern int CoAPMessageUserData_set(CoAPMessage *message, void *userdata); + +extern int CoAPMessageKeep_Set(CoAPMessage *message, int keep); + +extern int CoAPMessagePayload_set(CoAPMessage *message, unsigned char *payload, + unsigned short payloadlen); + +extern int CoAPMessageHandler_set(CoAPMessage *message, CoAPSendMsgHandler handler); + +extern int CoAPMessage_init(CoAPMessage *message); + +extern int CoAPMessage_destory(CoAPMessage *message); + +extern int CoAPMessage_send(CoAPContext *context, NetworkAddr *remote, CoAPMessage *message); + +extern int CoAPMessage_process(CoAPContext *context, unsigned int timeout); + +extern int CoAPMessage_retransmit(CoAPContext *context); + +extern int CoAPMessage_cycle(CoAPContext *context); + +extern int CoAPMessage_cancel(CoAPContext *context, CoAPMessage *message); + +extern int CoAPMessageId_cancel(CoAPContext *context, unsigned short msgid); + +extern void CoAPMessage_dump(NetworkAddr *remote, CoAPMessage *message); +/*CoAP Resource APIs*/ +extern int CoAPResource_register(CoAPContext *context, const char *path, + unsigned short permission, unsigned int ctype, + unsigned int maxage, CoAPRecvMsgHandler callback); + +/*CoAP observe APIs*/ +extern int CoAPObsServer_add(CoAPContext *context, const char *path, NetworkAddr *remote, CoAPMessage *request); + +extern int CoAPObsServer_notify(CoAPContext *context, + const char *path, unsigned char *payload, + unsigned short payloadlen, CoAPDataEncrypt handler); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPInternal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPInternal.h new file mode 100644 index 00000000..b5441be4 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPInternal.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef __COAP_INTERNAL_H__ +#define __COAP_INTERNAL_H__ +#include "CoAPNetwork.h" +#include "CoAPExport.h" +#include "iotx_coap_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct +{ + void *list_mutex; + struct list_head list; + unsigned char count; + unsigned char maxcount; +}CoAPList; + + +typedef struct +{ + unsigned short message_id; + NetworkContext *p_network; + CoAPEventNotifier notifier; + unsigned char *sendbuf; + unsigned char *recvbuf; + CoAPList sendlist; + CoAPList obsserver; + CoAPList obsclient; + CoAPList resource; + unsigned int waittime; + void *appdata; + void *mutex; +}CoAPIntContext; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPMessage.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPMessage.c new file mode 100644 index 00000000..69e96311 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPMessage.c @@ -0,0 +1,675 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + + +#include +#include "CoAPExport.h" +#include "CoAPSerialize.h" +#include "CoAPDeserialize.h" +#include "CoAPResource.h" +#include "CoAPObserve.h" +#include "CoAPPlatform.h" +#include "CoAPInternal.h" +#include "iotx_coap_internal.h" + +#define COAPAckMsg(header) \ + ((header.code == COAP_MSG_CODE_EMPTY_MESSAGE) \ + &&(header.type == COAP_MESSAGE_TYPE_ACK)) + +#define CoAPRespMsg(header)\ + ((header.code >= 0x40) && (header.code < 0xc0)) + +#define CoAPPingMsg(header)\ + ((header.code == COAP_MSG_CODE_EMPTY_MESSAGE)\ + && (header.type == COAP_MESSAGE_TYPE_CON)) + +#define CoAPResetMsg(header)\ + (header.type == COAP_MESSAGE_TYPE_RST) + +#define CoAPCONRespMsg(header)\ + ((header.code == COAP_MSG_CODE_205_CONTENT) \ + && (header.type == COAP_MESSAGE_TYPE_CON)) + +#define CoAPReqMsg(header)\ + ((1 <= header.code) && (32 > header.code)) + + +#define NOKEEP 0 +#define KEEPING 1 +#define TOREMOVEKEEP 2 +#define COAP_CUR_VERSION 1 +#define COAP_MAX_MESSAGE_ID 65535 +#define COAP_MAX_RETRY_COUNT 8 +#define COAP_ACK_TIMEOUT 600 +#define COAP_ACK_RANDOM_FACTOR 1 + +unsigned short CoAPMessageId_gen(CoAPContext *context) +{ + unsigned short msg_id = 0; + CoAPIntContext *ctx = NULL; + if (!context) { + return msg_id; + } + ctx = (CoAPIntContext *)context; + HAL_MutexLock(ctx->mutex); + msg_id = ((COAP_MAX_MESSAGE_ID == ctx->message_id) ? (ctx->message_id = 1) : ctx->message_id++); + HAL_MutexUnlock(ctx->mutex); + return msg_id; +} + +int CoAPMessageHandler_set(CoAPMessage *message, CoAPSendMsgHandler handler) +{ + if (NULL == message) { + return COAP_ERROR_NULL; + } + message->handler = handler; + return COAP_SUCCESS; +} + +static int CoAPMessageList_add(CoAPContext *context, NetworkAddr *remote, + CoAPMessage *message, unsigned char *buffer, int len) +{ + CoAPIntContext *ctx = (CoAPIntContext *)context; + CoAPSendNode *node = NULL; + uint64_t tick ; + node = coap_malloc(sizeof(CoAPSendNode)); + + if (NULL != node) { + memset(node, 0x00, sizeof(CoAPSendNode)); + node->acked = 0; + node->user = message->user; + node->header = message->header; + node->handler = message->handler; + node->msglen = len; + node->message = buffer; + node->timeout_val = COAP_ACK_TIMEOUT * COAP_ACK_RANDOM_FACTOR; + memcpy(&node->remote, remote, sizeof(NetworkAddr)); + if (platform_is_multicast((const char *)remote->addr) || 1 == message->keep) { + COAP_FLOW("The message %d need keep", message->header.msgid); + node->keep = KEEPING; + } else { + node->keep = NOKEEP; + } + + tick = HAL_UptimeMs (); + + if (COAP_MESSAGE_TYPE_CON == message->header.type) { + node->timeout = node->timeout_val + tick; + node->retrans_count = COAP_MAX_RETRY_COUNT; + } else { + node->timeout = node->timeout_val * 4 + tick; + node->retrans_count = 0; + } + + memcpy(node->token, message->token, message->header.tokenlen); + + HAL_MutexLock(ctx->sendlist.list_mutex); + if (ctx->sendlist.count >= ctx->sendlist.maxcount) { + HAL_MutexUnlock(ctx->sendlist.list_mutex); + coap_free(node); + COAP_INFO("The send list is full"); + return COAP_ERROR_DATA_SIZE; + } else { + list_add_tail(&node->sendlist, &ctx->sendlist.list); + ctx->sendlist.count ++; + HAL_MutexUnlock(ctx->sendlist.list_mutex); + return COAP_SUCCESS; + } + } else { + return COAP_ERROR_NULL; + } +} + +void CoAPMessageToken_dump(unsigned char *token, unsigned char tokenlen) +{ + int index = 0, count = 0; + int total = 2 * COAP_MSG_MAX_TOKEN_LEN; + char buff[2 * COAP_MSG_MAX_TOKEN_LEN + 1] = {0}, *ptr = NULL; + + ptr = buff; + for (index = 0; index < tokenlen; index++) { + count = HAL_Snprintf(ptr, total, "%02X", token[index]); + ptr += count; + total -= count; + } + + COAP_FLOW("Token Len : %d", tokenlen); + COAP_FLOW("Token : %s", buff); +} + +void CoAPMessage_dump(NetworkAddr *remote, CoAPMessage *message) +{ + int ret = COAP_SUCCESS; + unsigned int ctype; + unsigned char code, msgclass, detail; + + if (NULL == remote || NULL == message) { + return; + } + code = (unsigned char)message->header.code; + msgclass = code >> 5; + detail = code & 0x1F; + + COAP_FLOW("*********Message Info**********"); + COAP_FLOW("Version : %d", message->header.version); + COAP_FLOW("Code : %d.%02d(0x%x)", msgclass, detail, code); + COAP_FLOW("Type : 0x%x", message->header.type); + COAP_FLOW("Msgid : %d", message->header.msgid); + COAP_FLOW("Option : %d", message->optcount); + COAP_FLOW("Payload Len : %d", message->payloadlen); + + CoAPMessageToken_dump(message->token, message->header.tokenlen); + COAP_FLOW("Remote : %s:%d", remote->addr, remote->port); + ret = CoAPUintOption_get(message, COAP_OPTION_CONTENT_FORMAT, &ctype); + if (COAP_SUCCESS == ret && NULL != message->payload + && (COAP_CT_APP_OCTET_STREAM != ctype && COAP_CT_APP_CBOR != ctype)) { + /* COAP_FLOW("Payload : %s", message->payload); */ + } + + COAP_FLOW("********************************"); + +} + +int CoAPMessage_send(CoAPContext *context, NetworkAddr *remote, CoAPMessage *message) +{ + int ret = COAP_SUCCESS; + unsigned short msglen = 0; + unsigned char *buff = NULL; + unsigned short readlen = 0; + CoAPIntContext *ctx = NULL; + + if (NULL == message || NULL == context) { + return (COAP_ERROR_INVALID_PARAM); + } + + ctx = (CoAPIntContext *)context; + msglen = CoAPSerialize_MessageLength(message); + if (COAP_MSG_MAX_PDU_LEN < msglen) { + COAP_INFO("The message length %d is too loog", msglen); + return COAP_ERROR_DATA_SIZE; + } + + buff = (unsigned char *)coap_malloc(msglen); + if (NULL == buff) { + COAP_INFO("Malloc memory failed"); + return COAP_ERROR_NULL; + } + memset(buff, 0x00, msglen); + msglen = CoAPSerialize_Message(message, buff, msglen); + +#ifndef COAP_OBSERVE_CLIENT_DISABLE + CoAPObsClient_delete(ctx, message); +#endif + readlen = CoAPNetwork_write(ctx->p_network, remote, + buff, (unsigned int)msglen, ctx->waittime); + if (msglen == readlen) {/*Send message success*/ + if (CoAPReqMsg(message->header) || CoAPCONRespMsg(message->header)) { + COAP_FLOW("The message id %d len %d send success, add to the list", + message->header.msgid, msglen); + ret = CoAPMessageList_add(ctx, remote, message, buff, msglen); + if (COAP_SUCCESS != ret) { + coap_free(buff); + COAP_ERR("Add the message %d to list failed", message->header.msgid); + return ret; + } + } else { + coap_free(buff); + COAP_FLOW("The message %d isn't CON msg, needless to be retransmitted", + message->header.msgid); + } + } else { + coap_free(buff); + COAP_ERR("CoAP transport write failed, send message %d return %d", message->header.msgid, ret); + return COAP_ERROR_WRITE_FAILED; + } + + CoAPMessage_dump(remote, message); + return COAP_SUCCESS; +} + +int CoAPMessage_cancel(CoAPContext *context, CoAPMessage *message) +{ + CoAPSendNode *node = NULL, *next = NULL; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + if (NULL == context || NULL == message) { + return COAP_ERROR_NULL; + } + + + HAL_MutexLock(ctx->sendlist.list_mutex); + list_for_each_entry_safe(node, next, &ctx->sendlist.list, sendlist, CoAPSendNode) { + if (node->header.msgid == message->header.msgid) { + list_del(&node->sendlist); + ctx->sendlist.count--; + COAP_INFO("Cancel message %d from list, cur count %d", + node->header.msgid, ctx->sendlist.count); + coap_free(node->message); + coap_free(node); + } + } + HAL_MutexUnlock(ctx->sendlist.list_mutex); + return COAP_SUCCESS; +} + +int CoAPMessageId_cancel(CoAPContext *context, unsigned short msgid) +{ + CoAPSendNode *node = NULL, *next = NULL; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + if (NULL == context || NULL == ctx->sendlist.list_mutex) { + return COAP_ERROR_NULL; + } + + HAL_MutexLock(ctx->sendlist.list_mutex); + list_for_each_entry_safe(node, next, &ctx->sendlist.list, sendlist, CoAPSendNode) { + if (NULL != node) { + if (node->header.msgid == msgid) { + list_del(&node->sendlist); + ctx->sendlist.count--; + COAP_FLOW("Cancel message %d from list, cur count %d", + node->header.msgid, ctx->sendlist.count); + coap_free(node->message); + coap_free(node); + } + } + } + HAL_MutexUnlock(ctx->sendlist.list_mutex); + + return COAP_SUCCESS; +} + +static int CoAPAckMessage_handle(CoAPContext *context, CoAPMessage *message) +{ + CoAPSendNode *node = NULL, *next; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + HAL_MutexLock(ctx->sendlist.list_mutex); + list_for_each_entry_safe(node, next, &ctx->sendlist.list, sendlist, CoAPSendNode) { + if (node->header.msgid == message->header.msgid) { + CoAPSendMsgHandler handler = node->handler; + void *user_data = node->user; + NetworkAddr remote = {0}; + memcpy(&remote, &node->remote, sizeof(remote)); + node->acked = 1; + if (CoAPRespMsg(node->header)) { /* CON response message */ + list_del(&node->sendlist); + coap_free(node->message); + coap_free(node); + ctx->sendlist.count --; + COAP_DEBUG("The CON response message %d receive ACK, remove it", message->header.msgid); + } + if (handler) handler(ctx, COAP_RECV_RESP_SUC, user_data, &remote, NULL); + HAL_MutexUnlock(ctx->sendlist.list_mutex); + return COAP_SUCCESS; + } + } + HAL_MutexUnlock(ctx->sendlist.list_mutex); + + return COAP_SUCCESS; +} + +static int CoAPAckMessage_send(CoAPContext *context, NetworkAddr *remote, unsigned short msgid) +{ + int ret = COAP_SUCCESS; + CoAPMessage message; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + CoAPMessage_init(&message); + CoAPMessageId_set(&message, msgid); + COAP_DEBUG("Send Ack Response Message"); + ret = CoAPMessage_send(ctx, remote, &message); + CoAPMessage_destory(&message); + return ret; +} + +static int CoAPRestMessage_send(CoAPContext *context, NetworkAddr *remote, unsigned short msgid) +{ + int ret = COAP_SUCCESS; + CoAPMessage message; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + CoAPMessage_init(&message); + CoAPMessageType_set(&message, COAP_MESSAGE_TYPE_RST); + CoAPMessageId_set(&message, msgid); + COAP_DEBUG("Send Rest Pong Message"); + ret = CoAPMessage_send(ctx, remote, &message); + CoAPMessage_destory(&message); + return ret; +} + +static int CoAPErrRespMessage_send(CoAPContext *context, NetworkAddr *remote, CoAPMessage *message, + unsigned char err_code) +{ + CoAPMessage response; + int ret = COAP_SUCCESS; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + CoAPMessage_init(&response); + CoAPMessageCode_set(&response, err_code); + CoAPMessageId_set(&response, message->header.msgid); + CoAPMessageToken_set(&response, message->token, message->header.tokenlen); + if (COAP_MESSAGE_TYPE_CON == message->header.type) { + CoAPMessageType_set(&response, COAP_MESSAGE_TYPE_ACK); + } else { + CoAPMessageType_set(&response, message->header.type); + } + COAP_FLOW("Send Error Response Message"); + ret = CoAPMessage_send(ctx, remote, &response); + CoAPMessage_destory(&response); + return ret; +} + +static int CoAPRespMessage_handle(CoAPContext *context, NetworkAddr *remote, CoAPMessage *message) +{ + char found = 0; + CoAPSendNode *node = NULL, *next = NULL; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + if (COAP_MESSAGE_TYPE_CON == message->header.type) { + CoAPAckMessage_send(ctx, remote, message->header.msgid); + } + + HAL_MutexLock(ctx->sendlist.list_mutex); + list_for_each_entry_safe(node, next, &ctx->sendlist.list, sendlist, CoAPSendNode) { + if (0 != node->header.tokenlen && node->header.tokenlen == message->header.tokenlen + && 0 == memcmp(node->token, message->token, message->header.tokenlen)) { + if (!node->keep) { + list_del(&node->sendlist); + ctx->sendlist.count--; + COAP_FLOW("Remove the message id %d from list", node->header.msgid); + } else { + COAP_FLOW("Find the message id %d, It need keep", node->header.msgid); + } + found = 1; + + break; + } + } + + if (found && NULL != node) { + message->user = node->user; + /* TODO: comment it */ + /* + if (COAP_MSG_CODE_400_BAD_REQUEST <= message->header.code) { + if (NULL != ctx->notifier) { + ctx->notifier(message->header.code, remote, message); + } + } + */ + if (NULL != node->handler) { + CoAPSendMsgHandler handler = node->handler; +#ifndef COAP_OBSERVE_CLIENT_DISABLE + CoAPObsClient_add(ctx, message, remote, node); +#endif + HAL_MutexUnlock(ctx->sendlist.list_mutex); + COAP_FLOW("Call the response message callback %p", handler); + handler(ctx, COAP_REQUEST_SUCCESS, message->user, remote, message); + } else { + HAL_MutexUnlock(ctx->sendlist.list_mutex); + } + + if (!node->keep) { + if (NULL != node->message) { + coap_free(node->message); + } + coap_free(node); + COAP_DEBUG("The message needless keep, free it"); + } + } else { + HAL_MutexUnlock(ctx->sendlist.list_mutex); +#ifndef COAP_OBSERVE_CLIENT_DISABLE + CoAPObsClient_add(ctx, message, remote, NULL); +#endif + } + return COAP_ERROR_NOT_FOUND; +} + +#define PACKET_INTERVAL_THRE_MS 800 +#define PACKET_TRIGGER_NUM 100 + +static int CoAPRequestMessage_ack_send(CoAPContext *context, NetworkAddr *remote, unsigned short msgid) +{ + int ret = COAP_SUCCESS; + CoAPMessage message; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + CoAPMessage_init(&message); + CoAPMessageId_set(&message, msgid); + COAP_INFO("Send Ack Response Message: %d", msgid); + ret = CoAPMessage_send(ctx, remote, &message); + CoAPMessage_destory(&message); + return ret; +} + +static int CoAPRequestMessage_handle(CoAPContext *context, NetworkAddr *remote, CoAPMessage *message) +{ + int index = 0; + int ret = COAP_SUCCESS; + CoAPResource *resource = NULL; + unsigned char path[COAP_MSG_MAX_PATH_LEN] = {0}; + unsigned char *tmp = path; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + COAP_FLOW("CoAPRequestMessage_handle: %p", ctx); + /* TODO: if need only one callback */ + for (index = 0; index < message->optcount; index++) { + if (COAP_OPTION_URI_PATH == message->options[index].num) { + if ((COAP_MSG_MAX_PATH_LEN - 1) >= (tmp - path + message->options[index].len)) { + *tmp = '/'; + tmp += 1; + strncpy((char *)tmp, (const char *)message->options[index].val, message->options[index].len); + tmp += message->options[index].len; + } + } + } + if (strcmp("/sys/device/info/notify", (const char *)path)) { + COAP_DEBUG("Request path is %s", path); + } + + resource = CoAPResourceByPath_get(ctx, (char *)path); + if (NULL != resource) { + if (NULL != resource->callback) { + if (((resource->permission) & (1 << ((message->header.code) - 1))) > 0) { + if (message->header.type == COAP_MESSAGE_TYPE_CON) { + CoAPRequestMessage_ack_send(ctx, remote, message->header.msgid); + } + resource->callback(ctx, (char *)path, remote, message); + } else { + COAP_FLOW("The resource %s isn't allowed", resource->path); + ret = CoAPErrRespMessage_send(ctx, remote, message, COAP_MSG_CODE_405_METHOD_NOT_ALLOWED); + } + } else { + COAP_FLOW("The resource %s handler isn't exist", resource->path); + ret = CoAPErrRespMessage_send(ctx, remote, message, COAP_MSG_CODE_405_METHOD_NOT_ALLOWED); + } + } else { + COAP_FLOW("The resource %s isn't found", path); + ret = CoAPErrRespMessage_send(ctx, remote, message, COAP_MSG_CODE_404_NOT_FOUND); + } + + return ret; +} + + +static void CoAPMessage_handle(CoAPContext *context, + NetworkAddr *remote, + unsigned char *buf, + unsigned short datalen) +{ + int ret = COAP_SUCCESS; + CoAPMessage message; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + COAP_FLOW("CoAPMessage_handle: %p", ctx); + memset(&message, 0x00, sizeof(CoAPMessage)); + + ret = CoAPDeserialize_Message(&message, buf, datalen); + if (COAP_SUCCESS != ret) { + if (NULL != ctx->notifier) { + /* TODO: */ + /* context->notifier(context, event); */ + } + } + + COAP_FLOW("--------Receive a Message------"); + CoAPMessage_dump(remote, &message); + + if (COAPAckMsg(message.header) || CoAPResetMsg(message.header)) { + /* TODO: implement handle client observe */ + + /* TODO: if need call response callback */ + CoAPAckMessage_handle(ctx, &message); + + } else if (CoAPRespMsg(message.header)) { + CoAPRespMessage_handle(ctx, remote, &message); + } else if (CoAPPingMsg(message.header)) { + CoAPRestMessage_send(ctx, remote, message.header.msgid); + } else if (CoAPReqMsg(message.header)) { + CoAPRequestMessage_handle(ctx, remote, &message); + } else { + COAP_INFO("Weird packet,drop it"); + } + +} + +int CoAPMessage_process(CoAPContext *context, unsigned int timeout) +{ + int len = 0; + NetworkAddr remote; + char ip_addr[17] = {0}; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + if (NULL == context) { + return COAP_ERROR_NULL; + } + + HAL_Wifi_Get_IP(ip_addr, NULL); + + while (1) { + memset(&remote, 0x00, sizeof(NetworkAddr)); + memset(ctx->recvbuf, 0x00, COAP_MSG_MAX_PDU_LEN); + len = CoAPNetwork_read(ctx->p_network, + &remote, + ctx->recvbuf, + COAP_MSG_MAX_PDU_LEN, timeout); + if (strncmp((const char *)ip_addr, (const char *)remote.addr, sizeof(ip_addr)) == 0) /* drop the packet from itself*/ + continue; + if (len > 0) { + CoAPMessage_handle(ctx, &remote, ctx->recvbuf, len); + } else { + return len; + } + } +} + +static void Check_timeout (void *context) +{ + CoAPIntContext *ctx = (CoAPIntContext *)context; + CoAPSendNode *node = NULL, *next = NULL, *timeout_node = NULL; + uint64_t tick = HAL_UptimeMs (); + do { + timeout_node = NULL; + HAL_MutexLock(ctx->sendlist.list_mutex); + list_for_each_entry_safe(node, next, &ctx->sendlist.list, sendlist, CoAPSendNode) { + + if (node->keep != NOKEEP) { + continue; + } + if ((node->retrans_count > 0) || (node->timeout >= tick)) { + continue; + } + + /*Remove the node from the list*/ + list_del_init(&node->sendlist); + ctx->sendlist.count--; + COAP_INFO("Retransmit timeout,remove the message id %d count %d", + node->header.msgid, ctx->sendlist.count); + #ifndef COAP_OBSERVE_SERVER_DISABLE + CoapObsServerAll_delete(ctx, &node->remote); + #endif + timeout_node = node; + break; + } + HAL_MutexUnlock(ctx->sendlist.list_mutex); + + if (timeout_node) { + if(NULL != timeout_node->handler){ + timeout_node->handler(ctx, COAP_RECV_RESP_TIMEOUT, timeout_node->user, &timeout_node->remote, NULL); + } + coap_free(timeout_node->message); + coap_free(timeout_node); + } + } while (timeout_node); +} + +static void Retansmit (void *context) +{ + CoAPIntContext *ctx = (CoAPIntContext *)context; + CoAPSendNode *node = NULL, *next = NULL; + unsigned int ret = 0; + + uint64_t tick = HAL_UptimeMs (); + HAL_MutexLock(ctx->sendlist.list_mutex); + list_for_each_entry_safe(node, next, &ctx->sendlist.list, sendlist, CoAPSendNode) { + if (NULL == node || node->timeout > tick ) { + continue; + } + + if (node->retrans_count > 0) { + /*If has received ack message, don't resend the message*/ + if(0 == node->acked){ + COAP_DEBUG("Retansmit the message id %d len %d", node->header.msgid, node->msglen); + ret = CoAPNetwork_write(ctx->p_network, &node->remote, node->message, node->msglen, ctx->waittime); + if (ret != COAP_SUCCESS) { + } + } + node->timeout_val = node->timeout_val * 3 / 2; + -- node->retrans_count; + if (node->retrans_count == 0) { + node->timeout = tick + COAP_ACK_TIMEOUT; + } else { + node->timeout = tick + node->timeout_val; + } + + COAP_FLOW("node->timeout_val = %d , node->timeout=%d ,tick=%d", node->timeout_val,node->timeout,tick); + } + } + HAL_MutexUnlock(ctx->sendlist.list_mutex); +} + +extern void *coap_yield_mutex; + +int CoAPMessage_cycle(CoAPContext *context) +{ + int res = 0; + + CoAPIntContext *ctx = (CoAPIntContext *)context; + + if (NULL == context) { + return COAP_ERROR_NULL; + } + + if (coap_yield_mutex != NULL) { + HAL_MutexLock(coap_yield_mutex); + } + + res = CoAPMessage_process(ctx, ctx->waittime); + Retansmit (ctx); + Check_timeout (ctx); + + if (coap_yield_mutex != NULL) { + HAL_MutexUnlock(coap_yield_mutex); + } + + if (res < 0) { + HAL_SleepMs(20); + } + + return res; +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPMessage.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPMessage.h new file mode 100644 index 00000000..f5b43506 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPMessage.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __COAP_MESSAGE_H__ +#define __COAP_MESSAGE_H__ +#include "CoAPExport.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct +{ + CoAPMsgHeader header; + unsigned char retrans_count; + unsigned char token[COAP_MSG_MAX_TOKEN_LEN]; + unsigned long long timeout; + unsigned short timeout_val; + unsigned int msglen; + CoAPSendMsgHandler handler; + NetworkAddr remote; + struct list_head sendlist; + void *user; + unsigned char *message; + int acked; + int keep; +} CoAPSendNode; + + +int CoAPStrOption_add(CoAPMessage *message, unsigned short optnum, + unsigned char *data, unsigned short datalen); + +int CoAPStrOption_get(CoAPMessage *message, unsigned short optnum, + unsigned char *data, unsigned short *datalen); + +int CoAPUintOption_add(CoAPMessage *message, unsigned short optnum, + unsigned int data); + +int CoAPUintOption_get(CoAPMessage *message, + unsigned short optnum, + unsigned int *data); + +int CoAPOption_present(CoAPMessage *message, unsigned short option); + + +unsigned short CoAPMessageId_gen(CoAPContext *context); + +int CoAPMessageId_set(CoAPMessage *message, unsigned short msgid); + +int CoAPMessageType_set(CoAPMessage *message, unsigned char type); + +int CoAPMessageCode_set(CoAPMessage *message, CoAPMessageCode code); + +int CoAPMessageToken_set(CoAPMessage *message, unsigned char *token, + unsigned char tokenlen); + +int CoAPMessageUserData_set(CoAPMessage *message, void *userdata); + +int CoAPMessageKeep_Set(CoAPMessage *message, int keep); + +int CoAPMessagePayload_set(CoAPMessage *message, unsigned char *payload, + unsigned short payloadlen); + +int CoAPMessageHandler_set(CoAPMessage *message, CoAPSendMsgHandler handler); + +int CoAPMessage_init(CoAPMessage *message); + +int CoAPMessage_destory(CoAPMessage *message); + +int CoAPMessage_send(CoAPContext *context, NetworkAddr *remote, CoAPMessage *message); + +int CoAPMessage_recv(CoAPContext *context, unsigned int timeout, int readcount); + +int CoAPMessage_retransmit(CoAPContext *context); + +int CoAPMessage_process(CoAPContext *context, unsigned int timeout); + +int CoAPMessage_cycle(CoAPContext *context); + +int CoAPMessage_cancel(CoAPContext *context, CoAPMessage *message); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPNetwork.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPNetwork.c new file mode 100644 index 00000000..86755443 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPNetwork.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#include +#include +#include +#include + +#include "iotx_coap_internal.h" +#include "CoAPExport.h" +#include "CoAPPlatform.h" +#include "CoAPNetwork.h" + +int CoAPNetwork_read(NetworkContext *p_context, + NetworkAddr *p_remote, + unsigned char *p_data, + unsigned int datalen, + unsigned int timeout_ms) + +{ + int len = 0; + NetworkConf *network = NULL; + + if (NULL == p_context || NULL == p_remote || NULL == p_data) { + return -1; /* TODO */ + } + + network = (NetworkConf *)p_context; +#ifdef COAP_DTLS_SUPPORT + if (COAP_NETWORK_DTLS == network->type) { + } else { +#endif + len = HAL_UDP_recvfrom(network->fd, p_remote, p_data, + datalen, timeout_ms); + /* COAP_DEBUG("[CoAP-NWK]: Network read return %d", len); */ +#ifdef COAP_DTLS_SUPPORT + } +#endif + return len; +} + +int CoAPNetwork_write(NetworkContext *p_context, + NetworkAddr *p_remote, + const unsigned char *p_data, + unsigned int datalen, + unsigned int timeout_ms) + +{ + + int len = 0; + NetworkConf *network = NULL; + + if (NULL == p_context || NULL == p_remote || NULL == p_data) { + return -1; /* TODO */ + } + + network = (NetworkConf *)p_context; +#ifdef COAP_DTLS_SUPPORT + /* TODO: */ + if (COAP_NETWORK_DTLS == network->type) { + + } else { +#endif + len = HAL_UDP_sendto(network->fd, p_remote, + p_data, datalen, timeout_ms); +#ifdef COAP_DTLS_SUPPORT + } +#endif + return len; +} + + +NetworkContext *CoAPNetwork_init(const NetworkInit *p_param) +{ + NetworkConf *network = NULL; + + if (NULL == p_param) { + return NULL; + } + + network = coap_malloc(sizeof(NetworkConf)); + if (NULL == network) { + return NULL; + } + + memset(network, 0x00, sizeof(NetworkConf)); + network->type = p_param->type; + +#ifdef COAP_DTLS_SUPPORT + if (COAP_NETWORK_DTLS == network->type) { + /* TODO: */ + coap_free(network); + return NULL; + } else { +#endif + /*Create udp socket*/ + network->port = p_param->port; + network->fd = (intptr_t)HAL_UDP_create_without_connect(NULL, network->port); + if ((intptr_t) - 1 == network->fd) { + coap_free(network); + return NULL; + } + + HAL_UDP_joinmulticast(network->fd, p_param->group); +#ifdef COAP_DTLS_SUPPORT + } +#endif + return (NetworkContext *)network; +} + + +void CoAPNetwork_deinit(NetworkContext *p_context) +{ + NetworkConf *network = NULL; + if (NULL == p_context) { + return; + } + + network = (NetworkConf *)p_context; +#ifdef COAP_DTLS_SUPPORT + if (COAP_NETWORK_DTLS == network->type) { + /* TODO: */ + } else { +#endif + HAL_UDP_close_without_connect(network->fd); + coap_free(p_context); + p_context = NULL; +#ifdef COAP_DTLS_SUPPORT + } +#endif + return; +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPNetwork.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPNetwork.h new file mode 100644 index 00000000..361d640e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPNetwork.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __CoAPNETWORK_H__ +#define __CoAPNETWORK_H__ +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef enum { + COAP_NETWORK_NOSEC = 0, + COAP_NETWORK_DTLS, +} CoAPNetworkType; + +typedef struct { + CoAPNetworkType type; + unsigned short port; + intptr_t fd; +} NetworkConf; + +typedef void NetworkContext; + + +typedef struct { + CoAPNetworkType type; + char *group; + unsigned short port; +#ifdef COAP_DTLS_SUPPORT + /* TODO: */ +#endif +} NetworkInit; + +NetworkContext *CoAPNetwork_init(const NetworkInit *p_param); + + +int CoAPNetwork_write(NetworkContext *p_context, + NetworkAddr *p_remote, + const unsigned char *p_data, + unsigned int datalen, + unsigned int timeout); + +int CoAPNetwork_read(NetworkContext *p_context, + NetworkAddr *p_remote, + unsigned char *p_data, + unsigned int datalen, + unsigned int timeout); + +void CoAPNetwork_deinit(NetworkContext *p_context); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPObserve.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPObserve.c new file mode 100644 index 00000000..34450703 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPObserve.c @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "CoAPExport.h" +#include "CoAPResource.h" +#include "CoAPObserve.h" +#include "CoAPMessage.h" +#include "iotx_coap_internal.h" +#include "CoAPPlatform.h" +#include "CoAPInternal.h" + +#ifndef COAP_OBSERVE_SERVER_DISABLE +int CoAPObsServer_init(CoAPContext *context, unsigned char obs_maxcount) +{ + CoAPIntContext *ctx = (CoAPIntContext *)context; + + ctx->obsserver.list_mutex = HAL_MutexCreate(); + + HAL_MutexLock(ctx->obsserver.list_mutex); + INIT_LIST_HEAD(&ctx->obsserver.list); + ctx->obsserver.count = 0; + ctx->obsserver.maxcount = obs_maxcount; + HAL_MutexUnlock(ctx->obsserver.list_mutex); + + return COAP_SUCCESS; +} + +int CoAPObsServer_deinit(CoAPContext *context) +{ + CoAPIntContext *ctx = (CoAPIntContext *)context; + CoapObserver *node = NULL, *next = NULL; + + HAL_MutexLock(ctx->obsserver.list_mutex); + list_for_each_entry_safe(node, next, &ctx->obsserver.list, obslist, CoapObserver) { + list_del(&node->obslist); + COAP_DEBUG("Delete %s:%d from observe server", node->remote.addr, node->remote.port); + coap_free(node); + } + ctx->obsserver.count = 0; + ctx->obsserver.maxcount = 0; + HAL_MutexUnlock(ctx->obsserver.list_mutex); + + HAL_MutexDestroy(ctx->obsserver.list_mutex); + ctx->obsserver.list_mutex = NULL; + + return COAP_SUCCESS; +} + + +int CoAPObsServer_add(CoAPContext *context, const char *path, NetworkAddr *remote, CoAPMessage *request) +{ + int ret = COAP_SUCCESS; + unsigned int observe; + unsigned int acceptype = 0; + CoapObserver *obs = NULL; + CoAPResource *resource = NULL; + CoapObserver *node = NULL; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + resource = CoAPResourceByPath_get(ctx, path); + + ret = CoAPUintOption_get(request, COAP_OPTION_OBSERVE, &observe); + + if (NULL != resource && COAP_SUCCESS == ret && 0 == observe) { + /*Check if the observe client already exist*/ + HAL_MutexLock(ctx->obsserver.list_mutex); + list_for_each_entry(node, &ctx->obsserver.list, obslist, CoapObserver) { + if ((node->p_resource_of_interest == resource) && + (node->remote.port == remote->port) && + (0 == memcmp(node->remote.addr, remote->addr, NETWORK_ADDR_LEN))) { + COAP_DEBUG("The observe client %s:%d already exist,update it", node->remote.addr, node->remote.port); + memcpy(node->token, request->token, request->header.tokenlen); + node->tokenlen = request->header.tokenlen; + HAL_MutexUnlock(ctx->obsserver.list_mutex); + return COAP_ERROR_OBJ_ALREADY_EXIST; + } + } + HAL_MutexUnlock(ctx->obsserver.list_mutex); + + + obs = coap_malloc(sizeof(CoapObserver)); + if (NULL == obs) { + COAP_ERR("Allocate memory failed"); + return COAP_ERROR_MALLOC; + } + + memset(obs, 0x00, sizeof(CoapObserver)); + obs->msg_type = request->header.type; + obs->p_resource_of_interest = resource; + memcpy(&obs->remote, remote, sizeof(NetworkAddr)); + memcpy(obs->token, request->token, request->header.tokenlen); + obs->tokenlen = request->header.tokenlen; + + + CoAPUintOption_get(request, COAP_OPTION_ACCEPT, &acceptype); + obs->ctype = (acceptype == 0) ? COAP_CT_APP_JSON : acceptype; + obs->observer_sequence_num = 0; + + /* TODO: */ + /* CoAPObsServer_find(); */ + + HAL_MutexLock(ctx->obsserver.list_mutex); + if (ctx->obsserver.count >= ctx->obsserver.maxcount) { + HAL_MutexUnlock(ctx->obsserver.list_mutex); + coap_free(obs); + COAP_INFO("Cur have %d observer, max allow %d", ctx->obsserver.count, ctx->obsserver.maxcount); + return COAP_ERROR_DATA_SIZE; + } else { + list_add_tail(&obs->obslist, &ctx->obsserver.list); + ctx->obsserver.count ++; + COAP_DEBUG("Create a observe node, cur have %d nodes", ctx->obsserver.count); + HAL_MutexUnlock(ctx->obsserver.list_mutex); + return COAP_SUCCESS; + } + + } + + return COAP_ERROR_NOT_FOUND; +} + + +int CoapObsServer_delete(CoAPContext *context, NetworkAddr *remote, + CoAPResource *resource) +{ + CoapObserver *node = NULL, *next = NULL; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + HAL_MutexLock(ctx->obsserver.list_mutex); + list_for_each_entry_safe(node, next, &ctx->obsserver.list, obslist, CoapObserver) { + if ((node->p_resource_of_interest == resource) && + (node->remote.port == remote->port) && + (0 == memcmp(node->remote.addr, remote->addr, NETWORK_ADDR_LEN))) { + ctx->obsserver.count --; + list_del(&node->obslist); + COAP_DEBUG("Delete %s:%d from observe server", node->remote.addr, node->remote.port); + coap_free(node); + break; + } + } + HAL_MutexUnlock(ctx->obsserver.list_mutex); + + return COAP_SUCCESS; +} + +int CoapObsServerAll_delete(CoAPContext *context, NetworkAddr *remote) +{ + CoapObserver *node = NULL, *next = NULL; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + HAL_MutexLock(ctx->obsserver.list_mutex); + list_for_each_entry_safe(node, next, &ctx->obsserver.list, obslist, CoapObserver) { + if (NULL != node && (node->remote.port == remote->port) && + (0 == memcmp(node->remote.addr, remote->addr, NETWORK_ADDR_LEN))) { + ctx->obsserver.count --; + list_del(&node->obslist); + COAP_DEBUG("Delete %s:%d from observe server, cur observe count %d", + node->remote.addr, node->remote.port, ctx->obsserver.count); + coap_free(node); + } + } + HAL_MutexUnlock(ctx->obsserver.list_mutex); + + return COAP_SUCCESS; +} + + +int CoAPObsServer_notify(CoAPContext *context, + const char *path, unsigned char *payload, + unsigned short payloadlen, CoAPDataEncrypt handler) +{ + unsigned int ret = COAP_SUCCESS; + CoAPResource *resource = NULL; + CoapObserver *node = NULL; + CoAPLenString src; + CoAPLenString dest; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + resource = CoAPResourceByPath_get(ctx, path); + + if (NULL != resource) { + HAL_MutexLock(ctx->obsserver.list_mutex); + list_for_each_entry(node, &ctx->obsserver.list, obslist, CoapObserver) { + if (node->p_resource_of_interest == resource) { + CoAPMessage message; + CoAPMessage_init(&message); + CoAPMessageType_set(&message, node->msg_type); + CoAPMessageCode_set(&message, COAP_MSG_CODE_205_CONTENT); + CoAPMessageId_set(&message, CoAPMessageId_gen(ctx)); + CoAPMessageHandler_set(&message, NULL); + CoAPMessageUserData_set(&message, node->p_resource_of_interest); + CoAPMessageToken_set(&message, node->token, node->tokenlen); + CoAPUintOption_add(&message, COAP_OPTION_OBSERVE, node->observer_sequence_num++); + CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT, node->ctype); + CoAPUintOption_add(&message, COAP_OPTION_MAXAGE, resource->maxage); + COAP_DEBUG("Send notify message path %s to remote %s:%d ", + path, node->remote.addr, node->remote.port); + + memset(&dest, 0x00, sizeof(CoAPLenString)); + if (NULL != handler) { + src.len = payloadlen; + src.data = payload; + ret = handler(context, path, &node->remote, &message, &src, &dest); + if (COAP_SUCCESS == ret) { + CoAPMessagePayload_set(&message, dest.data, dest.len); + } else { + COAP_INFO("Encrypt payload failed"); + } + } else { + CoAPMessagePayload_set(&message, payload, payloadlen); + } + ret = CoAPMessage_send(ctx, &node->remote, &message); + if (NULL != handler && 0 != dest.len && NULL != dest.data) { + coap_free(dest.data); + dest.len = 0; + } + CoAPMessage_destory(&message); + } + } + + HAL_MutexUnlock(ctx->obsserver.list_mutex); + } + return ret; +} + +#endif + +#ifndef COAP_OBSERVE_CLIENT_DISABLE +int CoAPObsClient_init(CoAPContext *context, unsigned char obs_maxcount) +{ + CoAPIntContext *ctx = (CoAPIntContext *)context; + + ctx->obsclient.list_mutex = HAL_MutexCreate(); + + HAL_MutexLock(ctx->obsclient.list_mutex); + INIT_LIST_HEAD(&ctx->obsclient.list); + ctx->obsclient.count = 0; + ctx->obsclient.maxcount = obs_maxcount; + HAL_MutexUnlock(ctx->obsclient.list_mutex); + + return COAP_SUCCESS; +} + +int CoAPObsClient_deinit(CoAPContext *context) +{ + CoAPObservable *node = NULL, *next = NULL; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + HAL_MutexLock(ctx->obsclient.list_mutex); + list_for_each_entry_safe(node, next, &ctx->obsclient.list, obslist, CoAPObservable) { + list_del(&node->obslist); + coap_free(node); + } + ctx->obsclient.count = 0; + ctx->obsclient.maxcount = 0; + HAL_MutexUnlock(ctx->obsclient.list_mutex); + + HAL_MutexDestroy(ctx->obsclient.list_mutex); + ctx->obsclient.list_mutex = NULL; + return COAP_SUCCESS; +} + +int CoAPObsClient_add(CoAPContext *context, CoAPMessage *message, NetworkAddr *remote, CoAPSendNode *sendnode) +{ + CoAPObservable *node = NULL, *next = NULL; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + if (COAP_SUCCESS == CoAPOption_present(message, COAP_OPTION_OBSERVE)) { + COAP_DEBUG("There is Observe option in message, handle it"); + if (NULL == sendnode) { /* Not the first response */ + + HAL_MutexLock(ctx->obsclient.list_mutex); + list_for_each_entry(node, &ctx->obsclient.list, obslist, CoAPObservable) { + if (0 != node->tokenlen && node->tokenlen == message->header.tokenlen + && 0 == memcmp(node->token, message->token, node->tokenlen)) { + CoAPUintOption_get(message, COAP_OPTION_MAXAGE, &node->max_age); + if (NULL != node->callback) { + COAP_DEBUG("Call the observe client callback %p", node->callback); + node->callback(ctx, COAP_REQUEST_SUCCESS, node->userdata, remote, message); + } else { + COAP_INFO("The observe client callback is NULL"); + } + break; + } + } + HAL_MutexUnlock(ctx->obsclient.list_mutex); + + } else { + int found = 0; + HAL_MutexLock(ctx->obsclient.list_mutex); + list_for_each_entry(node, &ctx->obsclient.list, obslist, CoAPObservable) { + if (0 != node->tokenlen && node->tokenlen == message->header.tokenlen + && 0 == memcmp(node->token, message->token, node->tokenlen)) { + found = 1; + break; + } + } + if (!found && ctx->obsclient.count < ctx->obsclient.maxcount) { + CoAPObservable *newnode = coap_malloc(sizeof(CoAPObservable)); + if (NULL != newnode) { + memset(newnode, 0x00, sizeof(CoAPObservable)); + newnode->tokenlen = message->header.tokenlen; + memcpy(newnode->token, message->token, message->header.tokenlen); + memcpy(&newnode->remote, remote, sizeof(NetworkAddr)); + newnode->callback = sendnode->handler; + newnode->userdata = sendnode->user; + CoAPUintOption_get(message, COAP_OPTION_MAXAGE, &newnode->max_age); + list_add_tail(&newnode->obslist, &ctx->obsclient.list); + ctx->obsclient.count ++; + COAP_DEBUG("Add a new obsclient"); + } + } else { + COAP_INFO("Cur have %d obsclient, max allow %d", ctx->obsclient.count, ctx->obsclient.maxcount); + } + HAL_MutexUnlock(ctx->obsclient.list_mutex); + } + } else { + HAL_MutexLock(ctx->obsclient.list_mutex); + list_for_each_entry_safe(node, next, &ctx->obsclient.list, obslist, CoAPObservable) { + if (0 != node->tokenlen && node->tokenlen == message->header.tokenlen + && 0 == memcmp(node->token, message->token, node->tokenlen)) { + list_del(&node->obslist); + ctx->obsclient.count --; + coap_free(node); + break; + } + } + HAL_MutexUnlock(ctx->obsclient.list_mutex); + + } + + return COAP_SUCCESS; +} + +int CoAPObsClient_delete(CoAPContext *context, CoAPMessage *message) +{ + int ret = COAP_SUCCESS; + unsigned int observe_option = 0; + CoAPObservable *node = NULL, *next = NULL; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + if (NULL == ctx || NULL == message) { + return COAP_ERROR_INVALID_PARAM; + } + if (COAP_MSG_CODE_GET == message->header.code) { + if (COAP_SUCCESS == CoAPOption_present(message, COAP_OPTION_OBSERVE)) { + ret = CoAPUintOption_get(message, COAP_OPTION_OBSERVE, &observe_option); + if (COAP_SUCCESS == ret && 1 == observe_option) { + HAL_MutexLock(ctx->obsclient.list_mutex); + list_for_each_entry_safe(node, next, &ctx->obsclient.list, obslist, CoAPObservable) { + if (0 != node->tokenlen && node->tokenlen == message->header.tokenlen + && 0 == memcmp(node->token, message->token, node->tokenlen)) { + list_del(&node->obslist); + ctx->obsclient.count --; + coap_free(node); + break; + } + } + HAL_MutexUnlock(ctx->obsclient.list_mutex); + } + } + } + return COAP_SUCCESS; +} + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPObserve.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPObserve.h new file mode 100644 index 00000000..8ecc78a1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPObserve.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef __COAP_OBSERVE_H__ +#define __COAP_OBSERVE_H__ +#include "CoAPExport.h" +#include "CoAPMessage.h" +#include "CoAPResource.h" +#include "iotx_coap_internal.h" + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct +{ + NetworkAddr remote; + unsigned char token[COAP_MSG_MAX_TOKEN_LEN]; + unsigned char tokenlen; + unsigned char ctype; + CoAPResource *p_resource_of_interest; + unsigned int observer_sequence_num; + CoAPMessageCode msg_type; + struct list_head obslist; +} CoapObserver; + +typedef struct +{ + NetworkAddr remote; + unsigned char token[COAP_MSG_MAX_TOKEN_LEN]; + unsigned char tokenlen; + CoAPSendMsgHandler callback; + unsigned int max_age; + struct list_head obslist; + void *userdata; +} CoAPObservable; + +int CoAPObsServer_init(CoAPContext *context, unsigned char obs_maxcount); +int CoAPObsServer_deinit(CoAPContext *context); + +int CoAPObsServer_add(CoAPContext *context, const char *path, NetworkAddr *remote, CoAPMessage *request); +int CoapObsServer_delete(CoAPContext *context, NetworkAddr *remote, + CoAPResource *resource); +int CoapObsServerAll_delete(CoAPContext *context, NetworkAddr *remote); + +int CoAPObsServer_notify(CoAPContext *context, + const char *path, unsigned char *payload, + unsigned short payloadlen, CoAPDataEncrypt handler); + +int CoAPObsClient_init(CoAPContext *context, unsigned char obs_maxcount); +int CoAPObsClient_deinit(CoAPContext *context); +int CoAPObsClient_add(CoAPContext *context, CoAPMessage *message, NetworkAddr *remote, CoAPSendNode *sendnode); +int CoAPObsClient_delete(CoAPContext *context, CoAPMessage *message); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPPlatform.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPPlatform.c new file mode 100644 index 00000000..8cef1439 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPPlatform.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include +#include + +unsigned int platform_aton(const char *ip_str) +{ + int c; + unsigned char base; + unsigned int val = 0; + unsigned int parts[4] = {0}; + unsigned int *pp = parts; + + c = *ip_str; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, 1-9=decimal. + */ + if (!isdigit(c)) + return (0); + + val = 0; + base = 10; + if (c == '0') { + c = *++ip_str; + if (c == 'x' || c == 'X') { + base = 16; + c = *++ip_str; + } else { + base = 8; + } + } + for (;;) { + if (isdigit(c)) { + val = (val * base) + (int)(c - '0'); + c = *++ip_str; + } else if (base == 16 && isxdigit(c)) { + val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A')); + c = *++ip_str; + } else { + break; + } + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) + return (0); + *pp++ = val; + c = *++ip_str; + } else { + break; + } + } + /* + * Check for trailing characters. + */ + if (c != '\0' && !isspace(c)) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + switch (pp - parts + 1) { + case 0: + return (0); /* initial nondigit */ + case 1: /* a -- 32 bits */ + break; + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffffUL) + return (0); + val |= parts[0] << 24; + break; + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + default: + break; + } + + return val; +} + + +int platform_is_multicast(const char *ip_str) +{ + unsigned int addr_in; + addr_in = platform_aton(ip_str); + return (addr_in > 0xE00000FF && addr_in <= 0xEFFFFFFF); +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPResource.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPResource.c new file mode 100644 index 00000000..71c29f17 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPResource.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#include +#include "CoAPExport.h" +#include "CoAPResource.h" +#include "CoAPPlatform.h" +#include "CoAPInternal.h" +#include "iotx_coap_internal.h" + +#define COAP_PATH_DEFAULT_SUM_LEN (5) + +int CoAPPathMD5_sum(const char *path, int len, char outbuf[], int outlen) +{ + unsigned char md5[16] = {0}; + if (!path || !len || !outbuf || !outlen) { + return -1; + } + + utils_md5((unsigned char *)path, (size_t)len, md5); + memcpy(outbuf, md5, outlen > 16 ? 16 : outlen); + return 0; +} + + +int CoAPResource_init(CoAPContext *context, int res_maxcount) +{ + CoAPIntContext *ctx = (CoAPIntContext *)context; + + ctx->resource.list_mutex = HAL_MutexCreate(); + + HAL_MutexLock(ctx->resource.list_mutex); + INIT_LIST_HEAD(&ctx->resource.list); + ctx->resource.count = 0; + ctx->resource.maxcount = res_maxcount; + HAL_MutexUnlock(ctx->resource.list_mutex); + + return COAP_SUCCESS; +} + +int CoAPResource_deinit(CoAPContext *context) +{ + CoAPResource *node = NULL, *next = NULL; + CoAPIntContext *ctx = (CoAPIntContext *)context; + char tmpbuf[2 * COAP_MAX_PATH_CHECKSUM_LEN + 1] = {0}; + + HAL_MutexLock(ctx->resource.list_mutex); + list_for_each_entry_safe(node, next, &ctx->resource.list, reslist, CoAPResource) { + if (node->path_type == PATH_FILTER && node->filter_path) { + coap_free(node->filter_path); + } + list_del_init(&node->reslist); + infra_hex2str((unsigned char *)node->path, COAP_MAX_PATH_CHECKSUM_LEN, tmpbuf); + COAP_DEBUG("Release the resource %s", tmpbuf); + coap_free(node); + } + ctx->resource.count = 0; + ctx->resource.maxcount = 0; + HAL_MutexUnlock(ctx->resource.list_mutex); + + HAL_MutexDestroy(ctx->resource.list_mutex); + ctx->resource.list_mutex = NULL; + return COAP_SUCCESS; +} + +CoAPResource *CoAPResource_create(const char *path, path_type_t path_type, unsigned short permission, + unsigned int ctype, unsigned int maxage, + CoAPRecvMsgHandler callback) +{ + CoAPResource *resource = NULL; + + if (NULL == path) { + return NULL; + } + + if (strlen(path) >= COAP_MSG_MAX_PATH_LEN) { + return NULL; + } + + resource = coap_malloc(sizeof(CoAPResource)); + if (NULL == resource) { + return NULL; + } + + memset(resource, 0x00, sizeof(CoAPResource)); + if (path_type == PATH_NORMAL) { + resource->path_type = PATH_NORMAL; + CoAPPathMD5_sum(path, strlen(path), resource->path, COAP_PATH_DEFAULT_SUM_LEN); + } else { + int len = strlen(path) + 1; + resource->filter_path = coap_malloc(len); + if (NULL == resource->filter_path) { + coap_free(resource); + return NULL; + } + resource->path_type = PATH_FILTER; + memset(resource->filter_path, 0, len); + strncpy(resource->filter_path, path, strlen(path)); + + } + resource->callback = callback; + resource->ctype = ctype; + resource->maxage = maxage; + resource->permission = permission; + + return resource; +} + +int CoAPResource_register(CoAPContext *context, const char *path, + unsigned short permission, unsigned int ctype, + unsigned int maxage, CoAPRecvMsgHandler callback) +{ + int exist = 0; + char path_calc[COAP_PATH_DEFAULT_SUM_LEN] = {0}; + CoAPResource *node = NULL, *newnode = NULL; + CoAPIntContext *ctx = (CoAPIntContext *)context; + path_type_t type = PATH_NORMAL; + + if (context == NULL) { + return FAIL_RETURN; + } + + HAL_MutexLock(ctx->resource.list_mutex); + if (ctx->resource.count >= ctx->resource.maxcount) { + HAL_MutexUnlock(ctx->resource.list_mutex); + COAP_INFO("The resource count exceeds limit, cur %d, max %d", + ctx->resource.count, ctx->resource.maxcount); + return COAP_ERROR_DATA_SIZE; + } + + if (strstr(path, "/#") != NULL) { + type = PATH_FILTER; + } else { + CoAPPathMD5_sum(path, strlen(path), path_calc, COAP_PATH_DEFAULT_SUM_LEN); + } + + list_for_each_entry(node, &ctx->resource.list, reslist, CoAPResource) { + if (type == PATH_NORMAL && node->path_type == PATH_NORMAL) { + if (0 == memcmp(path_calc, node->path, COAP_PATH_DEFAULT_SUM_LEN)) { + /*Alread exist, re-write it*/ + COAP_INFO("CoAPResource_register:Alread exist"); + exist = 1; + node->callback = callback; + node->ctype = ctype; + node->maxage = maxage; + node->permission = permission; + COAP_INFO("The resource %s already exist, re-write it", path); + break; + } + } else if (type == PATH_FILTER && node->path_type == PATH_FILTER) { + if (strlen(path) == strlen(node->filter_path) && 0 == strncpy((char *)path, node->filter_path, strlen(path))) { + /*Alread exist, re-write it*/ + COAP_INFO("CoAPResource_register:Alread exist"); + exist = 1; + node->callback = callback; + node->ctype = ctype; + node->maxage = maxage; + node->permission = permission; + COAP_INFO("The resource %s already exist, re-write it", path); + break; + } + } + } + + if (0 == exist) { + newnode = CoAPResource_create(path, type, permission, ctype, maxage, callback); + if (NULL != newnode) { + COAP_DEBUG("CoAPResource_register, context:%p, new node", ctx); + list_add_tail(&newnode->reslist, &ctx->resource.list); + ctx->resource.count++; + COAP_DEBUG("Register new resource %s success, count: %d", path, ctx->resource.count); + } else { + COAP_ERR("New resource create failed"); + } + } + + HAL_MutexUnlock(ctx->resource.list_mutex); + + return COAP_SUCCESS; +} + +int CoAPResource_unregister(CoAPContext *context, const char *path) +{ + COAP_DEBUG("This feature isn't supported"); + return COAP_ERROR_UNSUPPORTED; +} + +CoAPResource *CoAPResourceByPath_get(CoAPContext *context, const char *path) +{ + char path_calc[COAP_PATH_DEFAULT_SUM_LEN] = {0}; + CoAPResource *node = NULL; + CoAPIntContext *ctx = (CoAPIntContext *)context; + + if (NULL == context || NULL == path) { + COAP_INFO("%s\n", "NULL == context || NULL == path"); + return NULL; + } + COAP_FLOW("CoAPResourceByPath_get, context:%p\n", ctx); + + CoAPPathMD5_sum(path, strlen(path), path_calc, COAP_PATH_DEFAULT_SUM_LEN); + + HAL_MutexLock(ctx->resource.list_mutex); + list_for_each_entry(node, &ctx->resource.list, reslist, CoAPResource) { + if (0 == memcmp(path_calc, node->path, COAP_PATH_DEFAULT_SUM_LEN)) { + HAL_MutexUnlock(ctx->resource.list_mutex); + COAP_DEBUG("Found the resource: %s", path); + return node; + } + if (node->path_type == PATH_FILTER && strlen(node->filter_path) > 0 + && 0 == strncmp(path, node->filter_path, strlen(node->filter_path) - 1)) { + HAL_MutexUnlock(ctx->resource.list_mutex); + COAP_DEBUG("Found the resource: %s", path); + return node; + } + + } + HAL_MutexUnlock(ctx->resource.list_mutex); + + return NULL; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPResource.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPResource.h new file mode 100644 index 00000000..f44ab891 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPResource.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#ifndef __COAP_RESOURCE_H__ +#define __COAP_RESOURCE_H__ + +#include +#include "iotx_coap_internal.h" +#include "CoAPExport.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define COAP_MAX_PATH_CHECKSUM_LEN (5) + +typedef struct { + unsigned short permission; + CoAPRecvMsgHandler callback; + unsigned int ctype; + unsigned int maxage; + struct list_head reslist; + char path[COAP_MAX_PATH_CHECKSUM_LEN]; + char *filter_path; + path_type_t path_type; +} CoAPResource; + +int CoAPResource_init(CoAPContext *context, int res_maxcount); + +int CoAPPathMD5_sum(const char *path, int len, char outbuf[], int outlen); + +int CoAPResource_register(CoAPContext *context, const char *path, + unsigned short permission, unsigned int ctype, + unsigned int maxage, CoAPRecvMsgHandler callback); + +CoAPResource *CoAPResourceByPath_get(CoAPContext *context, const char *path); + +int CoAPResource_deinit(CoAPContext *context); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPServer.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPServer.c new file mode 100644 index 00000000..168a00d8 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPServer.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include +#include "CoAPPlatform.h" +#include "CoAPExport.h" +#include "CoAPServer.h" + +#define COAP_INIT_TOKEN (0x01020304) + +static unsigned int g_coap_running = 0; +#ifdef COAP_SERV_MULTITHREAD + static void *g_coap_thread = NULL; + static void *g_semphore = NULL; +#endif +static CoAPContext *g_context = NULL; + +static unsigned int CoAPServerToken_get(unsigned char *p_encoded_data) +{ + static unsigned int value = COAP_INIT_TOKEN; + p_encoded_data[0] = (unsigned char)((value & 0x00FF) >> 0); + p_encoded_data[1] = (unsigned char)((value & 0xFF00) >> 8); + p_encoded_data[2] = (unsigned char)((value & 0xFF0000) >> 16); + p_encoded_data[3] = (unsigned char)((value & 0xFF000000) >> 24); + value++; + return sizeof(unsigned int); +} + +static int CoAPServerPath_2_option(char *uri, CoAPMessage *message) +{ + char *ptr = NULL; + char *pstr = NULL; + char path[COAP_MSG_MAX_PATH_LEN] = {0}; + + if (NULL == uri || NULL == message) { + COAP_ERR("Invalid paramter p_path %p, p_message %p", uri, message); + return COAP_ERROR_INVALID_PARAM; + } + if (COAP_MSG_MAX_PATH_LEN <= strlen(uri)) { + COAP_ERR("The uri length is too loog,len = %d", (int)strlen(uri)); + return COAP_ERROR_INVALID_LENGTH; + } + + COAP_DEBUG("The uri is %s", uri); + + ptr = pstr = uri; + while ('\0' != *ptr) { + if ('/' == *ptr) { + if (ptr != pstr) { + memset(path, 0x00, sizeof(path)); + strncpy(path, pstr, ptr - pstr); + CoAPStrOption_add(message, COAP_OPTION_URI_PATH, + (unsigned char *)path, (int)strlen(path)); + } + pstr = ptr + 1; + + } + if ('\0' == *(ptr + 1) && '\0' != *pstr) { + memset(path, 0x00, sizeof(path)); + strncpy(path, pstr, sizeof(path) - 1); + CoAPStrOption_add(message, COAP_OPTION_URI_PATH, + (unsigned char *)path, (int)strlen(path)); + } + ptr ++; + } + return COAP_SUCCESS; +} + +void CoAPServer_thread_leave() +{ + g_coap_running = 0; +} + +void *coap_yield_mutex = NULL; + +static void *CoAPServer_yield(void *param) +{ + CoAPContext *context = (CoAPContext *)param; + COAP_DEBUG("Enter to CoAP daemon task"); + + while (g_coap_running) { + CoAPMessage_cycle(context); + } + +#ifdef COAP_SERV_MULTITHREAD + HAL_SemaphorePost(g_semphore); + COAP_INFO("Exit the CoAP daemon task, Post semphore"); + + HAL_ThreadDelete(NULL); + g_coap_thread = NULL; +#endif + return NULL; +} + +typedef void (*func_v_v)(void *); +static func_v_v coapserver_timer = NULL; +void CoAPServer_add_timer(void (*on_timer)(void *)) +{ + coapserver_timer = on_timer; +} + + + +CoAPContext *CoAPServer_init() +{ + CoAPInitParam param = {0}; +#ifdef COAP_SERV_MULTITHREAD + int stack_used; + hal_os_thread_param_t task_parms = {0}; +#endif + + if (NULL == g_context) { + param.appdata = NULL; + param.group = "224.0.1.187"; + param.notifier = NULL; + param.obs_maxcount = 16; + param.res_maxcount = 255; + param.port = 5683; + param.send_maxcount = 16; + param.waittime = 50; + +#ifdef COAP_SERV_MULTITHREAD + g_semphore = HAL_SemaphoreCreate(); + if (NULL == g_semphore) { + COAP_ERR("Semaphore Create failed"); + return NULL; + } + + coap_yield_mutex = HAL_MutexCreate(); + if (NULL == coap_yield_mutex) { + COAP_ERR("coap_yield_mutex Create failed"); + HAL_SemaphoreDestroy(g_semphore); + g_semphore = NULL; + return NULL; + } +#endif + + g_context = CoAPContext_create(¶m); + if (NULL == g_context) { +#ifdef COAP_SERV_MULTITHREAD + HAL_SemaphoreDestroy(g_semphore); + HAL_MutexDestroy(coap_yield_mutex); + g_semphore = NULL; + coap_yield_mutex = NULL; +#endif + COAP_ERR("CoAP Context Create failed"); + return NULL; + } +#ifdef COAP_SERV_MULTITHREAD + g_coap_running = 1; + task_parms.stack_size = 4608; + task_parms.name = "CoAPServer_yield"; + HAL_ThreadCreate(&g_coap_thread, CoAPServer_yield, (void *)g_context, &task_parms, &stack_used); +#endif + + } else { + COAP_INFO("The CoAP Server already init"); + } + + return (CoAPContext *)g_context; +} + +void CoAPServer_deinit(CoAPContext *context) +{ + if (context != g_context) { + COAP_INFO("Invalid CoAP Server context"); + return; + } + + COAP_INFO("CoAP Server deinit"); + g_coap_running = 0; + +#ifdef COAP_SERV_MULTITHREAD + if (NULL != g_semphore) { + HAL_SemaphoreWait(g_semphore, PLATFORM_WAIT_INFINITE); + COAP_INFO("Wait Semaphore, will exit task"); + HAL_SemaphoreDestroy(g_semphore); + g_semphore = NULL; + } + if (NULL != coap_yield_mutex) { + HAL_MutexDestroy(coap_yield_mutex); + coap_yield_mutex = NULL; + } +#endif + if (NULL != context) { + CoAPContext_free(context); + g_context = NULL; + } +} + +int CoAPServer_register(CoAPContext *context, const char *uri, CoAPRecvMsgHandler callback) +{ + if (NULL == context || g_context != context) { + return COAP_ERROR_INVALID_PARAM; + } + + return CoAPResource_register(context, uri, COAP_PERM_GET, COAP_CT_APP_JSON, 60, callback); +} + +int CoAPServerMultiCast_send(CoAPContext *context, NetworkAddr *remote, const char *uri, unsigned char *buff, + unsigned short len, CoAPSendMsgHandler callback, unsigned short *msgid) +{ + int ret = COAP_SUCCESS; + CoAPMessage message; + unsigned char tokenlen; + unsigned char token[COAP_MSG_MAX_TOKEN_LEN] = {0}; + + if (NULL == context || g_context != context || NULL == remote + || NULL == uri || NULL == buff || NULL == msgid) { + return COAP_ERROR_INVALID_PARAM; + } + + + CoAPMessage_init(&message); + CoAPMessageType_set(&message, COAP_MESSAGE_TYPE_NON); + CoAPMessageCode_set(&message, COAP_MSG_CODE_POST); + CoAPMessageId_set(&message, CoAPMessageId_gen(context)); + tokenlen = CoAPServerToken_get(token); + CoAPMessageToken_set(&message, token, tokenlen); + CoAPMessageHandler_set(&message, callback); + CoAPMessageKeep_Set(&message, 1); + + CoAPServerPath_2_option((char *)uri, &message); + CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT, COAP_CT_APP_JSON); + CoAPMessagePayload_set(&message, buff, len); + if (msgid) *msgid = message.header.msgid; + ret = CoAPMessage_send(context, remote, &message); + + CoAPMessage_destory(&message); + + return ret; +} + +int CoAPServerResp_send(CoAPContext *context, NetworkAddr *remote, unsigned char *buff, unsigned short len, void *req, + const char *paths, CoAPSendMsgHandler callback, unsigned short *msgid, char qos) +{ + int ret = COAP_SUCCESS; + CoAPMessage response; + unsigned int observe = 0; + CoAPMessage *request = (CoAPMessage *)req; + + if (NULL == context || g_context != context || NULL == remote + || NULL == buff || NULL == paths || NULL == req) { + return COAP_ERROR_INVALID_PARAM; + } + + CoAPMessage_init(&response); + CoAPMessageType_set(&response, qos == 0 ? COAP_MESSAGE_TYPE_NON :COAP_MESSAGE_TYPE_CON); + CoAPMessageCode_set(&response, COAP_MSG_CODE_205_CONTENT); + CoAPMessageId_set(&response, request->header.msgid); + CoAPMessageToken_set(&response, request->token, request->header.tokenlen); + CoAPMessageHandler_set(&response, callback); + if (msgid) *msgid = response.header.msgid; + + ret = CoAPUintOption_get(request, COAP_OPTION_OBSERVE, &observe); + if (COAP_SUCCESS == ret && 0 == observe) { + CoAPObsServer_add(context, paths, remote, request); + CoAPUintOption_add(&response, COAP_OPTION_OBSERVE, 0); + } + + CoAPUintOption_add(&response, COAP_OPTION_CONTENT_FORMAT, COAP_CT_APP_JSON); + CoAPMessagePayload_set(&response, buff, len); + + COAP_DEBUG("Send a response message"); + ret = CoAPMessage_send(context, remote, &response); + CoAPMessage_destory(&response); + + return ret; +} + +void CoAPServer_loop(CoAPContext *context) +{ + if (g_context != context || 1 == g_coap_running) { + COAP_INFO("The CoAP Server is already running"); + return; + } + +#ifndef COAP_SERV_MULTITHREAD + g_coap_running = 1; + CoAPServer_yield((void *)context); +#endif +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPServer.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPServer.h new file mode 100644 index 00000000..795ef514 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/coap_server/server/CoAPServer.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __COAP_SERVER_H__ +#define __COAP_SERVER_H__ + +#include "CoAPExport.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +#define COAP_SERV_MULTITHREAD + +CoAPContext *CoAPServer_init(); + +void CoAPServer_add_timer (void (*on_timer)(void*)); +void CoAPServer_loop(CoAPContext *context); + +void CoAPServer_deinit(CoAPContext *context); + +int CoAPServer_register(CoAPContext *context, const char *uri, CoAPRecvMsgHandler callback); + +int CoAPServerMultiCast_send(CoAPContext *context, NetworkAddr *remote, const char *uri, + unsigned char *buff, unsigned short len, CoAPSendMsgHandler callback, unsigned short *msgid); + +int CoAPServerResp_send(CoAPContext *context, NetworkAddr *remote, unsigned char *buff, unsigned short len, void *req, + const char *paths, CoAPSendMsgHandler callback, unsigned short *msgid, char qos); + +void CoAPServer_thread_leave(); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/dev_bind_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/dev_bind_api.h new file mode 100644 index 00000000..93482be8 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/dev_bind_api.h @@ -0,0 +1,43 @@ +DLL_IOT_API int awss_report_cloud(void); + +/** + ** @brief check reset flag in perisistent storage. + ** + ** @retval -1 : failure + ** @retval 0 : sucess + ** @note + ** check reset flag in perisistent storage, if device failed to report reset message last time, retry it. + **/ +DLL_IOT_API int awss_check_reset(void); + +/** + ** @brief report reset to cloud. + ** + ** @retval -1 : failure + ** @retval 0 : sucess + ** @note + ** device will save reset flag if device dosen't connect cloud, device will fails to send reset to cloud. + ** when connection between device and cloud is ready, device will retry to report reset to cloud. + **/ +DLL_IOT_API int awss_report_reset(void); + +/** + ** @brief stop to report reset to cloud. + ** + ** @retval -1 : failure + ** @retval 0 : sucess + ** @note + ** just stop report reset to cloud without any touch reset flag in flash. + **/ +DLL_IOT_API int awss_stop_report_reset(void); + +DLL_IOT_API int awss_bind_deinit(void); + +/** + ** @brief deinit bind operation. + ** + ** @retval -1 : failure + ** @retval 0 : sucess + ** @note + ** stop report token to cloud and release coap topic and handler. + **/ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/dev_bind_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/dev_bind_wrapper.h new file mode 100644 index 00000000..2e1f3e4f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/dev_bind_wrapper.h @@ -0,0 +1,43 @@ +#include "infra_types.h" +#include "infra_defs.h" +#include "wrappers_defs.h" +#ifdef WIFI_PROVISION_ENABLED +#include "iot_import_awss.h" +#endif +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); +int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN]); +int HAL_GetProductSecret(char *product_secret); +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN]); +int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN]); +void *HAL_Timer_Create(const char *name, void (*func)(void *), void *user_data); +int HAL_Timer_Stop(void *timer); +int HAL_Timer_Start(void *timer, int ms); +int HAL_Timer_Delete(void *timer); +char *HAL_Wifi_Get_Mac(char mac_str[HAL_MAC_LEN]); +void HAL_Srandom(uint32_t seed); +uint32_t HAL_Random(uint32_t region); +void HAL_Reboot(); +void *HAL_MutexCreate(void); +void HAL_SleepMs(uint32_t ms); +void HAL_MutexDestroy(void *mutex); +void HAL_MutexLock(void *mutex); +void HAL_MutexUnlock(void *mutex); +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); +int HAL_Sys_Net_Is_Ready(); +uint64_t HAL_UptimeMs(void); +uint32_t HAL_Wifi_Get_IP(char ip_str[NETWORK_ADDR_LEN], const char *ifname); +#ifdef WIFI_PROVISION_ENABLED +int HAL_Wifi_Get_Ap_Info(char ssid[HAL_MAX_SSID_LEN],char passwd[HAL_MAX_PASSWD_LEN],uint8_t bssid[ETH_ALEN]); +int HAL_Awss_Connect_Ap( + _IN_ uint32_t connection_timeout_ms, + _IN_ char ssid[HAL_MAX_SSID_LEN], + _IN_ char passwd[HAL_MAX_PASSWD_LEN], + _IN_OPT_ enum AWSS_AUTH_TYPE auth, + _IN_OPT_ enum AWSS_ENC_TYPE encry, + _IN_OPT_ uint8_t bssid[ETH_ALEN], + _IN_OPT_ uint8_t channel); +#endif +/* dev reset */ +int HAL_Kv_Set(const char *key, const void *val, int len, int sync); +int HAL_Kv_Get(const char *key, void *val, int *buffer_len); diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_bind.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_bind.c new file mode 100644 index 00000000..50a3947c --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_bind.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" +#ifdef WIFI_PROVISION_ENABLED +#ifndef AWSS_DISABLE_REGISTRAR +#include "awss_enrollee.h" +#endif +#endif + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +static void *awss_bind_mutex = NULL; +int awss_report_cloud() +{ + if (awss_bind_mutex == NULL) { + awss_bind_mutex = HAL_MutexCreate(); + if (awss_bind_mutex == NULL) { + return -1; + } + } + + HAL_MutexLock(awss_bind_mutex); + + awss_cmp_online_init(); +#ifdef DEVICE_MODEL_ENABLED + awss_check_reset(); +#endif + awss_report_token(); + + awss_cmp_local_init(AWSS_LC_INIT_BIND); + awss_dev_bind_notify_stop(); + awss_dev_bind_notify(); +#ifdef WIFI_PROVISION_ENABLED +#ifndef AWSS_DISABLE_REGISTRAR + awss_registrar_init(); +#endif + AWSS_DISP_STATIS(); + AWSS_REPORT_STATIS("RDA5981"); +#endif + AWSS_DB_DISP_STATIS(); + AWSS_DB_REPORT_STATIS("RDA5981"); + HAL_MutexUnlock(awss_bind_mutex); + return 0; +} + +int awss_bind_deinit() +{ + if (awss_bind_mutex) { + HAL_MutexLock(awss_bind_mutex); + } + +#ifdef DEVICE_MODEL_ENABLED + awss_stop_report_reset(); +#endif + awss_stop_report_token(); + awss_cmp_online_deinit(); + + awss_dev_bind_notify_stop(); + + awss_cmp_local_deinit(1); +#ifdef WIFI_PROVISION_ENABLED +#ifndef AWSS_DISABLE_REGISTRAR + awss_registrar_deinit(); +#endif + AWSS_CLEAR_STATIS(); +#endif + AWSS_DB_CLEAR_STATIS(); + + if (awss_bind_mutex) { + HAL_MutexUnlock(awss_bind_mutex); + HAL_MutexDestroy(awss_bind_mutex); + } + + awss_bind_mutex = NULL; + + return 0; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_bind_statis.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_bind_statis.c new file mode 100644 index 00000000..a2533cba --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_bind_statis.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" + +#ifdef AWSS_SUPPORT_DEV_BIND_STATIS +static struct awss_statis_dev_bind_t g_db_statis = {0}; +static uint32_t awss_statis_db_report_id = 0; +static uint32_t awss_statis_db_trace_id = 0; +static void *awss_statis_db_mutex = NULL; + +#define DB_CNT g_db_statis.dev_bind_cnt +#define DB_SUC g_db_statis.dev_bind_suc +#define DB_TMEAN g_db_statis.dev_bind_time_mean +#define DB_TMIN g_db_statis.dev_bind_time_min +#define DB_TMAX g_db_statis.dev_bind_time_max +#define DB_START g_db_statis.dev_bind_start +#define DB_END g_db_statis.dev_bind_end + +#define AWSS_STATIS_DB_BUF_LEN (512) + +int awss_bind_report_statis(const char *module) +{ + const char *elem_fmt = "[%s max:%u min:%u mean:%u cnt:%u suc:%u]"; + int log_buf_len = AWSS_STATIS_DB_BUF_LEN + strlen(AWSS_STATIS_FMT) + 21; + char statis_topic[TOPIC_LEN_MAX] = {0}; + char *log_content = NULL; + char id_str[21] = {0}; + char *log_buf = NULL; + int len = 0; + int ret; + + log_content = os_zalloc(AWSS_STATIS_DB_BUF_LEN + 1); + if (log_content == NULL) { + goto BIND_STATIS_ERR; + } + log_buf = os_zalloc(log_buf_len + 1); + if (log_buf == NULL) { + goto BIND_STATIS_ERR; + } + + if (awss_build_topic(TOPIC_POST_STATIS, statis_topic, TOPIC_LEN_MAX) == NULL) { + awss_err("awss build statis topic fail\n"); + goto BIND_STATIS_ERR; + } + + if (awss_statis_db_mutex) { + HAL_MutexLock(awss_statis_db_mutex); + } + do { + if (DB_CNT == 0) { + break; + } + + len += HAL_Snprintf(log_buf + len, log_buf_len - len, elem_fmt, "SyncToken", + DB_TMAX, DB_TMIN, DB_TMEAN, DB_CNT, DB_SUC); + + HAL_Snprintf(log_content, AWSS_STATIS_DB_BUF_LEN, AWSS_STATIS_FMT, (uint32_t)HAL_UptimeMs(), "BIND_TRACE", + module == NULL ? "default" : module, awss_statis_db_trace_id, log_buf); + + HAL_Snprintf(id_str, sizeof(id_str), "%u", ++ awss_statis_db_report_id); + + awss_build_packet(AWSS_CMP_PKT_TYPE_REQ, id_str, ILOP_VER, METHOD_LOG_POST, log_content, 0, + log_buf, &log_buf_len); + + awss_debug("%s\n", log_buf); + + ret = awss_cmp_mqtt_send(statis_topic, log_buf, strlen(log_buf), 0); + + awss_info("bind report statis %s\n", ret == 0 ? "success" : "fail"); + } while (0); + + if (awss_statis_db_mutex) { + HAL_MutexUnlock(awss_statis_db_mutex); + } + + HAL_Free(log_buf); + HAL_Free(log_content); + + return 0; + +BIND_STATIS_ERR: + if (log_content) { + HAL_Free(log_content); + } + if (log_buf) { + HAL_Free(log_buf); + } + return -1; +} + +void awss_bind_clear_statis() +{ + if (awss_statis_db_mutex) { + HAL_MutexLock(awss_statis_db_mutex); + } + + memset(&g_db_statis, 0, sizeof(g_db_statis)); + + awss_statis_db_trace_id = 0; + awss_statis_db_report_id = 0; + + if (awss_statis_db_mutex) { + HAL_MutexUnlock(awss_statis_db_mutex); + HAL_MutexDestroy(awss_statis_db_mutex); + } + awss_statis_db_mutex = NULL; +} + +void awss_bind_update_statis(int type) +{ + uint32_t time = HAL_UptimeMs(); + + if (awss_statis_db_mutex == NULL) { + awss_statis_db_mutex = HAL_MutexCreate(); + if (awss_statis_db_mutex == NULL) { + awss_debug("a-statis am fail\n"); + return; + } + } + + HAL_MutexLock(awss_statis_db_mutex); + + if (type == AWSS_DB_STATIS_START) { + awss_statis_db_trace_id ++; + } + + switch (type) { + case AWSS_DB_STATIS_START: + DB_CNT ++; + DB_START = time; + break; + case AWSS_DB_STATIS_SUC: + DB_END = time; + DB_SUC ++; + time = (uint32_t)(DB_END - DB_START); + if (DB_SUC > 0) { + DB_TMEAN = (DB_TMEAN + time) / DB_SUC; + } else { + DB_SUC = 1; + DB_TMEAN = time; + } + if (DB_TMIN == 0 || DB_TMIN > time) { + DB_TMIN = time; + } + if (DB_TMAX == 0 || DB_TMAX < time) { + DB_TMAX = time; + } + break; + default: + break; + } + HAL_MutexUnlock(awss_statis_db_mutex); +} + +void awss_bind_disp_statis() +{ + if (awss_statis_db_mutex) { + HAL_MutexLock(awss_statis_db_mutex); + } + + awss_debug("--------------------------DEV BIND STATIS-----------------------------"); + awss_debug("name\t\tmax\tmin\tmean\tcnt\tsuc"); + awss_debug("SyncToken \t%u\t%u\t%u\t%u\t%u\t", + DB_TMAX, DB_TMIN, DB_TMEAN, DB_CNT, DB_SUC); + awss_debug("----------------------------------------------------------------------"); + + if (awss_statis_db_mutex) { + HAL_MutexUnlock(awss_statis_db_mutex); + } +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_bind_statis.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_bind_statis.h new file mode 100644 index 00000000..9fb5b7ae --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_bind_statis.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_BIND_STATIS_H__ +#define __AWSS_BIND_STATIS_H__ + +#ifndef AWSS_SUPPORT_DEV_BIND_STATIS + #define AWSS_SUPPORT_DEV_BIND_STATIS +#endif + +enum { + AWSS_DB_STATIS_START, + AWSS_DB_STATIS_SUC, +}; + +#ifdef AWSS_SUPPORT_DEV_BIND_STATIS +struct awss_statis_dev_bind_t { + uint32_t dev_bind_cnt; /* the count of token sync */ + uint32_t dev_bind_suc; /* the successful count of token sync */ + uint32_t dev_bind_time_mean; /* the mean time of token sync */ + uint32_t dev_bind_time_max; /* the max time of token sync */ + uint32_t dev_bind_time_min; /* the min time of token sync */ + uint32_t dev_bind_start; /* the start time to sync token */ + uint32_t dev_bind_end; /* the end time of token sync */ +}; /* statistics for token sync */ + + +int awss_bind_report_statis(const char *module); +void awss_bind_update_statis(int type); +void awss_bind_clear_statis(); +void awss_bind_disp_statis(); + + +#define AWSS_DB_UPDATE_STATIS(type) awss_bind_update_statis(type) +#define AWSS_DB_DISP_STATIS() awss_bind_disp_statis() +#define AWSS_DB_CLEAR_STATIS() awss_bind_clear_statis() +#define AWSS_DB_REPORT_STATIS(m) awss_bind_report_statis(m) +#else +#define AWSS_DB_UPDATE_STATIS(type) +#define AWSS_DB_DISP_STATIS() +#define AWSS_DB_CLEAR_STATIS() +#define AWSS_DB_REPORT_STATIS(m) +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_cmp.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_cmp.h new file mode 100644 index 00000000..0e467d4b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_cmp.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_CMP_H__ +#define __AWSS_CMP_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +/** + * @brief this is a network address structure, including host(ip or host name) and port. + */ +typedef struct { + char host[16]; /**< host ip(dotted-decimal notation) or host name(string) */ + uint16_t port; /**< udp port or tcp port */ +} platform_netaddr_t; + +enum { + AWSS_LC_INIT_ROUTER = 0x01, + AWSS_LC_INIT_PAP = 0x02, + AWSS_LC_INIT_DEV_AP = 0x04, + AWSS_LC_INIT_SUC = 0x08, + AWSS_LC_INIT_BIND = 0x100, +}; + +struct awss_cmp_couple { + int init_stage; + char *topic; + void *cb; +}; + +struct coap_session_ctx_t { + void *request; + void *remote; + char is_mcast; +}; + +int awss_cmp_local_init(int init_stage); +int awss_cmp_local_deinit(int force); +int awss_cmp_online_init(); +int awss_cmp_online_deinit(); +int awss_token_remain_time(); +int awss_token_timeout(); +int awss_update_token(); +int awss_report_token(); +int awss_stop_report_token(); + +int awss_cmp_coap_cancel_packet(uint16_t msgid); +int awss_cmp_coap_register_cb(char *topic, void *cb); +int awss_cmp_coap_send(void *buf, uint32_t len, void *sa, const char *uri, void *cb, uint16_t *msgid); +int awss_cmp_coap_send_resp(void *buf, uint32_t len, void *sa, const char *uri, void* req, void *cb, uint16_t *msgid, char qos); +int awss_cmp_coap_ob_send(void *buf, uint32_t len, void *sa, const char *uri, void *cb); +int awss_cmp_coap_deinit(); + +int awss_cmp_mqtt_register_cb(char *topic, void *cb); +int awss_cmp_mqtt_unregister_cb(char *topic); +int awss_cmp_mqtt_send(char *topic, void *pkt, int pkt_len, int qos); + +int awss_release_coap_ctx(void *session); +void *awss_cpy_coap_ctx(void *request, void *remote, char mcast); + +char *awss_cmp_get_coap_payload(void *request, int *payload_len); +uint8_t awss_cmp_get_coap_code(void *request); + +int online_dev_bind_monitor(void *ctx, void *resource, void *remote, void *request); + +void awss_enrollee_checkin(void *pcontext, void *pclient, void *msg); +void awss_online_switchap(void *pcontext, void *pclient, void *msg); +void awss_report_enrollee_reply(void *pcontext, void *pclient, void *msg); +void awss_get_cipher_reply(void *pcontext, void *pclient, void *msg); +void awss_report_token_reply(void *pcontext, void *pclient, void *msg); +int awss_cmp_mqtt_get_payload(void *mesg, char **payload, uint32_t *playload_len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_cmp_coap.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_cmp_coap.c new file mode 100644 index 00000000..5be0625f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_cmp_coap.c @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" +#ifdef WIFI_PROVISION_ENABLED +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) +#include "awss_wifimgr.h" +#endif +#endif + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +static void *g_coap_ctx = NULL; + +int awss_release_coap_ctx(void *session) +{ + struct coap_session_ctx_t *ctx = (struct coap_session_ctx_t *)session; + if (ctx == NULL) { + return 0; + } + + if (ctx->request) { + void *payload = ((struct CoAPMessage *)ctx->request)->payload; + if (payload) { + HAL_Free(payload); + } + HAL_Free(ctx->request); + } + if (ctx->remote) { + HAL_Free(ctx->remote); + } + HAL_Free(ctx); + return 0; +} + +void *awss_cpy_coap_ctx(void *request, void *remote, char mcast) +{ + struct coap_session_ctx_t *ctx = os_zalloc(sizeof(struct coap_session_ctx_t)); + if (ctx == NULL) { + goto CPY_CTX_FAIL; + } + + ctx->request = os_zalloc(sizeof(struct CoAPMessage)); + if (ctx->request == NULL) { + goto CPY_CTX_FAIL; + } + + memcpy(ctx->request, request, sizeof(struct CoAPMessage)); + do { + char *payload = NULL; + int len = 0; + struct CoAPMessage *req = (struct CoAPMessage *)ctx->request; + + payload = awss_cmp_get_coap_payload(request, &len); + req->payloadlen = len; + if (payload == NULL) { + break; + } + + req->payload = os_zalloc(len + 1); + if (req->payload == NULL) { + goto CPY_CTX_FAIL; + } + + memcpy(req->payload, payload, len); + } while (0); + + ctx->remote = os_zalloc(sizeof(platform_netaddr_t)); + if (ctx->remote == NULL) { + goto CPY_CTX_FAIL; + } + + memcpy(ctx->remote, remote, sizeof(platform_netaddr_t)); + ctx->is_mcast = mcast; + + return ctx; + +CPY_CTX_FAIL: + awss_release_coap_ctx(ctx); + return NULL; +} + +uint8_t awss_cmp_get_coap_code(void *request) +{ + struct CoAPMessage *msg = NULL; + if (request == NULL) { + return 0x60; + } + msg = (struct CoAPMessage *)request; + return msg->header.code; +} + +char *awss_cmp_get_coap_payload(void *request, int *payload_len) +{ + struct CoAPMessage *msg = (struct CoAPMessage *)request; + if (request == NULL) { + return NULL; + } + + msg = (struct CoAPMessage *)request; + if (payload_len) { + *payload_len = msg->payloadlen; + } + return (char *)msg->payload; +} + +int awss_cmp_coap_register_cb(char *topic, void *cb) +{ + if (g_coap_ctx == NULL) { + g_coap_ctx = (void *)CoAPServer_init(); + } + + if (g_coap_ctx == NULL) { + return -1; + } + if (topic == NULL) { + return -1; + } + + CoAPServer_register(g_coap_ctx, (const char *)topic, (CoAPRecvMsgHandler)cb); + return 0; +} + +int awss_cmp_coap_cancel_packet(uint16_t msgid) +{ + if (g_coap_ctx == NULL) { + return -1; + } + return CoAPMessageId_cancel(g_coap_ctx, msgid); +} + +int awss_cmp_coap_send(void *buf, uint32_t len, void *sa, const char *uri, void *cb, uint16_t *msgid) +{ + if (g_coap_ctx == NULL) { + g_coap_ctx = (void *)CoAPServer_init(); + } else { + CoAPMessageId_cancel(g_coap_ctx, *msgid); + } + return CoAPServerMultiCast_send(g_coap_ctx, (NetworkAddr *)sa, uri, (uint8_t *)buf, + (uint16_t)len, (CoAPSendMsgHandler)cb, msgid); +} + +int awss_cmp_coap_send_resp(void *buf, uint32_t len, void *sa, const char *uri, void *req, void *cb, uint16_t *msgid, + char qos) +{ + if (g_coap_ctx == NULL) { + g_coap_ctx = (void *)CoAPServer_init(); + } + + return CoAPServerResp_send(g_coap_ctx, (NetworkAddr *)sa, (uint8_t *)buf, (uint16_t)len, req, uri, + (CoAPSendMsgHandler)cb, msgid, qos); +} + +int awss_cmp_coap_ob_send(void *buf, uint32_t len, void *sa, const char *uri, void *cb) +{ + if (g_coap_ctx == NULL) { + g_coap_ctx = (void *)CoAPServer_init(); + } + + return CoAPObsServer_notify(g_coap_ctx, uri, (uint8_t *)buf, (uint16_t)len, cb); +} + +int awss_cmp_coap_deinit() +{ + void *coap_ctx = g_coap_ctx; + g_coap_ctx = NULL; + + if (coap_ctx) { + CoAPServer_deinit(coap_ctx); + } + + return 0; +} + +const struct awss_cmp_couple awss_local_couple[] = { +#ifdef WIFI_PROVISION_ENABLED +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + {AWSS_LC_INIT_PAP, TOPIC_AWSS_SWITCHAP, wifimgr_process_switch_ap_request}, + {AWSS_LC_INIT_PAP, TOPIC_AWSS_WIFILIST, wifimgr_process_get_wifilist_request}, + {AWSS_LC_INIT_ROUTER | AWSS_LC_INIT_PAP, TOPIC_AWSS_GETDEVICEINFO_MCAST, wifimgr_process_mcast_get_device_info}, + {AWSS_LC_INIT_ROUTER | AWSS_LC_INIT_PAP, TOPIC_AWSS_GETDEVICEINFO_UCAST, wifimgr_process_ucast_get_device_info}, +#endif +#ifdef AWSS_SUPPORT_DEV_AP + {AWSS_LC_INIT_DEV_AP, TOPIC_AWSS_DEV_AP_SWITCHAP, wifimgr_process_dev_ap_switchap_request}, +#endif + {AWSS_LC_INIT_SUC, TOPIC_AWSS_GET_CONNECTAP_INFO_MCAST, awss_process_mcast_get_connectap_info}, + {AWSS_LC_INIT_SUC, TOPIC_AWSS_GET_CONNECTAP_INFO_UCAST, awss_process_ucast_get_connectap_info}, +#ifndef AWSS_DISABLE_REGISTRAR + {AWSS_LC_INIT_BIND, TOPIC_NOTIFY, online_dev_bind_monitor}, + {AWSS_LC_INIT_BIND, TOPIC_AWSS_CONNECTAP_NOTIFY, online_dev_bind_monitor}, +#endif +#endif + {AWSS_LC_INIT_SUC | AWSS_LC_INIT_BIND, TOPIC_GETDEVICEINFO_MCAST, online_mcast_get_device_info}, + {AWSS_LC_INIT_SUC | AWSS_LC_INIT_BIND, TOPIC_GETDEVICEINFO_UCAST, online_ucast_get_device_info}, +}; + +int awss_cmp_local_init(int init_stage) +{ + char topic[TOPIC_LEN_MAX] = {0}; + int i; + + for (i = 0; i < sizeof(awss_local_couple) / sizeof(awss_local_couple[0]); i ++) { + if ((awss_local_couple[i].init_stage & init_stage) == 0) { + continue; + } + memset(topic, 0, sizeof(topic)); + awss_build_topic(awss_local_couple[i].topic, topic, TOPIC_LEN_MAX); + awss_cmp_coap_register_cb(topic, awss_local_couple[i].cb); + } + + return 0; +} + +int awss_cmp_local_deinit(int force) +{ + if (g_coap_ctx == NULL) { + return 0; + } +#ifdef WIFI_PROVISION_ENABLED +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + awss_devinfo_notify_stop(); +#endif + awss_suc_notify_stop(); +#endif + if (force) { + awss_cmp_coap_deinit(); + } + + return 0; +} +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_cmp_mqtt.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_cmp_mqtt.c new file mode 100644 index 00000000..f4e57dd7 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_cmp_mqtt.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +static char online_init = 0; + +int awss_cmp_mqtt_register_cb(char *topic, void *cb) +{ + if (topic == NULL) { + return -1; + } + + return IOT_MQTT_Subscribe(NULL, topic, 0, (iotx_mqtt_event_handle_func_fpt)cb, NULL); +} + +int awss_cmp_mqtt_unregister_cb(char *topic) +{ + return IOT_MQTT_Unsubscribe(NULL, topic); +} + +int awss_cmp_mqtt_send(char *topic, void *data, int len, int qos) +{ + return IOT_MQTT_Publish_Simple(NULL, topic, qos, data, len); /* IOTX_MQTT_QOS1 or IOTX_MQTT_QOS1 */ +} + +const struct awss_cmp_couple awss_online_couple[] = { + {-1, TOPIC_MATCH_REPORT_REPLY, awss_report_token_reply}, +#ifdef WIFI_PROVISION_ENABLED +#ifndef AWSS_DISABLE_REGISTRAR + {-1, TOPIC_ZC_CHECKIN, awss_enrollee_checkin}, + {-1, TOPIC_ZC_ENROLLEE_REPLY, awss_report_enrollee_reply}, + {-1, TOPIC_ZC_CIPHER_REPLY, awss_get_cipher_reply}, +#endif + {-1, TOPIC_SWITCHAP, awss_online_switchap} +#endif +}; + +int awss_cmp_online_init() +{ + int i; + char topic[TOPIC_LEN_MAX] = {0}; + if (online_init) { + return 0; + } + + + for (i = 0; i < sizeof(awss_online_couple) / sizeof(awss_online_couple[0]); i ++) { + int res = -1; + memset(topic, 0, sizeof(topic)); + awss_build_topic(awss_online_couple[i].topic, topic, TOPIC_LEN_MAX); + res = awss_cmp_mqtt_register_cb(topic, awss_online_couple[i].cb); + awss_debug("sub %s %s\n", topic, res < 0 ? "fail" : "success"); + } + + online_init = 1; + + return 0; +} + +int awss_cmp_online_deinit() +{ + uint8_t i; + char topic[TOPIC_LEN_MAX] = {0}; + + if (!online_init) { + return 0; + } + + awss_dev_bind_notify_stop(); + + for (i = 0; i < sizeof(awss_online_couple) / sizeof(awss_online_couple[0]); i ++) { + memset(topic, 0, sizeof(topic)); + awss_build_topic(awss_online_couple[i].topic, topic, TOPIC_LEN_MAX); + awss_cmp_mqtt_unregister_cb(topic); + } + + online_init = 0; + + return 0; +} + +int awss_cmp_mqtt_get_payload(void *mesg, char **payload, uint32_t *playload_len) +{ + iotx_mqtt_event_msg_pt msg; + iotx_mqtt_topic_info_pt ptopic_info; + if (mesg == NULL || payload == NULL || playload_len == NULL) { + return - 1; + } + + msg = (iotx_mqtt_event_msg_pt)mesg; + ptopic_info = (iotx_mqtt_topic_info_pt) msg->msg; + + + switch (msg->event_type) { + case IOTX_MQTT_EVENT_PUBLISH_RECEIVED: + *playload_len = ptopic_info->payload_len; + *payload = (char *)ptopic_info->payload; + break; + default: + return -1; + } + return 0; +} +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_event.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_event.c new file mode 100644 index 00000000..399b8908 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_event.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" + +extern int iotx_event_post(int event); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +int awss_event_post(int event) +{ + int ret = 0; + void *cb = NULL; + + ret = iotx_event_post(event); + + cb = (void *)iotx_event_callback(ITE_AWSS_STATUS); + if (cb) { + ret = ((int (*)(int))cb)(event); + } + + return ret; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_event.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_event.h new file mode 100644 index 00000000..f4eaef49 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_event.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_EVENT_H__ +#define __AWSS_EVENT_H__ + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +int awss_event_post(int event); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_info.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_info.c new file mode 100644 index 00000000..f85f01f2 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_info.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif +#define AWSS_CONNAP_MONITOR_TIMEOUT_MS (60 * 1000) + +static char g_awss_connectap_info_avaliable = 0; +static void *connectap_monitor_timer = NULL; +static void *connectap_monitor_mutex = NULL; + +static void awss_release_connectap_monitor() +{ + if (connectap_monitor_timer) { + HAL_Timer_Stop(connectap_monitor_timer); + HAL_Timer_Delete(connectap_monitor_timer); + connectap_monitor_timer = NULL; + } + if (connectap_monitor_mutex) { + HAL_MutexUnlock(connectap_monitor_mutex); + HAL_MutexDestroy(connectap_monitor_mutex); + connectap_monitor_mutex = NULL; + } +} + +static void awss_connectap_monitor(void *param) +{ + if (connectap_monitor_mutex) { + HAL_MutexLock(connectap_monitor_mutex); + } + g_awss_connectap_info_avaliable = 0; + awss_release_connectap_monitor(); +} + +int awss_stop_connectap_monitor() +{ + awss_connectap_monitor(NULL); + return 0; +} + +int awss_start_connectap_monitor() +{ + if (connectap_monitor_timer) { + awss_debug("connap-m exist"); + return 0; + } + + if (connectap_monitor_mutex == NULL) { + connectap_monitor_mutex = HAL_MutexCreate(); + if (connectap_monitor_mutex == NULL) { + awss_err("connap alloc-m fail"); + goto CONNAP_M_FAIL; + } + } + + HAL_MutexLock(connectap_monitor_mutex); + + connectap_monitor_timer = HAL_Timer_Create("connap_monitor", + awss_connectap_monitor, NULL); + if (connectap_monitor_timer == NULL) { + awss_err("connap alloc-t fail"); + goto CONNAP_M_FAIL; + } + + g_awss_connectap_info_avaliable = 1; + HAL_Timer_Stop(connectap_monitor_timer); + HAL_Timer_Start(connectap_monitor_timer, AWSS_CONNAP_MONITOR_TIMEOUT_MS); + HAL_MutexUnlock(connectap_monitor_mutex); + return 0; + +CONNAP_M_FAIL: + awss_release_connectap_monitor(); + return -1; +} + +int process_get_device_info(void *ctx, void *resource, void *remote, void *request, char is_mcast, int type) +{ + char *buf = NULL; + char *dev_info = NULL; + int len = 0, id_len = 0; + char *msg = NULL, *id = NULL; + const char *topic_fmt = NULL; + char topic[TOPIC_LEN_MAX] = {0}; + char req_msg_id[MSG_REQ_ID_LEN] = {0}; + + buf = os_zalloc(DEV_INFO_LEN_MAX); + if (!buf) { + goto DEV_INFO_ERR; + } + + dev_info = os_zalloc(DEV_INFO_LEN_MAX); + if (!dev_info) { + goto DEV_INFO_ERR; + } + + msg = awss_cmp_get_coap_payload(request, &len); + id = json_get_value_by_name(msg, len, "id", &id_len, 0); + if (id && id_len < MSG_REQ_ID_LEN) { + memcpy(req_msg_id, id, id_len); + } + + if (type == AWSS_NOTIFY_DEV_RAND_SIGN) { + topic_fmt = is_mcast ? TOPIC_AWSS_GETDEVICEINFO_MCAST : TOPIC_AWSS_GETDEVICEINFO_UCAST; + } else if (type == AWSS_NOTIFY_SUCCESS) { + topic_fmt = is_mcast ? TOPIC_AWSS_GET_CONNECTAP_INFO_MCAST : TOPIC_AWSS_GET_CONNECTAP_INFO_UCAST; + } else { + goto DEV_INFO_ERR; + } + awss_build_dev_info(type, buf, DEV_INFO_LEN_MAX); + HAL_Snprintf(dev_info, DEV_INFO_LEN_MAX - 1, "{%s}", buf); + + memset(buf, 0x00, DEV_INFO_LEN_MAX); + HAL_Snprintf(buf, DEV_INFO_LEN_MAX - 1, AWSS_ACK_FMT, req_msg_id, 200, dev_info); + + HAL_Free(dev_info); + + awss_info("tx msg to app: %s", buf); + + awss_build_topic(topic_fmt, topic, TOPIC_LEN_MAX); + + if (0 != awss_cmp_coap_send_resp(buf, strlen(buf), remote, topic, request, NULL, NULL, 0)) { + awss_err("tx dev info rsp fail."); + } + + HAL_Free(buf); + return 0; + +DEV_INFO_ERR: + if (buf) { + HAL_Free(buf); + } + if (dev_info) { + HAL_Free(dev_info); + } + + return -1; +} + +int awss_process_mcast_get_connectap_info(void *ctx, void *resource, void *remote, void *request) +{ + if (g_awss_connectap_info_avaliable == 0) { + return -1; + } + return process_get_device_info(ctx, resource, remote, request, 1, AWSS_NOTIFY_SUCCESS); +} + +int awss_process_ucast_get_connectap_info(void *ctx, void *resource, void *remote, void *request) +{ + if (g_awss_connectap_info_avaliable == 0) { + return -1; + } + return process_get_device_info(ctx, resource, remote, request, 0, AWSS_NOTIFY_SUCCESS); +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_info.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_info.h new file mode 100644 index 00000000..31c6db68 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_info.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_INFO_H__ +#define __AWSS_INFO_H__ + +#include + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +int process_get_device_info(void *ctx, void *resource, void *remote, void *request, char is_mcast, int type); +int awss_process_mcast_get_connectap_info(void *ctx, void *resource, void *remote, void *request); +int awss_process_ucast_get_connectap_info(void *ctx, void *resource, void *remote, void *request); + +int awss_stop_connectap_monitor(); +int awss_start_connectap_monitor(); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_log.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_log.h new file mode 100644 index 00000000..425929bc --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_log.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_LOG_H__ +#define __AWSS_LOG_H__ + +#include "infra_log.h" + +#define awss_flow(...) log_flow("awss", __VA_ARGS__) +#define awss_debug(...) log_debug("awss", __VA_ARGS__) +#define awss_info(...) log_info("awss", __VA_ARGS__) +#define awss_warn(...) log_warning("awss", __VA_ARGS__) +#define awss_err(...) log_err("awss", __VA_ARGS__) +#define awss_crit(...) log_crit("awss", __VA_ARGS__) +#define awss_emerg(...) log_emerg("awss", __VA_ARGS__) +#define awss_trace(...) log_crit("awss", __VA_ARGS__) + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_notify.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_notify.c new file mode 100644 index 00000000..a5e6d72d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_notify.c @@ -0,0 +1,680 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#define AWSS_CHECK_RESP_TIME (300) +#define AWSS_NOTIFY_PORT (5683) +#define AWSS_NOTIFY_HOST "255.255.255.255" +#define AWSS_DEV_NOTIFY_FMT "{\"id\":\"%u\",\"version\":\"1.0\",\"method\":\"%s\",\"params\":{%s}}" + +struct notify_map_t { + uint8_t notify_type; + char *notify_method; + char *notify_topic; + void *cb; +}; + +static uint8_t g_notify_id; +static char awss_notify_resp[AWSS_NOTIFY_TYPE_MAX] = {0}; +static uint16_t g_notify_msg_id[AWSS_NOTIFY_TYPE_MAX] = {0}; + +#ifdef WIFI_PROVISION_ENABLED +static void *success_notify_timer = NULL; +static void *devinfo_notify_timer = NULL; +static void *success_notify_mutex = NULL; +static void *devinfo_notify_mutex = NULL; +#endif +static void *dev_bind_notify_timer = NULL; +static void *get_devinfo_timer = NULL; +static void *dev_bind_notify_mutex = NULL; + +extern char awss_report_token_suc; +extern char awss_report_token_cnt; + +static int awss_dev_bind_notify_resp(void *context, int result, + void *userdata, void *remote, + void *message); +#ifdef WIFI_PROVISION_ENABLED +static int awss_devinfo_notify_resp(void *context, int result, + void *userdata, void *remote, + void *message); +static int awss_suc_notify_resp(void *context, int result, + void *userdata, void *remote, + void *message); +int awss_devinfo_notify(); +int awss_suc_notify(); +#endif +static int awss_notify_response(int type, int result, void *message); +static int awss_process_get_devinfo(); +int awss_dev_bind_notify(); + +static const struct notify_map_t notify_map[] = { + {AWSS_NOTIFY_DEV_BIND_TOKEN, METHOD_DEV_INFO_NOTIFY, TOPIC_NOTIFY, awss_dev_bind_notify_resp}, +#ifdef WIFI_PROVISION_ENABLED + {AWSS_NOTIFY_DEV_RAND_SIGN, METHOD_AWSS_DEV_INFO_NOTIFY, TOPIC_AWSS_NOTIFY, awss_devinfo_notify_resp}, + {AWSS_NOTIFY_SUCCESS, METHOD_AWSS_CONNECTAP_NOTIFY, TOPIC_AWSS_CONNECTAP_NOTIFY, awss_suc_notify_resp} +#endif +}; + +/* + * { + * "id": "123", + * "code": 200, + * "data": {} + * } + */ +static int awss_dev_bind_notify_resp(void *context, int result, + void *userdata, void *remote, + void *message) +{ + int res = awss_notify_response(AWSS_NOTIFY_DEV_BIND_TOKEN, result, message); + if (res == 1) { + awss_update_token(); +#ifdef DEV_BIND_TEST + HAL_Reboot(); +#endif + } + return res; +} + +#ifdef WIFI_PROVISION_ENABLED +static int awss_devinfo_notify_resp(void *context, int result, + void *userdata, void *remote, + void *message) +{ + return awss_notify_response(AWSS_NOTIFY_DEV_RAND_SIGN, result, message); +} + +static int awss_suc_notify_resp(void *context, int result, + void *userdata, void *remote, + void *message) +{ + return awss_notify_response(AWSS_NOTIFY_SUCCESS, result, message); +} +#endif + +static int awss_notify_response(int type, int result, void *message) +{ + uint8_t i = 0; + + awss_flow("%s, type:%d,result:%u\r\n", __func__, type, result); + + if (message == NULL) { + return -1; + } + + if (result != 0) { + return 0; + } + + if (awss_cmp_get_coap_code(message) >= 0x60) { + return 0; + } + + do { + int val = 0; + int len = 0, mlen = 0; + char *payload = NULL, *elem = NULL; + + if ((payload = awss_cmp_get_coap_payload(message, &len)) == NULL || + len > 0x40 || len == 0) { + return 0; + } + + awss_debug("payload:%s\r\n", payload); + + elem = json_get_value_by_name(payload, len, AWSS_JSON_ID, &mlen, 0); + if (elem == NULL) { + return 0; + } + + val = atoi(elem); + if (val != 123 && val > g_notify_id) { + return 0; + } + + elem = json_get_value_by_name(payload, len, AWSS_JSON_CODE, &mlen, 0); + if (elem == NULL) { + return 0; + } + + val = atoi(elem); + if (val != 200) { + return 0; + } + } while (0); + + for (i = 0; i < sizeof(notify_map) / sizeof(notify_map[0]); i ++) { + if (notify_map[i].notify_type != type) { + continue; + } + + awss_notify_resp[type] = 1; + break; + } + + return awss_notify_resp[type]; +} + +int awss_notify_dev_info(int type, int count) +{ + char *buf = NULL; + char *dev_info = NULL; + int i; + platform_netaddr_t notify_sa; + memset(¬ify_sa, 0, sizeof(notify_sa)); + + do { + void *cb = NULL; + char *method = NULL, *topic = NULL; + for (i = 0; i < sizeof(notify_map) / sizeof(notify_map[0]); i ++) { + if (notify_map[i].notify_type != type) { + continue; + } + + method = notify_map[i].notify_method; + topic = notify_map[i].notify_topic; + cb = notify_map[i].cb; + break; + } + if (method == NULL || topic == NULL) { + awss_err("parametes invalid"); + break; + } + + buf = os_zalloc(DEV_INFO_LEN_MAX); + dev_info = os_zalloc(DEV_INFO_LEN_MAX); + if (buf == NULL || dev_info == NULL) { + awss_err("alloc mem fail"); + break; + } + + memset(¬ify_sa, 0, sizeof(notify_sa)); + memcpy(notify_sa.host, AWSS_NOTIFY_HOST, strlen(AWSS_NOTIFY_HOST)); + notify_sa.port = AWSS_NOTIFY_PORT; + + awss_build_dev_info(type, dev_info, DEV_INFO_LEN_MAX); + + HAL_Snprintf(buf, DEV_INFO_LEN_MAX - 1, AWSS_DEV_NOTIFY_FMT, ++ g_notify_id, method, dev_info); + + awss_info("topic:%s\n", topic); + awss_debug("payload:%s\n", buf); + for (i = 0; i < count; i ++) { + int ret = awss_cmp_coap_send(buf, strlen(buf), ¬ify_sa, topic, cb, &g_notify_msg_id[type]); + awss_info("send notify %s", ret == 0 ? "success" : "fail"); + if (count > 1) { + HAL_SleepMs(200 + 100 * i); + } + + if (awss_notify_resp[type]) { + break; + } + } + } while (0); + + if (buf) { + HAL_Free(buf); + } + if (dev_info) { + HAL_Free(dev_info); + } + + return awss_notify_resp[type]; +} + +#define AWSS_NOTIFY_CNT_MAX (30) + +static void *coap_session_ctx = NULL; + +static int awss_process_get_devinfo() +{ + char *buf = NULL; + char *dev_info = NULL; + + if (awss_report_token_suc == 0) { + awss_debug("try to report token to cloud"); + HAL_Timer_Start(get_devinfo_timer, AWSS_CHECK_RESP_TIME); + return 0; + } + + if (coap_session_ctx == NULL) { + awss_debug("no get req"); + return -1; + } + + do { + int len = 0, id_len = 0; + char *msg = NULL, *id = NULL; + char req_msg_id[MSG_REQ_ID_LEN]; + char topic[TOPIC_LEN_MAX] = { 0 }; + struct coap_session_ctx_t *ctx = (struct coap_session_ctx_t *)coap_session_ctx; + + buf = os_zalloc(DEV_INFO_LEN_MAX); + if (buf == NULL) { + goto GET_DEV_INFO_ERR; + } + + dev_info = os_zalloc(DEV_INFO_LEN_MAX); + if (dev_info == NULL) { + goto GET_DEV_INFO_ERR; + } + + msg = awss_cmp_get_coap_payload(ctx->request, &len); + if (msg == NULL) { + goto GET_DEV_INFO_ERR; + } + + id = json_get_value_by_name(msg, len, "id", &id_len, 0); + memset(req_msg_id, 0, sizeof(req_msg_id)); + memcpy(req_msg_id, id, id_len); + + awss_build_dev_info(AWSS_NOTIFY_DEV_BIND_TOKEN, buf, DEV_INFO_LEN_MAX); + HAL_Snprintf(dev_info, DEV_INFO_LEN_MAX - 1, "{%s}", buf); + memset(buf, 0x00, DEV_INFO_LEN_MAX); + HAL_Snprintf(buf, DEV_INFO_LEN_MAX - 1, AWSS_ACK_FMT, req_msg_id, 200, dev_info); + HAL_Free(dev_info); + + awss_info("sending message to app: %s", buf); + if (ctx->is_mcast) { + awss_build_topic((const char *)TOPIC_GETDEVICEINFO_MCAST, topic, TOPIC_LEN_MAX); + } else { + awss_build_topic((const char *)TOPIC_GETDEVICEINFO_UCAST, topic, TOPIC_LEN_MAX); + } + + /*before tx to app, clear token suc flag*/ + awss_update_token(); + + if (0 != awss_cmp_coap_send_resp(buf, strlen(buf), ctx->remote, topic, ctx->request, NULL, NULL, 0)) { + awss_err("sending failed."); + } + + HAL_Free(buf); + awss_release_coap_ctx(coap_session_ctx); + coap_session_ctx = NULL; + awss_stop_timer(get_devinfo_timer); + get_devinfo_timer = NULL; + } while (0); + + return 0; + +GET_DEV_INFO_ERR: + awss_release_coap_ctx(coap_session_ctx); + coap_session_ctx = NULL; + awss_stop_timer(get_devinfo_timer); + get_devinfo_timer = NULL; + + if (buf) { + HAL_Free(buf); + } + if (dev_info) { + HAL_Free(dev_info); + } + + return -1; +} + +static int online_get_device_info(void *ctx, void *resource, void *remote, + void *request, char is_mcast) +{ + int timeout = 0; + /* + * if cloud is not ready, don't response token + */ + if (awss_report_token_cnt == 0) { + return -1; + } + /* + * if the last one is not finished, drop current request + */ + if (coap_session_ctx != NULL) { + awss_debug("no req"); + return -1; + } + /* + * copy coap session context + */ + coap_session_ctx = awss_cpy_coap_ctx(request, remote, is_mcast); + if (coap_session_ctx == NULL) { + awss_err("cpy req ctx fail"); + return -1; + } + + timeout = awss_token_timeout(); + if (timeout) { + produce_random(aes_random, sizeof(aes_random)); + awss_report_token(); + } + + if (get_devinfo_timer == NULL) { + get_devinfo_timer = HAL_Timer_Create("get_devinfo", (void (*)(void *))awss_process_get_devinfo, NULL); + } + HAL_Timer_Stop(get_devinfo_timer); + HAL_Timer_Start(get_devinfo_timer, timeout ? AWSS_CHECK_RESP_TIME : 1); + + return 0; +} + +int online_mcast_get_device_info(void *ctx, void *resource, void *remote, void *request) +{ + return online_get_device_info(ctx, resource, remote, request, 1); +} + +int online_ucast_get_device_info(void *ctx, void *resource, void *remote, void *request) +{ + return online_get_device_info(ctx, resource, remote, request, 0); +} + +static int dev_bind_interval = 0; +static char dev_bind_cnt = 0; +static int __awss_dev_bind_notify() +{ + /* + * wait for token is sent to cloud and rx reply from cloud + */ + if (awss_report_token_suc == 0) { + if (dev_bind_notify_timer == NULL) { + dev_bind_notify_timer = HAL_Timer_Create("dev_bind", (void (*)(void *))__awss_dev_bind_notify, NULL); + } + HAL_Timer_Stop(dev_bind_notify_timer); + HAL_Timer_Start(dev_bind_notify_timer, AWSS_CHECK_RESP_TIME); + return 0; + } + + if (dev_bind_notify_mutex == NULL) { + dev_bind_notify_mutex = HAL_MutexCreate(); + if (dev_bind_notify_mutex == NULL) { + return -1; + } + } + + if (dev_bind_cnt == 0) { + awss_event_post(IOTX_AWSS_BIND_NOTIFY); + } + + HAL_MutexLock(dev_bind_notify_mutex); + + do { + uint8_t i = 0; + + if (awss_notify_resp[AWSS_NOTIFY_DEV_BIND_TOKEN] != 0) { + break; + } + + for (i = 0; i < RANDOM_MAX_LEN; i ++) + if (aes_random[i] != 0x00) { + break; + } + + if (i >= RANDOM_MAX_LEN) { + produce_random(aes_random, sizeof(aes_random)); + } + + if (awss_token_timeout() == 0) { + awss_notify_dev_info(AWSS_NOTIFY_DEV_BIND_TOKEN, 1); + dev_bind_interval += 100; + dev_bind_cnt ++; + } +#ifdef DEV_BIND_TEST + if (dev_bind_cnt > 3) { + HAL_Reboot(); + } +#endif + + if (dev_bind_cnt < AWSS_NOTIFY_CNT_MAX && + awss_notify_resp[AWSS_NOTIFY_DEV_BIND_TOKEN] == 0) { + if (dev_bind_notify_timer == NULL) { + dev_bind_notify_timer = HAL_Timer_Create("dev_bind", (void (*)(void *))awss_dev_bind_notify, NULL); + } + HAL_Timer_Stop(dev_bind_notify_timer); + HAL_Timer_Start(dev_bind_notify_timer, dev_bind_interval); + HAL_MutexUnlock(dev_bind_notify_mutex); + return 0; + } + } while (0); + + awss_cmp_coap_cancel_packet(g_notify_msg_id[AWSS_NOTIFY_DEV_BIND_TOKEN]); + g_notify_msg_id[AWSS_NOTIFY_DEV_BIND_TOKEN] = 0; + awss_notify_resp[AWSS_NOTIFY_DEV_BIND_TOKEN] = 0; + dev_bind_interval = 0; + dev_bind_cnt = 0; + if (dev_bind_notify_timer) { + awss_stop_timer(dev_bind_notify_timer); + dev_bind_notify_timer = NULL; + } + if (dev_bind_notify_mutex) { + HAL_MutexUnlock(dev_bind_notify_mutex); + HAL_MutexDestroy(dev_bind_notify_mutex); + dev_bind_notify_mutex = NULL; + } + return 1; +} + +int awss_dev_bind_notify() +{ + dev_bind_cnt = 0; + dev_bind_interval = 0; + awss_notify_resp[AWSS_NOTIFY_DEV_BIND_TOKEN] = 0; + + return __awss_dev_bind_notify(); +} + +int awss_dev_bind_notify_stop() +{ + if (dev_bind_notify_mutex) { + HAL_MutexLock(dev_bind_notify_mutex); + } + + do { + awss_notify_resp[AWSS_NOTIFY_DEV_BIND_TOKEN] = 1; + dev_bind_cnt = AWSS_NOTIFY_CNT_MAX; + if (dev_bind_notify_timer == NULL) { + break; + } + + awss_stop_timer(dev_bind_notify_timer); + dev_bind_notify_timer = NULL; + } while (0); + + awss_cmp_coap_cancel_packet(g_notify_msg_id[AWSS_NOTIFY_DEV_BIND_TOKEN]); + g_notify_msg_id[AWSS_NOTIFY_DEV_BIND_TOKEN] = 0; + + if (dev_bind_notify_mutex) { + HAL_MutexUnlock(dev_bind_notify_mutex); + HAL_MutexDestroy(dev_bind_notify_mutex); + dev_bind_notify_mutex = NULL; + } + return 0; +} + +#ifdef WIFI_PROVISION_ENABLED +static int suc_interval = 0; +static char suc_cnt = 0; +static int __awss_suc_notify() +{ + awss_debug("resp:%d\r\n", awss_notify_resp[AWSS_NOTIFY_SUCCESS]); + + if (success_notify_mutex == NULL) { + success_notify_mutex = HAL_MutexCreate(); + if (success_notify_mutex == NULL) { + return -1; + } + } + + if (suc_cnt == 0) { + awss_event_post(IOTX_AWSS_SUC_NOTIFY); + } + + HAL_MutexLock(success_notify_mutex); + + do { + if (awss_notify_resp[AWSS_NOTIFY_SUCCESS] != 0) { + break; + } + + awss_notify_dev_info(AWSS_NOTIFY_SUCCESS, 1); + + suc_interval += 100; + if (suc_cnt ++ < AWSS_NOTIFY_CNT_MAX && + awss_notify_resp[AWSS_NOTIFY_SUCCESS] == 0) { + if (success_notify_timer == NULL) { + success_notify_timer = HAL_Timer_Create("awss_suc", (void (*)(void *))__awss_suc_notify, NULL); + } + HAL_Timer_Stop(success_notify_timer); + HAL_Timer_Start(success_notify_timer, suc_interval); + HAL_MutexUnlock(success_notify_mutex); + return 0; + } + } while (0); + + awss_cmp_coap_cancel_packet(g_notify_msg_id[AWSS_NOTIFY_SUCCESS]); + g_notify_msg_id[AWSS_NOTIFY_SUCCESS] = 0; + + awss_notify_resp[AWSS_NOTIFY_SUCCESS] = 0; + suc_interval = 0; + suc_cnt = 0; + if (success_notify_timer) { + awss_stop_timer(success_notify_timer); + success_notify_timer = NULL; + } + + if (success_notify_mutex) { + HAL_MutexUnlock(success_notify_mutex); + HAL_MutexDestroy(success_notify_mutex); + success_notify_mutex = NULL; + } + return 1; +} + +int awss_suc_notify() +{ + suc_cnt = 0; + suc_interval = 0; + awss_notify_resp[AWSS_NOTIFY_SUCCESS] = 0; + return __awss_suc_notify(); +} + +int awss_suc_notify_stop() +{ + if (success_notify_mutex) { + HAL_MutexLock(success_notify_mutex); + } + + do { + awss_notify_resp[AWSS_NOTIFY_SUCCESS] = 1; + suc_cnt = AWSS_NOTIFY_CNT_MAX; + if (success_notify_timer == NULL) { + break; + } + + awss_stop_timer(success_notify_timer); + success_notify_timer = NULL; + } while (0); + + awss_cmp_coap_cancel_packet(g_notify_msg_id[AWSS_NOTIFY_SUCCESS]); + g_notify_msg_id[AWSS_NOTIFY_SUCCESS] = 0; + + if (success_notify_mutex) { + HAL_MutexUnlock(success_notify_mutex); + HAL_MutexDestroy(success_notify_mutex); + success_notify_mutex = NULL; + } + return 0; +} + + +static int devinfo_interval = 0; +static char devinfo_cnt = 0; +static int __awss_devinfo_notify() +{ + if (devinfo_notify_mutex == NULL) { + devinfo_notify_mutex = HAL_MutexCreate(); + if (devinfo_notify_mutex == NULL) { + return -1; + } + } + HAL_MutexLock(devinfo_notify_mutex); + + do { + if (awss_notify_resp[AWSS_NOTIFY_DEV_RAND_SIGN] != 0) { + break; + } + + awss_notify_dev_info(AWSS_NOTIFY_DEV_RAND_SIGN, 1); + + devinfo_interval += 100; + if (devinfo_cnt ++ < AWSS_NOTIFY_CNT_MAX && + awss_notify_resp[AWSS_NOTIFY_DEV_RAND_SIGN] == 0) { + if (devinfo_notify_timer == NULL) { + devinfo_notify_timer = HAL_Timer_Create("devinfo", (void (*)(void *))__awss_devinfo_notify, NULL); + } + HAL_Timer_Stop(devinfo_notify_timer); + HAL_Timer_Start(devinfo_notify_timer, devinfo_interval); + HAL_MutexUnlock(devinfo_notify_mutex); + return 0; + } + } while (0); + + awss_cmp_coap_cancel_packet(g_notify_msg_id[AWSS_NOTIFY_DEV_RAND_SIGN]); + g_notify_msg_id[AWSS_NOTIFY_DEV_RAND_SIGN] = 0; + + awss_notify_resp[AWSS_NOTIFY_DEV_RAND_SIGN] = 0; + devinfo_interval = 0; + devinfo_cnt = 0; + if (devinfo_notify_timer) { + awss_stop_timer(devinfo_notify_timer); + devinfo_notify_timer = NULL; + } + if (devinfo_notify_mutex) { + HAL_MutexUnlock(devinfo_notify_mutex); + HAL_MutexDestroy(devinfo_notify_mutex); + devinfo_notify_mutex = NULL; + } + return 1; +} + +int awss_devinfo_notify() +{ + devinfo_cnt = 0; + devinfo_interval = 0; + awss_notify_resp[AWSS_NOTIFY_DEV_RAND_SIGN] = 0; + return __awss_devinfo_notify(); +} + +int awss_devinfo_notify_stop() +{ + if (devinfo_notify_mutex) { + HAL_MutexLock(devinfo_notify_mutex); + } + + do { + awss_notify_resp[AWSS_NOTIFY_DEV_RAND_SIGN] = 1; + devinfo_cnt = AWSS_NOTIFY_CNT_MAX; + if (devinfo_notify_timer == NULL) { + break; + } + + awss_stop_timer(devinfo_notify_timer); + devinfo_notify_timer = NULL; + } while (0); + + awss_cmp_coap_cancel_packet(g_notify_msg_id[AWSS_NOTIFY_DEV_RAND_SIGN]); + g_notify_msg_id[AWSS_NOTIFY_DEV_RAND_SIGN] = 0; + + if (devinfo_notify_mutex) { + HAL_MutexUnlock(devinfo_notify_mutex); + HAL_MutexDestroy(devinfo_notify_mutex); + devinfo_notify_mutex = NULL; + } + return 0; +} + +#endif + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_notify.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_notify.h new file mode 100644 index 00000000..4b5691a1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_notify.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_NOTIFY_H__ +#define __AWSS_NOTIFY_H__ + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +enum { + AWSS_NOTIFY_DEV_INFO = 0, + AWSS_NOTIFY_DEV_BIND_TOKEN, + AWSS_NOTIFY_DEV_RAND_SIGN, + AWSS_NOTIFY_SUCCESS, + AWSS_NOTIFY_TYPE_MAX, +}; + +#ifdef WIFI_PROVISION_ENABLED +int awss_suc_notify(); +int awss_devinfo_notify(); +int awss_suc_notify_stop(); +int awss_devinfo_notify_stop(); +#endif + +int awss_dev_bind_notify(); +int awss_dev_bind_notify_stop(); +int awss_notify_dev_info(int type, int count); +int online_mcast_get_device_info(void *ctx, void *resource, void *remote, void *request); +int online_ucast_get_device_info(void *ctx, void *resource, void *remote, void *request); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_packet.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_packet.c new file mode 100644 index 00000000..11a859e4 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_packet.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" + +#define AWSS_DEV_RAND_SIGN_FMT ",\"random\":\"%s\",\"signMethod\":%d,\"sign\":\"%s\"" +#define AWSS_DEV_BIND_TOKEN_FMT ",\"token\":\"%s\",\"remainTime\":%d,\"type\":%d" +#define AWSS_SUCCESS_FMT ",\"type\":%d" +#define AWSS_DEV_INFO_FMT "\"awssVer\":%s,\"productKey\":\"%s\",\"deviceName\":\"%s\",\"mac\":\"%s\",\"ip\":\"%s\",\"cipherType\":%d" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +static inline int bind_get_encrypt_type() +{ + return 3; +} + +static void *awss_get_dev_info(void *dev_info, int len) +{ + char dev_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char mac_str[HAL_MAC_LEN + 1] = {0}; + char pk[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char ip_str[OS_IP_LEN + 1] = {0}; + + if (dev_info == NULL || len <= 0) { + return NULL; + } + + HAL_GetProductKey(pk); + HAL_GetDeviceName(dev_name); + os_wifi_get_mac_str(mac_str); + HAL_Wifi_Get_IP(ip_str, NULL); +#if 0 + awss_dict_crypt(NOTIFY_ENCODE_TABLE, (uint8_t *)pk, strlen(pk)); + awss_dict_crypt(NOTIFY_ENCODE_TABLE, (uint8_t *)dev_name, strlen(dev_name)); +#endif + HAL_Snprintf(dev_info, len - 1, AWSS_DEV_INFO_FMT, AWSS_VER, pk, dev_name, mac_str, ip_str, + bind_get_encrypt_type()); + + return dev_info; +} + +void *awss_build_dev_info(int type, void *dev_info, int info_len) +{ + int len = 0; + char *buf = NULL; + + if (dev_info == NULL || info_len <= 0) { + return NULL; + } + + buf = os_zalloc(DEV_INFO_LEN_MAX); + if (buf == NULL) { + return NULL; + } + + len += HAL_Snprintf((char *)dev_info + len, info_len - len - 1, "%s", (char *)awss_get_dev_info(buf, DEV_INFO_LEN_MAX)); + HAL_Free(buf); + buf = NULL; + + switch (type) { + case AWSS_NOTIFY_DEV_BIND_TOKEN: { + char rand_str[(RANDOM_MAX_LEN << 1) + 1] = {0}; + utils_hex_to_str(aes_random, RANDOM_MAX_LEN, rand_str, sizeof(rand_str)); + len += HAL_Snprintf((char *)dev_info + len, info_len - len - 1, AWSS_DEV_BIND_TOKEN_FMT, rand_str, + awss_token_remain_time(), 0); + break; + } +#ifdef WIFI_PROVISION_ENABLED + case AWSS_NOTIFY_SUCCESS: { + len += HAL_Snprintf((char *)dev_info + len, info_len - len - 1, AWSS_SUCCESS_FMT, 0); + break; + } + case AWSS_NOTIFY_DEV_RAND_SIGN: { + char sign_str[DEV_SIGN_SIZE * 2 + 1] = {0}; + char rand_str[(RANDOM_MAX_LEN << 1) + 1] = {0}; + { + int txt_len = 80; + char txt[80] = {0}; + char key[IOTX_DEVICE_SECRET_LEN + 1] = {0}; + uint8_t sign[DEV_SIGN_SIZE + 1] = {0}; + + if (bind_get_encrypt_type() == 3) { /* aes-key per product */ + HAL_GetProductSecret(key); + } else { /* aes-key per device */ + HAL_GetDeviceSecret(key); + } + awss_build_sign_src(txt, &txt_len); + produce_signature(sign, (uint8_t *)txt, txt_len, key); + utils_hex_to_str(sign, DEV_SIGN_SIZE, sign_str, sizeof(sign_str)); + } + utils_hex_to_str(aes_random, RANDOM_MAX_LEN, rand_str, sizeof(rand_str)); + len += HAL_Snprintf((char *)dev_info + len, info_len - len - 1, AWSS_DEV_RAND_SIGN_FMT, rand_str, 0, sign_str); + break; + } +#endif + default: + break; + } + + return dev_info; +} + +#ifdef WIFI_PROVISION_ENABLED +char *awss_build_sign_src(char *sign_src, int *sign_src_len) +{ + char *pk = NULL, *dev_name = NULL; + int dev_name_len, pk_len, text_len; + + if (sign_src == NULL || sign_src_len == NULL) { + goto build_sign_src_err; + } + + pk = os_zalloc(IOTX_PRODUCT_KEY_LEN + 1); + dev_name = os_zalloc(IOTX_DEVICE_NAME_LEN + 1); + if (pk == NULL || dev_name == NULL) { + goto build_sign_src_err; + } + + HAL_GetProductKey(pk); + HAL_GetDeviceName(dev_name); + + pk_len = strlen(pk); + dev_name_len = strlen(dev_name); + + text_len = RANDOM_MAX_LEN + dev_name_len + pk_len; + if (*sign_src_len < text_len) { + goto build_sign_src_err; + } + + *sign_src_len = text_len; + + memcpy(sign_src, aes_random, RANDOM_MAX_LEN); + memcpy(sign_src + RANDOM_MAX_LEN, dev_name, dev_name_len); + memcpy(sign_src + RANDOM_MAX_LEN + dev_name_len, pk, pk_len); + + HAL_Free(pk); + HAL_Free(dev_name); + + return sign_src; + +build_sign_src_err: + if (pk) { + HAL_Free(pk); + } + if (dev_name) { + HAL_Free(dev_name); + } + return NULL; +} +#endif +const char *awss_build_topic(const char *topic_fmt, char *topic, uint32_t tlen) +{ + char pk[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char dev_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + if (topic == NULL || topic_fmt == NULL || tlen == 0) { + return NULL; + } + + HAL_GetProductKey(pk); + HAL_GetDeviceName(dev_name); + + HAL_Snprintf(topic, tlen - 1, topic_fmt, pk, dev_name); + + return topic; +} + +int awss_build_packet(int type, void *id, void *ver, void *method, void *data, int code, void *packet, int *packet_len) +{ + int len; + if (packet_len == NULL || data == NULL || packet == NULL) { + return -1; + } + + len = *packet_len; + if (len <= 0) { + return -1; + } + + if (type == AWSS_CMP_PKT_TYPE_REQ) { + if (ver == NULL || method == NULL) { + return -1; + } + + len = HAL_Snprintf(packet, len - 1, AWSS_REQ_FMT, (char *)id, (char *)ver, (char *)method, (char *)data); + return 0; + } else if (type == AWSS_CMP_PKT_TYPE_RSP) { + len = HAL_Snprintf(packet, len - 1, AWSS_ACK_FMT, (char *)id, code, (char *)data); + return 0; + } + return -1; +} + +void produce_random(uint8_t *random, uint32_t len) +{ + int i = 0; + int time = HAL_UptimeMs(); + HAL_Srandom(time); + for (i = 0; i < len; i ++) { + random[i] = HAL_Random(0xFF); + } +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_packet.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_packet.h new file mode 100644 index 00000000..45595a91 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_packet.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_PACKET_H__ +#define __AWSS_PACKET_H__ +#include "infra_sha1.h" + +#define MSG_REQ_ID_LEN (16) +#define TOPIC_LEN_MAX (128) +#define DEV_INFO_LEN_MAX (512) +#define DEV_SIGN_SIZE (SHA1_DIGEST_SIZE) + +#define ILOP_VER "1.0" +#define AWSS_VER "{\"smartconfig\":\"2.0\",\"zconfig\":\"2.0\",\"router\":\"2.0\",\"ap\":\"2.0\",\"softap\":\"2.0\"}" + +#define TOPIC_AWSS_WIFILIST "/sys/%s/%s/awss/event/wifilist/get" +#define TOPIC_AWSS_SWITCHAP "/sys/%s/%s/awss/device/switchap" +#define TOPIC_AWSS_GETDEVICEINFO_MCAST "/sys/awss/device/info/get" +#define TOPIC_AWSS_GETDEVICEINFO_UCAST "/sys/%s/%s/awss/device/info/get" +#define TOPIC_AWSS_GET_CONNECTAP_INFO_MCAST "/sys/awss/device/connectap/info/get" +#define TOPIC_AWSS_GET_CONNECTAP_INFO_UCAST "/sys/%s/%s/awss/device/connectap/info/get" +#define TOPIC_GETDEVICEINFO_MCAST "/sys/device/info/get" +#define TOPIC_GETDEVICEINFO_UCAST "/sys/%s/%s/device/info/get" +#define TOPIC_POST_STATIS "/sys/%s/%s/thing/log/post" +#define TOPIC_AWSS_NOTIFY "/sys/awss/device/info/notify" +#define TOPIC_AWSS_CONNECTAP_NOTIFY "/sys/awss/event/connectap/notify" +#define TOPIC_NOTIFY "/sys/device/info/notify" +#define TOPIC_SWITCHAP "/sys/%s/%s/thing/awss/device/switchap" +#define TOPIC_SWITCHAP_REPLY "/sys/%s/%s/thing/awss/device/switchap_reply" +#define TOPIC_ZC_ENROLLEE "/sys/%s/%s/thing/awss/enrollee/found" +#define TOPIC_ZC_ENROLLEE_REPLY "/sys/%s/%s/thing/awss/enrollee/found_reply" +#define TOPIC_ZC_CHECKIN "/sys/%s/%s/thing/awss/enrollee/checkin" +#define TOPIC_ZC_CHECKIN_REPLY "/sys/%s/%s/thing/awss/enrollee/checkin_reply" +#define TOPIC_ZC_CIPHER "/sys/%s/%s/thing/cipher/get" +#define TOPIC_ZC_CIPHER_REPLY "/sys/%s/%s/thing/cipher/get_reply" +#define TOPIC_MATCH_REPORT "/sys/%s/%s/thing/awss/enrollee/match" +#define TOPIC_MATCH_REPORT_REPLY "/sys/%s/%s/thing/awss/enrollee/match_reply" +#define TOPIC_AWSS_DEV_AP_SWITCHAP "/sys/awss/device/softap/switchap" + +#define METHOD_DEV_INFO_NOTIFY "device.info.notify" +#define METHOD_AWSS_DEV_INFO_NOTIFY "awss.device.info.notify" +#define METHOD_AWSS_CONNECTAP_NOTIFY "awss.event.connectap.notify" +#define METHOD_AWSS_DEV_AP_SWITCHAP "awss.device.softap.switchap" +#define METHOD_EVENT_ZC_SWITCHAP "thing.awss.device.switchap" +#define METHOD_EVENT_ZC_ENROLLEE "thing.awss.enrollee.found" +#define METHOD_EVENT_ZC_CHECKIN "thing.awss.enrollee.checkin" +#define METHOD_EVENT_ZC_CIPHER "thing.cipher.get" +#define METHOD_MATCH_REPORT "thing.awss.enrollee.match" +#define METHOD_LOG_POST "things.log.post" + +#define AWSS_ACK_FMT "{\"id\":%s,\"code\":%d,\"data\":%s}" +#define AWSS_REQ_FMT "{\"id\":%s,\"version\":\"%s\",\"method\":\"%s\",\"params\":%s}" +#define AWSS_JSON_PARAM "params" +#define AWSS_JSON_CODE "code" +#define AWSS_JSON_ID "id" +#define AWSS_STATIS_FMT "{\"template\":\"timestamp logLevel module traceContext logContent\",\"contents\":[\"%u %s %s %u %s\"]}" + +enum { + AWSS_CMP_PKT_TYPE_REQ = 1, + AWSS_CMP_PKT_TYPE_RSP, +}; + +void produce_random(uint8_t *random, uint32_t len); +char *awss_build_sign_src(char *sign_src, int *sign_src_len); +void *awss_build_dev_info(int type, void *dev_info, int info_len); +const char *awss_build_topic(const char *topic_fmt, char *topic, uint32_t tlen); +int awss_build_packet(int type, void *id, void *ver, void *method, void *data, int code, void *pkt, int *pkt_len); + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_report.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_report.c new file mode 100644 index 00000000..0deed97c --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_report.c @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#define AWSS_REPORT_LEN_MAX (256) +#define AWSS_TOKEN_TIMEOUT_MS (45 * 1000) +#define MATCH_MONITOR_TIMEOUT_MS (10 * 1000) +#define MATCH_REPORT_CNT_MAX (2) + +volatile char awss_report_token_suc = 0; +volatile char awss_report_token_cnt = 0; +static char awss_report_id = 0; +#ifdef WIFI_PROVISION_ENABLED +static uint8_t switchap_bssid[ETH_ALEN] = {0}; +static char switchap_ssid[OS_MAX_SSID_LEN] = {0}; +static char switchap_passwd[OS_MAX_PASSWD_LEN] = {0}; +static void *switchap_timer = NULL; +#endif + +static uint32_t awss_report_token_time = 0; +static void *report_token_timer = NULL; + +static int awss_report_token_to_cloud(); +#ifdef WIFI_PROVISION_ENABLED +static int awss_switch_ap_online(); +static int awss_reboot_system(); +#endif + +int awss_token_remain_time() +{ + int remain = 0; + uint32_t cur = os_get_time_ms(); + uint32_t diff = (uint32_t)(cur - awss_report_token_time); + + if (awss_report_token_suc == 0) { + return remain; + } + + if (diff < AWSS_TOKEN_TIMEOUT_MS) { + remain = AWSS_TOKEN_TIMEOUT_MS - diff; + } + + return remain; +} + +int awss_update_token() +{ + awss_report_token_time = 0; + awss_report_token_cnt = 0; + awss_report_token_suc = 0; + + if (report_token_timer == NULL) { + report_token_timer = HAL_Timer_Create("rp_token", (void (*)(void *))awss_report_token_to_cloud, NULL); + } + HAL_Timer_Stop(report_token_timer); + HAL_Timer_Start(report_token_timer, 10); + awss_info("update token"); + + produce_random(aes_random, sizeof(aes_random)); + return 0; +} + +int awss_token_timeout() +{ + uint32_t cur; + if (awss_report_token_time == 0) { + return 1; + } + + cur = os_get_time_ms(); + if ((uint32_t)(cur - awss_report_token_time) > AWSS_TOKEN_TIMEOUT_MS) { + return 1; + } + return 0; +} + +void awss_report_token_reply(void *pcontext, void *pclient, void *msg) +{ + int ret, len; + char *payload; + char *id = NULL; + char reply_id = 0; + uint32_t payload_len; + + ret = awss_cmp_mqtt_get_payload(msg, &payload, &payload_len); + + if (ret != 0 || payload == NULL || payload_len == 0) { + return; + } + + id = json_get_value_by_name(payload, payload_len, AWSS_JSON_ID, &len, NULL); + if (id == NULL) { + return; + } + + reply_id = atoi(id); + if (reply_id + 1 < awss_report_id) { + return; + } + awss_info("%s\r\n", __func__); + awss_report_token_suc = 1; + awss_stop_timer(report_token_timer); + report_token_timer = NULL; + AWSS_DB_UPDATE_STATIS(AWSS_DB_STATIS_SUC); + AWSS_DB_DISP_STATIS(); + return; +} + +#ifdef WIFI_PROVISION_ENABLED +void awss_online_switchap(void *pcontext, void *pclient, void *msg) +{ +#define SWITCHAP_RSP_LEN (64) +#define AWSS_BSSID_STR_LEN (17) +#define AWSS_SSID "ssid" +#define AWSS_PASSWD "passwd" +#define AWSS_BSSID "bssid" +#define AWSS_SWITCH_MODE "switchMode" +#define AWSS_TIMEOUT "timeout" + + int len = 0, timeout = 0; + char *packet = NULL, *awss_info = NULL, *elem = NULL; + int packet_len = SWITCHAP_RSP_LEN, awss_info_len = 0; + + uint32_t payload_len; + char *payload; + int ret; + + ret = awss_cmp_mqtt_get_payload(msg, &payload, &payload_len); + + if (ret != 0) { + goto ONLINE_SWITCHAP_FAIL; + } + + if (payload == NULL || payload_len == 0) { + goto ONLINE_SWITCHAP_FAIL; + } + + awss_debug("online switchap len:%u, payload:%s\r\n", payload_len, payload); + packet = os_zalloc(packet_len + 1); + if (packet == NULL) { + goto ONLINE_SWITCHAP_FAIL; + } + + awss_info = json_get_value_by_name(payload, payload_len, AWSS_JSON_PARAM, &awss_info_len, NULL); + if (awss_info == NULL || awss_info_len == 0) { + goto ONLINE_SWITCHAP_FAIL; + } + + /* + * get SSID , PASSWD, BSSID of router + */ + elem = json_get_value_by_name(awss_info, awss_info_len, AWSS_SSID, &len, NULL); + if (elem == NULL || len <= 0 || len >= OS_MAX_SSID_LEN) { + goto ONLINE_SWITCHAP_FAIL; + } + + memset(switchap_ssid, 0, sizeof(switchap_ssid)); + memcpy(switchap_ssid, elem, len); + + len = 0; + elem = json_get_value_by_name(awss_info, awss_info_len, AWSS_PASSWD, &len, NULL); + if (elem == NULL || len <= 0 || len >= OS_MAX_PASSWD_LEN) { + goto ONLINE_SWITCHAP_FAIL; + } + + memset(switchap_passwd, 0, sizeof(switchap_passwd)); + memcpy(switchap_passwd, elem, len); + + len = 0; + memset(switchap_bssid, 0, sizeof(switchap_bssid)); + elem = json_get_value_by_name(awss_info, awss_info_len, AWSS_BSSID, &len, NULL); + + if (elem != NULL && len == AWSS_BSSID_STR_LEN) { + uint8_t i = 0; + char *bssid_str = elem; + /* convert bssid string to bssid value */ + while (i < OS_ETH_ALEN) { + switchap_bssid[i ++] = (uint8_t)strtol(bssid_str, &bssid_str, 16); + ++ bssid_str; + /* + * fix the format of bssid string is not legal. + */ + if ((uint32_t)((unsigned long)bssid_str - (unsigned long)elem) > AWSS_BSSID_STR_LEN) { + memset(switchap_bssid, 0, sizeof(switchap_bssid)); + break; + } + } + } + + len = 0; + elem = json_get_value_by_name(awss_info, awss_info_len, AWSS_SWITCH_MODE, &len, NULL); + if (elem != NULL && (elem[0] == '0' || elem[0] == 0)) { + elem = json_get_value_by_name(awss_info, awss_info_len, AWSS_TIMEOUT, &len, NULL); + if (elem) { + timeout = (int)strtol(elem, &elem, 16); + } + } + + do { + /* reduce stack used */ + char *id = NULL; + char id_str[MSG_REQ_ID_LEN] = {0}; + id = json_get_value_by_name(payload, payload_len, AWSS_JSON_ID, &len, NULL); + memcpy(id_str, id, len > MSG_REQ_ID_LEN - 1 ? MSG_REQ_ID_LEN - 1 : len); + awss_build_packet(AWSS_CMP_PKT_TYPE_RSP, id_str, ILOP_VER, METHOD_EVENT_ZC_SWITCHAP, "{}", 200, packet, &packet_len); + } while (0); + + do { + char reply[TOPIC_LEN_MAX] = {0}; + awss_build_topic(TOPIC_SWITCHAP_REPLY, reply, TOPIC_LEN_MAX); + awss_cmp_mqtt_send(reply, packet, packet_len, 1); + HAL_Free(packet); + } while (0); + + /* + * make sure the response would been received + */ + if (timeout < 1000) { + timeout = 1000; + } + + do { + uint8_t bssid[ETH_ALEN] = {0}; + char ssid[OS_MAX_SSID_LEN + 1] = {0}, passwd[OS_MAX_PASSWD_LEN + 1] = {0}; + HAL_Wifi_Get_Ap_Info(ssid, passwd, bssid); + /* + * switch ap when destination ap is differenct from current ap + */ + if (strncmp(ssid, switchap_ssid, sizeof(ssid)) || + memcmp(bssid, switchap_bssid, sizeof(bssid)) || + strncmp(passwd, switchap_passwd, sizeof(passwd))) { + if (switchap_timer == NULL) { + switchap_timer = HAL_Timer_Create("swichap_online", (void (*)(void *))awss_switch_ap_online, NULL); + } + + HAL_Timer_Stop(switchap_timer); + HAL_Timer_Start(switchap_timer, timeout); + } + } while (0); + + return; + +ONLINE_SWITCHAP_FAIL: + awss_warn("ilop online switchap failed"); + memset(switchap_ssid, 0, sizeof(switchap_ssid)); + memset(switchap_bssid, 0, sizeof(switchap_bssid)); + memset(switchap_passwd, 0, sizeof(switchap_passwd)); + if (packet) { + HAL_Free(packet); + } + return; +} + +static void *reboot_timer = NULL; +static int awss_switch_ap_online() +{ + HAL_Awss_Connect_Ap(WLAN_CONNECTION_TIMEOUT_MS, switchap_ssid, switchap_passwd, + AWSS_AUTH_TYPE_INVALID, AWSS_ENC_TYPE_INVALID, switchap_bssid, 0); + + awss_stop_timer(switchap_timer); + switchap_timer = NULL; + + memset(switchap_ssid, 0, sizeof(switchap_ssid)); + memset(switchap_bssid, 0, sizeof(switchap_bssid)); + memset(switchap_passwd, 0, sizeof(switchap_passwd)); + + reboot_timer = HAL_Timer_Create("rb_timer", (void (*)(void *))awss_reboot_system, NULL); + HAL_Timer_Start(reboot_timer, 1000);; + + return 0; +} + +static int awss_reboot_system() +{ + awss_stop_timer(reboot_timer); + reboot_timer = NULL; + HAL_Reboot(); + return 0; +} +#endif + +static int awss_report_token_to_cloud() +{ + int packet_len, ret; + char *packet; + char topic[TOPIC_LEN_MAX] = {0}; +#define REPORT_TOKEN_PARAM_LEN (64) + if (awss_report_token_suc) { /* success ,no need to report */ + return 0; + } + + AWSS_DB_UPDATE_STATIS(AWSS_DB_STATIS_START); + + /* + * it is still failed after try to report token MATCH_REPORT_CNT_MAX times + */ + if (awss_report_token_cnt ++ > MATCH_REPORT_CNT_MAX) { + awss_stop_timer(report_token_timer); + report_token_timer = NULL; + awss_info("try %d times fail", awss_report_token_cnt); + return -2; + } + + if (report_token_timer == NULL) { + report_token_timer = HAL_Timer_Create("rp_token", (void (*)(void *))awss_report_token_to_cloud, NULL); + } + HAL_Timer_Stop(report_token_timer); + HAL_Timer_Start(report_token_timer, 3 * 1000); + + packet_len = AWSS_REPORT_LEN_MAX; + + packet = os_zalloc(packet_len + 1); + if (packet == NULL) { + awss_err("alloc mem(%d) failed", packet_len); + return -1; + } + + do { + /* reduce stack used */ + uint8_t i; + char id_str[MSG_REQ_ID_LEN] = {0}; + char param[REPORT_TOKEN_PARAM_LEN] = {0}; + char token_str[(RANDOM_MAX_LEN << 1) + 1] = {0}; + + for (i = 0; i < sizeof(aes_random); i ++) /* check aes_random is initialed or not */ + if (aes_random[i] != 0x00) { + break; + } + + if (i >= sizeof(aes_random)) { /* aes_random needs to be initialed */ + produce_random(aes_random, sizeof(aes_random)); + } + + awss_report_token_time = os_get_time_ms(); + + HAL_Snprintf(id_str, MSG_REQ_ID_LEN - 1, "\"%u\"", awss_report_id ++); + utils_hex_to_str(aes_random, RANDOM_MAX_LEN, token_str, sizeof(token_str) - 1); + HAL_Snprintf(param, REPORT_TOKEN_PARAM_LEN - 1, "{\"token\":\"%s\"}", token_str); + awss_build_packet(AWSS_CMP_PKT_TYPE_REQ, id_str, ILOP_VER, METHOD_MATCH_REPORT, param, 0, packet, &packet_len); + } while (0); + + awss_debug("report token:%s\r\n", packet); + awss_build_topic(TOPIC_MATCH_REPORT, topic, TOPIC_LEN_MAX); + + ret = awss_cmp_mqtt_send(topic, packet, packet_len, 1); + awss_info("report token res:%d\r\n", ret); + HAL_Free(packet); + + return ret; +} + +int awss_report_token() +{ + awss_report_token_cnt = 0; + awss_report_token_suc = 0; + + return awss_report_token_to_cloud(); +} + +int awss_stop_report_token() +{ + if (report_token_timer) { + awss_stop_timer(report_token_timer); + report_token_timer = NULL; + } + + memset(aes_random, 0x00, sizeof(aes_random)); + + return 0; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_reset.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_reset.h new file mode 100644 index 00000000..c05bbbb5 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_reset.h @@ -0,0 +1,39 @@ +#ifndef __AWSS_RESET__ +#define __AWSS_RESET__ + +#define AWSS_RESET_PKT_LEN (256) +#define AWSS_RESET_TOPIC_LEN (128) +#define AWSS_RESET_MSG_ID_LEN (16) + +#define TOPIC_RESET_REPORT "/sys/%s/%s/thing/reset" +#define TOPIC_RESET_REPORT_REPLY "/sys/%s/%s/thing/reset_reply" +#define METHOD_RESET_REPORT "thing.reset" + +#define AWSS_RESET_REQ_FMT "{\"id\":%s, \"version\":\"1.0\", \"method\":\"%s\", \"params\":%s}" + +#define AWSS_KV_RST "awss.rst" + +int awss_check_reset(); + +/** + * @brief report reset to cloud. + * + * @retval -1 : failure + * @retval 0 : sucess + * @note + * device will save reset flag if device dosen't connect cloud, device will fails to send reset to cloud. + * when connection between device and cloud is ready, device will retry to report reset to cloud. + */ +int awss_report_reset(); + +/** + * @brief stop to report reset to cloud. + * + * @retval -1 : failure + * @retval 0 : sucess + * @note + * just stop report reset to cloud without any touch reset flag in flash. + */ +int awss_stop_report_reset(); + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_reset/awss_dev_reset.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_reset/awss_dev_reset.c new file mode 100644 index 00000000..3a40c8f3 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_reset/awss_dev_reset.c @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#define AWSS_RESET_PKT_LEN (256) +#define AWSS_RESET_TOPIC_LEN (128) +#define AWSS_RESET_MSG_ID_LEN (16) + +#define TOPIC_RESET_REPORT "/sys/%s/%s/thing/reset" +#define TOPIC_RESET_REPORT_REPLY "/sys/%s/%s/thing/reset_reply" +#define METHOD_RESET_REPORT "thing.reset" + +#define AWSS_RESET_REQ_FMT "{\"id\":%s, \"version\":\"1.0\", \"method\":\"%s\", \"params\":%s}" + +#define AWSS_KV_RST "awss.rst" +#define AWSS_KV_RST_FLAG "awss.rst.flag" + +static uint8_t awss_report_reset_suc = 0; +static uint16_t awss_report_reset_id = 0; +static void *report_reset_timer = NULL; + +static int awss_report_reset_to_cloud(); + +void awss_report_reset_reply(void *pcontext, void *pclient, void *mesg) +{ + char rst = 0; + + iotx_mqtt_event_msg_pt msg = (iotx_mqtt_event_msg_pt)mesg; + + switch (msg->event_type) { + case IOTX_MQTT_EVENT_PUBLISH_RECEIVED: + break; + default: + return; + } + + devrst_debug("[RST]", "%s\r\n", __func__); + + awss_report_reset_suc = 1; + HAL_Kv_Set(AWSS_KV_RST, &rst, sizeof(rst), 0); + + HAL_Timer_Stop(report_reset_timer); + HAL_Timer_Delete(report_reset_timer); + report_reset_timer = NULL; + +#ifdef INFRA_EVENT + iotx_event_post(IOTX_RESET); /* for old version of event */ + do { /* for new version of event */ + void *cb = NULL; + cb = (void *)iotx_event_callback(ITE_AWSS_STATUS); + if (cb == NULL) { + break; + } + ((int (*)(int))cb)(IOTX_RESET); + } while (0); +#endif +} + +static int awss_report_reset_to_cloud() +{ + int ret = -1; + int final_len = 0; + char *topic = NULL; + char *packet = NULL; + int packet_len = AWSS_RESET_PKT_LEN; + int topic_len = AWSS_RESET_TOPIC_LEN; + + if (awss_report_reset_suc) { + return 0; + } + + if (report_reset_timer == NULL) { + report_reset_timer = HAL_Timer_Create("report_rst", (void (*)(void *))awss_report_reset_to_cloud, NULL); + } + HAL_Timer_Stop(report_reset_timer); + HAL_Timer_Start(report_reset_timer, 3000); + do { + char pk[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char dn[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + HAL_GetProductKey(pk); + HAL_GetDeviceName(dn); + + topic = (char *)devrst_malloc(topic_len + 1); + if (topic == NULL) { + goto REPORT_RST_ERR; + } + memset(topic, 0, topic_len + 1); + + HAL_Snprintf(topic, topic_len, TOPIC_RESET_REPORT_REPLY, pk, dn); + + ret = IOT_MQTT_Subscribe_Sync(NULL, topic, IOTX_MQTT_QOS0, + (iotx_mqtt_event_handle_func_fpt)awss_report_reset_reply, NULL, 1000); + if (ret < 0) { + goto REPORT_RST_ERR; + } + + memset(topic, 0, topic_len + 1); + HAL_Snprintf(topic, topic_len, TOPIC_RESET_REPORT, pk, dn); + } while (0); + + packet = devrst_malloc(packet_len + 1); + if (packet == NULL) { + ret = -1; + goto REPORT_RST_ERR; + } + memset(packet, 0, packet_len + 1); + + do { + char id_str[AWSS_RESET_MSG_ID_LEN + 1] = {0}; + HAL_Snprintf(id_str, AWSS_RESET_MSG_ID_LEN, "\"%u\"", awss_report_reset_id ++); + final_len = HAL_Snprintf(packet, packet_len, AWSS_RESET_REQ_FMT, id_str, METHOD_RESET_REPORT, "{}"); + } while (0); + + devrst_debug("[RST]", "report reset:%s\r\n", packet); + + ret = IOT_MQTT_Publish_Simple(NULL, topic, IOTX_MQTT_QOS0, packet, final_len); + devrst_debug("[RST]", "report reset result:%d\r\n", ret); + +REPORT_RST_ERR: + if (packet) { + devrst_free(packet); + } + if (topic) { + devrst_free(topic); + } + return ret; +} + +int awss_report_reset() +{ + char rst = 0; + int ret = 0, len = 1; + awss_report_reset_suc = 0; + + HAL_Kv_Get(AWSS_KV_RST_FLAG, &rst, &len); + + if (!rst) { + ret = 1; + /* guocheng.kgc add for filter unbind msg when device reset */ + HAL_Kv_Set(AWSS_KV_RST_FLAG, &rst, sizeof(rst), 0); + ret = HAL_Kv_Set(AWSS_KV_RST, &rst, sizeof(rst), 0); + if (ret < 0) { + devrst_err("[RST]", "set %s result is %d\r\n", AWSS_KV_RST, ret); + } + return awss_report_reset_to_cloud(); + } + return 0; +} + +int awss_check_reset() +{ + int len = 1; + char rst = 0; + + HAL_Kv_Get(AWSS_KV_RST, &rst, &len); + + if (rst != 0x01) { /* reset flag is not set */ + devrst_debug("[RST]", "no rst\r\n"); + return 0; + } + + awss_report_reset_suc = 0; + + return awss_report_reset_to_cloud(); +} + +int awss_stop_report_reset() +{ + if (report_reset_timer == NULL) { + return 0; + } + + HAL_Timer_Stop(report_reset_timer); + HAL_Timer_Delete(report_reset_timer); + report_reset_timer = NULL; + + return 0; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_reset/awss_dev_reset_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_reset/awss_dev_reset_internal.h new file mode 100644 index 00000000..5489edf7 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_reset/awss_dev_reset_internal.h @@ -0,0 +1,27 @@ +#ifndef _AWSS_DEV_RESET_INTERNAL_H_ +#define _AWSS_DEV_RESET_INTERNAL_H_ + +#include "os.h" + +#ifdef INFRA_LOG +#include "infra_log.h" +#define devrst_err(...) log_err("devrst", __VA_ARGS__) +#define devrst_info(...) log_info("devrst", __VA_ARGS__) +#define devrst_debug(...) log_debug("devrst", __VA_ARGS__) +#else +#define devrst_info(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define devrst_err(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define devrst_debug(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#endif + +#ifdef INFRA_MEM_STATS +#include "infra_mem_stats.h" +#define devrst_malloc(size) LITE_malloc(size, MEM_MAGIC, "devrst") +#define devrst_free(ptr) LITE_free(ptr) +#else +#define devrst_malloc(size) HAL_Malloc(size) +#define devrst_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_timer.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_timer.c new file mode 100644 index 00000000..86cb4a2a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_timer.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +int awss_stop_timer(void *timer) +{ + if (timer == NULL) + return 0; + HAL_Timer_Stop(timer); + HAL_Timer_Delete(timer); + return 0; +} +#if 0 +int awss_start_timer(void **timer, const char *name, void *func, void *user_data, int ms) +{ + if (timer == NULL) + return -1; + *timer = HAL_Timer_Create(name, (void (*)(void *))func, user_data); + if (*timer == NULL) + return -1; + HAL_Timer_Stop(*timer); + HAL_Timer_Start(*timer, ms); + return 0; +} +#endif +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_timer.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_timer.h new file mode 100644 index 00000000..f00dc82e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_timer.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_TIMER_H__ +#define __AWSS_TIMER_H__ + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +int awss_stop_timer(void *timer); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_utils.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_utils.h new file mode 100644 index 00000000..b41303df --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/awss_utils.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_UTILS_H__ +#define __AWSS_UTILS_H__ + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include "os.h" +#if 0 +#include "iotx_utils.h" +#endif +#include "infra_string.h" + +/** + * @brief string to hex + * + * @param[in] str: input hex string + * @param[in] str_len: length of input hex string + * @param[out] out: output hex byte stream + * @param[in/out] output_len: [in] for output buffer size, [out] for + * output hex byte len + * @Note None. + * + * @retval return num of hex bytes converted, 0 means error. + */ +#define utils_str_to_hex LITE_hexstr_convert + + +/** + * @brief hex to string + * + * @param[in] buf: input hex byte stream + * @param[in] buf_len: input stream length in byte + * @param[out] str: encoded hex string + * @param[in/out] str_len: [in] for str buffer size, [out] for + * encoded string length + * @Note output str buffer is NULL-terminated(if str_buf_len is longer enough) + * + * @retval return length of str converted, 0 means error. + */ +#define utils_hex_to_str(buf, buf_len, str, str_buf_len) LITE_hexbuf_convert(buf, str, buf_len, 1) + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/dev_bind_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/dev_bind_internal.h new file mode 100644 index 00000000..4bbdfd5a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/dev_bind_internal.h @@ -0,0 +1,27 @@ +#include "infra_config.h" +#include +#include +#include +#include "awss_event.h" +#include "awss_timer.h" +#include "awss_log.h" +#include "passwd.h" +#include "awss_utils.h" +#include "awss_reset.h" +#include "infra_compat.h" +#include "awss_packet.h" +#include "awss_notify.h" +#include "awss_cmp.h" +#include "awss_cmp.h" +#include "sha256.h" +#include "infra_json_parser.h" +#include "mqtt_api.h" +#include "awss_dev_reset_internal.h" +#include "awss_info.h" +#include "awss_bind_statis.h" +#include "dev_bind_wrapper.h" +#include "coap_api.h" +#include "iotx_coap.h" +#ifdef WIFI_PROVISION_ENABLED +#include "awss_statis.h" +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/iot_import_awss.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/iot_import_awss.h new file mode 100644 index 00000000..8faf4020 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/iot_import_awss.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __IOT_IMPORT_AWSS_H__ +#define __IOT_IMPORT_AWSS_H__ + +#include "infra_types.h" +#include "infra_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DLL_HAL_API + #define DLL_HAL_API +#endif +#ifndef _IN_ + #define _IN_ +#endif +#ifndef _OU_ + #define _OU_ +#endif +#ifndef _IN_OPT_ +#define _IN_OPT_ +#endif + +/* link type */ +enum AWSS_LINK_TYPE { + /* rtos HAL choose this type */ + AWSS_LINK_TYPE_NONE, + + /* linux HAL may choose the following type */ + AWSS_LINK_TYPE_PRISM, + AWSS_LINK_TYPE_80211_RADIO, + AWSS_LINK_TYPE_80211_RADIO_AVS, + AWSS_LINK_TYPE_HT40_CTRL /* for espressif HAL, see struct ht40_ctrl */ +}; + +struct HAL_Ht40_Ctrl { + uint16_t length; + uint8_t filter; + signed char rssi; +}; + +typedef int (*awss_recv_80211_frame_cb_t)(char *buf, int length, + enum AWSS_LINK_TYPE link_type, int with_fcs, signed char rssi); + +/* auth type */ +enum AWSS_AUTH_TYPE { + AWSS_AUTH_TYPE_OPEN, + AWSS_AUTH_TYPE_SHARED, + AWSS_AUTH_TYPE_WPAPSK, + AWSS_AUTH_TYPE_WPA8021X, + AWSS_AUTH_TYPE_WPA2PSK, + AWSS_AUTH_TYPE_WPA28021X, + AWSS_AUTH_TYPE_WPAPSKWPA2PSK, + AWSS_AUTH_TYPE_MAX = AWSS_AUTH_TYPE_WPAPSKWPA2PSK, + AWSS_AUTH_TYPE_INVALID = 0xff, +}; + +/* encryt type */ +enum AWSS_ENC_TYPE { + AWSS_ENC_TYPE_NONE, + AWSS_ENC_TYPE_WEP, + AWSS_ENC_TYPE_TKIP, + AWSS_ENC_TYPE_AES, + AWSS_ENC_TYPE_TKIPAES, + AWSS_ENC_TYPE_MAX = AWSS_ENC_TYPE_TKIPAES, + AWSS_ENC_TYPE_INVALID = 0xff, +}; + +typedef int (*awss_wifi_scan_result_cb_t)( + const char ssid[HAL_MAX_SSID_LEN], + const uint8_t bssid[ETH_ALEN], + enum AWSS_AUTH_TYPE auth, + enum AWSS_ENC_TYPE encry, + uint8_t channel, signed char rssi, + int is_last_ap); + +/* 80211 frame type */ +typedef enum HAL_Awss_Frame_Type { + FRAME_ACTION, + FRAME_BEACON, + FRAME_PROBE_REQ, + FRAME_PROBE_RESPONSE, + FRAME_DATA +} HAL_Awss_Frame_Type_t; + +#define FRAME_ACTION_MASK (1 << FRAME_ACTION) +#define FRAME_BEACON_MASK (1 << FRAME_BEACON) +#define FRAME_PROBE_REQ_MASK (1 << FRAME_PROBE_REQ) +#define FRAME_PROBE_RESP_MASK (1 << FRAME_PROBE_RESPONSE) +#define FRAME_DATA_MASK (1 << FRAME_DATA) + +typedef void (*awss_wifi_mgmt_frame_cb_t)(_IN_ uint8_t *buffer, _IN_ int len, + _IN_ signed char rssi_dbm, _IN_ int buffer_type); + +typedef struct { + enum AWSS_AUTH_TYPE auth; + enum AWSS_ENC_TYPE encry; + uint8_t channel; + signed char rssi_dbm; + char ssid[HAL_MAX_SSID_LEN]; + uint8_t mac[ETH_ALEN]; +} awss_ap_info_t; + +#ifdef __cplusplus +} +#endif + +#endif /* __IOT_IMPORT_AWSS_H__ */ + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/os/os.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/os/os.h new file mode 100644 index 00000000..5fe9a495 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/os/os.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_OS_H__ +#define __AWSS_OS_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include "infra_defs.h" +#include +#include +#include "infra_compat.h" + +#ifndef _IN_OPT_ +#define _IN_OPT_ +#endif +#ifndef _OUT_ +#define _OUT_ +#endif +#ifndef _OUT_OPT_ +#define _OUT_OPT_ +#endif +#ifndef _INOUT_ +#define _INOUT_ +#endif +#ifndef _INOUT_OPT_ +#define _INOUT_OPT_ +#endif + +/** @defgroup group_os os + * @{ + */ +#define OS_MAC_LEN HAL_MAC_LEN +#define OS_ETH_ALEN ETH_ALEN +#define OS_IP_LEN (NETWORK_ADDR_LEN) +#define OS_MAX_PASSWD_LEN HAL_MAX_PASSWD_LEN +#define OS_MAX_SSID_LEN HAL_MAX_SSID_LEN +#define OS_PRODUCT_KEY_LEN IOTX_PRODUCT_KEY_LEN +#define OS_PRODUCT_SECRET_LEN IOTX_PRODUCT_SECRET_LEN +#define OS_DEVICE_NAME_LEN IOTX_DEVICE_NAME_LEN +#define OS_DEVICE_SECRET_LEN IOTX_DEVICE_SECRET_LEN +#define PLATFORM_AES_DECRYPTION HAL_AES_DECRYPTION +#define PLATFORM_AES_ENCRYPTION HAL_AES_ENCRYPTION +#define PLATFORM_MAX_SSID_LEN HAL_MAX_SSID_LEN +#define PLATFORM_MAX_PASSWD_LEN HAL_MAX_PASSWD_LEN +typedef void *p_HAL_Aes128_t; +#define p_aes128_t p_HAL_Aes128_t + +char *os_wifi_get_mac_str(char mac_str[HAL_MAC_LEN]); +char *os_wifi_str2mac(char mac_str[HAL_MAC_LEN], char mac[ETH_ALEN]); +uint8_t *os_wifi_get_mac(uint8_t mac[ETH_ALEN]); +uint32_t os_get_time_ms(void); + +int os_is_big_endian(void); +uint16_t os_htobe16(uint16_t data); +uint16_t os_htole16(uint16_t data); +uint16_t os_be16toh(uint16_t data); +uint16_t os_le16toh(uint16_t data); +uint32_t os_le32toh(uint32_t data); +uint16_t os_get_unaligned_be16(uint8_t *ptr); +uint16_t os_get_unaligned_le16(uint8_t *ptr); +uint32_t os_get_unaligned_be32(uint8_t *ptr); +uint32_t os_get_unaligned_le32(uint8_t *ptr); +void *os_zalloc(uint32_t size); +uint32_t time_elapsed_ms_since(uint32_t start_timestamp); +#ifdef __cplusplus +} +#endif + +#endif /* SRC_OSA_ABSTRAC_H_ */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/os/os_misc.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/os/os_misc.c new file mode 100644 index 00000000..d06b4897 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/os/os_misc.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" + +/****** Convert values between host and big-/little-endian byte order ******/ + +/* reverse byte order */ +static uint16_t reverse_16bit(uint16_t data) +{ + return (data >> 8) | (data << 8); +} + +/* host byte order to big endian */ +uint16_t os_htobe16(uint16_t data) +{ + if (os_is_big_endian()) { + return data; + } + + return reverse_16bit(data); +} + +/* host byte order to little endian */ +uint16_t os_htole16(uint16_t data) +{ + if (os_is_big_endian()) { + return reverse_16bit(data); + } + + return data; +} + +/* big endian to host byte order */ +uint16_t os_be16toh(uint16_t data) +{ + return os_htobe16(data); +} + +/* little endian to host byte order */ +uint16_t os_le16toh(uint16_t data) +{ + return os_htole16(data); +} + +/* get unaligned data in big endian. */ +uint16_t os_get_unaligned_be16(uint8_t * ptr) +{ + uint16_t res; + + memcpy(&res, ptr, sizeof(uint16_t)); + + return os_be16toh(res); +} + +/* get unaligned data in little endian. */ +uint16_t os_get_unaligned_le16(uint8_t * ptr) +{ + uint16_t res; + + memcpy(&res, ptr, sizeof(uint16_t)); + + return os_le16toh(res); + +} + +/* format mac string uppercase */ +char *os_wifi_get_mac_str(char mac_str[OS_MAC_LEN]) +{ + char *str; + int colon_num = 0, i; + + str = HAL_Wifi_Get_Mac(mac_str); + + /* sanity check */ + while (str) { + str = strchr(str, ':'); + if (str) { + colon_num ++; + str ++; /* eating char ':' */ + } + } + + /* convert to capital letter */ + for (i = 0; i < OS_MAC_LEN && mac_str[i]; i ++) { + if ('a' <= mac_str[i] && mac_str[i] <= 'z') { + mac_str[i] -= 'a' - 'A'; + } + } + + return mac_str; +} +char *os_wifi_str2mac(char mac_str[OS_MAC_LEN], char mac[OS_ETH_ALEN]) +{ + int i = 0; + char *ptr = mac_str; + char mac_addr[OS_ETH_ALEN] = {0}; + + if (ptr == NULL) + return NULL; + + while (isxdigit((int)*ptr) && i < OS_ETH_ALEN) { + mac_addr[i ++] = (uint8_t)strtol(ptr, &ptr, 16); + ++ ptr; + } + + if (i < OS_ETH_ALEN) /* don't touch mac when fail */ + return NULL; + + if (mac) memcpy(mac, mac_addr, OS_ETH_ALEN); + + return mac; +} + +uint8_t *os_wifi_get_mac(uint8_t mac[OS_ETH_ALEN]) +{ + char mac_str[OS_MAC_LEN] = {0}; + + os_wifi_get_mac_str(mac_str); + + return (uint8_t *)os_wifi_str2mac(mac_str, (char *)mac); +} + +void *os_zalloc(uint32_t size) +{ + void *ptr = HAL_Malloc(size); + if (ptr != NULL) { + memset(ptr, 0, size); + } + return ptr; +} + +uint32_t os_get_time_ms(void) +{ + static uint32_t fixed_delta; + + if (!fixed_delta) { + fixed_delta = (uint32_t)HAL_UptimeMs() - 0xFFFF0000; + } + + /* add a big offset, for easier caught time overflow bug */ + return (uint32_t)HAL_UptimeMs() - fixed_delta; +} + +uint32_t time_elapsed_ms_since(uint32_t start_timestamp) +{ + uint32_t now = os_get_time_ms(); + return now - start_timestamp; +} + +int os_is_big_endian(void) +{ + uint32_t data = 0xFF000000; + + if (0xFF == *(uint8_t *) & data) { + return 1; /* big endian */ + } + + return 0; /* little endian */ +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/passwd.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/passwd.c new file mode 100644 index 00000000..67cf2208 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/passwd.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "dev_bind_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +uint8_t aes_random[RANDOM_MAX_LEN] = {0}; + +int awss_set_token(uint8_t token[RANDOM_MAX_LEN]) +{ + char rand_str[(RANDOM_MAX_LEN << 1) + 1] = {0}; + if (token == NULL) { + return -1; + } + + memcpy(aes_random, token, RANDOM_MAX_LEN); + utils_hex_to_str(aes_random, RANDOM_MAX_LEN, rand_str, sizeof(rand_str)); + awss_trace("bind: app token set %s", rand_str); + return 0; +} +#ifdef WIFI_PROVISION_ENABLED +/* + * 1. place 0 @ 0, because of java modified-UTF8 + * 2. translation follow utf8 stardard + */ +static const uint8_t ssid_dict_decode_table[] = { + 0x00, 0x0e, 0x6c, 0x3a, 0x6d, 0x44, 0x2a, 0x6f, + 0x4d, 0x05, 0x6b, 0x28, 0x08, 0x25, 0x5f, 0x2d, + 0x64, 0x76, 0x78, 0x37, 0x58, 0x60, 0x53, 0x31, + 0x36, 0x79, 0x43, 0x1a, 0x11, 0x72, 0x03, 0x59, + 0x50, 0x02, 0x71, 0x7c, 0x34, 0x3e, 0x23, 0x24, + 0x26, 0x5b, 0x73, 0x0f, 0x5e, 0x12, 0x54, 0x0b, + 0x61, 0x35, 0x3c, 0x57, 0x48, 0x55, 0x63, 0x4a, + 0x13, 0x75, 0x45, 0x70, 0x47, 0x0c, 0x2f, 0x21, + 0x17, 0x2e, 0x62, 0x49, 0x4b, 0x5c, 0x19, 0x51, + 0x69, 0x3b, 0x7e, 0x0d, 0x3d, 0x67, 0x2c, 0x22, + 0x14, 0x42, 0x5a, 0x7f, 0x32, 0x01, 0x07, 0x7b, + 0x15, 0x4f, 0x16, 0x29, 0x30, 0x27, 0x20, 0x18, + 0x65, 0x06, 0x1c, 0x3f, 0x68, 0x2b, 0x4c, 0x0a, + 0x1e, 0x46, 0x5d, 0x1f, 0x10, 0x6e, 0x56, 0x7a, + 0x1b, 0x09, 0x52, 0x38, 0x66, 0x7d, 0x41, 0x40, + 0x04, 0x6a, 0x39, 0x77, 0x33, 0x1d, 0x74, 0x4e, + 0xaf, 0xa6, 0x8c, 0xbd, 0x89, 0xa2, 0xa9, 0x9e, + 0xa1, 0x91, 0xb9, 0xad, 0xbf, 0xb7, 0x95, 0xa8, + 0xa5, 0x82, 0xaa, 0xa3, 0x94, 0x92, 0xb8, 0x87, + 0x88, 0xb1, 0x93, 0xbc, 0x80, 0xb5, 0xba, 0x99, + 0xab, 0xbe, 0x90, 0x8e, 0x83, 0x9f, 0x9a, 0x86, + 0x85, 0x98, 0xa4, 0xa0, 0xac, 0x9c, 0x96, 0x81, + 0xb0, 0x8d, 0xbb, 0xb2, 0x9d, 0xae, 0x84, 0x9b, + 0xb4, 0x8b, 0x97, 0xa7, 0xb3, 0x8a, 0x8f, 0xb6, + 0xc5, 0xc0, 0xc8, 0xd7, 0xde, 0xc4, 0xd1, 0xd2, + 0xd9, 0xcb, 0xcd, 0xd5, 0xcc, 0xc7, 0xdb, 0xdf, + 0xdc, 0xdd, 0xcf, 0xc6, 0xda, 0xc2, 0xc3, 0xc9, + 0xc1, 0xca, 0xd6, 0xd8, 0xce, 0xd3, 0xd0, 0xd4, + 0xe9, 0xe5, 0xe8, 0xe2, 0xe6, 0xeb, 0xe3, 0xec, + 0xed, 0xe7, 0xe1, 0xe4, 0xea, 0xef, 0xee, 0xe0, + 0xf6, 0xf0, 0xf4, 0xf5, 0xf2, 0xf3, 0xf7, 0xf1, + 0xfb, 0xf9, 0xfa, 0xf8, 0xfc, 0xfd, 0xfe, 0xff +}; + +static const uint8_t notify_encode_table[] = { + 0x00, 0x71, 0x21, 0x1e, 0x78, 0x09, 0x61, 0x56, + 0x0c, 0x55, 0x67, 0x2f, 0x3d, 0x4b, 0x01, 0x2b, + 0x6c, 0x1c, 0x1b, 0x38, 0x50, 0x58, 0x5a, 0x40, + 0x5f, 0x46, 0x2d, 0x70, 0x62, 0x7d, 0x68, 0x6b, + 0x5e, 0x3f, 0x4f, 0x65, 0x27, 0x0d, 0x28, 0x5d, + 0x0b, 0x5b, 0x06, 0x26, 0x4e, 0x0f, 0x41, 0x3e, + 0x5c, 0x17, 0x54, 0x7c, 0x32, 0x31, 0x18, 0x13, + 0x73, 0x7a, 0x03, 0x49, 0x24, 0x4c, 0x25, 0x63, + 0x77, 0x76, 0x51, 0x1a, 0x05, 0x08, 0x69, 0x3c, + 0x34, 0x43, 0x37, 0x44, 0x66, 0x3a, 0x7f, 0x59, + 0x20, 0x47, 0x72, 0x16, 0x2e, 0x35, 0x2c, 0x33, + 0x14, 0x1f, 0x52, 0x29, 0x45, 0x6a, 0x6e, 0x0e, + 0x15, 0x30, 0x42, 0x36, 0x10, 0x60, 0x74, 0x07, + 0x64, 0x48, 0x79, 0x0a, 0x02, 0x04, 0x6d, 0x4d, + 0x3b, 0x22, 0x1d, 0x2a, 0x7e, 0x39, 0x1a, 0x7b, + 0x12, 0x19, 0x6f, 0x57, 0x23, 0x75, 0x41, 0x53, + 0x9c, 0xaf, 0x91, 0xa4, 0xb6, 0xb1, 0xa7, 0x97, + 0x98, 0x84, 0xbd, 0xb9, 0x82, 0xa8, 0xa3, 0xbe, + 0xa2, 0x89, 0x95, 0x9a, 0x94, 0x8e, 0xae, 0xba, + 0xa9, 0x9f, 0xa6, 0xb7, 0xad, 0xb4, 0x87, 0xa5, + 0xab, 0x88, 0x85, 0x93, 0xaa, 0x90, 0x81, 0xbb, + 0x8f, 0x86, 0x92, 0xa0, 0xac, 0x8b, 0xb5, 0x80, + 0xb0, 0x99, 0xb3, 0xbc, 0xb8, 0x9d, 0xbf, 0x8d, + 0x96, 0x8a, 0x9e, 0xb2, 0x9b, 0x83, 0xa1, 0x8c, + 0xc1, 0xd8, 0xd5, 0xd6, 0xc5, 0xc0, 0xd3, 0xcd, + 0xc2, 0xd7, 0xd9, 0xc9, 0xcc, 0xca, 0xdc, 0xd2, + 0xde, 0xc6, 0xc7, 0xdd, 0xdf, 0xcb, 0xda, 0xc3, + 0xdb, 0xc8, 0xd4, 0xce, 0xd0, 0xd1, 0xc4, 0xcf, + 0xef, 0xea, 0xe3, 0xe6, 0xeb, 0xe1, 0xe4, 0xe9, + 0xe2, 0xe0, 0xec, 0xe5, 0xe7, 0xe8, 0xee, 0xed, + 0xf1, 0xf7, 0xf4, 0xf5, 0xf2, 0xf3, 0xf0, 0xf6, + 0xfb, 0xf9, 0xfa, 0xf8, 0xfc, 0xfd, 0xfe, 0xff +}; + +int awss_dict_crypt(char tab_idx, uint8_t *data, uint8_t len) +{ + uint8_t i = 0; + uint8_t *table = NULL; + + switch (tab_idx) { + case SSID_DECODE_TABLE: + table = (uint8_t *)ssid_dict_decode_table; + break; + case NOTIFY_ENCODE_TABLE: + table = (uint8_t *)notify_encode_table; + break; + default: + table = NULL; + break; + } + + if (table == NULL || data == NULL) + return -1; + + for (i = 0; i < len; i ++) + data[i] = table[data[i]]; + + return 0; +} + +int produce_signature(uint8_t *sign, uint8_t *txt, + uint32_t txt_len, const char *key) +{ + if (sign == NULL || txt == NULL || txt_len == 0 || key == NULL) + return -1; +/* TODO */ + utils_hmac_sha1_hex((const char *)txt, (int)txt_len, + (char *)sign, key, strlen(key)); + return 0; +} +#endif +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/passwd.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/passwd.h new file mode 100644 index 00000000..51c61531 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/passwd.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_PASSWD_H__ +#define __AWSS_PASSWD_H__ + +#define KEY_MAX_LEN (40) +#define AES128_KEY_LEN (16) +#define RANDOM_MAX_LEN (16) + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +enum { + SSID_DECODE_TABLE = 0x0, + NOTIFY_ENCODE_TABLE, + DICT_CRYPT_TABLE_IDX_MAX, +}; + +int awss_dict_crypt(char tab_idx, uint8_t *data, uint8_t len); +#ifdef WIFI_PROVISION_ENABLED +int produce_signature(uint8_t *sign, uint8_t *txt, uint32_t txt_len, const char *key); +#endif + +extern uint8_t aes_random[RANDOM_MAX_LEN]; + +int awss_set_token(uint8_t token[RANDOM_MAX_LEN]); +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/sha256.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/sha256.c new file mode 100644 index 00000000..2250d74a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/sha256.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +/* Optimized for minimal code size. */ +#include "dev_bind_internal.h" + +#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits)))) +#define shr(value, bits) ((value) >> (bits)) + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; + +static void SHA256_Transform(SHA256_CTX* ctx) +{ + uint32_t W[64]; + uint32_t A, B, C, D, E, F, G, H; + uint8_t* p = ctx->buf; + int t; + + for(t = 0; t < 16; ++t) { + uint32_t tmp = *p++ << 24; + tmp |= *p++ << 16; + tmp |= *p++ << 8; + tmp |= *p++; + W[t] = tmp; + } + + for(; t < 64; t++) { + uint32_t s0 = ror(W[t-15], 7) ^ ror(W[t-15], 18) ^ shr(W[t-15], 3); + uint32_t s1 = ror(W[t-2], 17) ^ ror(W[t-2], 19) ^ shr(W[t-2], 10); + W[t] = W[t-16] + s0 + W[t-7] + s1; + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + + for(t = 0; t < 64; t++) { + uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22); + uint32_t maj = (A & B) ^ (A & C) ^ (B & C); + uint32_t t2 = s0 + maj; + uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25); + uint32_t ch = (E & F) ^ ((~E) & G); + uint32_t t1 = H + s1 + ch + K[t] + W[t]; + H = G; + G = F; + F = E; + E = D + t1; + D = C; + C = B; + B = A; + A = t1 + t2; + } + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} + +#if 0 +static const HASH_VTAB SHA256_VTAB = { + SHA256_init, + SHA256_update, + SHA256_final, + SHA256_hash, + SHA256_DIGEST_SIZE +}; +#endif + +void SHA256_init(SHA256_CTX* ctx) +{ + /* ctx->f = &SHA256_VTAB;*/ + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; + ctx->count = 0; +} + +void SHA256_update(SHA256_CTX* ctx, const void* data, int len) +{ + int i = (int) (ctx->count & 63); + const uint8_t* p = (const uint8_t*)data; + ctx->count += len; + while (len--) { + ctx->buf[i++] = *p++; + if (i == 64) { + SHA256_Transform(ctx); + i = 0; + } + } +} + +const uint8_t* SHA256_final(SHA256_CTX* ctx) +{ + uint8_t *p = ctx->buf; + uint64_t cnt = ctx->count * 8; + int i; + SHA256_update(ctx, (uint8_t*)"\x80", 1); + while ((ctx->count & 63) != 56) { + SHA256_update(ctx, (uint8_t*)"\0", 1); + } + for (i = 0; i < 8; ++i) { + uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8)); + SHA256_update(ctx, &tmp, 1); + } + for (i = 0; i < 8; i++) { + uint32_t tmp = ctx->state[i]; + *p++ = tmp >> 24; + *p++ = tmp >> 16; + *p++ = tmp >> 8; + *p++ = tmp >> 0; + } + return ctx->buf; +} + +/* Convenience function */ +const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest) +{ + SHA256_CTX ctx; + SHA256_init(&ctx); + SHA256_update(&ctx, data, len); + memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE); + return digest; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/sha256.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/sha256.h new file mode 100644 index 00000000..b22f2815 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_bind/impl/sha256.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_SHA256_H__ +#define __AWSS_SHA256_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SHA256_CTX { +/* const HASH_VTAB * f; */ + uint64_t count; + uint8_t buf[64]; + uint32_t state[8]; /* upto SHA2 */ +} SHA256_CTX; + +/* typedef HASH_CTX SHA256_CTX; */ +void SHA256_init(SHA256_CTX* ctx); +void SHA256_update(SHA256_CTX* ctx, const void* data, int len); +const uint8_t* SHA256_final(SHA256_CTX* ctx); +/* Convenience method. Returns digest address. */ +const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest); + +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + +#ifdef __cplusplus +} +#endif /*__cplusplus */ + +#endif /* SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_ */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_adapter.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_adapter.c new file mode 100644 index 00000000..f5895501 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_adapter.c @@ -0,0 +1,910 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#include +#include + +#include "alcs_internal.h" +#include "alcs_api.h" +#include "alcs_coap.h" +#include "alcs_mqtt.h" +#include "CoAPInternal.h" +#include "CoAPExport.h" +#include "CoAPServer.h" +#include "alcs_adapter.h" +#include "alcs_mqtt.h" +#include "alcs_localsetup.h" +#include "CoAPPlatform.h" + +static iotx_alcs_adapter_t g_alcs_adapter; + +static void alcs_heartbeat(void *handle); + +static iotx_alcs_adapter_t *__iotx_alcs_get_ctx(void) +{ + return &g_alcs_adapter; +} + +static char *iotx_alcs_topic_parse_pk(char *topic, uint16_t *length) +{ + char *pos = NULL; + uint8_t slash_count = 0; + uint16_t idx = 0; + uint16_t topic_len = 0; + + if (topic == NULL || length == NULL) { + COAP_ERR("Invalid Parameter"); + return NULL; + } + + topic_len = strlen(topic); + + while (idx < topic_len) { + if (topic[idx] == '/') { + slash_count++; + if (slash_count == 2) { + pos = topic + idx + 1; + } + if (slash_count == 3) { + *length = topic + idx - pos; + } + } + idx++; + } + + return pos; +} + +static char *iotx_alcs_topic_parse_dn(char *topic, uint16_t *length) +{ + char *pos = NULL; + uint8_t slash_count = 0; + uint16_t idx = 0; + uint16_t topic_len = 0; + + if (topic == NULL || length == NULL) { + COAP_ERR("Invalid Parameter"); + return NULL; + } + + topic_len = strlen(topic); + + while (idx < topic_len) { + if (topic[idx] == '/') { + slash_count++; + if (slash_count == 3) { + pos = topic + idx + 1; + } + if (slash_count == 4) { + *length = topic + idx - pos; + } + } + idx++; + } + + return pos; +} + +static int _iotx_alcs_send_list_search_and_remove(iotx_alcs_adapter_t *adapter, CoAPMessage *message, + iotx_alcs_send_msg_t **send_msg) +{ + iotx_alcs_send_msg_t *node = NULL; + iotx_alcs_send_msg_t *next = NULL; + + list_for_each_entry_safe(node, next, &adapter->alcs_send_list, linked_list, iotx_alcs_send_msg_t) { + if (message->header.tokenlen == node->token_len && + memcmp(message->token, node->token, node->token_len) == 0) { + *send_msg = node; + list_del(&node->linked_list); + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +void iotx_alcs_coap_adapter_send_msg_handle(CoAPContext *context, + CoAPReqResult result, + void *userdata, + NetworkAddr *remote, + CoAPMessage *message) +{ + int res = 0; + iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)userdata; + iotx_alcs_event_msg_t event; + memset(&event, 0, sizeof(iotx_alcs_event_msg_t)); + + switch (result) { + case COAP_REQUEST_SUCCESS: { + iotx_alcs_transfer_msg_t transfer_msg; + iotx_alcs_send_msg_t *send_msg = NULL; + + memset(&transfer_msg, 0, sizeof(iotx_alcs_transfer_msg_t)); + + transfer_msg.ip = (char *)remote->addr; + transfer_msg.port = remote->port; + HAL_MutexLock(adapter->mutex); + res = _iotx_alcs_send_list_search_and_remove(adapter, message, &send_msg); + HAL_MutexUnlock(adapter->mutex); + + if (res < SUCCESS_RETURN) { + return; + } + + transfer_msg.uri = send_msg->uri; + transfer_msg.token_len = send_msg->token_len; + transfer_msg.token = send_msg->token; + transfer_msg.payload_len = message->payloadlen; + transfer_msg.payload = message->payload; + + event.event_type = IOTX_ALCS_EVENT_MSG_SEND_MESSAGE_SUCCESS; + event.msg = &transfer_msg; + + adapter->alcs_event_handle->h_fp(adapter->alcs_event_handle->pcontext, (void *)adapter, &event); + + ALCS_free(send_msg->token); + ALCS_free(send_msg->uri); + ALCS_free(send_msg); + } + break; + case COAP_RECV_RESP_TIMEOUT: { + iotx_alcs_transfer_msg_t transfer_msg; + iotx_alcs_send_msg_t *send_msg = NULL; + + memset(&transfer_msg, 0, sizeof(iotx_alcs_transfer_msg_t)); + + transfer_msg.ip = (char *)remote->addr; + transfer_msg.port = remote->port; + HAL_MutexLock(adapter->mutex); + res = _iotx_alcs_send_list_search_and_remove(adapter, message, &send_msg); + HAL_MutexUnlock(adapter->mutex); + + if (res < SUCCESS_RETURN) { + return; + } + + transfer_msg.uri = send_msg->uri; + transfer_msg.token_len = send_msg->token_len; + transfer_msg.token = send_msg->token; + transfer_msg.payload_len = 0; + transfer_msg.payload = NULL; + + event.event_type = IOTX_ALCS_EVENT_MSG_SEND_MESSAGE_RESP_TIMEOUT; + event.msg = &transfer_msg; + + adapter->alcs_event_handle->h_fp(adapter->alcs_event_handle->pcontext, (void *)adapter, &event); + + ALCS_free(send_msg->token); + ALCS_free(send_msg->uri); + ALCS_free(send_msg); + } + break; + default: + COAP_WRN("Unknown Coap Request Result: %d", result); + break; + } +} + +void iotx_alcs_coap_adapter_event_notifier(unsigned int event, NetworkAddr *remote, void *message) +{ + COAP_INFO("ALCS Coap Event: %d, Remote Device Address: %s, Remote Device Port: %d", + event, remote->addr, remote->port); +} + +int iotx_alcs_adapter_list_init(iotx_alcs_adapter_t *adapter) +{ + /* initialze send list */ + INIT_LIST_HEAD(&adapter->alcs_send_list); + INIT_LIST_HEAD(&adapter->alcs_subdev_list); + + return SUCCESS_RETURN; +} + +static void _iotx_alcs_adapter_send_list_destroy(iotx_alcs_adapter_t *adapter) +{ + iotx_alcs_send_msg_t *node = NULL; + iotx_alcs_send_msg_t *next = NULL; + + list_for_each_entry_safe(node, next, &adapter->alcs_send_list, linked_list, iotx_alcs_send_msg_t) { + list_del(&node->linked_list); + ALCS_free(node->token); + ALCS_free(node->uri); + ALCS_free(node); + } +} + +static void _iotx_alcs_adapter_subdev_list_destroy(iotx_alcs_adapter_t *adapter) +{ + iotx_alcs_send_msg_t *node = NULL; + iotx_alcs_send_msg_t *next = NULL; + + list_for_each_entry_safe(node, next, &adapter->alcs_subdev_list, linked_list, iotx_alcs_send_msg_t) { + list_del(&node->linked_list); + ALCS_free(node); + } +} + +int iotx_alcs_adapter_deinit(void) +{ + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx(); + + HAL_GetProductKey(product_key); + HAL_GetDeviceName(device_name); + + HAL_MutexLock(adapter->mutex); + _iotx_alcs_adapter_send_list_destroy(adapter); + _iotx_alcs_adapter_subdev_list_destroy(adapter); + HAL_MutexUnlock(adapter->mutex); + + if (adapter->alcs_event_handle) { + ALCS_free(adapter->alcs_event_handle); + } + + HAL_MutexDestroy(adapter->mutex); + + alcs_mqtt_deinit(adapter->coap_ctx, product_key, device_name); + + /* if (adapter->coap_ctx) CoAPContext_free(adapter->coap_ctx); */ + + alcs_context_deinit(); + alcs_deinit(); + alcs_auth_deinit(); + + return SUCCESS_RETURN; +} + +int iotx_alcs_adapter_init(iotx_alcs_adapter_t *adapter, iotx_alcs_param_t *param) +{ + int res; + CoAPInitParam coap_param; + CoAPContext *coap_ctx = NULL; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + COAP_INFO("iotx_alcs_adapter_init"); + memset(&coap_param, 0, sizeof(CoAPInitParam)); + + adapter->mutex = HAL_MutexCreate(); + if (adapter->mutex == NULL) { + COAP_ERR("Mutex Init Failed"); + return FAIL_RETURN; + } + + coap_param.send_maxcount = param->send_maxcount; + coap_param.obs_maxcount = param->obs_maxcount; + coap_param.port = param->port; + coap_param.group = param->group; + coap_param.waittime = param->waittime; + coap_param.res_maxcount = param->res_maxcount; + coap_param.appdata = NULL; + coap_param.notifier = iotx_alcs_coap_adapter_event_notifier; + + coap_ctx = alcs_context_init(&coap_param); + if (coap_ctx == NULL) { + COAP_ERR("Coap Context Init Failed"); + HAL_MutexDestroy(adapter->mutex); + return FAIL_RETURN; + } + adapter->coap_ctx = coap_ctx; + + res = HAL_GetProductKey(product_key); + if (res <= 0 || res > IOTX_PRODUCT_KEY_LEN + 1 - 1) { + iotx_alcs_adapter_deinit(); + COAP_ERR("Get Product Key Failed"); + return FAIL_RETURN; + } + + res = HAL_GetDeviceName(device_name); + if (res <= 0 || res > IOTX_DEVICE_NAME_LEN + 1 - 1) { + iotx_alcs_adapter_deinit(); + COAP_ERR("Get Device Name Failed"); + return FAIL_RETURN; + } + + alcs_init(); + + res = alcs_auth_init(coap_ctx, product_key, device_name, param->role); + if (res != COAP_SUCCESS) { + iotx_alcs_adapter_deinit(); + COAP_ERR("ALCS Auth Init Failed"); + return FAIL_RETURN; + } + adapter->role = param->role; +#ifdef ALCS_SERVER_ENABLED + { + extern void on_svr_auth_timer(CoAPContext *); + if (adapter->role & IOTX_ALCS_ROLE_SERVER) { + adapter->alcs_server_auth_timer_func = on_svr_auth_timer; + } + } +#endif + +#ifdef ALCS_CLIENT_ENABLED + { + extern void on_client_auth_timer(CoAPContext *); + if (adapter->role & IOTX_ALCS_ROLE_CLIENT) { + adapter->alcs_client_auth_timer_func = on_client_auth_timer; + } + } +#endif + + adapter->alcs_event_handle = (iotx_alcs_event_handle_t *)ALCS_ADAPTER_malloc(sizeof(iotx_alcs_event_handle_t)); + if (adapter->alcs_event_handle == NULL) { + iotx_alcs_adapter_deinit(); + COAP_ERR("ALCS Event Handle Init Failed"); + return FAIL_RETURN; + } + memcpy(adapter->alcs_event_handle, param->handle_event, sizeof(iotx_alcs_event_handle_t)); + + if (iotx_alcs_adapter_list_init(adapter) != SUCCESS_RETURN) { + iotx_alcs_adapter_deinit(); + COAP_ERR("ALCS Linked List Init Failed"); + return FAIL_RETURN; + } + + alcs_localsetup_init(adapter, coap_ctx, product_key, device_name); + + return SUCCESS_RETURN; +} + +static int _iotx_alcs_subdev_list_search(const char *pk, const char *dn, iotx_alcs_subdev_item_t **subdev_item) +{ + iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx(); + iotx_alcs_subdev_item_t *node = NULL; + + if (pk == NULL || dn == NULL) { + COAP_ERR("Invalid Parameter"); + return FAIL_RETURN; + } + + list_for_each_entry(node, &adapter->alcs_subdev_list, linked_list, iotx_alcs_subdev_item_t) { + if (strlen(node->product_key) == strlen(pk) && + memcmp(node->product_key, pk, strlen(pk)) == 0 && + strlen(node->device_name) == strlen(dn) && + memcmp(node->device_name, dn, strlen(dn)) == 0) { + *subdev_item = node; + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +int iotx_alcs_subdev_remove(const char *pk, const char *dn) +{ + int res = 0; + iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx(); + iotx_alcs_subdev_item_t *subdev_item = NULL; + + if (pk == NULL || dn == NULL) { + COAP_ERR("Invalid Parameter"); + return FAIL_RETURN; + } + + HAL_MutexLock(adapter->mutex); + res = _iotx_alcs_subdev_list_search(pk, dn, &subdev_item); + if (res < SUCCESS_RETURN) { + COAP_ERR("No Matched Item"); + HAL_MutexUnlock(adapter->mutex); + return FAIL_RETURN; + } + + list_del(&subdev_item->linked_list); + HAL_MutexUnlock(adapter->mutex); + + ALCS_free(subdev_item); + + return SUCCESS_RETURN; +} + +int iotx_alcs_subdev_update_stage(iotx_alcs_subdev_item_t *item) +{ + int res = 0; + iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx(); + iotx_alcs_subdev_item_t *subdev_item = NULL; + + if (item == NULL) { + COAP_ERR("Invalid Parameter"); + return FAIL_RETURN; + } + + HAL_MutexLock(adapter->mutex); + res = _iotx_alcs_subdev_list_search(item->product_key, item->device_name, &subdev_item); + + if (res < SUCCESS_RETURN) { + COAP_WRN("No Matched Item"); + HAL_MutexUnlock(adapter->mutex); + return FAIL_RETURN; + } + + subdev_item->stage = item->stage; + + HAL_MutexUnlock(adapter->mutex); + return SUCCESS_RETURN; +} + +void iotx_alcs_subdev_stage_check(void) +{ + iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx(); + iotx_alcs_subdev_item_t *node = NULL; + uint64_t time_now = HAL_UptimeMs(); + + HAL_MutexLock(adapter->mutex); + list_for_each_entry(node, &adapter->alcs_subdev_list, linked_list, iotx_alcs_subdev_item_t) { + if (node->stage == IOTX_ALCS_SUBDEV_DISCONNCET_CLOUD) { + if (((time_now > node->retry_ms) && + (time_now - node->retry_ms >= IOTX_ALCS_SUBDEV_RETRY_INTERVAL_MS)) || + ((time_now <= node->retry_ms) && + ((0xFFFFFFFFFFFFFFFF - node->retry_ms) + time_now >= IOTX_ALCS_SUBDEV_RETRY_INTERVAL_MS))) { + /* Get Prefix And Secret From Cloud */ + alcs_mqtt_subdev_prefix_get(node->product_key, node->device_name); + node->retry_ms = time_now; + } + } + } + HAL_MutexUnlock(adapter->mutex); +} + +void *iotx_alcs_construct(iotx_alcs_param_t *params) +{ + int res = 0; + iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx(); + + COAP_INFO("iotx_alcs_construct enter"); + + if (params == NULL || params->group == NULL || + strlen(params->group) == 0) { + return NULL; + } + + memset(adapter, 0, sizeof(iotx_alcs_adapter_t)); + + res = iotx_alcs_adapter_init(adapter, params); + if (res != SUCCESS_RETURN) { + COAP_ERR("Adapter Init Failed"); + return NULL; + } + + return (void *)adapter; +} + +int iotx_alcs_cloud_init(void *handle) +{ + int res = 0; + iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx(); + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + COAP_INFO("Start ALCS Cloud Init"); + + if (adapter->local_cloud_inited == 1) { + return SUCCESS_RETURN; + } + + if (handle == NULL) { + return FAIL_RETURN; + } + + res = HAL_GetProductKey(product_key); + if (res <= 0 || res > IOTX_PRODUCT_KEY_LEN + 1 - 1) { + iotx_alcs_adapter_deinit(); + COAP_ERR("Get Product Key Failed"); + return FAIL_RETURN; + } + + res = HAL_GetDeviceName(device_name); + if (res <= 0 || res > IOTX_DEVICE_NAME_LEN + 1 - 1) { + iotx_alcs_adapter_deinit(); + COAP_ERR("Get Device Name Failed"); + return FAIL_RETURN; + } + + if (alcs_mqtt_init(adapter->coap_ctx, product_key, device_name) != ALCS_MQTT_STATUS_SUCCESS) { + /*solve the prpblem of hard fault when mqtt connection fails once*/ + COAP_ERR("ALCS MQTT Init Failed"); + return FAIL_RETURN; + } + + adapter->local_cloud_inited = 1; + + return SUCCESS_RETURN; +} + +int iotx_alcs_destroy(void **phandle) +{ + if (phandle == NULL || *phandle == NULL) { + return NULL_VALUE_ERROR; + } + + iotx_alcs_adapter_deinit(); + + return SUCCESS_RETURN; +} + +static void alcs_heartbeat(void *handle) +{ + iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle; + + if (adapter->role & IOTX_ALCS_ROLE_SERVER && adapter->alcs_server_auth_timer_func != NULL) { + adapter->alcs_server_auth_timer_func(adapter->coap_ctx); + } + + if (adapter->role & IOTX_ALCS_ROLE_CLIENT && adapter->alcs_client_auth_timer_func != NULL) { + adapter->alcs_client_auth_timer_func(adapter->coap_ctx); + } +} +int iotx_alcs_yield(void *handle) +{ + int res = 0; + iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle; + + if (adapter == NULL || adapter->coap_ctx == NULL) { + return NULL_VALUE_ERROR; + } + + alcs_heartbeat(handle); + + iotx_alcs_subdev_stage_check(); + + return res; +} + +int iotx_alcs_send(void *handle, iotx_alcs_msg_t *msg) +{ + int res = 0; + iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle; + CoAPMessage coap_msg; + CoAPLenString coap_payload; + NetworkAddr network_addr; + + AlcsDeviceKey devKey; + char productKey[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char deviceName[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char *uri_pk = NULL; + char *uri_dn = NULL; + uint16_t uri_pk_len = 0; + uint16_t uri_dn_len = 0; + iotx_alcs_send_msg_t *alcs_send_msg = NULL; + + if (adapter == NULL || adapter->coap_ctx || + msg == NULL || msg->payload == NULL || + msg->ip == NULL || strlen(msg->ip) == 0 || + msg->uri == NULL || strlen(msg->uri) == 0) { + return NULL_VALUE_ERROR; + } + + if (strlen(msg->ip) > NETWORK_ADDR_LEN) { + COAP_ERR("Invalid Ip Address Length"); + return FAIL_RETURN; + } + + memset(&coap_msg, 0, sizeof(CoAPMessage)); + memset(&coap_payload, 0, sizeof(CoAPLenString)); + + coap_payload.len = msg->payload_len; + coap_payload.data = msg->payload; + + alcs_msg_init(adapter->coap_ctx, &coap_msg, msg->msg_code, msg->msg_type, 0, &coap_payload, (void *)adapter); + + res = alcs_msg_setAddr(&coap_msg, msg->uri, NULL); + if (res != COAP_SUCCESS) { + COAP_ERR("ALCS Message Set URI Failed"); + return FAIL_RETURN; + } + + memset(&network_addr, 0, sizeof(NetworkAddr)); + memcpy(network_addr.addr, msg->ip, strlen(msg->ip)); + network_addr.port = msg->port; + + + memset(&devKey, 0, sizeof(AlcsDeviceKey)); + memcpy(&devKey.addr, &network_addr, sizeof(NetworkAddr)); + + uri_pk = iotx_alcs_topic_parse_pk(msg->uri, &uri_pk_len); + uri_dn = iotx_alcs_topic_parse_dn(msg->uri, &uri_dn_len); + + if (uri_pk == NULL || uri_pk_len >= IOTX_PRODUCT_KEY_LEN + 1 || + uri_dn == NULL || uri_dn_len >= IOTX_DEVICE_NAME_LEN + 1) { + COAP_ERR("Invalid Parameter"); + return FAIL_RETURN; + } + memcpy(productKey, uri_pk, uri_pk_len); + memcpy(deviceName, uri_dn, uri_dn_len); + + devKey.pk = productKey; + devKey.dn = deviceName; + + res = alcs_sendmsg_secure(adapter->coap_ctx, &devKey, &coap_msg, 2, iotx_alcs_coap_adapter_send_msg_handle); + alcs_msg_deinit(&coap_msg); + + if (res != COAP_SUCCESS) { + COAP_ERR("ALCS Message Send Message Failed"); + return FAIL_RETURN; + } + + alcs_send_msg = (iotx_alcs_send_msg_t *)ALCS_ADAPTER_malloc(sizeof(iotx_alcs_send_msg_t)); + if (alcs_send_msg == NULL) { + COAP_WRN("Not Enough Memory"); + return FAIL_RETURN; + } + memset(alcs_send_msg, 0, sizeof(iotx_alcs_send_msg_t)); + + alcs_send_msg->token = (uint8_t *)ALCS_ADAPTER_malloc(coap_msg.header.tokenlen + 1); + if (alcs_send_msg->token == NULL) { + ALCS_free(alcs_send_msg); + COAP_WRN("Not Enough Memory"); + return FAIL_RETURN; + } + alcs_send_msg->token_len = coap_msg.header.tokenlen; + + memset(alcs_send_msg->token, 0, alcs_send_msg->token_len + 1); + memcpy(alcs_send_msg->token, coap_msg.token, alcs_send_msg->token_len); + + alcs_send_msg->uri = (char *)ALCS_ADAPTER_malloc(strlen(msg->uri) + 1); + if (alcs_send_msg->uri == NULL) { + ALCS_free(alcs_send_msg->token); + ALCS_free(alcs_send_msg); + COAP_WRN("ALCS Message Buffer Failed"); + return FAIL_RETURN; + } + memset(alcs_send_msg->uri, 0, strlen(msg->uri) + 1); + memcpy(alcs_send_msg->uri, msg->uri, strlen(msg->uri)); + INIT_LIST_HEAD(&alcs_send_msg->linked_list); + + HAL_MutexLock(adapter->mutex); + list_add_tail(&alcs_send_msg->linked_list, &adapter->alcs_send_list); + HAL_MutexUnlock(adapter->mutex); + + return SUCCESS_RETURN; +} + +int iotx_alcs_send_Response(void *handle, iotx_alcs_msg_t *msg, uint8_t token_len, uint8_t *token) +{ + int res = 0; + iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle; + CoAPMessage coap_msg; + CoAPLenString coap_payload; + CoAPLenString token_payload; + NetworkAddr network_addr; + + AlcsDeviceKey devKey; + char productKey[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char deviceName[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char *uri_pk = NULL; + char *uri_dn = NULL; + uint16_t uri_pk_len = 0; + uint16_t uri_dn_len = 0; + + if (adapter == NULL || adapter->coap_ctx == NULL || + msg == NULL || msg->payload == NULL || + msg->ip == NULL || strlen(msg->ip) == 0 || + msg->uri == NULL || strlen(msg->uri) == 0) { + return NULL_VALUE_ERROR; + } + + if (token_len == 0 || token == NULL) { + return FAIL_RETURN; + } + + + if (strlen(msg->ip) > NETWORK_ADDR_LEN) { + COAP_ERR("Invalid Ip Address Length"); + return FAIL_RETURN; + } + + memset(&coap_msg, 0, sizeof(CoAPMessage)); + memset(&coap_payload, 0, sizeof(CoAPLenString)); + memset(&token_payload, 0, sizeof(CoAPLenString)); + + coap_payload.len = msg->payload_len; + coap_payload.data = msg->payload; + + alcs_msg_init(adapter->coap_ctx, &coap_msg, msg->msg_code, msg->msg_type, 0, &coap_payload, (void *)adapter); + + res = alcs_msg_setAddr(&coap_msg, msg->uri, NULL); + if (res != COAP_SUCCESS) { + COAP_ERR("ALCS Message Set URI Failed"); + return FAIL_RETURN; + } + + memset(&network_addr, 0, sizeof(NetworkAddr)); + memcpy(network_addr.addr, msg->ip, strlen(msg->ip)); + network_addr.port = msg->port; + + token_payload.len = token_len; + token_payload.data = token; + + memset(&devKey, 0, sizeof(AlcsDeviceKey)); + memcpy(&devKey.addr, &network_addr, sizeof(NetworkAddr)); + + uri_pk = iotx_alcs_topic_parse_pk(msg->uri, &uri_pk_len); + uri_dn = iotx_alcs_topic_parse_dn(msg->uri, &uri_dn_len); + + if (uri_pk == NULL || uri_pk_len >= IOTX_PRODUCT_KEY_LEN + 1 || + uri_dn == NULL || uri_dn_len >= IOTX_DEVICE_NAME_LEN + 1) { + COAP_ERR("Invalid Parameter"); + return FAIL_RETURN; + } + memcpy(productKey, uri_pk, uri_pk_len); + memcpy(deviceName, uri_dn, uri_dn_len); + + devKey.pk = productKey; + devKey.dn = deviceName; + + if (alcs_resource_need_auth(adapter->coap_ctx, msg->uri)) { + res = alcs_sendrsp_secure(adapter->coap_ctx, &devKey, &coap_msg, 0, 0, &token_payload); + } else { + res = alcs_sendrsp(adapter->coap_ctx, &network_addr, &coap_msg, 0, 0, &token_payload); + } + + alcs_msg_deinit(&coap_msg); + + if (res != COAP_SUCCESS) { + COAP_ERR("ALCS Message Send Message Failed"); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int iotx_alcs_register_resource(void *handle, iotx_alcs_res_t *resource) +{ + int res = 0; + iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle; + char productKey[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char deviceName[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char *uri_pk = NULL; + char *uri_dn = NULL; + uint16_t uri_pk_len = 0; + uint16_t uri_dn_len = 0; + int needAuth = 0; + + if (adapter == NULL || adapter->coap_ctx == NULL || + resource->uri == NULL || strlen(resource->uri) == 0) { + return NULL_VALUE_ERROR; + } + + uri_pk = iotx_alcs_topic_parse_pk(resource->uri, &uri_pk_len); + uri_dn = iotx_alcs_topic_parse_dn(resource->uri, &uri_dn_len); + + if (uri_pk == NULL || uri_pk_len >= IOTX_PRODUCT_KEY_LEN + 1 || + uri_dn == NULL || uri_dn_len >= IOTX_DEVICE_NAME_LEN + 1) { + COAP_ERR("Invalid Parameter"); + return FAIL_RETURN; + } + memcpy(productKey, uri_pk, uri_pk_len); + memcpy(deviceName, uri_dn, uri_dn_len); + + COAP_INFO("alcs register resource, uri:%s", resource->uri); + needAuth = resource->need_auth; /* strcmp (resource->uri, "/dev/core/service/dev"); */ + + res = alcs_resource_register(adapter->coap_ctx, + productKey, + deviceName, + resource->uri, + resource->msg_perm, + resource->msg_ct, + resource->maxage, + needAuth, + (void (*)(CoAPContext * context, const char *paths, NetworkAddr * remote, + CoAPMessage * message))resource->callback); + + if (res != COAP_SUCCESS) { + COAP_ERR("ALCS Register Resource Failed, Code: %d", res); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int iotx_alcs_observe_notify(void *handle, const char *uri, uint32_t payload_len, uint8_t *payload) +{ + int res = 0; + iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle; + CoAPLenString coap_payload; + + coap_payload.len = (int32_t)payload_len; + coap_payload.data = payload; + + res = alcs_observe_notify(adapter->coap_ctx, uri, &coap_payload); + if (res != COAP_SUCCESS) { + COAP_ERR("ALCS Observe Notify Failed, Code: %d", res); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int iotx_alcs_unregister_resource(void *handle, char *uri) +{ + return SUCCESS_RETURN; +} + +int iotx_alcs_add_sub_device(void *handle, const char *pk, const char *dn) +{ + int res = 0; + iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle; + iotx_alcs_subdev_item_t *subdev_item = NULL; + char prefix[ALCS_MQTT_PREFIX_MAX_LEN] = {0}; + char secret[ALCS_MQTT_SECRET_MAX_LEN] = {0}; + + if (handle == NULL || pk == NULL || strlen(pk) >= IOTX_PRODUCT_KEY_LEN + 1 || + dn == NULL || strlen(dn) >= IOTX_DEVICE_NAME_LEN + 1) { + COAP_ERR("Invalid Argument"); + return FAIL_RETURN; + } + + if (adapter->coap_ctx != NULL) { + alcs_auth_subdev_init(adapter->coap_ctx, pk, dn); + } + + /* Search Subdev In Linked List */ + HAL_MutexLock(adapter->mutex); + res = _iotx_alcs_subdev_list_search(pk, dn, &subdev_item); + if (res == SUCCESS_RETURN) { + COAP_INFO("This Product Key And Device Name Have Been Added"); + HAL_MutexUnlock(adapter->mutex); + return SUCCESS_RETURN; + } + HAL_MutexUnlock(adapter->mutex); + + /* Insert New Subdev Into Linked List */ + subdev_item = (iotx_alcs_subdev_item_t *)ALCS_ADAPTER_malloc(sizeof(iotx_alcs_subdev_item_t)); + if (subdev_item == NULL) { + COAP_ERR("No Enough Memory"); + return FAIL_RETURN; + } + memset(subdev_item, 0, sizeof(iotx_alcs_subdev_item_t)); + + /* Set Product Key And Device Name */ + memcpy(subdev_item->product_key, pk, strlen(pk)); + memcpy(subdev_item->device_name, dn, strlen(dn)); + subdev_item->stage = IOTX_ALCS_SUBDEV_DISCONNCET_CLOUD; + subdev_item->retry_ms = HAL_UptimeMs(); + INIT_LIST_HEAD(&subdev_item->linked_list); + + HAL_MutexLock(adapter->mutex); + list_add_tail(&subdev_item->linked_list, &adapter->alcs_subdev_list); + HAL_MutexUnlock(adapter->mutex); + + alcs_localsetup_add_sub_device(adapter, subdev_item->product_key, subdev_item->device_name); + + /* Get Prefix And Secret From KV */ + res = alcs_mqtt_prefix_secret_load(pk, strlen(pk), dn, strlen(dn), prefix, secret); + if (res == SUCCESS_RETURN) { + memcpy(subdev_item->prefix, prefix, strlen(prefix)); + memcpy(subdev_item->secret, secret, strlen(secret)); + alcs_mqtt_add_srv_key(prefix, secret); + } + + /* Get Prefix And Secret From Cloud */ + alcs_mqtt_subdev_prefix_get(pk, dn); + + return SUCCESS_RETURN; +} + +int iotx_alcs_remove_sub_device(void *handle, const char *pk, const char *dn) +{ + int res = 0; + + if (handle == NULL || pk == NULL || strlen(pk) >= IOTX_PRODUCT_KEY_LEN + 1 || + dn == NULL || strlen(dn) >= IOTX_DEVICE_NAME_LEN + 1) { + COAP_ERR("Invalid Parameter"); + return FAIL_RETURN; + } + + res = iotx_alcs_subdev_remove(pk, dn); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Remove Subdev Item From KV */ + alcs_mqtt_prefix_secret_del(pk, strlen(pk), dn, strlen(dn)); + return SUCCESS_RETURN; +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_adapter.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_adapter.h new file mode 100644 index 00000000..dabfca5e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_adapter.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef __ALCS_ADAPTER_H__ +#define __ALCS_ADAPTER_H__ +#if defined(__cplusplus) +extern "C" { +#endif + +#include "alcs_internal.h" +#include "mqtt_api.h" +#include "CoAPExport.h" +#include "alcs_mqtt.h" +#include "iotx_alcs.h" + +typedef struct iotx_alcs_send_msg_st { + uint8_t token_len; + uint8_t *token; + char *uri; + struct list_head linked_list; +} iotx_alcs_send_msg_t, *iotx_alcs_send_msg_pt; + +typedef enum { + IOTX_ALCS_SUBDEV_DISCONNCET_CLOUD, + IOTX_ALCS_SUBDEV_CONNECT_CLOUD +} iotx_alcs_subdev_stage_t; + +#define IOTX_ALCS_SUBDEV_RETRY_INTERVAL_MS (10000) + +typedef struct iotx_alcs_subdev_item_st { + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + char prefix[ALCS_MQTT_PREFIX_MAX_LEN]; + char secret[ALCS_MQTT_SECRET_MAX_LEN]; + uint8_t stage; + uint64_t retry_ms; + struct list_head linked_list; +} iotx_alcs_subdev_item_t, *iotx_alcs_subdev_item_pt; + +typedef void (*iotx_alcs_auth_timer_fnuc_t)(CoAPContext *); + +typedef struct iotx_alcs_adapter_st { + void *mutex; + int local_cloud_inited; + CoAPContext *coap_ctx; + uint8_t role; + iotx_alcs_auth_timer_fnuc_t alcs_client_auth_timer_func; + iotx_alcs_auth_timer_fnuc_t alcs_server_auth_timer_func; + iotx_alcs_event_handle_t *alcs_event_handle; + struct list_head alcs_send_list; + struct list_head alcs_subdev_list; + char local_ip[NETWORK_ADDR_LEN]; + uint16_t local_port; +} iotx_alcs_adapter_t, *iotx_alcs_adapter_pt; + +int iotx_alcs_subdev_insert(iotx_alcs_subdev_item_t *item); +int iotx_alcs_subdev_remove(const char *pk, const char *dn); +int iotx_alcs_subdev_search(const char *pk, const char *dn, iotx_alcs_subdev_item_t **item); +int iotx_alcs_subdev_update_stage(iotx_alcs_subdev_item_t *item); +void iotx_alcs_send_list_handle(void *list_node, va_list *params); +int iotx_alcs_adapter_list_init(iotx_alcs_adapter_t *adapter); + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_api.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_api.c new file mode 100644 index 00000000..1cec4662 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_api.c @@ -0,0 +1,718 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include +#include +#include "alcs_internal.h" +#include "alcs_api.h" +#include "alcs_coap.h" +#include "alcs_api_internal.h" +#include "CoAPPlatform.h" +#include "CoAPObserve.h" + +ALIYUN_LIST_HEAD(secure_resource_cb_head); + +static bool is_inited = 0; +#ifdef SUPPORT_MULTI_DEVICES +ALIYUN_LIST_HEAD(device_list); + +device_auth_list *get_device(CoAPContext *context) +{ + device_auth_list *node = NULL, *next = NULL; + list_for_each_entry_safe(node, next, &device_list, lst, device_auth_list) { + if (node->context == context) { + return node; + } + } + return NULL; +} + +auth_list *get_list(CoAPContext *context) +{ + device_auth_list *dev_lst = get_device(context); + return dev_lst ? &dev_lst->lst_auth : NULL; +} + +#ifdef ALCS_CLIENT_ENABLED +struct list_head *get_ctl_session_list(CoAPContext *context) +{ + device_auth_list *dev_lst = get_device(context); + if (!dev_lst || !(dev_lst->role & ROLE_CLIENT)) { + return NULL; + } + return &dev_lst->lst_ctl_sessions; +} +#endif +#ifdef ALCS_SERVER_ENABLED +struct list_head *get_svr_session_list(CoAPContext *context) +{ + device_auth_list *dev_lst = get_device(context); + return dev_lst && (dev_lst->role & ROLE_SERVER) ? &dev_lst->lst_svr_sessions : NULL; +} +#endif + +#else +device_auth_list _device; +#endif + +void remove_session(CoAPContext *ctx, session_item *session) +{ + COAP_INFO("remove_session"); + if (session) { + CoapObsServerAll_delete(ctx, &session->addr); + list_del(&session->lst); + coap_free(session); + } +} + +session_item *get_session_by_checksum(struct list_head *sessions, NetworkAddr *addr, char ck[PK_DN_CHECKSUM_LEN]) +{ + session_item *node = NULL, *next = NULL; + if (!sessions || !ck) { + return NULL; + } + list_for_each_entry_safe(node, next, sessions, lst, session_item) { + if (is_networkadd_same(addr, &node->addr) + && strncmp(node->pk_dn, ck, PK_DN_CHECKSUM_LEN) == 0) { + COAP_DEBUG("find node, sessionid:%d", node->sessionId); + return node; + } + } + return NULL; +} + +static session_item *get_session(struct list_head *sessions, AlcsDeviceKey *devKey) +{ + char ck[PK_DN_CHECKSUM_LEN] = {0}; + char path[100] = {0}; + if (!sessions || !devKey || !devKey->pk || !devKey->dn) { + return NULL; + } + HAL_Snprintf(path, sizeof(path), "%s%s", devKey->pk, devKey->dn); + CoAPPathMD5_sum(path, strlen(path), ck, PK_DN_CHECKSUM_LEN); + + return get_session_by_checksum(sessions, &devKey->addr, ck); +} + +#ifdef ALCS_CLIENT_ENABLED +session_item *get_ctl_session(CoAPContext *ctx, AlcsDeviceKey *devKey) +{ + struct list_head *sessions = get_ctl_session_list(ctx); + COAP_DEBUG("get_ctl_session"); + return get_session(sessions, devKey); +} + +#endif + +#ifdef ALCS_SERVER_ENABLED +session_item *get_svr_session(CoAPContext *ctx, AlcsDeviceKey *devKey) +{ + struct list_head *sessions = get_svr_session_list(ctx); + return get_session(sessions, devKey); +} +#endif + +static session_item *get_auth_session(CoAPContext *ctx, AlcsDeviceKey *devKey) +{ +#ifdef ALCS_CLIENT_ENABLED + session_item *node = get_ctl_session(ctx, devKey); + if (node && node->sessionId) { + return node; + } +#endif +#ifdef ALCS_SERVER_ENABLED + session_item *node1 = get_svr_session(ctx, devKey); + if (node1 && node1->sessionId) { + return node1; + } +#endif + + return NULL; +} + +static session_item *get_auth_session_by_checksum(CoAPContext *ctx, NetworkAddr *addr, char ck[]) +{ +#ifdef ALCS_CLIENT_ENABLED + struct list_head *sessions = get_ctl_session_list(ctx); + session_item *node = get_session_by_checksum(sessions, addr, ck); + if (node && node->sessionId) { + return node; + } +#endif +#ifdef ALCS_SERVER_ENABLED + struct list_head *sessions1 = get_svr_session_list(ctx); + session_item *node1 = get_session_by_checksum(sessions1, addr, ck); + if (node1 && node1->sessionId) { + return node1; + } +#endif + + return NULL; +} + +void gen_random_key(unsigned char random[], int len) +{ + int i = 0, flag = 0; + + memset(random, 0x00, len); + srand((unsigned)time(NULL)); + + for (i = 0; i < len - 1; i++) { + flag = rand() % 3; + switch (flag) { + case 0: + random[i] = 'A' + rand() % 26; + break; + case 1: + random[i] = 'a' + rand() % 26; + break; + case 2: + random[i] = '0' + rand() % 10; + break; + default: + random[i] = 'x'; + break; + } + } +} + +#ifdef ALCS_SERVER_ENABLED + extern void alcs_rec_auth_select(CoAPContext *context, const char *paths, NetworkAddr *remote, CoAPMessage *request); + extern void alcs_rec_auth(CoAPContext *context, const char *paths, NetworkAddr *remote, CoAPMessage *request); + extern void alcs_rec_heart_beat(CoAPContext *context, const char *paths, NetworkAddr *remote, CoAPMessage *request); +#endif + +int alcs_auth_init(CoAPContext *ctx, const char *productKey, const char *deviceName, char role) +{ + device_auth_list *dev; +#ifdef ALCS_SERVER_ENABLED + char path[256]; +#endif + if (is_inited) { + return 0; + } + is_inited = 1; + + /* auth_list* lst_auth; */ + +#ifdef SUPPORT_MULTI_DEVICES + INIT_LIST_HEAD(&device_list); + + dev = coap_malloc(sizeof(device_auth_list)); + list_add_tail(&dev->lst, &device_list); +#else + dev = &_device; +#endif + dev->context = ctx; + dev->seq = 1; + dev->role = role; + memset(&dev->lst_auth, 0, sizeof(auth_list)); + /* strcpy (dev->deviceName, deviceName); */ + /* strcpy (dev->productKey, productKey); */ + + INIT_LIST_HEAD(&dev->lst); + INIT_LIST_HEAD(&secure_resource_cb_head); + + if (role & ROLE_SERVER) { +#ifdef ALCS_SERVER_ENABLED + INIT_LIST_HEAD(&dev->lst_svr_sessions); + INIT_LIST_HEAD(&dev->lst_auth.lst_svr); + + HAL_Snprintf(path, sizeof(path), "/dev/%s/%s/core/service/auth", productKey, deviceName); + alcs_resource_register(ctx, productKey, deviceName, path, COAP_PERM_GET, COAP_CT_APP_JSON, 60, 0, alcs_rec_auth); + strcat(path, "/select"); + alcs_resource_register(ctx, productKey, deviceName, path, COAP_PERM_GET, COAP_CT_APP_JSON, 60, 0, alcs_rec_auth_select); + alcs_resource_register(ctx, productKey, deviceName, "/dev/core/service/heartBeat", COAP_PERM_GET, COAP_CT_APP_JSON, 60, + 0, alcs_rec_heart_beat); +#endif + } + + if (role & ROLE_CLIENT) { +#ifdef ALCS_CLIENT_ENABLED + INIT_LIST_HEAD(&dev->lst_ctl_sessions); + INIT_LIST_HEAD(&dev->lst_auth.lst_ctl); +#endif + } + + INIT_LIST_HEAD(&dev->lst_auth.lst_ctl_group); + INIT_LIST_HEAD(&dev->lst_auth.lst_svr_group); + dev->lst_auth.list_mutex = HAL_MutexCreate(); + + return COAP_SUCCESS; +} + +void alcs_auth_subdev_init(CoAPContext *ctx, const char *productKey, const char *deviceName) +{ + char path[256]; + HAL_Snprintf(path, sizeof(path), "/dev/%s/%s/core/service/auth", productKey, deviceName); + alcs_resource_register(ctx, productKey, deviceName, path, COAP_PERM_GET, COAP_CT_APP_JSON, 60, 0, alcs_rec_auth); + strcat(path, "/select"); + alcs_resource_register(ctx, productKey, deviceName, path, COAP_PERM_GET, COAP_CT_APP_JSON, 60, 0, alcs_rec_auth_select); +} + +void alcs_auth_deinit(void) +{ +#ifdef SUPPORT_MULTI_DEVICES + device_auth_list *node = NULL, *next = NULL; +#endif + + alcs_resource_cb_deinit(); + alcs_auth_list_deinit(); + +#ifdef SUPPORT_MULTI_DEVICES + list_for_each_entry_safe(node, next, &device_list, lst, device_auth_list) { + if (node->lst_auth.list_mutex) { + HAL_MutexDestroy(node->lst_auth.list_mutex); + } + } +#else + if (_device.lst_auth.list_mutex) { + HAL_MutexDestroy(_device.lst_auth.list_mutex); + } +#endif +} + +bool is_networkadd_same(NetworkAddr *addr1, NetworkAddr *addr2) +{ + if (!addr1 || !addr2) { + return 0; + } + COAP_DEBUG("compare addr1:%s,addr2:%s", addr1->addr, addr2->addr); + return addr1->port == addr2->port && !strcmp((const char *)addr1->addr, (const char *)addr2->addr); +} + +int alcs_encrypt(const char *src, int len, const char *key, void *out) +{ + char *iv = "a1b1c1d1e1f1g1h1"; + + int len1 = len & 0xfffffff0; + int len2 = len1 + 16; + int pad = len2 - len; + int ret = 0; + + if (len1) { + p_HAL_Aes128_t aes_e_h = HAL_Aes128_Init((uint8_t *)key, (uint8_t *)iv, HAL_AES_ENCRYPTION); + ret = HAL_Aes128_Cbc_Encrypt(aes_e_h, src, len1 >> 4, out); + HAL_Aes128_Destroy(aes_e_h); + } + if (!ret && pad) { + char buf[16]; + p_HAL_Aes128_t aes_e_h = NULL; + memcpy(buf, src + len1, len - len1); + memset(buf + len - len1, pad, pad); + aes_e_h = HAL_Aes128_Init((uint8_t *)key, (uint8_t *)iv, HAL_AES_ENCRYPTION); + ret = HAL_Aes128_Cbc_Encrypt(aes_e_h, buf, 1, (uint8_t *)out + len1); + HAL_Aes128_Destroy(aes_e_h); + } + + COAP_DEBUG("to encrypt src:%s, len:%d", src, len2); + return ret == 0 ? len2 : 0; +} + +int alcs_decrypt(const char *src, int len, const char *key, void *out) +{ + char *iv = "a1b1c1d1e1f1g1h1"; + p_HAL_Aes128_t aes_d_h; + int n = len >> 4; + char *out_c = NULL; + int offset = 0; + int ret = 0; + char pad = 0; + + COAP_DEBUG("to decrypt len:%d", len); + + do { + if (n > 1) { + aes_d_h = HAL_Aes128_Init((uint8_t *)key, (uint8_t *)iv, HAL_AES_DECRYPTION); + if (!aes_d_h) { + COAP_ERR("fail to decrypt init"); + break; + } + + ret = HAL_Aes128_Cbc_Decrypt(aes_d_h, src, n - 1, out); + HAL_Aes128_Destroy(aes_d_h); + + if (ret != 0) { + COAP_ERR("fail to decrypt"); + break; + } + } + + out_c = (char *)out; + offset = n > 0 ? ((n - 1) << 4) : 0; + out_c[offset] = 0; + + aes_d_h = HAL_Aes128_Init((uint8_t *)key, (uint8_t *)iv, HAL_AES_DECRYPTION); + if (!aes_d_h) { + COAP_ERR("fail to decrypt init"); + break; + } + + ret = HAL_Aes128_Cbc_Decrypt(aes_d_h, src + offset, 1, out_c + offset); + HAL_Aes128_Destroy(aes_d_h); + + if (ret != 0) { + COAP_ERR("fail to decrypt remain data"); + break; + } + + pad = out_c[len - 1]; + out_c[len - pad] = 0; + COAP_DEBUG("decrypt data:%s, len:%d", out_c, len - pad); + return len - pad; + } while (0); + + return 0; +} + +bool alcs_is_auth(CoAPContext *ctx, AlcsDeviceKey *devKey) +{ + return get_auth_session(ctx, devKey) != NULL; +} + +/*---------------------------------------------------------*/ +typedef struct { + void *orig_user_data; + char pk_dn[PK_DN_CHECKSUM_LEN]; + CoAPSendMsgHandler orig_handler; +} secure_send_item; + +static int do_secure_send(CoAPContext *ctx, NetworkAddr *addr, CoAPMessage *message, const char *key, char *buf) +{ + int ret = COAP_SUCCESS; + void *payload_old = message->payload; + int len_old = message->payloadlen; + + COAP_DEBUG("do_secure_send"); + + message->payload = (unsigned char *)buf; + message->payloadlen = alcs_encrypt((const char *)payload_old, len_old, key, message->payload); + ret = CoAPMessage_send(ctx, addr, message); + + message->payload = payload_old; + message->payloadlen = len_old; + + return ret; +} + +void secure_sendmsg_handler(CoAPContext *context, CoAPReqResult result, void *userdata, NetworkAddr *remote, + CoAPMessage *message); +int internal_secure_send(CoAPContext *ctx, session_item *session, NetworkAddr *addr, CoAPMessage *message, char observe, + CoAPSendMsgHandler handler) +{ + int encryptlen = 0; + + COAP_DEBUG("internal_secure_send"); + if (!ctx || !session || !addr || !message) { + COAP_ERR("parameter is null"); + return COAP_ERROR_INVALID_PARAM; + } + + if (handler) { + secure_send_item *item = (secure_send_item *)coap_malloc(sizeof(secure_send_item)); + item->orig_user_data = message->user; + item->orig_handler = handler; + memcpy(item->pk_dn, session->pk_dn, PK_DN_CHECKSUM_LEN); + + message->handler = secure_sendmsg_handler; + message->user = item; + } + + if (observe == 0) { + CoAPUintOption_add(message, COAP_OPTION_OBSERVE, observe); + } + CoAPUintOption_add(message, COAP_OPTION_CONTENT_FORMAT, COAP_CT_APP_OCTET_STREAM); + CoAPUintOption_add(message, COAP_OPTION_SESSIONID, session->sessionId); + COAP_DEBUG("secure_send sessionId:%d", session->sessionId); + + encryptlen = (message->payloadlen & 0xfffffff0) + 16; + if (encryptlen > 64) { + char *buf = (char *)coap_malloc(encryptlen); + int rt = do_secure_send(ctx, addr, message, session->sessionKey, buf); + coap_free(buf); + return rt; + } else { + char buf[64]; + return do_secure_send(ctx, addr, message, session->sessionKey, buf); + } +} + +static void call_cb(CoAPContext *context, NetworkAddr *remote, CoAPMessage *message, const char *key, char *buf, + secure_send_item *send_item) +{ + if (send_item->orig_handler) { + int len = alcs_decrypt((const char *)message->payload, message->payloadlen, key, buf); + CoAPMessage tmpMsg; + memcpy(&tmpMsg, message, sizeof(CoAPMessage)); + tmpMsg.payload = (unsigned char *)buf; + tmpMsg.payloadlen = len; + send_item->orig_handler(context, COAP_REQUEST_SUCCESS, send_item->orig_user_data, remote, &tmpMsg); + } +} + +void secure_sendmsg_handler(CoAPContext *context, CoAPReqResult result, void *userdata, NetworkAddr *remote, + CoAPMessage *message) +{ + secure_send_item *send_item = (secure_send_item *)userdata; + session_item *session = NULL; + unsigned int obsVal; + + if (!context || !userdata || !remote) { + return; + } + if (result == COAP_RECV_RESP_TIMEOUT) { + if (send_item->orig_handler) { + send_item->orig_handler(context, COAP_RECV_RESP_TIMEOUT, send_item->orig_user_data, remote, NULL); + } + COAP_INFO("secure_sendmsg_handler timeout"); + } else { + unsigned int sessionId = 0; + CoAPUintOption_get(message, COAP_OPTION_SESSIONID, &sessionId); + COAP_DEBUG("secure_sendmsg_handler, sessionID:%d", (int)sessionId); + + session = get_auth_session_by_checksum(context, remote, send_item->pk_dn); + + if (!session || session->sessionId != sessionId) { + COAP_ERR("secure_sendmsg_handler, need auth, from:%s", remote->addr); + /* todo */ + } else { + session->heart_time = HAL_UptimeMs(); + if (message->payloadlen < 128) { + char buf[128]; + call_cb(context, remote, message, session->sessionKey, buf, send_item); + } else { + char *buf = (char *)coap_malloc(message->payloadlen); + if (buf) { + call_cb(context, remote, message, session->sessionKey, buf, send_item); + coap_free(buf); + } + } + } + } + + if (CoAPUintOption_get(message, COAP_OPTION_OBSERVE, &obsVal) != COAP_SUCCESS) { + coap_free(send_item); + } +} + +int alcs_sendmsg_secure(CoAPContext *ctx, AlcsDeviceKey *devKey, CoAPMessage *message, char observe, + CoAPSendMsgHandler handler) +{ + session_item *session = NULL; + + if (!ctx || !devKey || !message) { + return COAP_ERROR_INVALID_PARAM; + } + + session = get_auth_session(ctx, devKey); + if (!session) { + COAP_DEBUG("alcs_sendmsg_secure, session not found"); + return ALCS_ERR_AUTH_UNAUTH; + } + + return internal_secure_send(ctx, session, &devKey->addr, message, observe, handler); +} + +int alcs_sendrsp_secure(CoAPContext *ctx, AlcsDeviceKey *devKey, CoAPMessage *message, char observe, + unsigned short msgid, CoAPLenString *token) +{ + session_item *session = NULL; + + COAP_DEBUG("alcs_sendrsp_secure"); + if (!ctx || !devKey || !message) { + return COAP_ERROR_INVALID_PARAM; + } + + if (msgid == 0) { + message->header.msgid = CoAPMessageId_gen(ctx); + } else { + message->header.msgid = msgid; + } + + if (token) { + message->header.tokenlen = token->len; + memcpy(&message->token, token->data, token->len); + } + + session = get_auth_session(ctx, devKey); + if (!session) { + COAP_DEBUG("alcs_sendrsp_secure, session not found"); + return ALCS_ERR_AUTH_UNAUTH; + } + + return internal_secure_send(ctx, session, &devKey->addr, message, observe, NULL); +} + +bool req_payload_parser(const char *payload, int len, char **seq, int *seqlen, char **data, int *datalen) +{ + if (!payload || !len || !seq || !seqlen || !datalen || !data) { + return 0; + } + + *seq = json_get_value_by_name((char *)payload, len, "id", seqlen, NULL); + + *data = json_get_value_by_name((char *)payload, len, "params", datalen, NULL); + return *data && datalen; +} + +void on_auth_timer(void *param) +{ + CoAPContext *ctx = NULL; + if (!is_inited) { + return; + } + + ctx = (CoAPContext *) param; +#ifdef ALCS_CLIENT_ENABLED + { + extern void on_client_auth_timer(CoAPContext *); + on_client_auth_timer(ctx); + } +#endif +#ifdef ALCS_SERVER_ENABLED + { + extern void on_svr_auth_timer(CoAPContext *); + on_svr_auth_timer(ctx); + } +#endif +} + +int alcs_add_ctl_group(CoAPContext *context, const char *groupid, const char *accesskey, const char *accesstoken) +{ + ctl_group_item *item = NULL; + auth_list *lst = get_list(context); + if (!lst || lst->ctl_group_count >= KEY_MAXCOUNT) { + return COAP_ERROR_INVALID_LENGTH; + } + + item = (ctl_group_item *) coap_malloc(sizeof(ctl_group_item)); + if (!item) { + return COAP_ERROR_MALLOC; + } + memset(item, 0, sizeof(ctl_group_item)); + + do { + item->id = (char *) coap_malloc(strlen(groupid) + 1); + if (!item->id) { + break; + } + + item->accessKey = (char *) coap_malloc(strlen(accesskey) + 1); + if (!item->accessKey) { + break; + } + + item->accessToken = (char *) coap_malloc(strlen(accesstoken) + 1); + if (!item->accessToken) { + break; + } + + strcpy(item->accessKey, accesskey); + strcpy(item->accessToken, accesstoken); + strcpy(item->id, groupid); + + HAL_MutexLock(lst->list_mutex); + list_add_tail(&item->lst, &lst->lst_ctl_group); + ++lst->ctl_group_count; + HAL_MutexUnlock(lst->list_mutex); + + return 0; + + } while (0); + + if (item->id) { + coap_free(item->id); + } + if (item->accessKey) { + coap_free(item->accessKey); + } + if (item->accessToken) { + coap_free(item->accessToken); + } + coap_free(item); + + return COAP_ERROR_MALLOC; +} + +int alcs_remove_ctl_group(CoAPContext *context, const char *groupid) +{ + return 0; +} + +int alcs_add_svr_group(CoAPContext *context, const char *groupid, const char *keyprefix, const char *secret) +{ + svr_group_item *item = NULL; + auth_list *lst = get_list(context); + if (!lst || lst->svr_group_count >= KEY_MAXCOUNT) { + return COAP_ERROR_INVALID_LENGTH; + } + + item = (svr_group_item *) coap_malloc(sizeof(svr_group_item)); + if (!item) { + return COAP_ERROR_MALLOC; + } + memset(item, 0, sizeof(svr_group_item)); + + do { + item->id = (char *) coap_malloc(strlen(groupid) + 1); + if (!item->id) { + break; + } + + item->keyInfo.secret = (char *) coap_malloc(strlen(secret) + 1); + if (!item->keyInfo.secret) { + break; + } + + strncpy(item->keyInfo.keyprefix, keyprefix, sizeof(item->keyInfo.keyprefix) - 1); + strcpy(item->keyInfo.secret, secret); + strcpy(item->id, groupid); + + HAL_MutexLock(lst->list_mutex); + list_add_tail(&item->lst, &lst->lst_svr_group); + ++lst->svr_group_count; + HAL_MutexUnlock(lst->list_mutex); + + return 0; + + } while (0); + + if (item->id) { + coap_free(item->id); + } + if (item->keyInfo.secret) { + coap_free(item->keyInfo.secret); + } + coap_free(item); + + return COAP_ERROR_MALLOC; +} + +int alcs_remove_svr_group(CoAPContext *context, const char *groupid) +{ + return 0; +} + +void alcs_utils_md5_hexstr(unsigned char input[16], unsigned char output[32]) +{ + unsigned char idx = 0; + unsigned char output_char = 0; + + for (idx = 0; idx < 16; idx++) { + if (((input[idx] >> 4) & 0x0F) <= 0x09) { + output_char = ((input[idx] >> 4) & 0x0F) + '0'; + } else if (((input[idx] >> 4) & 0x0F) >= 0x0A) { + output_char = ((input[idx] >> 4) & 0x0F) + 'a' - 0x0A; + } + output[2 * idx] = output_char; + + if (((input[idx]) & 0x0F) <= 0x09) { + output_char = ((input[idx]) & 0x0F) + '0'; + } else if (((input[idx]) & 0x0F) >= 0x0A) { + output_char = ((input[idx]) & 0x0F) + 'a' - 0x0A; + } + output[2 * idx + 1] = output_char; + } +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_api.h new file mode 100644 index 00000000..cdeb96ed --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_api.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#include "alcs_coap.h" + +#ifndef __ALCS_API_H__ +#define __ALCS_API_H__ + +#define SESSIONID_LEN 8 +#define SESSIONKEY_MAXLEN 30 + +#define ALCS_ERR_AUTH_BASE (COAP_ERROR_BASE | 100) +#define ALCS_ERR_AUTH_AUTHING (ALCS_ERR_AUTH_BASE | 1) +#define ALCS_ERR_AUTH_NOCTLKEY (ALCS_ERR_AUTH_BASE | 2) +#define ALCS_ERR_AUTH_UNAUTH (ALCS_ERR_AUTH_BASE | 3) +#define ALCS_ERR_ENCRYPT_FAILED (ALCS_ERR_AUTH_BASE | 5) + +typedef enum { + ALCS_AUTH_OK = 200, + ALCS_AUTH_REVOCATE = 501, + ALCS_AUTH_UNMATCHPREFIX, + ALCS_AUTH_INVALIDPARAM, + ALCS_AUTH_AUTHLISTEMPTY, + ALCS_AUTH_VERNOTSUPPORT, + ALCS_AUTH_ILLEGALSIGN, + ALCS_HEART_FAILAUTH, +} Auth_Result_Code; + +#include "iotx_alcs_config.h" + +typedef struct { + int code; + char *msg;/* MUST call coap_free to free memory */ +} ResponseMsg; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* +typedef struct +{ + ResponseMsg msg; + char sessionId [SESSIONID_LEN]; + char sessionKey[SESSIONKEY_MAXLEN]; + NetworkAddr addr; +} AuthResult; +*/ + +typedef void (*AuthHandler)(CoAPContext *context, NetworkAddr *addr, void *user_data, ResponseMsg *result); +typedef struct { + char *productKey; + char *deviceName; + char *accessKey; + char *accessToken; + void *user_data; + AuthHandler handler; +} AuthParam; + +typedef struct { + NetworkAddr addr; + char *pk; + char *dn; +} AlcsDeviceKey; + +/* 初始化认证模块 + * context: 为当前设备生成的CoAPContext对象指针 + * productKey:当前设备的productKey,可以为空 + * deviceName: 当前设备的deviceName,可以为空 + * role: 1 --client + * 2 --server + * 3 --client&server + */ +int alcs_auth_init(CoAPContext *context, const char *productKey, const char *deviceName, char role); +void alcs_auth_subdev_init(CoAPContext *ctx, const char *productKey, const char *deviceName); +void alcs_auth_deinit(void); + +bool alcs_is_auth(CoAPContext *ctx, AlcsDeviceKey *devKey); +int alcs_sendmsg_secure(CoAPContext *ctx, AlcsDeviceKey *devKey, CoAPMessage *message, char observe, + CoAPSendMsgHandler handler); +int alcs_sendrsp_secure(CoAPContext *ctx, AlcsDeviceKey *devKey, CoAPMessage *message, char observe, + unsigned short msgid, CoAPLenString *token); + +#ifdef ALCS_CLIENT_ENABLED +/* 身份认证-- 直接传入accesskey&accesstoken + * context: 当前设备生成的CoAPContext对象指针 + * addr: 待连设备地址 + * auth_param:包含待连设备的信息和回调接口 + */ +void alcs_auth_has_key(CoAPContext *ctx, NetworkAddr *addr, AuthParam *auth_param); + +/* 身份认证--通过productkey&devicename在缓存的accesskey列表中查找合适accesskey + * 此函数需要和alcs_add_client_key 配合使用 + * 若不知道准确的accessKey,认证前client会和server协商合适的accessKey + * + * context: 为当前设备生成的CoAPContext对象指针 + * addr: 待连设备地址 + * productKey:待连设备的productKey + * deviceName:待连设备的deviceName + * handler: 结果回调接口 + */ +void alcs_auth_nego_key(CoAPContext *ctx, AlcsDeviceKey *devKey, AuthHandler handler); +/* + * + * + */ +int alcs_add_client_key(CoAPContext *context, const char *accesskey, const char *accesstoken, const char *productKey, + const char *deviceName); +int alcs_remove_client_key(CoAPContext *context, const char *key, char isfullkey); +/* + * + * + */ +bool alcs_device_online(CoAPContext *context, AlcsDeviceKey *devKey); + +#endif + +#ifdef ALCS_SERVER_ENABLED +typedef enum { + LOCALDEFAULT, + LOCALSETUP, + FROMCLOUDSVR +} ServerKeyPriority; + +int alcs_add_svr_key(CoAPContext *context, const char *keyprefix, const char *secret, ServerKeyPriority priority); +int alcs_remove_svr_key(CoAPContext *context, const char *keyprefix); +/* 设置吊销列表* +* context: 为当前设备生成的CoAPContext对象指针 +* seqlist: 吊销列表字符串,每个被吊销设备占用三字节 +*/ +int alcs_set_revocation(CoAPContext *context, const char *seqlist); +#endif + +int alcs_add_ctl_group(CoAPContext *context, const char *groupid, const char *accesskey, const char *accesstoken); +int alcs_remove_ctl_group(CoAPContext *context, const char *groupid); + +int alcs_add_svr_group(CoAPContext *context, const char *groupid, const char *keyprefix, const char *secret); +int alcs_remove_svr_group(CoAPContext *context, const char *groupid); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_api_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_api_internal.h new file mode 100644 index 00000000..31adbab5 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_api_internal.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __ALCS_API_INTERNAL_H__ +#define __ALCS_API_INTERNAL_H__ +#include "CoAPExport.h" +#include "alcs_api.h" +#include "alcs_internal.h" + +#define KEY_MAXCOUNT 10 +#define RANDOMKEY_LEN 16 +#define KEYSEQ_LEN 3 +#define COAP_OPTION_SESSIONID 71 + +#ifdef ALCS_CLIENT_ENABLED +typedef struct { + char *accessKey; + char *accessToken; + char *deviceName; + char *productKey; + struct list_head lst; +} ctl_key_item; +#endif + +#ifdef ALCS_SERVER_ENABLED + +typedef struct { + char keyprefix[KEYPREFIX_LEN + 1]; + char *secret; + ServerKeyPriority priority; +} svr_key_info; + +typedef struct { + svr_key_info keyInfo; + struct list_head lst; +} svr_key_item; + +typedef struct { + char *id; + char *revocation; + svr_key_info keyInfo; + struct list_head lst; +} svr_group_item; +#endif + +typedef struct { + char *id; + char *accessKey; + char *accessToken; + struct list_head lst; +} ctl_group_item; + +typedef struct { + void *list_mutex; +#ifdef ALCS_CLIENT_ENABLED + struct list_head lst_ctl; + unsigned char ctl_count; +#endif +#ifdef ALCS_SERVER_ENABLED + struct list_head lst_svr; + unsigned char svr_count; + char *revocation; +#endif + struct list_head lst_ctl_group; + int ctl_group_count; + struct list_head lst_svr_group; + int svr_group_count; +} auth_list; + +#define PK_DN_CHECKSUM_LEN 6 +typedef struct { + char randomKey[RANDOMKEY_LEN + 1]; + int sessionId; + char sessionKey[32]; + int authed_time; + int heart_time; + int interval; + NetworkAddr addr; + char pk_dn[PK_DN_CHECKSUM_LEN]; + struct list_head lst; +} session_item; + +#define ROLE_SERVER 2 +#define ROLE_CLIENT 1 + +typedef struct { + CoAPContext *context; + int seq; + auth_list lst_auth; +#ifdef ALCS_SERVER_ENABLED + struct list_head lst_svr_sessions; +#endif +#ifdef ALCS_CLIENT_ENABLED + struct list_head lst_ctl_sessions; +#endif + char role; + struct list_head lst; +} device_auth_list; + +#ifdef SUPPORT_MULTI_DEVICES + extern struct list_head device_list; + + device_auth_list *get_device(CoAPContext *context); + + auth_list *get_list(CoAPContext *context); + + #ifdef ALCS_CLIENT_ENABLED + struct list_head *get_ctl_session_list(CoAPContext *context); + #endif + + #ifdef ALCS_SERVER_ENABLED + struct list_head *get_svr_session_list(CoAPContext *context); + #endif + +#else + extern device_auth_list _device; + #define get_device(v) (&_device) + + #ifdef ALCS_SERVER_ENABLED + #define get_svr_session_list(v) (_device.role&ROLE_SERVER? &_device.lst_svr_sessions : NULL) + #endif + #ifdef ALCS_CLIENT_ENABLED + #define get_ctl_session_list(v) (_device.role&ROLE_CLIENT? &_device.lst_ctl_sessions : NULL) + #endif + + #define get_list(v) (&_device.lst_auth) +#endif + +void remove_session(CoAPContext *ctx, session_item *session); + +#ifdef ALCS_CLIENT_ENABLED + session_item *get_ctl_session(CoAPContext *ctx, AlcsDeviceKey *key); +#endif + +#ifdef ALCS_SERVER_ENABLED +session_item *get_svr_session(CoAPContext *ctx, AlcsDeviceKey *key); +session_item *get_session_by_checksum(struct list_head *sessions, NetworkAddr *addr, char ck[PK_DN_CHECKSUM_LEN]); + +#define MAX_PATH_CHECKSUM_LEN (5) +typedef struct { + char path[MAX_PATH_CHECKSUM_LEN]; + char pk_dn[PK_DN_CHECKSUM_LEN]; + char *filter_path; + path_type_t path_type; + CoAPRecvMsgHandler cb; + struct list_head lst; +} secure_resource_cb_item; + +extern struct list_head secure_resource_cb_head; +#endif + +int alcs_encrypt(const char *src, int len, const char *key, void *out); +int alcs_decrypt(const char *src, int len, const char *key, void *out); +int observe_data_encrypt(CoAPContext *ctx, const char *paths, NetworkAddr *addr, + CoAPMessage *message, CoAPLenString *src, CoAPLenString *dest); + +bool is_networkadd_same(NetworkAddr *addr1, NetworkAddr *addr2); +void gen_random_key(unsigned char random[], int len); +bool req_payload_parser(const char *payload, int len, char **seq, int *seqlen, char **data, int *datalen); +int internal_secure_send(CoAPContext *ctx, session_item *session, NetworkAddr *addr, + CoAPMessage *message, char observe, CoAPSendMsgHandler handler); + +int alcs_resource_register_secure(CoAPContext *context, const char *pk, const char *dn, const char *path, + unsigned short permission, + unsigned int ctype, unsigned int maxage, CoAPRecvMsgHandler callback); +void alcs_resource_cb_deinit(void); +void alcs_auth_list_deinit(void); +void alcs_utils_md5_hexstr(unsigned char input[16], unsigned char output[32]); + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_base64.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_base64.c new file mode 100644 index 00000000..3f4a3d27 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_base64.c @@ -0,0 +1,132 @@ + +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include +#include +#include "infra_types.h" +#include "infra_defs.h" +#include "alcs_base64.h" + +static int8_t g_encodingTable[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' + }; + +static int8_t g_decodingTable[256]; +static int32_t g_modTable[] = { 0, 2, 1 }; + +static void build_decoding_table() +{ + static int32_t signal = 0; + int32_t i = 0; + + if (signal != 0) { + return; + } + + for (i = 0; i < 64; i++) { + g_decodingTable[(uint8_t) g_encodingTable[i]] = i; + } + + signal = 1; + return; +} + +int utils_base64encode(const uint8_t *data, uint32_t inputLength, uint32_t outputLenMax, + uint8_t *encodedData, uint32_t *outputLength) +{ + uint32_t i = 0; + uint32_t j = 0; + + if (NULL == encodedData) { + return FAIL_RETURN; + } + + *outputLength = 4 * ((inputLength + 2) / 3); + + if (outputLenMax < *outputLength) { + return FAIL_RETURN; + } + + for (i = 0, j = 0; i < inputLength;) { + uint32_t octet_a = i < inputLength ? (uint8_t) data[i++] : 0; + uint32_t octet_b = i < inputLength ? (uint8_t) data[i++] : 0; + uint32_t octet_c = i < inputLength ? (uint8_t) data[i++] : 0; + + uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + + encodedData[j++] = g_encodingTable[(triple >> 3 * 6) & 0x3F]; + encodedData[j++] = g_encodingTable[(triple >> 2 * 6) & 0x3F]; + encodedData[j++] = g_encodingTable[(triple >> 1 * 6) & 0x3F]; + encodedData[j++] = g_encodingTable[(triple >> 0 * 6) & 0x3F]; + } + + for (i = 0; i < g_modTable[inputLength % 3]; i++) { + encodedData[*outputLength - 1 - i] = '='; + } + + return SUCCESS_RETURN; +} + +int utils_base64decode(const uint8_t *data, uint32_t inputLength, uint32_t outputLenMax, + uint8_t *decodedData, uint32_t *outputLength) +{ + uint32_t i = 0; + uint32_t j = 0; + uint32_t sextet_a = 0; + uint32_t sextet_b = 0; + uint32_t sextet_c = 0; + uint32_t sextet_d = 0; + uint32_t triple = 0; + + build_decoding_table(); + + if (inputLength % 4 != 0) { + return FAIL_RETURN; + } + + *outputLength = inputLength / 4 * 3; + + + if (data[inputLength - 1] == '=') { + (*outputLength)--; + } + + if (data[inputLength - 2] == '=') { + (*outputLength)--; + } + + if (outputLenMax < *outputLength) { + return FAIL_RETURN; + } + + for (i = 0, j = 0; i < inputLength;) { + sextet_a = data[i] == '=' ? 0 & i++ : g_decodingTable[data[i++]]; + sextet_b = data[i] == '=' ? 0 & i++ : g_decodingTable[data[i++]]; + sextet_c = data[i] == '=' ? 0 & i++ : g_decodingTable[data[i++]]; + sextet_d = data[i] == '=' ? 0 & i++ : g_decodingTable[data[i++]]; + + triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6); + + if (j < *outputLength) { + decodedData[j++] = (triple >> 2 * 8) & 0xFF; + } + + if (j < *outputLength) { + decodedData[j++] = (triple >> 1 * 8) & 0xFF; + } + + if (j < *outputLength) { + decodedData[j++] = (triple >> 0 * 8) & 0xFF; + } + } + + return SUCCESS_RETURN; +} \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_base64.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_base64.h new file mode 100644 index 00000000..6912a09f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_base64.h @@ -0,0 +1,10 @@ +#ifndef _ALCS_BASE64_H_ +#define _ALCS_BASE64_H_ + +#include "infra_types.h" + +int utils_base64encode(const uint8_t *data, uint32_t inputLength, uint32_t outputLenMax, + uint8_t *encodedData, uint32_t *outputLength); +int utils_base64decode(const uint8_t *data, uint32_t inputLength, uint32_t outputLenMax, + uint8_t *decodedData, uint32_t *outputLength); +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_client.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_client.c new file mode 100644 index 00000000..54313bde --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_client.c @@ -0,0 +1,587 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "alcs_internal.h" +#include "alcs_api_internal.h" +#include "CoAPPlatform.h" +#include "CoAPResource.h" + +#ifdef ALCS_CLIENT_ENABLED +static int default_heart_interval = 30000; +char match_key(const char *accesskey, const char *keyprefix) +{ + if (strlen(keyprefix) == KEYPREFIX_LEN && strstr(accesskey, keyprefix) == accesskey) { + return 1; + } + + return 0; +} + +int do_auth(CoAPContext *ctx, NetworkAddr *addr, ctl_key_item *ctl_item, void *userdata, AuthHandler handler); +bool res_parse(const char *payload, int len, int *seq, ResponseMsg *res_msg, char **data, int *datalen) +{ + if (!payload || !len || !seq || !res_msg || !data) { + return 0; + } + + COAP_DEBUG("payload:%.*s", len, payload); + + int tmplen; + char *tmp; + + tmp = json_get_value_by_name((char *)payload, len, "id", &tmplen, NULL); + if (!tmp) { + return 0; + } + + char back; + backup_json_str_last_char(tmp, tmplen, back); + *seq = atoi(tmp); + restore_json_str_last_char(tmp, tmplen, back); + + tmp = json_get_value_by_name((char *)payload, len, "code", &tmplen, NULL); + if (!tmp) { + return 0; + } + + backup_json_str_last_char(tmp, tmplen, back); + res_msg->code = atoi(tmp); + restore_json_str_last_char(tmp, tmplen, back); + + tmp = json_get_value_by_name((char *)payload, len, "msg", &tmplen, NULL); + if (tmp && tmplen) { + res_msg->msg = (char *)coap_malloc(tmplen); + memcpy(res_msg->msg, tmp, tmplen); + } else { + res_msg->msg = NULL; + } + + *data = json_get_value_by_name((char *)payload, len, "data", datalen, NULL); + return 1; +} + +bool fillAccessKey(CoAPContext *ctx, char *buf) +{ + auth_list *lst = get_list(ctx); + if (!lst) { + return 0; + } + + HAL_MutexLock(lst->list_mutex); + + if (list_empty(&lst->lst_ctl)) { + HAL_MutexUnlock(lst->list_mutex); + return 0; + } + strcpy(buf, ",\"accessKeys\":["); + ctl_key_item *node = NULL, *next = NULL; + list_for_each_entry_safe(node, next, &lst->lst_ctl, lst, ctl_key_item) { + char *format; + if (lst->ctl_group_count || !list_is_last(&node->lst, &lst->lst_ctl)) { + format = "\"%s\","; + } else { + format = "\"%s\"]"; + } + sprintf(buf + strlen(buf), format, node->accessKey); + } + + ctl_group_item *gnode = NULL, *gnext = NULL; + list_for_each_entry_safe(gnode, gnext, &lst->lst_ctl_group, lst, ctl_group_item) { + char *format; + if (!list_is_last(&gnode->lst, &lst->lst_ctl_group)) { + format = "\"%s\","; + } else { + format = "\"%s\"]"; + } + sprintf(buf + strlen(buf), format, gnode->accessKey); + } + + HAL_MutexUnlock(lst->list_mutex); + return 1; +} + +#define payload_format "{\"version\":\"1.0\",\"method\":\"%s\",\"id\":%d,\"params\":{\"prodKey\":\"%s\", \"deviceName\":\"%s\"%s}}" +void nego_cb(CoAPContext *ctx, CoAPReqResult result, void *userdata, NetworkAddr *remote, CoAPMessage *message) +{ + COAP_INFO("nego_cb, message addr:%p, networkaddr:%p!", message, remote); + AuthParam *auth_param = (AuthParam *)userdata; + + if (COAP_RECV_RESP_TIMEOUT == result) { + ResponseMsg msg = {-1, "response time!"}; + auth_param->handler(ctx, remote, auth_param->user_data, &msg); + coap_free(auth_param->productKey); + coap_free(auth_param->deviceName); + coap_free(auth_param); + + } else { + COAP_DEBUG("recv response message"); + int seq, datalen; + ResponseMsg msg; + char *data; + + res_parse((const char *)message->payload, message->payloadlen, &seq, &msg, &data, &datalen); + do { + if (msg.code != 200) { + break; + } + + int keylen; + char *accessKey = json_get_value_by_name(data, datalen, "accessKey", &keylen, NULL); + if (!accessKey || !keylen) { + break; + } + COAP_DEBUG("accesskey:%.*s", keylen, accessKey); + + auth_list *lst = get_list(ctx); + ctl_key_item *node = NULL, *next = NULL; + char *accessTokenFound = NULL; + HAL_MutexLock(lst->list_mutex); + + list_for_each_entry_safe(node, next, &lst->lst_ctl, lst, ctl_key_item) { + COAP_DEBUG("node:%s", node->accessKey); + if (strncmp(node->accessKey, accessKey, keylen) == 0) { + accessTokenFound = node->accessToken; + break; + } + } + + if (!accessTokenFound) { + ctl_group_item *gnode = NULL, *gnext = NULL; + list_for_each_entry_safe(gnode, gnext, &lst->lst_ctl_group, lst, ctl_group_item) { + COAP_DEBUG("node:%s", gnode->accessKey); + if (strncmp(gnode->accessKey, accessKey, keylen) == 0) { + accessTokenFound = gnode->accessKey; + break; + } + } + } + + HAL_MutexUnlock(lst->list_mutex); + + if (accessTokenFound) { + ctl_key_item item; + item.deviceName = auth_param->deviceName; + item.productKey = auth_param->productKey; + + item.accessKey = accessKey; + item.accessToken = accessTokenFound; + char back; + backup_json_str_last_char(accessKey, keylen, back); + do_auth(ctx, remote, &item, auth_param->user_data, auth_param->handler); + restore_json_str_last_char(accessKey, keylen, back); + + coap_free(auth_param->productKey); + coap_free(auth_param->deviceName); + coap_free(auth_param); + return; + } + } while (0); + + /* todo */ + ResponseMsg tmp = {-1, ""}; + auth_param->handler(ctx, remote, auth_param->user_data, &tmp); + coap_free(auth_param->productKey); + coap_free(auth_param->deviceName); + coap_free(auth_param); + + } +} + +static int CoAPServerPath_2_option(char *uri, CoAPMessage *message) +{ + char *ptr = NULL; + char *pstr = NULL; + char path[COAP_MSG_MAX_PATH_LEN] = {0}; + + if (NULL == uri || NULL == message) { + COAP_ERR("Invalid paramter p_path %p, p_message %p", uri, message); + return COAP_ERROR_INVALID_PARAM; + } + if (256 < strlen(uri)) { + COAP_ERR("The uri length is too loog,len = %d", (int)strlen(uri)); + return COAP_ERROR_INVALID_LENGTH; + } + COAP_DEBUG("The uri is %s", uri); + ptr = pstr = uri; + while ('\0' != *ptr) { + if ('/' == *ptr) { + if (ptr != pstr) { + memset(path, 0x00, sizeof(path)); + strncpy(path, pstr, ptr - pstr); + COAP_DEBUG("path: %s,len=%d", path, (int)(ptr - pstr)); + CoAPStrOption_add(message, COAP_OPTION_URI_PATH, + (unsigned char *)path, (int)strlen(path)); + } + pstr = ptr + 1; + + } + if ('\0' == *(ptr + 1) && '\0' != *pstr) { + memset(path, 0x00, sizeof(path)); + strncpy(path, pstr, sizeof(path) - 1); + COAP_DEBUG("path: %s,len=%d", path, (int)strlen(path)); + CoAPStrOption_add(message, COAP_OPTION_URI_PATH, + (unsigned char *)path, (int)strlen(path)); + } + ptr ++; + } + return COAP_SUCCESS; +} + +void auth_cb(CoAPContext *ctx, CoAPReqResult result, void *userdata, NetworkAddr *remote, CoAPMessage *message) +{ + AlcsDeviceKey devKey; + COAP_DEBUG("recv auth_cb response message"); + + AuthParam *auth_param = (AuthParam *)userdata; + memset(&devKey, 0x00, sizeof(AlcsDeviceKey)); + memcpy(&devKey.addr, remote, sizeof(NetworkAddr)); + devKey.pk = auth_param->productKey; + devKey.dn = auth_param->deviceName; + session_item *session = get_ctl_session(ctx, &devKey); + + if (!session) { + COAP_INFO("receive unknown auth_cb response, pk:%s, dn:%s", devKey.pk, devKey.dn); + ResponseMsg msg = {-1, "no session found!"}; + auth_param->handler(ctx, remote, auth_param->user_data, &msg); + } else if (COAP_RECV_RESP_TIMEOUT == result) { + COAP_ERR("response time!"); + ResponseMsg msg = {-1, "response time!"}; + auth_param->handler(ctx, remote, auth_param->user_data, &msg); + remove_session(ctx, session); + } else { + int seq, datalen; + ResponseMsg msg; + char *data; + + res_parse((const char *)message->payload, message->payloadlen, &seq, &msg, &data, &datalen); + if (msg.code == 200) { + do { + int tmplen; + char *tmp; + + tmp = json_get_value_by_name(data, datalen, "sessionId", &tmplen, NULL); + if (!tmp) { + msg.code = -1; + msg.msg = "sessionid = NULL!"; + COAP_ERR("sessionid = NULL!"); + auth_param->handler(ctx, remote, auth_param->user_data, &msg); + break; + } + char back; + backup_json_str_last_char(tmp, tmplen, back); + session->sessionId = atoi(tmp); + restore_json_str_last_char(tmp, tmplen, back); + COAP_INFO("sessionId:%d", session->sessionId); + + tmp = json_get_value_by_name(data, datalen, "randomKey", &tmplen, NULL); + if (!tmp) { + msg.code = -1; + msg.msg = "randomKey = NULL!"; + COAP_ERR("randomKey = NULL!"); + auth_param->handler(ctx, remote, auth_param->user_data, &msg); + break; + } + + char buf[32]; + HAL_Snprintf(buf, sizeof(buf), "%s%.*s", session->randomKey, tmplen, tmp); + utils_hmac_sha1_hex(buf, strlen(buf), session->sessionKey, auth_param->accessToken, strlen(auth_param->accessToken)); + session->authed_time = HAL_UptimeMs(); + session->heart_time = session->authed_time; + session->interval = default_heart_interval; + COAP_INFO("sessionKey is created"); + } while (0); + } else { + remove_session(ctx, session); + COAP_ERR("message code :%d", msg.code); + } + auth_param->handler(ctx, remote, auth_param->user_data, &msg); + } + + coap_free(auth_param->productKey); + coap_free(auth_param->deviceName); + coap_free(auth_param->accessToken); + coap_free(auth_param); +} + +#define auth_payload_format "{\"version\":\"1.0\",\"method\":\"core/service/auth\",\"id\":%d,\"params\":{\"prodKey\":\"%s\", \"deviceName\":\"%s\",\"encrypt\":\"payload\",\"randomKey\":\"%s\",\"sign\":\"%s\",\"accessKey\":\"%s\"}}" + +int do_auth(CoAPContext *ctx, NetworkAddr *addr, ctl_key_item *ctl_item, void *user_data, AuthHandler handler) +{ + int ret = COAP_SUCCESS; + AlcsDeviceKey devKey; + device_auth_list *dev = get_device(ctx); + if (!dev) { + return COAP_ERROR_INVALID_PARAM; + } + + memset(&devKey, 0x00, sizeof(AlcsDeviceKey)); + memcpy(&devKey.addr, addr, sizeof(NetworkAddr)); + devKey.pk = ctl_item->productKey; + devKey.dn = ctl_item->deviceName; + + session_item *session = get_ctl_session(ctx, &devKey); + if (session) { + if (session->sessionId) { + COAP_INFO("no need to reauth!"); + ResponseMsg res = {COAP_SUCCESS, NULL}; + handler(ctx, addr, user_data, &res); + return COAP_SUCCESS; + } else { + COAP_INFO("is authing, no need to reauth!"); + return ALCS_ERR_AUTH_AUTHING; + } + } + + /* create&save session item */ + { + session = (session_item *)coap_malloc(sizeof(session_item)); + memset(session, 0, sizeof(session_item)); + + char path[100] = {0}; + strncpy(path, ctl_item->productKey, sizeof(path) - 1); + strncat(path, ctl_item->deviceName, sizeof(path) - strlen(path) - 1); + CoAPPathMD5_sum(path, strlen(path), session->pk_dn, PK_DN_CHECKSUM_LEN); + COAP_INFO("pk:%s, dn:%s, checksum:%s", devKey.pk, devKey.dn, session->pk_dn); + memcpy(&session->addr, addr, sizeof(NetworkAddr)); + gen_random_key((unsigned char *)session->randomKey, RANDOMKEY_LEN); + + struct list_head *ctl_head = get_ctl_session_list(ctx); + list_add_tail(&session->lst, ctl_head); + } + + char sign[64] = {0}; + int sign_len = sizeof(sign); + utils_hmac_sha1_base64(session->randomKey, RANDOMKEY_LEN, ctl_item->accessToken, + strlen(ctl_item->accessToken), sign, &sign_len); + COAP_INFO("calc randomKey:%s,token:%s,sign:%.*s", session->randomKey, ctl_item->accessToken, sign_len, sign); + + char payloadbuf[512]; + sprintf(payloadbuf, auth_payload_format, ++dev->seq, ctl_item->productKey, ctl_item->deviceName, session->randomKey, + sign, ctl_item->accessKey); + COAP_INFO("payload:%s", payloadbuf); + + CoAPLenString payload; + payload.data = (unsigned char *)payloadbuf; + payload.len = strlen(payloadbuf); + CoAPMessage message; + alcs_msg_init(ctx, &message, COAP_MSG_CODE_GET, COAP_MESSAGE_TYPE_CON, 0, &payload, NULL); + + char path[120]; + sprintf(path, "/dev/%s/%s/core/service/auth", ctl_item->productKey, ctl_item->deviceName); + CoAPServerPath_2_option(path, &message); + + AuthParam *authParam = (AuthParam *) coap_malloc(sizeof(AuthParam)); + authParam->handler = handler; + authParam->user_data = user_data; + authParam->productKey = (char *) coap_malloc(strlen(ctl_item->productKey) + 1); + strcpy(authParam->productKey, ctl_item->productKey); + authParam->deviceName = (char *) coap_malloc(strlen(ctl_item->deviceName) + 1); + strcpy(authParam->deviceName, ctl_item->deviceName); + authParam->accessToken = (char *) coap_malloc(strlen(ctl_item->accessToken) + 1); + strcpy(authParam->accessToken, ctl_item->accessToken); + message.user = authParam; + message.handler = auth_cb; + + ret = CoAPMessage_send(ctx, addr, &message); + CoAPMessage_destory(&message); + + return ret; +} + +void alcs_auth_has_key(CoAPContext *ctx, NetworkAddr *addr, AuthParam *auth_param) +{ + ctl_key_item item; + item.accessKey = auth_param->accessKey; + item.deviceName = auth_param->deviceName; + item.productKey = auth_param->productKey; + item.accessToken = auth_param->accessToken;/* (char*) coap_malloc (strlen(auth_param->accessToken) + 1); */ + /* strcpy (item.accessToken, auth_param->accessToken); */ + do_auth(ctx, addr, &item, auth_param->user_data, auth_param->handler); +} + +void alcs_auth_nego_key(CoAPContext *ctx, AlcsDeviceKey *devKey, AuthHandler handler) +{ + COAP_DEBUG("alcs_auth_nego_key"); + + device_auth_list *dev = get_device(ctx); + if (!dev) { + COAP_INFO("no device!"); + return; + } + + char accesskeys[1024] = {0}; + if (!fillAccessKey(ctx, accesskeys)) { + COAP_INFO("no ctl key!"); + return; + } + COAP_INFO("accesskeys:%s", accesskeys); + + const char *method = "core/service/auth/select"; + char payloadbuf[1024]; + sprintf(payloadbuf, payload_format, method, ++dev->seq, devKey->pk, devKey->dn, accesskeys); + + CoAPLenString payload; + payload.data = (unsigned char *)payloadbuf; + payload.len = strlen(payloadbuf); + CoAPMessage message; + alcs_msg_init(ctx, &message, COAP_MSG_CODE_GET, COAP_MESSAGE_TYPE_CON, 0, &payload, NULL); + + char path[120]; + sprintf(path, "/dev/%s/%s/core/service/auth/select", devKey->pk, devKey->dn); + CoAPServerPath_2_option(path, &message); + + AuthParam *authParam = (AuthParam *) coap_malloc(sizeof(AuthParam)); + memset(authParam, 0, sizeof(AuthParam)); + + authParam->handler = handler; + authParam->productKey = (char *) coap_malloc(strlen(devKey->pk) + 1); + strcpy(authParam->productKey, devKey->pk); + authParam->deviceName = (char *) coap_malloc(strlen(devKey->dn) + 1); + strcpy(authParam->deviceName, devKey->dn); + + message.user = authParam; + message.handler = nego_cb; + CoAPMessage_send(ctx, &devKey->addr, &message); + CoAPMessage_destory(&message); +} + +int alcs_add_client_key(CoAPContext *ctx, const char *accesskey, const char *accesstoken, const char *productKey, + const char *deviceName) +{ + auth_list *lst = get_list(ctx); + if (!lst || lst->ctl_count >= KEY_MAXCOUNT) { + return COAP_ERROR_INVALID_LENGTH; + } + + ctl_key_item *item = (ctl_key_item *) coap_malloc(sizeof(ctl_key_item)); + if (!item) { + return COAP_ERROR_MALLOC; + } + item->accessKey = (char *) coap_malloc(strlen(accesskey) + 1); + item->accessToken = (char *) coap_malloc(strlen(accesstoken) + 1); + + if (!item->accessKey || !item->accessToken) { + coap_free(item); + return COAP_ERROR_MALLOC; + } + strcpy(item->accessKey, accesskey); + strcpy(item->accessToken, accesstoken); + + if (deviceName) { + item->deviceName = (char *) coap_malloc(strlen(deviceName) + 1); + strcpy(item->deviceName, deviceName); + } + + HAL_MutexLock(lst->list_mutex); + list_add_tail(&item->lst, &lst->lst_ctl); + ++lst->ctl_count; + HAL_MutexUnlock(lst->list_mutex); + + return COAP_SUCCESS; +} + +int alcs_remove_client_key(CoAPContext *ctx, const char *key, char isfullkey) +{ + auth_list *lst = get_list(ctx); + if (!lst) { + return COAP_ERROR_NULL; + } + + ctl_key_item *node = NULL, *next = NULL; + HAL_MutexLock(lst->list_mutex); + + list_for_each_entry_safe(node, next, &lst->lst_ctl, lst, ctl_key_item) { + if (match_key(node->accessKey, key)) { + coap_free(node->accessKey); + coap_free(node->accessToken); + list_del(&node->lst); + coap_free(node); + break; + } + } + HAL_MutexUnlock(lst->list_mutex); + return COAP_SUCCESS; +} + +bool alcs_device_online(CoAPContext *ctx, AlcsDeviceKey *devKey) +{ + session_item *session = get_ctl_session(ctx, devKey); + return session && session->sessionId ? 1 : 0; +} + +void heart_beat_cb(CoAPContext *ctx, CoAPReqResult result, void *userdata, NetworkAddr *remote, CoAPMessage *message) +{ + COAP_DEBUG("heart_beat_cb, message addr:%p, networkaddr:%p!", message, remote); + + struct list_head *ctl_head = get_ctl_session_list(ctx); + if (!ctl_head || list_empty(ctl_head)) { + return; + } + + if (result == COAP_RECV_RESP_TIMEOUT) { + COAP_ERR("heart beat timeout"); + session_item *node = NULL, *next = NULL; + list_for_each_entry_safe(node, next, ctl_head, lst, session_item) { + if (node->sessionId && is_networkadd_same(&node->addr, remote)) { + remove_session(ctx, node); + } + } + } else { + session_item *node = NULL, *next = NULL; + list_for_each_entry_safe(node, next, ctl_head, lst, session_item) { + + if (node->sessionId && is_networkadd_same(&node->addr, remote)) { + unsigned int sessionId = 0; + CoAPUintOption_get(message, COAP_OPTION_SESSIONID, &sessionId); + + if (node->sessionId != sessionId) { + COAP_INFO("receive stale heart beat response"); + remove_session(ctx, node); + } else { + node->heart_time = HAL_UptimeMs(); + } + } + } + } +} + +void on_client_auth_timer(CoAPContext *ctx) +{ + struct list_head *ctl_head = get_ctl_session_list(ctx); + if (!ctl_head || list_empty(ctl_head)) { + return; + } + COAP_DEBUG("on_client_auth_timer:%d", (int)HAL_UptimeMs()); + + device_auth_list *dev = get_device(ctx); + char payloadbuf[64]; + sprintf(payloadbuf, "{\"id\":%d,\"version\":\"1.0\",\"params\":{\"delayTime\":%d}}", ++dev->seq, 5000); + + CoAPLenString payload; + payload.data = (unsigned char *)payloadbuf; + payload.len = strlen(payloadbuf); + int tick = HAL_UptimeMs(); + + session_item *node = NULL, *next = NULL; + list_for_each_entry_safe(node, next, ctl_head, lst, session_item) { + if (!node->sessionId) { + continue; + } + + if (node->heart_time + node->interval > tick) { + CoAPMessage message; + alcs_msg_init(ctx, &message, COAP_MSG_CODE_GET, COAP_MESSAGE_TYPE_CON, 0, &payload, NULL); + CoAPServerPath_2_option("/dev/core/service/heartBeat", &message); + message.handler = heart_beat_cb; + CoAPMessage_send(ctx, &node->addr, &message); + COAP_DEBUG("send heartbeat to :%s", node->addr.addr); + CoAPMessage_destory(&message); + } + } +} + +#endif + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_coap.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_coap.c new file mode 100644 index 00000000..857a7b4d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_coap.c @@ -0,0 +1,405 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include +#include +#include "alcs_internal.h" +#include "alcs_coap.h" +#include "CoAPPlatform.h" +#include "CoAPResource.h" +#include "alcs_api_internal.h" +#include "CoAPServer.h" + +#define MAX_PATH_CHECKSUM_LEN (5) +typedef struct { + char path[MAX_PATH_CHECKSUM_LEN]; + CoAPRecvMsgHandler cb; + struct list_head lst; +} resource_cb_item; + +ALIYUN_LIST_HEAD(resource_cb_head); + +static uint32_t tokenSeed = 0; +uint32_t getToken() +{ + if (tokenSeed == 0) { + HAL_Srandom((uint32_t)HAL_UptimeMs()); + tokenSeed = HAL_Random(0xffffffff); + } else { + ++tokenSeed; + } + + return tokenSeed; +} + +void alcs_msg_init(CoAPContext *ctx, CoAPMessage *message, int code, unsigned char type, + int keep, CoAPLenString *payload, void *userdata) +{ + uint32_t token = 0; + + CoAPMessage_init(message); + message->header.code = code; + message->header.type = type; + message->user = userdata; + message->payload = payload->data; + message->payloadlen = payload->len; + message->keep = keep; + + message->header.msgid = CoAPMessageId_gen(ctx); + message->header.tokenlen = 4; + token = getToken(); + memcpy(&message->token, &token, 4); +} + +void alcs_msg_deinit(CoAPMessage *message) +{ + CoAPMessage_destory(message); +} + +static int do_sendmsg(CoAPContext *context, NetworkAddr *addr, CoAPMessage *message, char observe, unsigned short msgid, + CoAPLenString *token) +{ + int ret = COAP_SUCCESS; + if (!context || !addr || !message) { + return COAP_ERROR_NULL; + } + + if (msgid == 0) { + message->header.msgid = CoAPMessageId_gen(context); + } else { + message->header.msgid = msgid; + } + + if (observe == 0) { + CoAPUintOption_add(message, COAP_OPTION_OBSERVE, observe); + } + + if (token) { + message->header.tokenlen = token->len; + memcpy(&message->token, token->data, token->len); + } + + ret = CoAPMessage_send(context, addr, message); + CoAPMessage_destory(message); + return ret; +} + +int alcs_sendmsg(CoAPContext *context, NetworkAddr *addr, CoAPMessage *message, char observe, + CoAPSendMsgHandler handler) +{ + message->handler = handler; + return do_sendmsg(context, addr, message, observe, message->header.msgid, NULL); +} + +int alcs_sendrsp(CoAPContext *context, NetworkAddr *addr, CoAPMessage *message, char observe, unsigned short msgid, + CoAPLenString *token) +{ + return do_sendmsg(context, addr, message, observe, msgid, token); +} + +/* observe */ +int alcs_observe_notify(CoAPContext *context, const char *path, CoAPLenString *payload) +{ + int needAuth = 0; +#ifdef USE_ALCS_SECURE + needAuth = alcs_resource_need_auth(context, path); +#endif + COAP_DEBUG("payload:%s", payload->data); + /* HEXDUMP_DEBUG(payload->data, payload->len); */ + return CoAPObsServer_notify(context, path, payload->data, payload->len, + needAuth ? &observe_data_encrypt : NULL); +} + +static void send_err_rsp(CoAPContext *ctx, NetworkAddr *addr, int code, CoAPMessage *fromMsg) +{ + CoAPMessage sendMsg; + CoAPLenString payload = {0}; + CoAPLenString token = {fromMsg->header.tokenlen, fromMsg->token}; + + alcs_msg_init(ctx, &sendMsg, code, COAP_MESSAGE_TYPE_ACK, 0, &payload, NULL); + alcs_sendrsp(ctx, addr, &sendMsg, 1, fromMsg->header.msgid, &token); +} + +static void recv_msg_handler(CoAPContext *context, const char *path, NetworkAddr *remote, CoAPMessage *message) +{ + unsigned int obsVal; + resource_cb_item *node = NULL, *next = NULL; + char path_calc[MAX_PATH_CHECKSUM_LEN] = {0}; + CoAPPathMD5_sum(path, strlen(path), path_calc, MAX_PATH_CHECKSUM_LEN); + + list_for_each_entry_safe(node, next, &resource_cb_head, lst, resource_cb_item) { + if (0 == memcmp(path_calc, node->path, MAX_PATH_CHECKSUM_LEN)) { + if (CoAPUintOption_get(message, COAP_OPTION_OBSERVE, &obsVal) == COAP_SUCCESS) { + if (obsVal == 0) { + CoAPObsServer_add(context, path, remote, message); + } + } + COAP_INFO("recv_msg_handler call callback"); + node->cb(context, path, remote, message); + return; + } + } + + COAP_ERR("receive unknown request, path:%s", path); + send_err_rsp(context, remote, COAP_MSG_CODE_401_UNAUTHORIZED, message); +} + +/* resource */ +int alcs_resource_register(CoAPContext *context, const char *pk, const char *dn, const char *path, + unsigned short permission, + unsigned int ctype, unsigned int maxage, char needAuth, CoAPRecvMsgHandler callback) +{ + COAP_DEBUG("alcs_resource_register, ctx:%p", context); + COAP_DEBUG("ALCS Resource Register: %s", path); + + if (!needAuth) { + resource_cb_item *item = (resource_cb_item *)coap_malloc(sizeof(resource_cb_item)); + CoAPPathMD5_sum(path, strlen(path), item->path, MAX_PATH_CHECKSUM_LEN); + item->cb = callback; + list_add_tail(&item->lst, &resource_cb_head); + + return CoAPResource_register(context, path, permission, ctype, maxage, &recv_msg_handler); + } else { +#ifdef USE_ALCS_SECURE + return alcs_resource_register_secure(context, pk, dn, path, permission, ctype, maxage, callback); +#else + return -1; +#endif + } +} + +int alcs_resource_need_auth(CoAPContext *context, const char *path) +{ + resource_cb_item *node = NULL, *next = NULL; + char path_calc[MAX_PATH_CHECKSUM_LEN] = {0}; + CoAPPathMD5_sum(path, strlen(path), path_calc, MAX_PATH_CHECKSUM_LEN); + + list_for_each_entry_safe(node, next, &resource_cb_head, lst, resource_cb_item) { + if (memcmp(path_calc, node->path, MAX_PATH_CHECKSUM_LEN) == 0) { + return 0; + } + } + + return 1; +} + +typedef struct { + CoAPContext *ctx; + char loop; + bool inited; + struct list_head lst; +} ALCSContext; + +#ifdef SUPPORT_MULTI_DEVICES +ALIYUN_LIST_HEAD(context_head); + +ALCSContext *get_context(CoAPContext *ctx) +{ + ALCSContext *node = NULL, *next = NULL; + + list_for_each_entry_safe(node, next, &context_head, lst, ALCSContext) { + if (node->ctx == ctx) { + return node; + } + } + return NULL; +} + +CoAPContext *alcs_context_create(CoAPInitParam *param) +{ + ALCSContext *alcs_ctx = (ALCSContext *) coap_malloc(sizeof(ALCSContext)); + alcs_ctx->ctx = CoAPContext_create(param); + COAP_INFO("CoAPContext_create return :%p", alcs_ctx->ctx); + alcs_ctx->loop = 0; + alcs_ctx->inited = 0; + + list_add_tail(&alcs_ctx->lst, &context_head); + return alcs_ctx->ctx; +} + +void alcs_context_free(CoAPContext *ctx) +{ + ALCSContext *alcs_ctx = get_context(ctx); + if (alcs_ctx) { + CoAPContext_free(alcs_ctx->ctx); + coap_free(alcs_ctx); + } +} + +#else +ALCSContext *g_alcs_ctx = NULL; +ALCSContext *get_context(CoAPContext *ctx) +{ + return g_alcs_ctx; +} + +CoAPContext *alcs_context_init(CoAPInitParam *param) +{ + if (g_alcs_ctx) { + return g_alcs_ctx->ctx; + } + + g_alcs_ctx = (ALCSContext *)coap_malloc(sizeof(ALCSContext)); + if (g_alcs_ctx) { + g_alcs_ctx->loop = 0; + g_alcs_ctx->inited = 0; + g_alcs_ctx->ctx = CoAPServer_init(); + COAP_INFO("CoAPServer_init return :%p", g_alcs_ctx->ctx); + if (!g_alcs_ctx->ctx) { + coap_free(g_alcs_ctx); + g_alcs_ctx = NULL; + return NULL; + } + return g_alcs_ctx->ctx; + } else { + return NULL; + } +} + +void alcs_context_deinit() +{ + if (g_alcs_ctx) { + if (g_alcs_ctx->ctx) { + CoAPServer_deinit(g_alcs_ctx->ctx); + } + coap_free(g_alcs_ctx); + g_alcs_ctx = NULL; + } +} + +CoAPContext *alcs_get_context() +{ + return g_alcs_ctx ? g_alcs_ctx->ctx : NULL; +} + +#endif + +extern void on_auth_timer(void *arg); + +void *thread_routine(void *arg) +{ + ALCSContext *ctx = (ALCSContext *)arg; + ctx->loop = 1; + + COAP_INFO("thread_routine"); + + while (ctx->loop) { + CoAPMessage_cycle(ctx->ctx); +#ifdef USE_ALCS_SECURE + on_auth_timer(ctx->ctx); +#endif + } + + return NULL; +} + +void alcs_start_loop(CoAPContext *ctx, int newThread) +{ +#ifdef SUPPORT_MULTI_DEVICES + void *handle = NULL; + ALCSContext *alcs_ctx = get_context(ctx); + if (alcs_ctx && !alcs_ctx->loop) { + int stack_used = 0; + if (!newThread || 0 != HAL_ThreadCreate(&handle, thread_routine, alcs_ctx, NULL, &stack_used)) { + thread_routine(alcs_ctx); + } + } +#else + +#ifdef USE_ALCS_SECURE + CoAPServer_add_timer(on_auth_timer); +#endif + CoAPServer_loop(ctx); +#endif +} + +void alcs_stop_loop(CoAPContext *ctx) +{ +#ifdef SUPPORT_MULTI_DEVICES + ALCSContext *alcs_ctx = get_context(ctx); + if (alcs_ctx) { + alcs_ctx->loop = 0; + } +#else + CoAPServer_deinit(ctx); +#endif +} + +void alcs_init() +{ +#ifdef SUPPORT_MULTI_DEVICES + INIT_LIST_HEAD(&context_head); +#endif + INIT_LIST_HEAD(&resource_cb_head); +} + +void alcs_deinit() +{ + resource_cb_item *del_item = NULL; + + list_for_each_entry(del_item, &resource_cb_head, lst, resource_cb_item) { + list_del(&del_item->lst); + coap_free(del_item); + del_item = list_entry(&resource_cb_head, resource_cb_item, lst); + } +} + +static int path_2_option(const char *uri, CoAPMessage *message) +{ + const char *ptr = NULL; + const char *pstr = NULL; + char path[COAP_MSG_MAX_PATH_LEN] = {0}; + + if (256 < strlen(uri)) { + COAP_ERR("The uri length is too loog,len = %d", (int)strlen(uri)); + return COAP_ERROR_INVALID_LENGTH; + } + COAP_DEBUG("The uri is %s", uri); + ptr = pstr = uri; + while ('\0' != *ptr) { + if ('/' == *ptr) { + if (ptr != pstr) { + memset(path, 0x00, sizeof(path)); + strncpy(path, pstr, ptr - pstr); + COAP_DEBUG("path: %s,len=%d", path, (int)(ptr - pstr)); + CoAPStrOption_add(message, COAP_OPTION_URI_PATH, + (unsigned char *)path, (int)strlen(path)); + } + pstr = ptr + 1; + + } + if ('\0' == *(ptr + 1) && '\0' != *pstr) { + memset(path, 0x00, sizeof(path)); + strncpy(path, pstr, sizeof(path) - 1); + COAP_DEBUG("path: %s,len=%d", path, (int)strlen(path)); + CoAPStrOption_add(message, COAP_OPTION_URI_PATH, + (unsigned char *)path, (int)strlen(path)); + } + ptr ++; + } + return COAP_SUCCESS; +} + +int alcs_msg_setAddr(CoAPMessage *message, const char *path, const char *query) +{ + int rt = 0; + + if (NULL == path || NULL == message) { + COAP_ERR("Invalid paramter p_path %p, p_message %p", path, message); + return COAP_ERROR_INVALID_PARAM; + } + + if (255 < strlen(path)) { + COAP_ERR("The uri length is too loog,len = %d", (int)strlen(path)); + return COAP_ERROR_INVALID_LENGTH; + } + + rt = path_2_option(path, message); + if (query) { + CoAPStrOption_add(message, COAP_OPTION_URI_QUERY, (unsigned char *)query, strlen(query)); + } + + return rt; +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_coap.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_coap.h new file mode 100644 index 00000000..398d9dff --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_coap.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#include "CoAPExport.h" + +#ifndef __COAP_ALCS_H__ +#define __COAP_ALCS_H__ + +#define OPTSESESSION 62 +#define ALCSPORT 5683 +#define ALCSPORT_SECURE 5684 +#define MULTICAST_ADDRESS "224.0.1.187" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef bool +#define bool char +#endif + +typedef struct { + NetworkAddr addr; + char *path; + char *query; +} ResourceAddr; + +/* 会自动生成msgid & token */ +void alcs_msg_init(CoAPContext *ctx, CoAPMessage *message, int code, unsigned char type, int keep, + CoAPLenString *payload, void *userdata); +void alcs_msg_deinit(CoAPMessage *message); +int alcs_msg_setAddr(CoAPMessage *message, const char *path, const char *query); + +/* observe: 0 register */ +/* observer:1 deregister */ +/* observer:other 没意义 */ +int alcs_sendmsg(CoAPContext *ctx, NetworkAddr *addr, CoAPMessage *message, char observe, CoAPSendMsgHandler handler); + +/* msgid & token从接收到CoAPMessage获取, 若发送的是事件通知,msgid设置为0 */ +/* observe: 0: accept register */ +/* observe: other: 没意义 */ +int alcs_sendrsp(CoAPContext *ctx, NetworkAddr *addr, CoAPMessage *message, char observe, unsigned short msgid, + CoAPLenString *token); + +void alcs_start_loop(CoAPContext *ctx, int newThread); +void alcs_stop_loop(CoAPContext *ctx); + +/* 服务端接口 + * + */ +/* observe */ +int alcs_observe_notify(CoAPContext *context, const char *path, CoAPLenString *payload); + +/* resource */ +int alcs_resource_register(CoAPContext *context, const char *pk, const char *dn, const char *path, + unsigned short permission, + unsigned int ctype, unsigned int maxage, char needAuth, CoAPRecvMsgHandler callback); + +int alcs_resource_need_auth(CoAPContext *context, const char *path); + + +/* init */ +void alcs_init(); +void alcs_deinit(); + +#ifdef SUPPORT_MULTI_DEVICES +CoAPContext *alcs_context_create(CoAPInitParam *param); +void alcs_context_free(CoAPContext *ctx); +#else +CoAPContext *alcs_context_init(CoAPInitParam *param); +void alcs_context_deinit(); +CoAPContext *alcs_get_context(); +#endif + +/* option */ +extern int CoAPUintOption_add(CoAPMessage *message, unsigned short optnum, unsigned int data); +extern int CoAPUintOption_get(CoAPMessage *message, unsigned short optnum, unsigned int *data); +extern int CoAPStrOption_add(CoAPMessage *message, unsigned short optnum, + unsigned char *data, unsigned short datalen); +extern int CoAPMessage_cancel(CoAPContext *context, CoAPMessage *message); + +uint32_t getToken(); + +/* */ +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_internal.h new file mode 100644 index 00000000..de02f287 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_internal.h @@ -0,0 +1,24 @@ +#ifndef _ALCS_INTERNAL_H_ +#define _ALCS_INTERNAL_H_ + +#include "infra_config.h" +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_md5.h" +#include "infra_sha1.h" +#include "infra_json_parser.h" +#include "alcs_base64.h" +#include "dm_wrapper.h" + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define ALCS_malloc(size) LITE_malloc(size, MEM_MAGIC, "alcs") + #define ALCS_ADAPTER_malloc(size) LITE_malloc(size, MEM_MAGIC, "alcs_adapter") + #define ALCS_free(ptr) LITE_free(ptr) +#else + #define ALCS_malloc(size) HAL_Malloc(size) + #define ALCS_ADAPTER_malloc(size) HAL_Malloc(size) + #define ALCS_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_localsetup.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_localsetup.c new file mode 100644 index 00000000..53a66c72 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_localsetup.c @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include + +#include "alcs_internal.h" +#include "alcs_api_internal.h" +#include "CoAPExport.h" +#include "alcs_api.h" +#include "alcs_mqtt.h" +#include "alcs_adapter.h" +#include "CoAPPlatform.h" +#include "CoAPExport.h" +#include "iotx_alcs.h" + +char *DEFAULT_AC = "Xtau@iot"; +char *DEFAULT_AS = "Yx3DdsyetbSezlvc"; +void *g_adapter_handle = NULL; +void *g_coap_handle = NULL; + +typedef enum { + ALCS_LOCALSETUP_SUCCESS, + ALCS_LOCALSETUP_ERROR +} localsetup_status; + +static localsetup_status __alcs_localsetup_kv_set(const char *key, const void *val, int len, int sync) +{ + if (HAL_Kv_Set(key, val, len, sync) != 0) { + return ALCS_LOCALSETUP_ERROR; + } + + COAP_INFO("ALCS KV Set, Key: %s, Val: %s, Len: %d", key, (char *)val, len); + return ALCS_LOCALSETUP_SUCCESS; +} + +static localsetup_status __alcs_localsetup_kv_get(const char *key, void *buffer, int *buffer_len) +{ + int rc = -1; + + if ((rc = HAL_Kv_Get(key, buffer, buffer_len)) != 0) { + COAP_WRN("HAL_Kv_Get('%s') = %d (!= 0), return %d", key, rc, ALCS_LOCALSETUP_ERROR); + return ALCS_LOCALSETUP_ERROR; + } + + COAP_INFO("ALCS KV Get, Key: %s", key); + + return ALCS_LOCALSETUP_SUCCESS; +} + +static localsetup_status __alcs_localsetup_kv_del(const char *key) +{ + if (HAL_Kv_Del(key) != 0) { + return ALCS_LOCALSETUP_ERROR; + } + + COAP_INFO("ALCS KV Del, Key: %s", key); + + return ALCS_LOCALSETUP_SUCCESS; +} + +static localsetup_status __fill_key(const char *pk, uint16_t pk_len, + const char *dn, uint16_t dn_len, char key_md5_hexstr[33]) +{ + uint8_t key_md5[16] = {0}; + char key_source[IOTX_PRODUCT_KEY_LEN + 1 + IOTX_DEVICE_NAME_LEN + 1 + 3]; + + if (pk == NULL || pk_len >= IOTX_PRODUCT_KEY_LEN + 1 || + dn == NULL || dn_len >= IOTX_DEVICE_NAME_LEN + 1) { + COAP_ERR("Invalid Parameter"); + return ALCS_LOCALSETUP_ERROR; + } + + /* Calculate Key */ + HAL_Snprintf(key_source, sizeof(key_source), "%.*s%.*s.l", pk_len, pk, dn_len, dn); + + utils_md5((const unsigned char *)key_source, strlen(key_source), key_md5); + alcs_utils_md5_hexstr(key_md5, (unsigned char *)key_md5_hexstr); + return ALCS_LOCALSETUP_SUCCESS; +} + +static localsetup_status __alcs_localsetup_ac_as_save(const char *pk, uint16_t pk_len, + const char *dn, uint16_t dn_len, + const char *prefix, uint16_t prefix_len, + const char *secret, uint16_t secret_len) +{ + char key_md5_hexstr[33] = {0}; + char *value = NULL; + int rt; + if (prefix == NULL || secret == NULL) { + COAP_ERR("Invalid Parameter"); + return ALCS_LOCALSETUP_ERROR; + } + + rt = __fill_key(pk, pk_len, dn, dn_len, key_md5_hexstr); + if (rt != ALCS_LOCALSETUP_SUCCESS) { + return rt; + } + + /* Calculate Value */ + value = ALCS_ADAPTER_malloc(prefix_len + secret_len + 3); + if (value == NULL) { + COAP_ERR("No Enough Memory"); + return ALCS_LOCALSETUP_ERROR; + } + memset(value, 0, prefix_len + secret_len + 3); + + value[0] = prefix_len; + value[1] = secret_len; + HAL_Snprintf(&value[2], prefix_len + secret_len + 1, "%.*s%.*s", prefix_len, prefix, secret_len, secret); + + if (ALCS_LOCALSETUP_SUCCESS != __alcs_localsetup_kv_set(key_md5_hexstr, value, prefix_len + secret_len + 3, 1)) { + COAP_WRN("ALCS KV Set Prefix And Secret Fail"); + ALCS_free(value); + return ALCS_LOCALSETUP_ERROR; + } + + ALCS_free(value); + return ALCS_LOCALSETUP_SUCCESS; +} + +localsetup_status alcs_localsetup_ac_as_load(const char *pk, uint16_t pk_len, + const char *dn, uint16_t dn_len, + char *prefix, int prefix_len, char *secret, int secret_len) +{ + char key_md5_hexstr[33] = {0}; + char value[128] = {0}; + int value_len = sizeof(value); + + int rt; + if (prefix == NULL || secret == NULL) { + COAP_ERR("Invalid Parameter"); + return ALCS_LOCALSETUP_ERROR; + } + + rt = __fill_key(pk, pk_len, dn, dn_len, key_md5_hexstr); + if (rt != ALCS_LOCALSETUP_SUCCESS) { + return rt; + } + + /* Get Value */ + if (ALCS_LOCALSETUP_SUCCESS != __alcs_localsetup_kv_get(key_md5_hexstr, value, &value_len)) { + COAP_WRN("ALCS KV Get local Prefix And Secret Fail"); + return ALCS_LOCALSETUP_ERROR; + } + + if (value[0] >= prefix_len || value[1] >= secret_len) { + COAP_ERR("insuffient buffer!"); + return ALCS_LOCALSETUP_ERROR; + } + + memset(prefix, 0, prefix_len); + memcpy(prefix, &value[2], value[0]); + memset(secret, 0, secret_len); + memcpy(secret, &value[2 + value[0]], value[1]); + return ALCS_LOCALSETUP_SUCCESS; +} + +static localsetup_status __alcs_localsetup_ac_as_del(const char *pk, uint16_t pk_len, + const char *dn, uint16_t dn_len) +{ + char key_md5_hexstr[33] = {0}; + int rt; + rt = __fill_key(pk, pk_len, dn, dn_len, key_md5_hexstr); + if (rt != ALCS_LOCALSETUP_SUCCESS) { + return rt; + } + + if (ALCS_LOCALSETUP_SUCCESS != __alcs_localsetup_kv_del(key_md5_hexstr)) { + COAP_ERR("ALCS KV Get local Prefix And Secret Fail"); + return ALCS_LOCALSETUP_ERROR; + } + + return ALCS_LOCALSETUP_SUCCESS; +} + +static void alcs_service_cb_setup(CoAPContext *context, const char *paths, NetworkAddr *remote, CoAPMessage *message) +{ + char payload[128]; + char *id = NULL, *p; + int idlen = 0, len, aclen, aslen, pklen, dnlen; + char *ac = NULL, *as = NULL, *pk = NULL, *dn = dn; + bool success = 0; + char *err_msg = NULL; + char configValueBack, acBack, asBack; + char *str_pos, *entry; + int entry_len, type; + iotx_alcs_msg_t rsp_msg; + + COAP_DEBUG("alcs_service_cb_setup, path:%s", paths); + do { + if (!remote || !message) { + COAP_DEBUG("alcs_service_cb_setup, param is NULL!"); + err_msg = "invalid package"; + break; + } + + id = json_get_value_by_name((char *)message->payload, message->payloadlen, "id", &idlen, (int *)NULL); + p = json_get_value_by_name((char *)message->payload, message->payloadlen, "params", &len, (int *)NULL); + if (!p || !len) { + err_msg = "params is not found"; + break; + } + + p = json_get_value_by_name(p, len, "configValue", &len, (int *)NULL); + if (!p || !len) { + err_msg = "configValue is not found"; + break; + } + + backup_json_str_last_char(p, len, configValueBack); + + json_array_for_each_entry(p, len, str_pos, entry, entry_len, type) { + COAP_DEBUG("entry:%.*s", entry_len, entry); + ac = json_get_value_by_name(entry, entry_len, "authCode", &aclen, (int *)NULL); + as = json_get_value_by_name(entry, entry_len, "authSecret", &aslen, (int *)NULL); + pk = json_get_value_by_name(entry, entry_len, "productKey", &pklen, (int *)NULL); + dn = json_get_value_by_name(entry, entry_len, "deviceName", &dnlen, (int *)NULL); + break; + } /* end json_array_for_each_entry */ + restore_json_str_last_char(p, len, configValueBack); + + if (!ac || !aclen || !as || !aslen || !pk || !pklen || !dn || !dnlen) { + err_msg = "authinfo is not found"; + break; + } + + /* save */ + backup_json_str_last_char(ac, aclen, acBack); + backup_json_str_last_char(as, aslen, asBack); + __alcs_localsetup_ac_as_del(pk, pklen, dn, dnlen); + __alcs_localsetup_ac_as_save(pk, pklen, dn, dnlen, ac, aclen, as, aslen); + + alcs_add_svr_key(g_coap_handle, ac, as, LOCALSETUP); + + restore_json_str_last_char(ac, aclen, acBack); + restore_json_str_last_char(as, aslen, asBack) + success = 1; + + } while (0); + + if (success) { + HAL_Snprintf(payload, sizeof(payload), "{\"id\":\"%.*s\",\"code\":200}", idlen, id ? id : ""); + } else { + HAL_Snprintf(payload, sizeof(payload), "{\"id\":\"%.*s\",\"code\":400,\"msg\":\"%s\"}", idlen, id ? id : "", err_msg); + COAP_ERR("alcs_service_cb_setup, %s", err_msg); + } + + memset(&rsp_msg, 0, sizeof(iotx_alcs_msg_t)); + + rsp_msg.msg_code = ITOX_ALCS_COAP_MSG_CODE_205_CONTENT; + rsp_msg.msg_type = IOTX_ALCS_MESSAGE_TYPE_CON; + rsp_msg.payload = (unsigned char *)payload; + rsp_msg.payload_len = strlen(payload); + rsp_msg.ip = (char *)(remote ? remote->addr : NULL); + rsp_msg.port = remote ? remote->port : 5683; + rsp_msg.uri = (char *)paths; + + if (message) { + iotx_alcs_send_Response(g_adapter_handle, &rsp_msg, message->header.tokenlen, message->token); + } +} + +static void alcs_localsetup_register_resource(void *adapter_handle, char *pk, char *dn) +{ + iotx_alcs_res_t alcs_res; + char uri [IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 24]; + + if (adapter_handle == NULL || pk == NULL || strlen(pk) > IOTX_PRODUCT_KEY_LEN || + dn == NULL || strlen(dn) > IOTX_DEVICE_NAME_LEN) { + return; + } + + HAL_Snprintf(uri, sizeof(uri), "/dev/%s/%s/core/service/setup", pk, dn); + + memset(&alcs_res, 0, sizeof(iotx_alcs_res_t)); + alcs_res.uri = uri; + alcs_res.msg_ct = IOTX_ALCS_MESSAGE_CT_APP_JSON; + alcs_res.msg_perm = IOTX_ALCS_MESSAGE_PERM_GET | IOTX_ALCS_MESSAGE_PERM_PUT; + alcs_res.maxage = 60; + alcs_res.need_auth = 1; + alcs_res.callback = alcs_service_cb_setup; + + iotx_alcs_register_resource(adapter_handle, &alcs_res); +} + +void alcs_localsetup_init(void *adapter_handle, void *coap_handler, char *pk, char *dn) +{ + char prefix [10]; + char secret [64]; + g_adapter_handle = adapter_handle; + g_coap_handle = coap_handler; + alcs_localsetup_register_resource(adapter_handle, pk, dn); + + if (alcs_localsetup_ac_as_load(pk, strlen(pk), dn, strlen(dn), prefix, sizeof(prefix), secret, + sizeof(secret)) != ALCS_LOCALSETUP_SUCCESS) { + alcs_add_svr_key(g_coap_handle, DEFAULT_AC, DEFAULT_AS, LOCALDEFAULT); + } else { + alcs_add_svr_key(g_coap_handle, prefix, secret, LOCALSETUP); + } +} + +void alcs_localsetup_add_sub_device(void *adapter_handle, char *pk, char *dn) +{ + alcs_localsetup_register_resource(adapter_handle, pk, dn); +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_localsetup.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_localsetup.h new file mode 100644 index 00000000..e3d41715 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_localsetup.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _ALCS_LOCALSETUP_H_ +#define _ALCS_LOCALSETUP_H_ + +void alcs_localsetup_init(void *adapter_handle, void* coap_handler, char *product_key,char *device_name); +void alcs_localsetup_add_sub_device (void *adapter_handle,char *product_key,char *device_name); +void alcs_localsetup_deinit(void *handle); + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_mqtt.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_mqtt.c new file mode 100644 index 00000000..ac099492 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_mqtt.c @@ -0,0 +1,618 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#include +#include +#include "alcs_internal.h" +#include "alcs_api_internal.h" +#include "CoAPExport.h" +#include "alcs_api.h" +#include "alcs_adapter.h" +#include "alcs_mqtt.h" +#include "alcs_adapter.h" +#include "CoAPPlatform.h" + +static alcs_mqtt_ctx_t g_alcs_mqtt_ctx; + +static alcs_mqtt_ctx_t *__alcs_mqtt_get_ctx(void) +{ + return &g_alcs_mqtt_ctx; +} + +static alcs_mqtt_status_e __alcs_mqtt_publish(char *topic, int qos, void *data, int len) +{ + return (IOT_MQTT_Publish_Simple(NULL, topic, qos, data, len) < 0) ? ALCS_MQTT_STATUS_ERROR : ALCS_MQTT_STATUS_SUCCESS; +} + +static alcs_mqtt_status_e __alcs_mqtt_send_response(char *topic, int id, int code, char *data) +{ + char *msg_pub = NULL; + uint16_t msg_len = 0; + alcs_mqtt_status_e status = ALCS_MQTT_STATUS_SUCCESS; + + if (data == NULL || strlen(data) == 0) { + data = "{}"; + } + + msg_len = strlen(ALCS_MQTT_THING_LAN_PREFIX_RESPONSE_FMT) + 20 + strlen(data) + 1; + + if ((msg_pub = ALCS_ADAPTER_malloc(msg_len)) == NULL) { + return ALCS_MQTT_STATUS_ERROR; + } + + HAL_Snprintf(msg_pub, msg_len, ALCS_MQTT_THING_LAN_PREFIX_RESPONSE_FMT, id, code, data); + + status = __alcs_mqtt_publish(topic, 1, msg_pub, strlen(msg_pub)); + + ALCS_free(msg_pub); + + return status; +} + +static alcs_mqtt_status_e __alcs_mqtt_kv_set(const char *key, const void *val, int len, int sync) +{ + if (HAL_Kv_Set(key, val, len, sync) != 0) { + return ALCS_MQTT_STATUS_ERROR; + } + + COAP_INFO("ALCS KV Set, Key: %s, Val: %s, Len: %d", key, (char *)val, len); + return ALCS_MQTT_STATUS_SUCCESS; +} + +static alcs_mqtt_status_e __alcs_mqtt_kv_get(const char *key, void *buffer, int *buffer_len) +{ + if (HAL_Kv_Get(key, buffer, buffer_len) != 0) { + return ALCS_MQTT_STATUS_ERROR; + } + + COAP_INFO("ALCS KV Get, Key: %s", key); + + return ALCS_MQTT_STATUS_SUCCESS; +} + +static alcs_mqtt_status_e __alcs_mqtt_kv_del(const char *key) +{ + if (HAL_Kv_Del(key) != 0) { + return ALCS_MQTT_STATUS_ERROR; + } + + COAP_INFO("ALCS KV Del, Key: %s", key); + + return ALCS_MQTT_STATUS_SUCCESS; +} + +alcs_mqtt_status_e __alcs_mqtt_prefix_secret_save(const char *pk, uint16_t pk_len, + const char *dn, uint16_t dn_len, + const char *prefix, uint16_t prefix_len, + const char *secret, uint16_t secret_len) +{ + char *key_source = NULL; + uint8_t key_md5[16] = {0}; + char key_md5_hexstr[33] = {0}; + char *value = NULL; + + if (pk == NULL || pk_len >= IOTX_PRODUCT_KEY_LEN + 1 || + dn == NULL || dn_len >= IOTX_DEVICE_NAME_LEN + 1 || + prefix == NULL || secret == NULL) { + COAP_ERR("Invalid Parameter"); + return ALCS_MQTT_STATUS_ERROR; + } + + /* Calculate Key */ + key_source = ALCS_ADAPTER_malloc(pk_len + dn_len + 1); + if (key_source == NULL) { + COAP_ERR("No Enough Memory"); + return ALCS_MQTT_STATUS_ERROR; + } + memset(key_source, 0, pk_len + dn_len + 1); + + HAL_Snprintf(key_source, pk_len + dn_len + 1, "%.*s%.*s", pk_len, pk, dn_len, dn); + + utils_md5((const unsigned char *)key_source, strlen(key_source), key_md5); + alcs_utils_md5_hexstr(key_md5, (unsigned char *)key_md5_hexstr); + + /* Calculate Value */ + value = ALCS_ADAPTER_malloc(prefix_len + secret_len + 3); + if (value == NULL) { + COAP_ERR("No Enough Memory"); + ALCS_free(key_source); + return ALCS_MQTT_STATUS_ERROR; + } + memset(value, 0, prefix_len + secret_len + 3); + + value[0] = prefix_len; + value[1] = secret_len; + HAL_Snprintf(&value[2], prefix_len + secret_len + 1, "%.*s%.*s", prefix_len, prefix, secret_len, secret); + + if (ALCS_MQTT_STATUS_SUCCESS != __alcs_mqtt_kv_set(key_md5_hexstr, value, prefix_len + secret_len + 3, 1)) { + COAP_ERR("ALCS KV Set Prefix And Secret Fail"); + ALCS_free(key_source); + ALCS_free(value); + return ALCS_MQTT_STATUS_ERROR; + } + + ALCS_free(key_source); + ALCS_free(value); + return ALCS_MQTT_STATUS_SUCCESS; +} + +alcs_mqtt_status_e alcs_mqtt_prefix_secret_load(const char *pk, uint16_t pk_len, + const char *dn, uint16_t dn_len, + char *prefix, char *secret) +{ + char *key_source = NULL; + uint8_t key_md5[16] = {0}; + char key_md5_hexstr[33] = {0}; + char value[128] = {0}; + int value_len = sizeof(value); + + if (pk == NULL || strlen(pk) >= IOTX_PRODUCT_KEY_LEN + 1 || + dn == NULL || strlen(dn) >= IOTX_DEVICE_NAME_LEN + 1 || + prefix == NULL || secret == NULL) { + COAP_ERR("Invalid Parameter"); + return ALCS_MQTT_STATUS_ERROR; + } + + /* Calculate Key */ + key_source = ALCS_ADAPTER_malloc(pk_len + dn_len + 1); + if (key_source == NULL) { + COAP_ERR("No Enough Memory"); + return ALCS_MQTT_STATUS_ERROR; + } + memset(key_source, 0, pk_len + dn_len + 1); + + HAL_Snprintf(key_source, pk_len + dn_len + 1, "%.*s%.*s", pk_len, pk, dn_len, dn); + + utils_md5((const unsigned char *)key_source, strlen(key_source), key_md5); + alcs_utils_md5_hexstr(key_md5, (unsigned char *)key_md5_hexstr); + + /* Get Value */ + if (ALCS_MQTT_STATUS_SUCCESS != __alcs_mqtt_kv_get(key_md5_hexstr, value, &value_len)) { + COAP_ERR("ALCS KV Get Prefix And Secret Fail"); + ALCS_free(key_source); + return ALCS_MQTT_STATUS_ERROR; + } + + memcpy(prefix, &value[2], value[0]); + memcpy(secret, &value[2 + value[0]], value[1]); + ALCS_free(key_source); + + return ALCS_MQTT_STATUS_SUCCESS; +} + +alcs_mqtt_status_e alcs_mqtt_prefix_secret_del(const char *pk, uint16_t pk_len, + const char *dn, uint16_t dn_len) +{ + char *key_source = NULL; + uint8_t key_md5[16] = {0}; + char key_md5_hexstr[33] = {0}; + + if (pk == NULL || strlen(pk) >= IOTX_PRODUCT_KEY_LEN + 1 || + dn == NULL || strlen(dn) >= IOTX_DEVICE_NAME_LEN + 1) { + COAP_ERR("Invalid Parameter"); + return ALCS_MQTT_STATUS_ERROR; + } + + /* Calculate Key */ + key_source = ALCS_ADAPTER_malloc(pk_len + dn_len + 1); + if (key_source == NULL) { + COAP_ERR("No Enough Memory"); + return ALCS_MQTT_STATUS_ERROR; + } + memset(key_source, 0, pk_len + dn_len + 1); + + HAL_Snprintf(key_source, pk_len + dn_len + 1, "%.*s%.*s", pk_len, pk, dn_len, dn); + + utils_md5((const unsigned char *)key_source, strlen(key_source), key_md5); + alcs_utils_md5_hexstr(key_md5, (unsigned char *)key_md5_hexstr); + + if (ALCS_MQTT_STATUS_SUCCESS != __alcs_mqtt_kv_del(key_md5_hexstr)) { + COAP_ERR("ALCS KV Get Prefix And Secret Fail"); + ALCS_free(key_source); + return ALCS_MQTT_STATUS_ERROR; + } + + ALCS_free(key_source); + return ALCS_MQTT_STATUS_SUCCESS; +} + +static void __alcs_mqtt_subscribe_callback(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg) +{ + char topic_compare[ALCS_MQTT_TOPIC_MAX_LEN] = {0}; + char reqid[16] = {0}; + char *topic; + int topic_len; + void *payload; + int payload_len; + alcs_mqtt_ctx_t *alcs_mqtt_ctx = NULL; + iotx_mqtt_topic_info_pt ptopic_info = NULL; + + if (msg == NULL) { + return; + } + alcs_mqtt_ctx = (alcs_mqtt_ctx_t *)pcontext; + ptopic_info = (iotx_mqtt_topic_info_pt) msg->msg; + + switch (msg->event_type) { + case IOTX_MQTT_EVENT_SUBCRIBE_SUCCESS: + return; + case IOTX_MQTT_EVENT_SUBCRIBE_TIMEOUT: + return; + case IOTX_MQTT_EVENT_SUBCRIBE_NACK: + return; + case IOTX_MQTT_EVENT_PUBLISH_RECEIVED: + topic = (char *)ptopic_info->ptopic; + topic_len = ptopic_info->topic_len; + payload = (char *)ptopic_info->payload; + payload_len = ptopic_info->payload_len; + break; + default: + return; + } + + if (topic == NULL || payload == NULL || topic_len == 0 || payload_len == 0) { + return; + } + + memset(topic_compare, 0, ALCS_MQTT_TOPIC_MAX_LEN); + HAL_Snprintf(topic_compare, ALCS_MQTT_TOPIC_MAX_LEN, ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_GET_REPLY_FMT, + alcs_mqtt_ctx->product_key, alcs_mqtt_ctx->device_name); + + COAP_INFO("Receivce Message, Topic: %.*s\n", topic_len, topic); + + if ((strlen(topic_compare) == topic_len) && (strncmp(topic_compare, topic, topic_len) == 0)) { + int data_len = 0, prefix_len = 0, secret_len = 0, productKey_len = 0, deviceName_len = 0; + char *data = NULL, *prefix = NULL, *secret = NULL, *productKey = NULL, *deviceName = NULL; + data = json_get_value_by_name((char *)payload, payload_len, "data", &data_len, NULL); + + if (NULL != data && 0 != data_len) { + char back1, back2; + prefix = json_get_value_by_name(data, data_len, ALCS_MQTT_JSON_KEY_PREFIX, &prefix_len, NULL); + secret = json_get_value_by_name(data, data_len, ALCS_MQTT_JSON_KEY_SECRET, &secret_len, NULL); + productKey = json_get_value_by_name(data, data_len, ALCS_MQTT_JSON_KEY_PRODUCT_KEY, &productKey_len, NULL); + deviceName = json_get_value_by_name(data, data_len, ALCS_MQTT_JSON_KEY_DEVICE_NAME, &deviceName_len, NULL); + + COAP_INFO("Get Reply, Product Key: %.*s, Device Name: %.*s\n", productKey_len, productKey, deviceName_len, deviceName); + + if (NULL != alcs_mqtt_ctx->coap_ctx && prefix && secret) { + back1 = prefix[prefix_len]; + prefix[prefix_len] = 0; + back2 = secret[secret_len]; + secret[secret_len] = 0; + alcs_add_svr_key(alcs_mqtt_ctx->coap_ctx, prefix, secret, FROMCLOUDSVR); + prefix[prefix_len] = back1; + secret[secret_len] = back2; + + if (productKey && deviceName) { + if (__alcs_mqtt_prefix_secret_save(productKey, productKey_len, deviceName, deviceName_len, prefix, prefix_len, secret, + secret_len) == ALCS_MQTT_STATUS_SUCCESS) { + iotx_alcs_subdev_item_t subdev_item; + memset(&subdev_item, 0, sizeof(iotx_alcs_subdev_item_t)); + + memcpy(subdev_item.product_key, productKey, productKey_len); + memcpy(subdev_item.device_name, deviceName, deviceName_len); + subdev_item.stage = IOTX_ALCS_SUBDEV_CONNECT_CLOUD; + + iotx_alcs_subdev_update_stage(&subdev_item); + } + } else { + iotx_alcs_subdev_remove(alcs_mqtt_ctx->product_key, alcs_mqtt_ctx->device_name); + if (ALCS_MQTT_STATUS_SUCCESS != __alcs_mqtt_kv_set(ALCS_MQTT_JSON_KEY_PREFIX, prefix, prefix_len, 1)) { + COAP_ERR("ALCS KV Set Prefix Fail"); + } + if (ALCS_MQTT_STATUS_SUCCESS != __alcs_mqtt_kv_set(ALCS_MQTT_JSON_KEY_SECRET, secret, secret_len, 1)) { + COAP_ERR("ALCS KV Set Secret Fail"); + } + } + } + } else { + if (ALCS_MQTT_STATUS_SUCCESS == __alcs_mqtt_kv_get(ALCS_MQTT_JSON_KEY_PREFIX, prefix, &prefix_len) && + ALCS_MQTT_STATUS_SUCCESS == __alcs_mqtt_kv_get(ALCS_MQTT_JSON_KEY_SECRET, secret, &secret_len)) { + if (NULL != alcs_mqtt_ctx->coap_ctx && prefix_len && secret_len) { + alcs_add_svr_key(alcs_mqtt_ctx->coap_ctx, prefix, secret, FROMCLOUDSVR); + } + } + } + return; + } + + memset(topic_compare, 0, ALCS_MQTT_TOPIC_MAX_LEN); + HAL_Snprintf(topic_compare, ALCS_MQTT_TOPIC_MAX_LEN, ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_UPDATE_FMT, + alcs_mqtt_ctx->product_key, alcs_mqtt_ctx->device_name); + + if ((strlen(topic_compare) == topic_len) && (strncmp(topic_compare, topic, topic_len) == 0)) { + int param_len = 0, prefix_len = 0, id_len = 0; + char *param = NULL, *prefix = NULL, *id = NULL; + id = json_get_value_by_name((char *)payload, payload_len, "id", &id_len, NULL); + + if (NULL != id && 0 != id_len) { + strncpy(reqid, id, sizeof(reqid) - 1); + } + param = json_get_value_by_name((char *)payload, payload_len, "params", ¶m_len, NULL); + if (NULL != param && 0 != param_len) { + char reply_topic[ALCS_MQTT_TOPIC_MAX_LEN] = {0}; + prefix = json_get_value_by_name(param, param_len, ALCS_MQTT_JSON_KEY_PREFIX, &prefix_len, NULL); + + if (NULL != alcs_mqtt_ctx->coap_ctx && prefix) + if (0 != alcs_remove_svr_key(alcs_mqtt_ctx->coap_ctx, prefix)) { + } + if (ALCS_MQTT_STATUS_SUCCESS != __alcs_mqtt_kv_del(ALCS_MQTT_JSON_KEY_PREFIX)) { + COAP_ERR("Remove the keyprefix from aos_kv fail"); + ; + } + + HAL_Snprintf(reply_topic, ALCS_MQTT_TOPIC_MAX_LEN, ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_UPDATE_REPLY_FMT, + alcs_mqtt_ctx->product_key, alcs_mqtt_ctx->device_name); + __alcs_mqtt_send_response(reply_topic, atoi(reqid), 200, NULL); + } + return; + } + + memset(topic_compare, 0, ALCS_MQTT_TOPIC_MAX_LEN); + HAL_Snprintf(topic_compare, ALCS_MQTT_TOPIC_MAX_LEN, ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_BLACKLIST_UPDATE_FMT, + alcs_mqtt_ctx->product_key, alcs_mqtt_ctx->device_name); + + if ((strlen(topic_compare) == topic_len) && (strncmp(topic_compare, topic, topic_len) == 0)) { + int param_len = 0, blacklist_len = 0, id_len = 0; + char *param = NULL, *blacklist = NULL, *id = NULL; + id = json_get_value_by_name((char *)payload, payload_len, "id", &id_len, NULL); + + if (NULL != id && 0 != id_len) { + strncpy(reqid, id, sizeof(reqid) - 1); + } + param = json_get_value_by_name((char *)payload, payload_len, "params", ¶m_len, NULL); + if (NULL != param && 0 != param_len) { + char reply_topic[ALCS_MQTT_TOPIC_MAX_LEN] = {0}; + blacklist = json_get_value_by_name(param, param_len, ALCS_MQTT_JSON_KEY_BLACK, &blacklist_len, NULL); + if (NULL != alcs_mqtt_ctx->coap_ctx && blacklist) { + alcs_set_revocation(alcs_mqtt_ctx->coap_ctx, blacklist); + if (ALCS_MQTT_STATUS_SUCCESS != __alcs_mqtt_kv_set(ALCS_MQTT_JSON_KEY_BLACK, blacklist, blacklist_len, 1)) { + COAP_ERR("aos_kv_set set blacklist fail"); + ; + } + } + + HAL_Snprintf(reply_topic, ALCS_MQTT_TOPIC_MAX_LEN, + ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_BLACKLIST_UPDATE_REPLY_FMT, + alcs_mqtt_ctx->product_key, alcs_mqtt_ctx->device_name); + __alcs_mqtt_send_response(reply_topic, atoi(reqid), 200, NULL); + } else { + if (ALCS_MQTT_STATUS_SUCCESS == __alcs_mqtt_kv_get(ALCS_MQTT_JSON_KEY_BLACK, blacklist, &blacklist_len)) { + if (NULL != alcs_mqtt_ctx->coap_ctx) { + alcs_set_revocation(alcs_mqtt_ctx->coap_ctx, blacklist); + } + } + } + return; + } +} + + +static alcs_mqtt_status_e __alcs_mqtt_subscribe(void *ctx, char *topic) +{ + return (IOT_MQTT_Subscribe(NULL, topic, 0, __alcs_mqtt_subscribe_callback, + ctx) < 0) ? ALCS_MQTT_STATUS_ERROR : ALCS_MQTT_STATUS_SUCCESS; +} + +#if 0 +static alcs_mqtt_status_e __alcs_mqtt_unsubscribe(void *ctx, char *topic) +{ + return (mqtt_unsubscribe(topic) != 0) ? ALCS_MQTT_STATUS_ERROR : ALCS_MQTT_STATUS_SUCCESS; +} +#endif + +alcs_mqtt_status_e alcs_mqtt_init(void *handle, char *product_key, char *device_name) +{ + char topic[ALCS_MQTT_TOPIC_MAX_LEN] = {0}; + alcs_mqtt_status_e status = ALCS_MQTT_STATUS_SUCCESS; + alcs_mqtt_ctx_t *ctx = __alcs_mqtt_get_ctx(); + + if (handle == NULL || product_key == NULL || strlen(product_key) > IOTX_PRODUCT_KEY_LEN || + device_name == NULL || strlen(device_name) > IOTX_DEVICE_NAME_LEN) { + return ALCS_MQTT_STATUS_ERROR; + } + + memset(ctx, 0, sizeof(alcs_mqtt_ctx_t)); + ctx->coap_ctx = (CoAPContext *)handle; + memcpy(ctx->product_key, product_key, strlen(product_key)); + memcpy(ctx->device_name, device_name, strlen(device_name)); + + memset(topic, 0, ALCS_MQTT_TOPIC_MAX_LEN); + HAL_Snprintf(topic, ALCS_MQTT_TOPIC_MAX_LEN, ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_GET_REPLY_FMT, + ctx->product_key, ctx->device_name); + if (__alcs_mqtt_subscribe((void *)ctx, topic) != ALCS_MQTT_STATUS_SUCCESS) { + COAP_ERR("ALCS Subscribe Failed, Topic: %s", topic); + status = ALCS_MQTT_STATUS_ERROR; + } + + memset(topic, 0, ALCS_MQTT_TOPIC_MAX_LEN); + HAL_Snprintf(topic, ALCS_MQTT_TOPIC_MAX_LEN, ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_UPDATE_FMT, + ctx->product_key, ctx->device_name); + if (__alcs_mqtt_subscribe((void *)ctx, topic) != ALCS_MQTT_STATUS_SUCCESS) { + COAP_ERR("ALCS Subscribe Failed, Topic: %s", topic); + status = ALCS_MQTT_STATUS_ERROR; + } + + memset(topic, 0, ALCS_MQTT_TOPIC_MAX_LEN); + HAL_Snprintf(topic, ALCS_MQTT_TOPIC_MAX_LEN, ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_BLACKLIST_UPDATE_FMT, + ctx->product_key, ctx->device_name); + if (__alcs_mqtt_subscribe((void *)ctx, topic) != ALCS_MQTT_STATUS_SUCCESS) { + COAP_ERR("ALCS Subscribe Failed, Topic: %s", topic); + status = ALCS_MQTT_STATUS_ERROR; + } + + alcs_mqtt_prefixkey_update((void *)ctx->coap_ctx); + alcs_mqtt_blacklist_update((void *)ctx->coap_ctx); + + alcs_prefixkey_get(ctx->product_key, ctx->device_name); + + return status; +} + + +alcs_mqtt_status_e alcs_mqtt_deinit(void *handle, char *product_key, char *device_name) +{ +#if 0 + char topic[ALCS_MQTT_TOPIC_MAX_LEN] = {0}; + alcs_mqtt_status_e status = ALCS_MQTT_STATUS_SUCCESS; + alcs_mqtt_ctx_t *ctx = __alcs_mqtt_get_ctx(); + + ARGUMENT_SANITY_CHECK(product_key && strlen(product_key), FAIL_RETURN); + ARGUMENT_SANITY_CHECK(device_name && strlen(device_name), FAIL_RETURN); + + if (handle == NULL || product_key == NULL || strlen(product_key) > IOTX_PRODUCT_KEY_LEN || + device_name == NULL || strlen(device_name) > IOTX_DEVICE_NAME_LEN || ctx == NULL) { + return ALCS_MQTT_STATUS_ERROR; + } + + memset(topic, 0, ALCS_MQTT_TOPIC_MAX_LEN); + HAL_Snprintf(topic, ALCS_MQTT_TOPIC_MAX_LEN, ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_GET_REPLY_FMT, + ctx->product_key, ctx->device_name); + if (__alcs_mqtt_unsubscribe((void *)ctx, topic) != ALCS_MQTT_STATUS_SUCCESS) { + COAP_ERR("ALCS Subscribe Failed, Topic: %s", topic); + status = ALCS_MQTT_STATUS_ERROR; + } + + memset(topic, 0, ALCS_MQTT_TOPIC_MAX_LEN); + HAL_Snprintf(topic, ALCS_MQTT_TOPIC_MAX_LEN, ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_UPDATE_FMT, + ctx->product_key, ctx->device_name); + if (__alcs_mqtt_unsubscribe((void *)ctx, topic) != ALCS_MQTT_STATUS_SUCCESS) { + COAP_ERR("ALCS Subscribe Failed, Topic: %s", topic); + status = ALCS_MQTT_STATUS_ERROR; + } + + memset(topic, 0, ALCS_MQTT_TOPIC_MAX_LEN); + HAL_Snprintf(topic, ALCS_MQTT_TOPIC_MAX_LEN, ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_BLACKLIST_UPDATE_FMT, + ctx->product_key, ctx->device_name); + if (__alcs_mqtt_unsubscribe((void *)ctx, topic) != ALCS_MQTT_STATUS_SUCCESS) { + COAP_ERR("ALCS Subscribe Failed, Topic: %s", topic); + status = ALCS_MQTT_STATUS_ERROR; + } + + return status; +#endif + return ALCS_MQTT_STATUS_SUCCESS; +} + +void alcs_mqtt_add_srv_key(const char *prefix, const char *secret) +{ + alcs_mqtt_ctx_t *alcs_mqtt_ctx = __alcs_mqtt_get_ctx(); + alcs_add_svr_key(alcs_mqtt_ctx->coap_ctx, prefix, secret, FROMCLOUDSVR); +} + +alcs_mqtt_status_e alcs_mqtt_blacklist_update(void *ctx) +{ + CoAPContext *context = (CoAPContext *)ctx; + char blacklist[ALCS_MQTT_BLACK_MAX_LEN] = {0}; + int blacklist_len = ALCS_MQTT_BLACK_MAX_LEN; + + if (NULL == context) { + return -1; + } + + if (ALCS_MQTT_STATUS_SUCCESS == __alcs_mqtt_kv_get(ALCS_MQTT_JSON_KEY_BLACK, blacklist, &blacklist_len)) { + COAP_INFO("The blacklist is %.*s", blacklist_len, blacklist); + if (blacklist_len) { + alcs_set_revocation(context, blacklist); + return ALCS_MQTT_STATUS_SUCCESS; + } + } + + return ALCS_MQTT_STATUS_ERROR; +} + +alcs_mqtt_status_e alcs_mqtt_prefixkey_update(void *ctx) +{ + CoAPContext *context = (CoAPContext *)ctx; + char prefix[ALCS_MQTT_PREFIX_MAX_LEN] = {0}; + char secret[ALCS_MQTT_SECRET_MAX_LEN] = {0}; + int prefix_len = ALCS_MQTT_PREFIX_MAX_LEN, secret_len = ALCS_MQTT_SECRET_MAX_LEN; + + if (NULL == context) { + return ALCS_MQTT_STATUS_ERROR; + } + + COAP_INFO("start alcs_prefixkey_update\n"); + + if (ALCS_MQTT_STATUS_SUCCESS == __alcs_mqtt_kv_get(ALCS_MQTT_JSON_KEY_PREFIX, prefix, &prefix_len) && + ALCS_MQTT_STATUS_SUCCESS == __alcs_mqtt_kv_get(ALCS_MQTT_JSON_KEY_SECRET, secret, &secret_len)) { + COAP_INFO("The prefix is %.*s, deviceSecret is %.*s", prefix_len, prefix, secret_len, secret); + if (prefix_len && secret_len) { + alcs_add_svr_key(context, prefix, secret, FROMCLOUDSVR); + return ALCS_MQTT_STATUS_SUCCESS; + } + } + + return ALCS_MQTT_STATUS_ERROR; +} + +alcs_mqtt_status_e alcs_prefixkey_get(const char *product_key, const char *device_name) +{ + /* int ret = 0; */ + char *msg_pub = NULL; + uint16_t msg_len = 0; + char topic[ALCS_MQTT_TOPIC_MAX_LEN] = {0}; + alcs_mqtt_ctx_t *ctx = __alcs_mqtt_get_ctx(); + alcs_mqtt_status_e status = ALCS_MQTT_STATUS_SUCCESS; + int id = ctx->send_id++; + + if (product_key == NULL || strlen(product_key) > IOTX_PRODUCT_KEY_LEN || + device_name == NULL || strlen(device_name) > IOTX_DEVICE_NAME_LEN) { + return ALCS_MQTT_STATUS_ERROR; + } + HAL_Snprintf(topic, ALCS_MQTT_TOPIC_MAX_LEN, ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_GET_FMT, + product_key, device_name); + + msg_len = strlen(ALCS_MQTT_THING_ALCS_REQUEST) + 10 + 1; + if ((msg_pub = ALCS_ADAPTER_malloc(msg_len)) == NULL) { + return ALCS_MQTT_STATUS_ERROR; + } + + HAL_Snprintf(msg_pub, msg_len, ALCS_MQTT_THING_ALCS_REQUEST, id); + + COAP_INFO("ALCS Prefix Get, Topic: %s, Payload: %s", topic, msg_pub); + status = __alcs_mqtt_publish(topic, 1, msg_pub, strlen(msg_pub)); + + ALCS_free(msg_pub); + + return status; +} + +alcs_mqtt_status_e alcs_mqtt_subdev_prefix_get(const char *product_key, const char *device_name) +{ + /* int ret = 0; */ + char *msg_pub = NULL; + uint16_t msg_len = 0; + char topic[ALCS_MQTT_TOPIC_MAX_LEN] = {0}; + alcs_mqtt_ctx_t *ctx = __alcs_mqtt_get_ctx(); + alcs_mqtt_status_e status = ALCS_MQTT_STATUS_SUCCESS; + int id = ctx->send_id++; + + if (product_key == NULL || strlen(product_key) > IOTX_PRODUCT_KEY_LEN || + device_name == NULL || strlen(device_name) > IOTX_DEVICE_NAME_LEN) { + return ALCS_MQTT_STATUS_ERROR; + } + + COAP_INFO("Subdevice, PK: %s, DN: %s\n", product_key, device_name); + HAL_Snprintf(topic, ALCS_MQTT_TOPIC_MAX_LEN, ALCS_MQTT_PREFIX ALCS_MQTT_THING_LAN_PREFIX_GET_FMT, + ctx->product_key, ctx->device_name); + + msg_len = strlen(ALCS_MQTT_THING_ALCS_SUBDEV_REQUEST) + 10 + strlen(product_key) + strlen(device_name) + 1; + if ((msg_pub = ALCS_ADAPTER_malloc(msg_len)) == NULL) { + return ALCS_MQTT_STATUS_ERROR; + } + + HAL_Snprintf(msg_pub, msg_len, ALCS_MQTT_THING_ALCS_SUBDEV_REQUEST, id, + (int)strlen(product_key), product_key, (int)strlen(device_name), device_name); + + COAP_ERR("ALCS Prefix Get, Topic: %s, Payload: %s", topic, msg_pub); + status = __alcs_mqtt_publish(topic, 1, msg_pub, strlen(msg_pub)); + + ALCS_free(msg_pub); + + return status; +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_mqtt.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_mqtt.h new file mode 100644 index 00000000..05902530 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_mqtt.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _ALCS_MQTT_H_ +#define _ALCS_MQTT_H_ + +#include "alcs_internal.h" + +typedef enum { + ALCS_MQTT_STATUS_SUCCESS, + ALCS_MQTT_STATUS_ERROR +} alcs_mqtt_status_e; + +typedef struct { + CoAPContext *coap_ctx; + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char device_name[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 2]; + uint32_t send_id; +} alcs_mqtt_ctx_t; + +#define ALCS_MQTT_PREFIX "/sys/%s/%s" + +#define ALCS_MQTT_THING_LAN_PREFIX_GET_REPLY_FMT "/thing/lan/prefix/get_reply" +#define ALCS_MQTT_THING_LAN_PREFIX_GET_FMT "/thing/lan/prefix/get" +#define ALCS_MQTT_THING_LAN_PREFIX_UPDATE_FMT "/thing/lan/prefix/update" +#define ALCS_MQTT_THING_LAN_PREFIX_UPDATE_REPLY_FMT "/thing/lan/prefix/update_reply" +#define ALCS_MQTT_THING_LAN_PREFIX_BLACKLIST_UPDATE_FMT "/thing/lan/blacklist/update" +#define ALCS_MQTT_THING_LAN_PREFIX_BLACKLIST_UPDATE_REPLY_FMT "/thing/lan/blacklist/update_reply" + +#define ALCS_MQTT_THING_ALCS_REQUEST "{\"id\":\"%d\",\"version\":\"1.0\",\"params\":\"{}\",\"method\":\"thing.lan.prefix.get\"}" +#define ALCS_MQTT_THING_LAN_PREFIX_RESPONSE_FMT "{\"id\": \"%d\", \"code\": %d, \"data\": %s}" +#define ALCS_MQTT_THING_ALCS_SUBDEV_REQUEST "{\"id\":\"%d\",\"version\":\"1.0\",\"params\":{\"productKey\":\"%.*s\",\"deviceName\":\"%.*s\"},\"method\":\"thing.lan.prefix.get\"}" + +#define ALCS_MQTT_TOPIC_MAX_LEN (128) + +#define ALCS_MQTT_JSON_KEY_PRODUCT_KEY "productKey" +#define ALCS_MQTT_JSON_KEY_DEVICE_NAME "deviceName" +#define ALCS_MQTT_JSON_KEY_PREFIX "prefix" +#define ALCS_MQTT_JSON_KEY_SECRET "deviceSecret" +#define ALCS_MQTT_JSON_KEY_BLACK "blacklist" + +#define ALCS_MQTT_PREFIX_MAX_LEN (40) +#define ALCS_MQTT_SECRET_MAX_LEN (40) +#define ALCS_MQTT_BLACK_MAX_LEN (100) + +alcs_mqtt_status_e alcs_mqtt_init(void *handle, char *product_key, char *device_name); +alcs_mqtt_status_e alcs_mqtt_deinit(void *handle, char *product_key, char *device_name); +alcs_mqtt_status_e alcs_mqtt_blacklist_update(void *ctx); +alcs_mqtt_status_e alcs_mqtt_prefixkey_update(void *ctx); +void alcs_mqtt_add_srv_key(const char *prefix, const char *secret); +alcs_mqtt_status_e alcs_mqtt_prefix_secret_load(const char *pk, uint16_t pk_len, + const char *dn, uint16_t dn_len, + char *prefix, char *secret); +alcs_mqtt_status_e alcs_mqtt_prefix_secret_del(const char *pk, uint16_t pk_len, + const char *dn, uint16_t dn_len); +alcs_mqtt_status_e alcs_mqtt_subdev_prefix_get(const char *product_key, const char *device_name); +alcs_mqtt_status_e alcs_prefixkey_get(const char *product_key, const char *device_name); + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_server.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_server.c new file mode 100644 index 00000000..d609fba2 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/alcs_server.c @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "alcs_internal.h" +#include "alcs_api_internal.h" +#include "CoAPPlatform.h" +#include "CoAPResource.h" +#ifdef LOG_REPORT_TO_CLOUD + #include "iotx_log_report.h" +#endif +#define RES_FORMAT "{\"id\":\"%.*s\",\"code\":%d,\"data\":{%s}}" + +#ifdef ALCS_SERVER_ENABLED + +int sessionid_seed = 0xff; +static int default_heart_expire = 120000; + +void utils_hmac_sha1_base64(const char *msg, int msg_len, const char *key, int key_len, char *digest, int *digest_len) +{ + char buf[20]; + uint32_t outlen; + utils_hmac_sha1_hex(msg, msg_len, buf, key, key_len); + + utils_base64encode((unsigned char *)buf, 20, *digest_len, (unsigned char *)digest, &outlen); + *digest_len = outlen; +} + +void alcs_rec_auth_select(CoAPContext *ctx, const char *paths, NetworkAddr *from, CoAPMessage *resMsg) +{ + int seqlen, datalen; + char *seq, *data; + char *targetKey = ""; + int targetLen = 0; + auth_list *lst = NULL; + char *accesskeys; + int keylen; + char back; + char *str_pos, *entry; + int entry_len, type; + CoAPMessage msg; + char keybuf[32]; + char payloadbuf[512]; + CoAPLenString token = {resMsg->header.tokenlen, resMsg->token}; + CoAPLenString payload; + + /* int res_code = 200; */ + COAP_DEBUG("receive data:%.*s", resMsg->payloadlen, resMsg->payload); + + do { + + if (!req_payload_parser((const char *)resMsg->payload, resMsg->payloadlen, &seq, &seqlen, &data, &datalen)) { + break; + } + lst = get_list(ctx); + + accesskeys = json_get_value_by_name(data, datalen, "accessKeys", &keylen, NULL); + if (!accesskeys || !keylen) { + break; + } + COAP_DEBUG("accessKeys:%.*s", keylen, accesskeys); + + backup_json_str_last_char(accesskeys, keylen, back); + json_array_for_each_entry(accesskeys, keylen, str_pos, entry, entry_len, type) { + svr_key_item *node = NULL, *next = NULL; + svr_group_item *gnode = NULL, *gnext = NULL; + COAP_DEBUG("entry:%.*s", entry_len, entry); + list_for_each_entry_safe(node, next, &lst->lst_svr, lst, svr_key_item) { + COAP_DEBUG("keyprefix:%s", node->keyInfo.keyprefix); + if (strstr(entry, node->keyInfo.keyprefix) == entry) { + COAP_DEBUG("target keyprefix:%s", entry); + targetKey = entry; + targetLen = entry_len; + break; + } + } + if (targetKey) { + break; + } + + list_for_each_entry_safe(gnode, gnext, &lst->lst_svr_group, lst, svr_group_item) { + COAP_DEBUG("keyprefix:%s", gnode->keyInfo.keyprefix); + if (strstr(entry, gnode->keyInfo.keyprefix) == entry) { + COAP_DEBUG("target keyprefix:%s", entry); + targetKey = entry; + targetLen = entry_len; + break; + } + } + if (targetKey) { + break; + } + } + restore_json_str_last_char(accesskeys, keylen, back); + + } while (0); + + COAP_DEBUG("key:%s", targetKey); + + + HAL_Snprintf(keybuf, sizeof(keybuf), "\"accessKey\":\"%.*s\"", targetLen, targetKey); + + HAL_Snprintf(payloadbuf, sizeof(payloadbuf), RES_FORMAT, seqlen, seq, targetKey ? 200 : COAP_MSG_CODE_401_UNAUTHORIZED, + keybuf); + payload.data = (unsigned char *)payloadbuf; + payload.len = strlen(payloadbuf); + + alcs_msg_init(ctx, &msg, COAP_MSG_CODE_205_CONTENT, COAP_MESSAGE_TYPE_ACK, 0, &payload, NULL); + alcs_sendrsp(ctx, from, &msg, 1, resMsg->header.msgid, &token); +} + +svr_key_info *is_legal_key(CoAPContext *ctx, const char *keyprefix, int prefixlen, const char *keyseq, int seqlen, + int *res_code) +{ + auth_list *lst = get_list(ctx); + COAP_INFO("islegal prefix:%.*s, seq:%.*s", prefixlen, keyprefix, seqlen, keyseq); + + if (lst) { + COAP_DEBUG("find devices"); + HAL_MutexLock(lst->list_mutex); + + if (lst->revocation) { + int len = strlen(lst->revocation); + int i; + for (i = 0; i < len; i += KEYSEQ_LEN) { + if (strncmp(keyseq, lst->revocation + i, seqlen) == 0) { + HAL_MutexUnlock(lst->list_mutex); + *res_code = ALCS_AUTH_REVOCATE; + COAP_INFO("accesskey is revocated"); + return NULL; + } + } + } + + if (list_empty(&lst->lst_svr)) { + COAP_INFO("ALCS_AUTH_AUTHLISTEMPTY:%d\r\n", ALCS_AUTH_AUTHLISTEMPTY); + *res_code = ALCS_AUTH_AUTHLISTEMPTY; + } else { + svr_key_item *node = NULL, *next = NULL; + svr_group_item *gnode = NULL, *gnext = NULL; + list_for_each_entry_safe(node, next, &lst->lst_svr, lst, svr_key_item) { + COAP_DEBUG("node prefix:%s", node->keyInfo.keyprefix); + if (strlen(node->keyInfo.keyprefix) == prefixlen && strncmp(keyprefix, node->keyInfo.keyprefix, prefixlen) == 0) { + *res_code = ALCS_AUTH_OK; + HAL_MutexUnlock(lst->list_mutex); + return &node->keyInfo; + } + } + list_for_each_entry_safe(gnode, gnext, &lst->lst_svr_group, lst, svr_group_item) { + COAP_DEBUG("node prefix:%s", gnode->keyInfo.keyprefix); + if (strlen(gnode->keyInfo.keyprefix) == prefixlen && strncmp(keyprefix, gnode->keyInfo.keyprefix, prefixlen) == 0) { + *res_code = ALCS_AUTH_OK; + HAL_MutexUnlock(lst->list_mutex); + return &gnode->keyInfo; + } + } + + COAP_INFO("ALCS_AUTH_UNMATCHPREFIX:%d\r\n", ALCS_AUTH_UNMATCHPREFIX); + *res_code = ALCS_AUTH_UNMATCHPREFIX; + } + + HAL_MutexUnlock(lst->list_mutex); + } + + return NULL; +} + +void alcs_rec_auth(CoAPContext *ctx, const char *paths, NetworkAddr *from, CoAPMessage *resMsg) +{ + int seqlen, datalen; + char *seq, *data; + int res_code = 200; + char body[200] = {0}; + char *accesskey, *randomkey, *sign; + int tmplen; + char *keyprefix; + char *keyseq; + char accessToken[64]; + int tokenlen; + int randomkeylen; + char buf[40]; + int calc_sign_len; + int pklen, dnlen; + char *pk; + char *dn; + char tmp1; + char tmp2; + svr_key_info *item; + AlcsDeviceKey devKey; + session_item *session; + CoAPMessage message; + char payloadbuf[512]; + CoAPLenString payload; + CoAPLenString token; + COAP_INFO("receive data:%.*s, from:%s", resMsg->payloadlen, resMsg->payload, from->addr); + + do { + if (!req_payload_parser((const char *)resMsg->payload, resMsg->payloadlen, &seq, &seqlen, &data, &datalen)) { + break; + } + + accesskey = json_get_value_by_name(data, datalen, "accessKey", &tmplen, NULL); + COAP_INFO("accesskey:%.*s", tmplen, accesskey); + + if (!accesskey || tmplen != KEYPREFIX_LEN + 1 + 1 + KEYSEQ_LEN) { + break; + } + + keyprefix = accesskey; + keyseq = accesskey + KEYPREFIX_LEN + 1 + 1; + + item = is_legal_key(ctx, keyprefix, KEYPREFIX_LEN, keyseq, KEYSEQ_LEN, &res_code); + if (!item) { + COAP_INFO("islegal return null"); + break; + } + + tokenlen = sizeof(accessToken); + utils_hmac_sha1_base64(accesskey, tmplen, item->secret, strlen(item->secret), accessToken, &tokenlen); + + COAP_INFO("accessToken:%.*s", tokenlen, accessToken); + randomkey = json_get_value_by_name(data, datalen, "randomKey", &randomkeylen, NULL); + if (!randomkey || !randomkeylen) { + res_code = ALCS_AUTH_INVALIDPARAM; + break; + } + + /*calc sign, save in buf*/ + + calc_sign_len = sizeof(buf); + utils_hmac_sha1_base64(randomkey, randomkeylen, accessToken, tokenlen, buf, &calc_sign_len); + + COAP_INFO("calc randomKey:%.*s,token:%.*s,sign:%.*s", randomkeylen, randomkey, tokenlen, + accessToken, calc_sign_len, buf); + + sign = json_get_value_by_name(data, datalen, "sign", &tmplen, NULL); + if (!sign || tmplen != calc_sign_len || strncmp(sign, buf, calc_sign_len)) { + res_code = ALCS_AUTH_ILLEGALSIGN; + break; + } + + pk = json_get_value_by_name(data, datalen, "prodKey", &pklen, NULL); + dn = json_get_value_by_name(data, datalen, "deviceName", &dnlen, NULL); + + if (!pk || !pklen || !dn || !dnlen) { + res_code = ALCS_AUTH_INVALIDPARAM; + break; + } + tmp1 = pk[pklen]; + tmp2 = dn[dnlen]; + pk[pklen] = 0; + dn[dnlen] = 0; + + + memset(&devKey, 0x00, sizeof(AlcsDeviceKey)); + memcpy(&devKey.addr, from, sizeof(NetworkAddr)); + devKey.pk = pk; + devKey.dn = dn; + session = get_svr_session(ctx, &devKey); + + if (!session) { + char path[100] = {0}; + struct list_head *svr_head; + session = (session_item *)coap_malloc(sizeof(session_item)); + gen_random_key((unsigned char *)session->randomKey, RANDOMKEY_LEN); + session->sessionId = ++sessionid_seed; + + strncpy(path, pk, sizeof(path)); + strncat(path, dn, sizeof(path) - strlen(path) - 1); + CoAPPathMD5_sum(path, strlen(path), session->pk_dn, PK_DN_CHECKSUM_LEN); + + memcpy(&session->addr, from, sizeof(NetworkAddr)); + COAP_INFO("new session, addr:%s, port:%d", session->addr.addr, session->addr.port); + svr_head = get_svr_session_list(ctx); + list_add_tail(&session->lst, svr_head); + } + + pk[pklen] = tmp1; + dn[dnlen] = tmp2; + + HAL_Snprintf(buf, sizeof(buf), "%.*s%s", randomkeylen, randomkey, session->randomKey); + utils_hmac_sha1_hex(buf, strlen(buf), session->sessionKey, accessToken, tokenlen); + + /*calc sign, save in buf*/ + calc_sign_len = sizeof(buf); + utils_hmac_sha1_base64(session->randomKey, RANDOMKEY_LEN, accessToken, tokenlen, buf, &calc_sign_len); + HAL_Snprintf(body, sizeof(body), "\"sign\":\"%.*s\",\"randomKey\":\"%s\",\"sessionId\":%d,\"expire\":86400", + calc_sign_len, buf, session->randomKey, session->sessionId); + + session->authed_time = HAL_UptimeMs(); + session->heart_time = session->authed_time; + /* ??? */ + /* result = 1; */ + + } while (0); + + HAL_Snprintf(payloadbuf, sizeof(payloadbuf), RES_FORMAT, seqlen, seq, res_code, body); + payload.len = strlen(payloadbuf); + payload.data = (unsigned char *)payloadbuf; + alcs_msg_init(ctx, &message, COAP_MSG_CODE_205_CONTENT, COAP_MESSAGE_TYPE_ACK, 0, &payload, NULL); + token.len = resMsg->header.tokenlen; + token.data = resMsg->token; + alcs_sendrsp(ctx, from, &message, 1, resMsg->header.msgid, &token); +} + +static int alcs_remove_low_priority_key(CoAPContext *ctx, ServerKeyPriority priority) +{ + auth_list *lst = get_list(ctx); + svr_key_item *node = NULL, *next = NULL; + + HAL_MutexLock(lst->list_mutex); + + list_for_each_entry_safe(node, next, &lst->lst_svr, lst, svr_key_item) { + if (node->keyInfo.priority < priority) { + coap_free(node->keyInfo.secret); + list_del(&node->lst); + coap_free(node); + --lst->svr_count; + } + } + HAL_MutexUnlock(lst->list_mutex); + + return COAP_SUCCESS; +} + +static int add_svr_key(CoAPContext *ctx, const char *keyprefix, const char *secret, bool isGroup, + ServerKeyPriority priority) +{ + auth_list *lst = get_list(ctx); + svr_key_item *node = NULL, *next = NULL; + svr_key_item *item; + COAP_INFO("add_svr_key\n"); + if (!lst || lst->svr_count >= KEY_MAXCOUNT || strlen(keyprefix) != KEYPREFIX_LEN) { + return COAP_ERROR_INVALID_LENGTH; + } + alcs_remove_low_priority_key(ctx, priority); + + HAL_MutexLock(lst->list_mutex); + list_for_each_entry_safe(node, next, &lst->lst_svr, lst, svr_key_item) { + if (node->keyInfo.priority > priority) { + /* find high priority key */ + HAL_MutexUnlock(lst->list_mutex); + return COAP_ERROR_UNSUPPORTED; + } + } + + item = (svr_key_item *) coap_malloc(sizeof(svr_key_item)); + if (!item) { + HAL_MutexUnlock(lst->list_mutex); + return COAP_ERROR_MALLOC; + } + + item->keyInfo.secret = (char *) coap_malloc(strlen(secret) + 1); + if (!item->keyInfo.secret) { + HAL_MutexUnlock(lst->list_mutex); + coap_free(item); + return COAP_ERROR_MALLOC; + } + strcpy(item->keyInfo.secret, secret); + memcpy(item->keyInfo.keyprefix, keyprefix, KEYPREFIX_LEN); + item->keyInfo.priority = priority; + + list_add_tail(&item->lst, &lst->lst_svr); + ++lst->svr_count; + HAL_MutexUnlock(lst->list_mutex); + + return COAP_SUCCESS; +} + +int alcs_add_svr_key(CoAPContext *ctx, const char *keyprefix, const char *secret, ServerKeyPriority priority) +{ + COAP_INFO("alcs_add_svr_key, priority=%d", priority); + return add_svr_key(ctx, keyprefix, secret, 0, priority); +} + + +int alcs_remove_svr_key(CoAPContext *ctx, const char *keyprefix) +{ + auth_list *lst = get_list(ctx); + svr_key_item *node = NULL, *next = NULL; + + HAL_MutexLock(lst->list_mutex); + + list_for_each_entry_safe(node, next, &lst->lst_svr, lst, svr_key_item) { + if (strcmp(node->keyInfo.keyprefix, keyprefix) == 0) { + coap_free(node->keyInfo.secret); + list_del(&node->lst); + coap_free(node); + --lst->svr_count; + break; + } + } + HAL_MutexUnlock(lst->list_mutex); + + return COAP_SUCCESS; +} + +int alcs_set_revocation(CoAPContext *ctx, const char *seqlist) +{ + auth_list *lst = get_list(ctx); + int len; + + HAL_MutexLock(lst->list_mutex); + + len = seqlist ? strlen(seqlist) : 0; + if (lst->revocation) { + coap_free(lst->revocation); + lst->revocation = NULL; + } + + if (len > 0) { + lst->revocation = (char *)coap_malloc(len + 1); + strcpy(lst->revocation, seqlist); + } + HAL_MutexUnlock(lst->list_mutex); + + return COAP_SUCCESS; +} + +/* ----------------------------------------- */ + +void send_err_rsp(CoAPContext *ctx, NetworkAddr *addr, int code, CoAPMessage *request) +{ + CoAPMessage sendMsg; + CoAPLenString payload = {0}; + CoAPLenString token; + alcs_msg_init(ctx, &sendMsg, code, COAP_MESSAGE_TYPE_ACK, 0, &payload, NULL); + token.len = request->header.tokenlen; + token.data = request->token; + alcs_sendrsp(ctx, addr, &sendMsg, 1, request->header.msgid, &token); +} + +void call_cb(CoAPContext *context, const char *path, NetworkAddr *remote, CoAPMessage *message, const char *key, + char *buf, CoAPRecvMsgHandler cb) +{ + CoAPMessage tmpMsg; + memcpy(&tmpMsg, message, sizeof(CoAPMessage)); + + if (key && buf) { + int len = alcs_decrypt((const char *)message->payload, message->payloadlen, key, buf); + tmpMsg.payload = (unsigned char *)buf; + tmpMsg.payloadlen = len; +#ifdef LOG_REPORT_TO_CLOUD + get_msgid(buf, 0); +#endif + } else { + tmpMsg.payload = NULL; + tmpMsg.payloadlen = 0; + } + + cb(context, path, remote, &tmpMsg); +} + +static secure_resource_cb_item *get_resource_by_path(const char *path) +{ + secure_resource_cb_item *node, *next; + char path_calc[MAX_PATH_CHECKSUM_LEN] = {0}; + CoAPPathMD5_sum(path, strlen(path), path_calc, MAX_PATH_CHECKSUM_LEN); + + list_for_each_entry_safe(node, next, &secure_resource_cb_head, lst, secure_resource_cb_item) { + if (node->path_type == PATH_NORMAL) { + if (memcmp(node->path, path_calc, MAX_PATH_CHECKSUM_LEN) == 0) { + return node; + } + } else if (strlen(node->filter_path) > 0) { + if (strncmp(node->filter_path, path, strlen(node->filter_path) - 1) == 0) { + return node; + } + } + } + + COAP_ERR("receive unknown request, path:%s", path); + return NULL; +} + +void recv_msg_handler(CoAPContext *context, const char *path, NetworkAddr *remote, CoAPMessage *message) +{ + secure_resource_cb_item *node = get_resource_by_path(path); + struct list_head *sessions; + session_item *session; + unsigned int obsVal; + + unsigned int sessionId = 0; + CoAPUintOption_get(message, COAP_OPTION_SESSIONID, &sessionId); + COAP_DEBUG("recv_msg_handler, sessionID:%d", (int)sessionId); + if (!node) { + return; + } + sessions = get_svr_session_list(context); + session = get_session_by_checksum(sessions, remote, node->pk_dn); + if (!session || session->sessionId != sessionId) { + send_err_rsp(context, remote, COAP_MSG_CODE_401_UNAUTHORIZED, message); + COAP_ERR("need auth, path:%s, from:%s", path, remote->addr); + return; + } + + if (CoAPUintOption_get(message, COAP_OPTION_OBSERVE, &obsVal) == COAP_SUCCESS) { + if (obsVal == 0) { + CoAPObsServer_add(context, path, remote, message); + } + } + + if (message->payloadlen < 256) { + char buf[256]; + call_cb(context, path, remote, message, session->sessionKey, buf, node->cb); + } else { + char *buf = (char *)coap_malloc(message->payloadlen); + if (buf) { + call_cb(context, path, remote, message, session->sessionKey, buf, node->cb); + coap_free(buf); + } + } +} + +int alcs_resource_register_secure(CoAPContext *context, const char *pk, const char *dn, const char *path, + unsigned short permission, + unsigned int ctype, unsigned int maxage, CoAPRecvMsgHandler callback) +{ + secure_resource_cb_item *node = NULL, *next_node = NULL; + char pk_dn[100] = {0}; + int dup = 0; + secure_resource_cb_item *item; + + COAP_INFO("alcs_resource_register_secure"); + item = (secure_resource_cb_item *)coap_malloc(sizeof(secure_resource_cb_item)); + if (item == NULL) { + return -1; + } + memset(item, 0, sizeof(secure_resource_cb_item)); + item->cb = callback; + item->path_type = PATH_NORMAL; + if (strstr(path, "/#") != NULL) { + item->path_type = PATH_FILTER; + } else { + CoAPPathMD5_sum(path, strlen(path), item->path, MAX_PATH_CHECKSUM_LEN); + } + list_for_each_entry_safe(node, next_node, &secure_resource_cb_head, lst, secure_resource_cb_item) { + if (item->path_type == PATH_NORMAL && node->path_type == PATH_NORMAL) { + if (memcmp(node->path, item->path, MAX_PATH_CHECKSUM_LEN) == 0) { + dup = 1; + } + } else if (item->path_type == PATH_FILTER && node->path_type == PATH_FILTER) { + if (strncpy(node->filter_path, item->filter_path, strlen(item->filter_path)) == 0) { + dup = 1; + } + } + } + if (dup == 0) { + if (item->path_type == PATH_FILTER) { + item->filter_path = coap_malloc(strlen(path) + 1); + if (item->filter_path == NULL) { + coap_free(item); + return -1; + } + memset(item->filter_path, 0, strlen(path) + 1); + strncpy(item->filter_path, path, strlen(path)); + } + + strncpy(pk_dn, pk, sizeof(pk_dn) - 1); + strncat(pk_dn, dn, sizeof(pk_dn) - strlen(pk_dn) - 1); + + CoAPPathMD5_sum(pk_dn, strlen(pk_dn), item->pk_dn, PK_DN_CHECKSUM_LEN); + + list_add_tail(&item->lst, &secure_resource_cb_head); + } else { + coap_free(item); + } + + return CoAPResource_register(context, path, permission, ctype, maxage, &recv_msg_handler); +} + +void alcs_resource_cb_deinit(void) +{ + secure_resource_cb_item *del_item = NULL; + + list_for_each_entry(del_item, &secure_resource_cb_head, lst, secure_resource_cb_item) { + list_del(&del_item->lst); + if (del_item->path_type == PATH_FILTER) { + coap_free(del_item->filter_path); + } + coap_free(del_item); + del_item = list_entry(&secure_resource_cb_head, secure_resource_cb_item, lst); + } +} + +void alcs_auth_list_deinit(void) +{ + auth_list *auth_list_ctx = get_list(ctx); + svr_key_item *del_item = NULL, *next_item = NULL; + + list_for_each_entry_safe(del_item, next_item, &auth_list_ctx->lst_svr, lst, svr_key_item) { + list_del(&del_item->lst); + if (del_item->keyInfo.secret) { + coap_free(del_item->keyInfo.secret); + } + coap_free(del_item); + } +} + +void alcs_rec_heart_beat(CoAPContext *ctx, const char *path, NetworkAddr *remote, CoAPMessage *request) +{ + struct list_head *ctl_head = get_svr_session_list(ctx); + session_item *session = NULL; + session_item *node = NULL, *next = NULL; + int seqlen, datalen; + char *seq, *data; + CoAPMessage msg; + char databuf[32]; + char payloadbuf[128]; + CoAPLenString payload; + + COAP_DEBUG("alcs_rec_heart_beat"); + if (!ctl_head || list_empty(ctl_head)) { + return; + } + + list_for_each_entry_safe(node, next, ctl_head, lst, session_item) { + if (node->sessionId && is_networkadd_same(&node->addr, remote)) { + node->heart_time = HAL_UptimeMs(); + session = node; + } + } + + if (!session) { + COAP_INFO("receive stale heart beat"); + } + + + if (!req_payload_parser((const char *)request->payload, request->payloadlen, &seq, &seqlen, &data, &datalen)) { + /* do nothing */ + } + + if (session) { + HAL_Snprintf(databuf, sizeof(databuf), "\"delayTime\":%d", default_heart_expire / 1000); + HAL_Snprintf(payloadbuf, sizeof(payloadbuf), RES_FORMAT, seqlen, seq, 200, databuf); + } else { + HAL_Snprintf(payloadbuf, sizeof(payloadbuf), RES_FORMAT, seqlen, seq, ALCS_HEART_FAILAUTH, ""); + } + + payload.data = (unsigned char *)payloadbuf; + payload.len = strlen(payloadbuf); + alcs_msg_init(ctx, &msg, COAP_MSG_CODE_205_CONTENT, COAP_MESSAGE_TYPE_CON, 0, &payload, NULL); + if (session) { + msg.header.msgid = request->header.msgid; + msg.header.tokenlen = request->header.tokenlen; + memcpy(&msg.token, request->token, request->header.tokenlen); + internal_secure_send(ctx, session, remote, &msg, 1, NULL); + } else { + CoAPLenString token = {request->header.tokenlen, request->token}; + alcs_sendrsp(ctx, remote, &msg, 1, request->header.msgid, &token); + } + alcs_msg_deinit(&msg); +} + +int observe_data_encrypt(CoAPContext *ctx, const char *path, NetworkAddr *from, CoAPMessage *message, + CoAPLenString *src, CoAPLenString *dest) +{ + secure_resource_cb_item *node = get_resource_by_path(path); + struct list_head *sessions; + session_item *session; + COAP_DEBUG("observe_data_encrypt, src:%.*s", src->len, src->data); + if (!node) { + return COAP_ERROR_NOT_FOUND; + } + + sessions = get_svr_session_list(ctx); + session = get_session_by_checksum(sessions, from, node->pk_dn); + + if (session) { + dest->len = (src->len & 0xfffffff0) + 16; + dest->data = (unsigned char *)coap_malloc(dest->len); + alcs_encrypt((const char *)src->data, src->len, session->sessionKey, dest->data); + CoAPUintOption_add(message, COAP_OPTION_SESSIONID, session->sessionId); + return COAP_SUCCESS; + } + + return COAP_ERROR_NOT_FOUND; +} + +void on_svr_auth_timer(CoAPContext *ctx) +{ + struct list_head *head = get_svr_session_list(ctx); + int tick; + session_item *node = NULL, *next = NULL; + + if (!head || list_empty(head)) { + return; + } + /* COAP_INFO ("on_svr_auth_timer:%d", (int)HAL_UptimeMs()); */ + + /* device_auth_list* dev = get_device (ctx); */ + tick = HAL_UptimeMs(); + + list_for_each_entry_safe(node, next, head, lst, session_item) { + if (node->sessionId && node->heart_time + default_heart_expire < tick) { + COAP_ERR("heart beat timeout"); + remove_session(ctx, node); + } + } +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dev_model_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dev_model_api.h new file mode 100644 index 00000000..1c954c9b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dev_model_api.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _IOT_EXPORT_LINKKIT_H_ +#define _IOT_EXPORT_LINKKIT_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +#include "infra_types.h" +#include "infra_defs.h" + +typedef enum { + IOTX_LINKKIT_DEV_TYPE_MASTER, + IOTX_LINKKIT_DEV_TYPE_SLAVE, + IOTX_LINKKIT_DEV_TYPE_MAX +} iotx_linkkit_dev_type_t; + +typedef struct { + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char product_secret[IOTX_PRODUCT_SECRET_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1]; +} iotx_linkkit_dev_meta_info_t; + +typedef enum { + /* post property value to cloud */ + ITM_MSG_POST_PROPERTY, + + /* post device info update message to cloud */ + ITM_MSG_DEVICEINFO_UPDATE, + + /* post device info delete message to cloud */ + ITM_MSG_DEVICEINFO_DELETE, + + /* post raw data to cloud */ + ITM_MSG_POST_RAW_DATA, + + /* only for slave device, send login request to cloud */ + ITM_MSG_LOGIN, + + /* only for slave device, send logout request to cloud */ + ITM_MSG_LOGOUT, + + /* only for slave device, send delete topo request to cloud */ + ITM_MSG_DELETE_TOPO, + + /* query ntp time from cloud */ + ITM_MSG_QUERY_TIMESTAMP, + + /* only for master device, query topo list */ + ITM_MSG_QUERY_TOPOLIST, + + /* only for master device, qurey firmware ota data */ + ITM_MSG_QUERY_FOTA_DATA, + + /* only for master device, qurey config ota data */ + ITM_MSG_QUERY_COTA_DATA, + + /* only for master device, request config ota data from cloud */ + ITM_MSG_REQUEST_COTA, + + /* only for master device, request fota image from cloud */ + ITM_MSG_REQUEST_FOTA_IMAGE, + + /* report subdev's firmware version */ + ITM_MSG_REPORT_SUBDEV_FIRMWARE_VERSION, + + /* get a device's desired property */ + ITM_MSG_PROPERTY_DESIRED_GET, + + /* delete a device's desired property */ + ITM_MSG_PROPERTY_DESIRED_DELETE, + + IOTX_LINKKIT_MSG_MAX +} iotx_linkkit_msg_type_t; + +/** + * @brief create a new device + * + * @param dev_type. type of device which will be created. see iotx_linkkit_dev_type_t + * @param meta_info. The product key, product secret, device name and device secret of new device. + * + * @return success: device id (>=0), fail: -1. + * + */ +DLL_IOT_API int IOT_Linkkit_Open(iotx_linkkit_dev_type_t dev_type, iotx_linkkit_dev_meta_info_t *meta_info); + +/** + * @brief start device network connection. + * for master device, start to connect aliyun server. + * for slave device, send message to cloud for register new device and add topo with master device + * + * @param devid. device identifier. + * + * @return success: device id (>=0), fail: -1. + * + */ +DLL_IOT_API int IOT_Linkkit_Connect(int devid); + +/** + * @brief try to receive message from cloud and dispatch these message to user event callback + * + * @param timeout_ms. timeout for waiting new message arrived + * + * @return void. + * + */ +DLL_IOT_API void IOT_Linkkit_Yield(int timeout_ms); + +/** + * @brief close device network connection and release resources. + * for master device, disconnect with aliyun server and release all local resources. + * for slave device, send message to cloud for delete topo with master device and unregister itself, then release device's resources. + * + * @param devid. device identifier. + * + * @return success: 0, fail: -1. + * + */ +DLL_IOT_API int IOT_Linkkit_Close(int devid); + +/** + * @brief Report message to cloud + * + * @param devid. device identifier. + * @param msg_type. message type. see iotx_linkkit_msg_type_t, as follows: + * ITM_MSG_POST_PROPERTY + * ITM_MSG_DEVICEINFO_UPDATE + * ITM_MSG_DEVICEINFO_DELETE + * ITM_MSG_POST_RAW_DATA + * ITM_MSG_LOGIN + * ITM_MSG_LOGOUT + * + * @param payload. message payload. + * @param payload_len. message payload length. + * + * @return success: 0 or message id (>=1), fail: -1. + * + */ +DLL_IOT_API int IOT_Linkkit_Report(int devid, iotx_linkkit_msg_type_t msg_type, unsigned char *payload, + int payload_len); + +/** + * @brief post message to cloud + * + * @param devid. device identifier. + * @param msg_type. message type. see iotx_linkkit_msg_type_t, as follows: + * ITM_MSG_QUERY_TIMESTAMP + * ITM_MSG_QUERY_TOPOLIST + * ITM_MSG_QUERY_FOTA_DATA + * ITM_MSG_QUERY_COTA_DATA + * ITM_MSG_REQUEST_COTA + * ITM_MSG_REQUEST_FOTA_IMAGE + * + * @param payload. message payload. + * @param payload_len. message payload length. + * + * @return success: 0 or message id (>=1), fail: -1. + * + */ +DLL_IOT_API int IOT_Linkkit_Query(int devid, iotx_linkkit_msg_type_t msg_type, unsigned char *payload, + int payload_len); + +/** + * @brief post event to cloud + * + * @param devid. device identifier. + * @param eventid. tsl event id. + * @param eventid_len. length of tsl event id. + * @param payload. event payload. + * @param payload_len. event payload length. + * + * @return success: message id (>=1), fail: -1. + * + */ +DLL_IOT_API int IOT_Linkkit_TriggerEvent(int devid, char *eventid, int eventid_len, char *payload, int payload_len); + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_api.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_api.c new file mode 100644 index 00000000..60f256e1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_api.c @@ -0,0 +1,2070 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#include "iotx_dm_internal.h" + +static dm_api_ctx_t g_dm_api_ctx; + +static dm_api_ctx_t *_dm_api_get_ctx(void) +{ + return &g_dm_api_ctx; +} + +static void _dm_api_lock(void) +{ + dm_api_ctx_t *ctx = _dm_api_get_ctx(); + if (ctx->mutex) { + HAL_MutexLock(ctx->mutex); + } +} + +static void _dm_api_unlock(void) +{ + dm_api_ctx_t *ctx = _dm_api_get_ctx(); + if (ctx->mutex) { + HAL_MutexUnlock(ctx->mutex); + } +} + +int iotx_dm_open(void) +{ + int res = 0; + dm_api_ctx_t *ctx = _dm_api_get_ctx(); +#if defined(ALCS_ENABLED) || defined(DEPRECATED_LINKKIT) + lite_cjson_hooks hooks; +#endif + memset(ctx, 0, sizeof(dm_api_ctx_t)); + +#if defined(ALCS_ENABLED) || defined(DEPRECATED_LINKKIT) + /* lite-cjson Hooks Init */ + hooks.malloc_fn = dm_utils_malloc; + hooks.free_fn = dm_utils_free; + lite_cjson_init_hooks(&hooks); +#endif + + /* DM Mutex Create*/ + ctx->mutex = HAL_MutexCreate(); + if (ctx->mutex == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + /* DM OTA Module Init */ + res = dm_ota_init(); + if (res != SUCCESS_RETURN) { + goto ERROR; + } +#endif + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + /* DM Message Cache Init */ + res = dm_msg_cache_init(); + if (res != SUCCESS_RETURN) { + goto ERROR; + } +#endif + /* DM Cloud Message Parse And Assemble Module Init */ + res = dm_msg_init(); + if (res != SUCCESS_RETURN) { + goto ERROR; + } + + /* DM IPC Module Init */ + res = dm_ipc_init(CONFIG_DISPATCH_QUEUE_MAXLEN); + if (res != SUCCESS_RETURN) { + goto ERROR; + } + + /* DM Manager Module Init */ + res = dm_mgr_init(); + if (res != SUCCESS_RETURN) { + goto ERROR; + } + +#ifdef ALCS_ENABLED + /* Open Local Connection */ + res = dm_server_open(); + if (res < SUCCESS_RETURN) { + goto ERROR; + } +#endif +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + /* DM OTA Module Init */ + res = dm_ota_sub(); + if (res == SUCCESS_RETURN) { + /* DM Config OTA Module Init */ + dm_cota_init(); + + /* DM Firmware OTA Mudule Init */ + dm_fota_init(); + } +#endif + + /* Open Cloud Connection */ + res = dm_client_open(); + if (res < SUCCESS_RETURN) { + goto ERROR; + } + + return SUCCESS_RETURN; + +ERROR: + dm_client_close(); +#ifdef ALCS_ENABLED + dm_server_close(); +#endif + dm_mgr_deinit(); + dm_ipc_deinit(); + dm_msg_deinit(); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_deinit(); +#endif +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + dm_ota_deinit(); +#endif + + if (ctx->mutex) { + HAL_MutexDestroy(ctx->mutex); + } + return FAIL_RETURN; +} + +int iotx_dm_connect(_IN_ iotx_dm_init_params_t *init_params) +{ + int res = 0; + dm_api_ctx_t *ctx = _dm_api_get_ctx(); + + if (init_params == NULL) { + return DM_INVALID_PARAMETER; + } + + /* DM Event Callback */ + if (init_params->event_callback != NULL) { + ctx->event_callback = init_params->event_callback; + } + + res = dm_client_connect(IOTX_DM_CLIENT_CONNECT_TIMEOUT_MS); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + +#ifdef ALCS_ENABLED + /* DM Connect Local */ + res = dm_server_connect(); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } +#endif + + return SUCCESS_RETURN; +} + +int iotx_dm_subscribe(_IN_ int devid) +{ + int res = 0, dev_type = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1] = {0}; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_search_device_by_devid(devid, product_key, device_name, device_secret); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return res; + } + + res = dm_mgr_get_dev_type(devid, &dev_type); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return res; + } + +#ifdef ALCS_ENABLED + if (devid > 0) { + dm_server_add_device(product_key, device_name); + } + + res = dm_server_subscribe_all(product_key, device_name); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return res; + } +#endif + + res = dm_client_subscribe_all(product_key, device_name, dev_type); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return res; + } + + _dm_api_unlock(); + dm_log_info("Devid %d Sub Completed", devid); + + return SUCCESS_RETURN; +} + +int iotx_dm_close(void) +{ + dm_api_ctx_t *ctx = _dm_api_get_ctx(); + + dm_client_close(); +#ifdef ALCS_ENABLED + dm_server_close(); +#endif + dm_mgr_deinit(); + dm_ipc_deinit(); + dm_msg_deinit(); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_deinit(); +#endif +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + dm_cota_deinit(); + dm_fota_deinit(); + dm_ota_deinit(); +#endif + + if (ctx->mutex) { + HAL_MutexDestroy(ctx->mutex); + } + +#ifdef LOG_REPORT_TO_CLOUD + remove_log_poll(); +#endif + + return SUCCESS_RETURN; +} + +int iotx_dm_yield(int timeout_ms) +{ + if (timeout_ms <= 0) { + return DM_INVALID_PARAMETER; + } + + dm_client_yield(timeout_ms); +#ifdef ALCS_ENABLED + dm_server_yield(); +#endif + + return SUCCESS_RETURN; +} + +void iotx_dm_dispatch(void) +{ + int count = 0; + void *data = NULL; + dm_api_ctx_t *ctx = _dm_api_get_ctx(); + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_tick(); +#endif +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + dm_cota_status_check(); + dm_fota_status_check(); +#endif + while (CONFIG_DISPATCH_QUEUE_MAXLEN == 0 || count++ < CONFIG_DISPATCH_QUEUE_MAXLEN) { + if (dm_ipc_msg_next(&data) == SUCCESS_RETURN) { + dm_ipc_msg_t *msg = (dm_ipc_msg_t *)data; + + if (ctx->event_callback) { + ctx->event_callback(msg->type, msg->data); + } + + if (msg->data) { + DM_free(msg->data); + } + DM_free(msg); + data = NULL; + } else { + break; + } + } +} + +int iotx_dm_post_rawdata(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + + if (devid < 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + res = dm_mgr_upstream_thing_model_up_raw(devid, payload, payload_len); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) +int iotx_dm_set_opt(int opt, void *data) +{ + return dm_opt_set(opt, data); +} + +int iotx_dm_get_opt(int opt, void *data) +{ + if (data == NULL) { + return FAIL_RETURN; + } + + return dm_opt_get(opt, data); +} +#ifdef DEVICE_MODEL_SHADOW +int iotx_dm_property_desired_get(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + + _dm_api_lock(); + + res = dm_mgr_upstream_thing_property_desired_get(devid, payload, payload_len); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return res; +} + +int iotx_dm_property_desired_delete(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + + _dm_api_lock(); + + res = dm_mgr_upstream_thing_property_desired_delete(devid, payload, payload_len); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return res; +} +#endif + +int iotx_dm_post_property(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + + _dm_api_lock(); + + res = dm_mgr_upstream_thing_property_post(devid, payload, payload_len); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return res; +} + +#ifdef LOG_REPORT_TO_CLOUD +int iotx_dm_log_post(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + + _dm_api_lock(); + + res = dm_mgr_upstream_thing_log_post(devid, payload, payload_len, 0); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return res; +} +#endif + + +int iotx_dm_post_event(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len, _IN_ char *payload, + _IN_ int payload_len) +{ + int res = 0, method_len = 0; + const char *method_fmt = "thing.event.%.*s.post"; + char *method = NULL; + + if (devid < 0 || identifier == NULL || identifier_len == 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + method_len = strlen(method_fmt) + strlen(identifier) + 1; + method = DM_malloc(method_len); + if (method == NULL) { + _dm_api_unlock(); + return DM_MEMORY_NOT_ENOUGH; + } + memset(method, 0, method_len); + HAL_Snprintf(method, method_len, method_fmt, identifier_len, identifier); + + res = dm_mgr_upstream_thing_event_post(devid, identifier, identifier_len, method, payload, payload_len); + if (res < SUCCESS_RETURN) { + DM_free(method); + _dm_api_unlock(); + return FAIL_RETURN; + } + + DM_free(method); + _dm_api_unlock(); + return res; +} + + +int iotx_dm_send_service_response(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, _IN_ iotx_dm_error_code_t code, + _IN_ char *identifier, + _IN_ int identifier_len, _IN_ char *payload, _IN_ int payload_len, void *ctx) +{ + int res = 0; + + if (devid < 0 || msgid == NULL || msgid_len <= 0 || identifier == NULL || identifier_len <= 0 || payload == NULL + || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + dm_log_debug("Current Service Response Payload, Length: %d, Payload: %.*s", payload_len, payload_len, payload); + + res = dm_mgr_upstream_thing_service_response(devid, msgid, msgid_len, code, identifier, identifier_len, payload, + payload_len, ctx); + + _dm_api_unlock(); + return res; +} + +int iotx_dm_send_property_get_response(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, + _IN_ iotx_dm_error_code_t code, _IN_ char *payload, _IN_ int payload_len, void *ctx) +{ + int res = 0; + + if (devid < 0 || msgid == NULL || msgid_len <= 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + dm_log_debug("Current Property Get Response Payload, Length: %d, Payload: %.*s", payload_len, payload_len, payload); + + res = dm_mgr_upstream_thing_property_get_response(devid, msgid, msgid_len, code, payload, + payload_len, ctx); + + _dm_api_unlock(); + return res; +} + +int iotx_dm_deviceinfo_update(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + + if (devid < 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + res = dm_mgr_upstream_thing_deviceinfo_update(devid, payload, payload_len); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return res; +} + +int iotx_dm_deviceinfo_delete(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + + if (devid < 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + res = dm_mgr_upstream_thing_deviceinfo_delete(devid, payload, payload_len); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return res; +} + +int iotx_dm_qurey_ntp(void) +{ + int res = 0; + + _dm_api_lock(); + + res = dm_mgr_upstream_ntp_request(); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return res; +} + +int iotx_dm_send_aos_active(int devid) +{ + int active_param_len; + int i; + char *active_param; + char aos_active_data[AOS_ACTIVE_INFO_LEN]; + char subdev_aos_verson[VERSION_NUM_SIZE] = {0}; + char subdev_mac_num[MAC_ADDRESS_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, ACTIVE_SUBDEV, ACTIVE_LINKKIT_OTHERS}; + char subdev_chip_code[CHIP_CODE_SIZE] = {0x01, 0x02, 0x03, 0x04}; + char random_num[RANDOM_NUM_SIZE]; + const char *fmt = + "[{\"attrKey\":\"SYS_ALIOS_ACTIVATION\",\"attrValue\":\"%s\",\"domain\":\"SYSTEM\"}]"; + + aos_get_version_hex((unsigned char *)subdev_aos_verson); + + HAL_Srandom(HAL_UptimeMs()); + for (i = 0; i < 4; i ++) { + random_num[i] = (char)HAL_Random(0xFF); + } + aos_get_version_info((unsigned char *)subdev_aos_verson, (unsigned char *)random_num, (unsigned char *)subdev_mac_num, + (unsigned char *)subdev_chip_code, (unsigned char *)aos_active_data, AOS_ACTIVE_INFO_LEN); + memcpy(aos_active_data + 40, "1111111111222222222233333333334444444444", 40); + + active_param_len = strlen(fmt) + strlen(aos_active_data) + 1; + active_param = DM_malloc(active_param_len); + if (active_param == NULL) { + return FAIL_RETURN; + } + HAL_Snprintf(active_param, active_param_len, fmt, aos_active_data); + iotx_dm_deviceinfo_update(devid, active_param, active_param_len); + DM_free(active_param); + + return SUCCESS_RETURN; +} + +int iotx_dm_send_rrpc_response(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, _IN_ iotx_dm_error_code_t code, + _IN_ char *rrpcid, _IN_ int rrpcid_len, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + + if (devid < 0 || msgid == NULL || msgid_len <= 0 || rrpcid == NULL || rrpcid_len <= 0 || payload == NULL + || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + res = dm_mgr_upstream_rrpc_response(devid, msgid, msgid_len, code, rrpcid, rrpcid_len, payload, payload_len); + + _dm_api_unlock(); + return res; +} +#endif + +int iotx_dm_cota_perform_sync(_OU_ char *buffer, _IN_ int buffer_len) +{ +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + return dm_cota_perform_sync(buffer, buffer_len); +#else + return -1; +#endif +} + +int iotx_dm_cota_get_config(_IN_ const char *config_scope, const char *get_type, const char *attribute_keys) +{ +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + return dm_cota_get_config(config_scope, get_type, attribute_keys); +#else + return -1; +#endif +} + +int iotx_dm_fota_perform_sync(_OU_ char *buffer, _IN_ int buffer_len) +{ +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + return dm_fota_perform_sync(buffer, buffer_len); +#else + return -1; +#endif +} + +int iotx_dm_fota_request_image(const char *version, int buffer_len) +{ +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + return dm_fota_request_image(version, buffer_len); +#else + return -1; +#endif +} + +#ifdef DEVICE_MODEL_GATEWAY +int iotx_dm_query_topo_list(void) +{ + int res = 0; + + _dm_api_lock(); + + res = dm_mgr_upstream_thing_topo_get(); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return res; +} + +int iotx_dm_subdev_create(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1], _OU_ int *devid) +{ + int res = 0; + + if (product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) || + devid == NULL) { + return DM_INVALID_PARAMETER; + } + + if (device_secret != NULL && strlen(device_secret) >= IOTX_DEVICE_SECRET_LEN + 1) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_device_create(IOTX_DM_DEVICE_SUBDEV, product_key, device_name, device_secret, devid); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_subdev_destroy(_IN_ int devid) +{ + int res = 0; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_device_destroy(devid); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_subdev_number(void) +{ + int number = 0; + + _dm_api_lock(); + number = dm_mgr_device_number(); + _dm_api_unlock(); + + return number; +} + +int iotx_dm_subdev_register(_IN_ int devid) +{ + int res = 0; + dm_mgr_dev_node_t *search_node = NULL; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_search_device_node_by_devid(devid, (void **)&search_node); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + if ((strlen(search_node->device_secret) > 0) && (strlen(search_node->device_secret) < IOTX_DEVICE_SECRET_LEN + 1)) { + _dm_api_unlock(); + return SUCCESS_RETURN; + } + + res = dm_mgr_upstream_thing_sub_register(devid); + + _dm_api_unlock(); + return res; +} + +int iotx_dm_subdev_unregister(_IN_ int devid) +{ + int res = 0; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + res = dm_mgr_upstream_thing_sub_unregister(devid); + + _dm_api_unlock(); + return res; +} + +int iotx_dm_subdev_topo_add(_IN_ int devid) +{ + int res = 0; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + res = dm_mgr_upstream_thing_topo_add(devid); + + _dm_api_unlock(); + return res; +} + +int iotx_dm_subdev_topo_del(_IN_ int devid) +{ + int res = 0; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + res = dm_mgr_upstream_thing_topo_delete(devid); + + _dm_api_unlock(); + return res; +} + +int iotx_dm_subdev_login(_IN_ int devid) +{ + int res = 0; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + res = dm_mgr_upstream_combine_login(devid); + + _dm_api_unlock(); + return res; +} + +int iotx_dm_subdev_logout(_IN_ int devid) +{ + int res = 0; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + res = dm_mgr_upstream_combine_logout(devid); + + _dm_api_unlock(); + return res; +} + +int iotx_dm_get_device_type(_IN_ int devid, _OU_ int *type) +{ + int res = 0; + + if (devid < 0 || type == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_get_dev_type(devid, type); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_get_device_avail_status(_IN_ int devid, _OU_ iotx_dm_dev_avail_t *status) +{ + int res = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1] = {0}; + + if (devid < 0 || status == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_search_device_by_devid(devid, product_key, device_name, device_secret); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + res = dm_mgr_get_dev_avail(product_key, device_name, status); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_get_device_status(_IN_ int devid, _OU_ iotx_dm_dev_status_t *status) +{ + int res = 0; + + if (devid < 0 || status == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_get_dev_status(devid, status); + _dm_api_unlock(); + + return res; +} +#ifdef DEVICE_MODEL_SUBDEV_OTA +int iotx_dm_firmware_version_update(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + + if (devid < 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_upstream_thing_firmware_version_update(devid, payload, payload_len); + if (res < SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return res; +} + +int iotx_dm_send_firmware_version(int devid, const char *version) +{ + char msg[FIRMWARE_VERSION_MSG_LEN] = {0}; + int msg_len = 0; + /* firmware report message json data generate */ + int ret = HAL_Snprintf(msg, + FIRMWARE_VERSION_MSG_LEN, + "{\"id\":\"%d\",\"params\":{\"version\":\"%s\"}}", + iotx_report_id(), + version + ); + if (ret <= 0) { + printf("firmware report message json data generate err"); + return FAIL_RETURN; + } + + msg_len = strlen(msg); + + ret = iotx_dm_firmware_version_update(devid, msg, msg_len); + return SUCCESS_RETURN; +} + +int iotx_dm_ota_switch_device(_IN_ int devid) +{ + return dm_ota_switch_device(devid); +} +#endif +#endif + +#ifdef DEPRECATED_LINKKIT +int iotx_dm_deprecated_set_tsl(_IN_ int devid, _IN_ iotx_dm_tsl_source_t source, _IN_ const char *tsl, _IN_ int tsl_len) +{ + int res = 0; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + if (source == IOTX_DM_TSL_SOURCE_CLOUD) { + res = dm_mgr_upstream_thing_dynamictsl_get(devid); + + _dm_api_unlock(); + return res; + } + + if (source == IOTX_DM_TSL_SOURCE_LOCAL) { + if (tsl == NULL || tsl_len <= 0) { + _dm_api_unlock(); + return DM_INVALID_PARAMETER; + } + + res = dm_mgr_deprecated_set_tsl(devid, IOTX_DM_TSL_TYPE_ALINK, tsl, tsl_len); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; + } + + _dm_api_unlock(); + return FAIL_RETURN; +} + +int iotx_dm_deprecated_set_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len) +{ + int res = 0; + + if (devid < 0 || key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_set_property_value(devid, key, key_len, value, value_len); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_get_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value) +{ + int res = 0; + + if (devid < 0 || key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_get_property_value(devid, key, key_len, value); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_set_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len) +{ + int res = 0; + + if (devid < 0 || key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_set_event_output_value(devid, key, key_len, value, value_len); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_get_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value) +{ + int res = 0; + + if (devid < 0 || key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_get_event_output_value(devid, key, key_len, value); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_get_service_input_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value) +{ + int res = 0; + + if (devid < 0 || key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_get_service_input_value(devid, key, key_len, value); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_set_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len) +{ + int res = 0; + + if (devid < 0 || key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_set_service_output_value(devid, key, key_len, value, value_len); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_get_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value) +{ + int res = 0; + + if (devid < 0 || key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_get_service_output_value(devid, key, key_len, value); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_post_property_start(_IN_ int devid, _OU_ void **handle) +{ + dm_api_property_t *dapi_property = NULL; + + if (devid < 0 || handle == NULL || *handle != NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + dapi_property = DM_malloc(sizeof(dm_api_property_t)); + if (dapi_property == NULL) { + _dm_api_unlock(); + return DM_MEMORY_NOT_ENOUGH; + } + memset(dapi_property, 0, sizeof(dm_api_property_t)); + + + /* Create Mutex */ + dapi_property->mutex = HAL_MutexCreate(); + if (dapi_property->mutex == NULL) { + DM_free(dapi_property); + _dm_api_unlock(); + return DM_MEMORY_NOT_ENOUGH; + } + + /* Set Devid */ + dapi_property->devid = devid; + + /* Init Json Object */ + dapi_property->lite = lite_cjson_create_object(); + if (dapi_property->lite == NULL) { + DM_free(dapi_property->mutex); + DM_free(dapi_property); + _dm_api_unlock(); + return FAIL_RETURN; + } + + *handle = (void *)dapi_property; + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +static int _iotx_dm_deprecated_post_property_add(_IN_ void *handle, _IN_ char *identifier, _IN_ int identifier_len) +{ + int res = 0; + dm_api_property_t *dapi_property = NULL; + + if (handle == NULL || identifier == NULL || identifier_len <= 0) { + return DM_INVALID_PARAMETER; + } + dapi_property = (dm_api_property_t *)handle; + + /* Assemble Property Payload */ + res = dm_mgr_deprecated_assemble_property(dapi_property->devid, identifier, identifier_len, dapi_property->lite); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_post_property_add(_IN_ void *handle, _IN_ char *identifier, _IN_ int identifier_len) +{ + int ret = SUCCESS_RETURN, res = 0, index = 0, number = 0; + void *property_refer = NULL; + char *identifier_refer = NULL; + dm_api_property_t *dapi_property = NULL; + + if (handle == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + dapi_property = (dm_api_property_t *)handle; + + if (identifier != IOTX_DM_POST_PROPERTY_ALL) { + if (identifier_len <= 0) { + _dm_api_unlock(); + return FAIL_RETURN; + } + ret = _iotx_dm_deprecated_post_property_add(handle, identifier, identifier_len); + + _dm_api_unlock(); + return ret; + } + + res = dm_mgr_deprecated_get_property_number(dapi_property->devid, &number); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + for (index = 0; index < number; index++) { + property_refer = NULL; + identifier_refer = NULL; + + res = dm_mgr_deprecated_get_property_by_index(dapi_property->devid, index, &property_refer); + if (res != SUCCESS_RETURN) { + continue; + } + + res = dm_mgr_deprecated_get_property_identifier(property_refer, &identifier_refer); + if (res != SUCCESS_RETURN) { + continue; + } + + res = _iotx_dm_deprecated_post_property_add(handle, identifier_refer, strlen(identifier_refer)); + if (res != SUCCESS_RETURN) { + ret = FAIL_RETURN; + } + } + + _dm_api_unlock(); + return ret; +} + +int iotx_dm_deprecated_post_property_end(_IN_ void **handle) +{ + int res = 0; + char *payload = NULL; + dm_api_property_t *dapi_property = NULL; + + if (handle == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + dapi_property = *((dm_api_property_t **)handle); + + payload = lite_cjson_print_unformatted(dapi_property->lite); + if (payload == NULL) { + lite_cjson_delete(dapi_property->lite); + if (dapi_property->mutex) { + HAL_MutexDestroy(dapi_property->mutex); + } + DM_free(dapi_property); + _dm_api_unlock(); + return DM_MEMORY_NOT_ENOUGH; + } + + dm_log_debug("Current Property Post Payload, Length: %d, Payload: %s", strlen(payload), payload); + + res = dm_mgr_upstream_thing_property_post(dapi_property->devid, payload, strlen(payload)); + + DM_free(payload); + lite_cjson_delete(dapi_property->lite); + if (dapi_property->mutex) { + HAL_MutexDestroy(dapi_property->mutex); + } + DM_free(dapi_property); + *handle = NULL; + + _dm_api_unlock(); + return res; +} + +int iotx_dm_deprecated_post_event(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len) +{ + int res = 0; + void *event = NULL; + lite_cjson_item_t *lite = NULL; + char *method = NULL, *payload = NULL; + + if (devid < 0 || identifier == NULL || identifier_len <= 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + lite = lite_cjson_create_object(); + if (lite == NULL) { + _dm_api_unlock(); + return DM_MEMORY_NOT_ENOUGH; + } + + res = dm_mgr_deprecated_assemble_event_output(devid, identifier, identifier_len, lite); + if (res != SUCCESS_RETURN) { + lite_cjson_delete(lite); + _dm_api_unlock(); + return FAIL_RETURN; + } + + payload = lite_cjson_print_unformatted(lite); + lite_cjson_delete(lite); + if (payload == NULL) { + _dm_api_unlock(); + return DM_MEMORY_NOT_ENOUGH; + } + + dm_log_debug("Current Event Post Payload, Length: %d, Payload: %s", strlen(payload), payload); + + res = dm_mgr_deprecated_get_event_by_identifier(devid, identifier, &event); + if (res != SUCCESS_RETURN) { + DM_free(payload); + _dm_api_unlock(); + return FAIL_RETURN; + } + + res = dm_mgr_deprecated_get_event_method(event, &method); + if (res != SUCCESS_RETURN) { + DM_free(payload); + _dm_api_unlock(); + return FAIL_RETURN; + } + + dm_log_debug("Current Event Method: %s", method); + + res = dm_mgr_upstream_thing_event_post(devid, identifier, identifier_len, method, payload, strlen(payload)); + + DM_free(payload); + DM_free(method); + + _dm_api_unlock(); + return res; +} + +int iotx_dm_deprecated_legacy_set_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ char *value_str) +{ + int res = 0; + void *data = NULL; + dm_shw_data_type_e type; + + if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_get_property_data(devid, key, key_len, &data); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + res = dm_mgr_deprecated_get_data_type(data, &type); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + switch (type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_ENUM: + case DM_SHW_DATA_TYPE_BOOL: { + int value_int = (value == NULL) ? (atoi(value_str)) : (*(int *)value); + res = dm_mgr_deprecated_set_property_value(devid, key, key_len, &value_int, sizeof(int)); + } + break; + case DM_SHW_DATA_TYPE_FLOAT: { + float value_float = (value == NULL) ? (atof(value_str)) : (*(float *)value); + res = dm_mgr_deprecated_set_property_value(devid, key, key_len, &value_float, sizeof(float)); + } + break; + case DM_SHW_DATA_TYPE_DOUBLE: { + double value_double = (value == NULL) ? (atof(value_str)) : (*(double *)value); + res = dm_mgr_deprecated_set_property_value(devid, key, key_len, &value_double, sizeof(double)); + } + break; + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_DATE: { + char *value_string = (value == NULL) ? (value_str) : (value); + res = dm_mgr_deprecated_set_property_value(devid, key, key_len, value_string, strlen(value_string)); + } + break; + default: { + res = FAIL_RETURN; + } + break; + } + + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_legacy_get_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ char **value_str) +{ + int res = 0; + void *data = NULL; + dm_shw_data_type_e type; + + if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_get_property_data(devid, key, key_len, &data); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + res = dm_mgr_deprecated_get_data_type(data, &type); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + switch (type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_ENUM: + case DM_SHW_DATA_TYPE_BOOL: { + int value_int = 0; + res = dm_mgr_deprecated_get_property_value(devid, key, key_len, (void *)&value_int); + if (res == SUCCESS_RETURN) { + if (value) { + *(int *)value = value_int; + } + if (value_str) { + res = dm_utils_itoa_direct(value_int, value_str); + } + } + } + break; + case DM_SHW_DATA_TYPE_FLOAT: { + float value_float = 0; + res = dm_mgr_deprecated_get_property_value(devid, key, key_len, (void *)&value_float); + if (res == SUCCESS_RETURN) { + if (value) { + *(float *)value = value_float; + } + if (value_str) { + res = dm_utils_ftoa_direct(value_float, value_str); + } + } + } + break; + case DM_SHW_DATA_TYPE_DOUBLE: { + double value_double = 0; + res = dm_mgr_deprecated_get_property_value(devid, key, key_len, (void *)&value_double); + if (res == SUCCESS_RETURN) { + if (value) { + *(double *)value = value_double; + } + if (value_str) { + res = dm_utils_ftoa_direct(value_double, value_str); + } + } + } + break; + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_DATE: { + char *value_string = NULL; + res = dm_mgr_deprecated_get_property_value(devid, key, key_len, (void *)&value_string); + if (res == SUCCESS_RETURN) { + if (value) { + memcpy(value, value_string, strlen(value_string)); + } + if (value_str) { + *value_str = value_string; + } else { + HAL_Free(value_string); + } + } + } + break; + default: { + res = FAIL_RETURN; + } + break; + } + + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_legacy_set_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ char *value_str) +{ + int res = 0; + void *data = NULL; + dm_shw_data_type_e type; + + if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_get_event_output_data(devid, key, key_len, &data); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + res = dm_mgr_deprecated_get_data_type(data, &type); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + switch (type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_ENUM: + case DM_SHW_DATA_TYPE_BOOL: { + int value_int = (value == NULL) ? (atoi(value_str)) : (*(int *)value); + res = dm_mgr_deprecated_set_event_output_value(devid, key, key_len, &value_int, sizeof(int)); + } + break; + case DM_SHW_DATA_TYPE_FLOAT: { + float value_float = (value == NULL) ? (atof(value_str)) : (*(float *)value); + res = dm_mgr_deprecated_set_event_output_value(devid, key, key_len, &value_float, sizeof(float)); + } + break; + case DM_SHW_DATA_TYPE_DOUBLE: { + double value_double = (value == NULL) ? (atof(value_str)) : (*(double *)value); + res = dm_mgr_deprecated_set_event_output_value(devid, key, key_len, &value_double, sizeof(double)); + } + break; + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_DATE: { + char *value_string = (value == NULL) ? (value_str) : (value); + res = dm_mgr_deprecated_set_event_output_value(devid, key, key_len, value_string, strlen(value_string)); + } + break; + default: { + res = FAIL_RETURN; + } + break; + } + + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_legacy_get_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ char **value_str) +{ + int res = 0; + void *data = NULL; + dm_shw_data_type_e type; + + if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_get_event_output_data(devid, key, key_len, &data); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + res = dm_mgr_deprecated_get_data_type(data, &type); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + switch (type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_ENUM: + case DM_SHW_DATA_TYPE_BOOL: { + int value_int = 0; + res = dm_mgr_deprecated_get_event_output_value(devid, key, key_len, (void *)&value_int); + if (res == SUCCESS_RETURN) { + if (value) { + *(int *)value = value_int; + } + if (value_str) { + res = dm_utils_itoa_direct(value_int, value_str); + } + } + } + break; + case DM_SHW_DATA_TYPE_FLOAT: { + float value_float = 0; + res = dm_mgr_deprecated_get_event_output_value(devid, key, key_len, (void *)&value_float); + if (res == SUCCESS_RETURN) { + if (value) { + *(float *)value = value_float; + } + if (value_str) { + res = dm_utils_ftoa_direct(value_float, value_str); + } + } + } + break; + case DM_SHW_DATA_TYPE_DOUBLE: { + double value_double = 0; + res = dm_mgr_deprecated_get_event_output_value(devid, key, key_len, (void *)&value_double); + if (res == SUCCESS_RETURN) { + if (value) { + *(double *)value = value_double; + } + if (value_str) { + res = dm_utils_ftoa_direct(value_double, value_str); + } + } + } + break; + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_DATE: { + char *value_string = NULL; + res = dm_mgr_deprecated_get_event_output_value(devid, key, key_len, (void *)&value_string); + if (res == SUCCESS_RETURN) { + if (value) { + memcpy(value, value_string, strlen(value_string)); + } + if (value_str) { + *value_str = value_string; + } else { + HAL_Free(value_string); + } + } + } + break; + default: { + res = FAIL_RETURN; + } + break; + } + + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_legacy_get_service_input_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, + _IN_ void *value, + _IN_ char **value_str) +{ + int res = 0; + void *data = NULL; + dm_shw_data_type_e type; + + if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + res = dm_mgr_deprecated_get_service_input_data(devid, key, key_len, &data); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + res = dm_mgr_deprecated_get_data_type(data, &type); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + switch (type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_ENUM: + case DM_SHW_DATA_TYPE_BOOL: { + int value_int = 0; + res = dm_mgr_deprecated_get_service_input_value(devid, key, key_len, (void *)&value_int); + if (res == SUCCESS_RETURN) { + if (value) { + *(int *)value = value_int; + } + if (value_str) { + res = dm_utils_itoa_direct(value_int, value_str); + } + } + } + break; + case DM_SHW_DATA_TYPE_FLOAT: { + float value_float = 0; + res = dm_mgr_deprecated_get_service_input_value(devid, key, key_len, (void *)&value_float); + if (res == SUCCESS_RETURN) { + if (value) { + *(float *)value = value_float; + } + if (value_str) { + res = dm_utils_ftoa_direct(value_float, value_str); + } + } + } + break; + case DM_SHW_DATA_TYPE_DOUBLE: { + double value_double = 0; + res = dm_mgr_deprecated_get_service_input_value(devid, key, key_len, (void *)&value_double); + if (res == SUCCESS_RETURN) { + if (value) { + *(double *)value = value_double; + } + if (value_str) { + res = dm_utils_ftoa_direct(value_double, value_str); + } + } + } + break; + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_DATE: { + char *value_string = NULL; + res = dm_mgr_deprecated_get_service_input_value(devid, key, key_len, (void *)&value_string); + if (res == SUCCESS_RETURN) { + if (value) { + memcpy(value, value_string, strlen(value_string)); + } + if (value_str) { + *value_str = value_string; + } else { + HAL_Free(value_string); + } + } + } + break; + default: { + res = FAIL_RETURN; + } + break; + } + + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_legacy_set_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, + _IN_ void *value, + _IN_ char *value_str) +{ + int res = 0; + void *data = NULL; + dm_shw_data_type_e type; + + if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_get_service_output_data(devid, key, key_len, &data); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + res = dm_mgr_deprecated_get_data_type(data, &type); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + switch (type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_ENUM: + case DM_SHW_DATA_TYPE_BOOL: { + int value_int = (value == NULL) ? (atoi(value_str)) : (*(int *)value); + res = dm_mgr_deprecated_set_service_output_value(devid, key, key_len, &value_int, sizeof(int)); + } + break; + case DM_SHW_DATA_TYPE_FLOAT: { + float value_float = (value == NULL) ? (atof(value_str)) : (*(float *)value); + res = dm_mgr_deprecated_set_service_output_value(devid, key, key_len, &value_float, sizeof(float)); + } + break; + case DM_SHW_DATA_TYPE_DOUBLE: { + double value_double = (value == NULL) ? (atof(value_str)) : (*(double *)value); + res = dm_mgr_deprecated_set_service_output_value(devid, key, key_len, &value_double, sizeof(double)); + } + break; + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_DATE: { + char *value_string = (value == NULL) ? (value_str) : (value); + res = dm_mgr_deprecated_set_service_output_value(devid, key, key_len, value_string, strlen(value_string)); + } + break; + default: { + res = FAIL_RETURN; + } + break; + } + + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_legacy_get_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, + _IN_ void *value, + _IN_ char **value_str) +{ + int res = 0; + void *data = NULL; + dm_shw_data_type_e type; + + if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + + res = dm_mgr_deprecated_get_service_output_data(devid, key, key_len, &data); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + res = dm_mgr_deprecated_get_data_type(data, &type); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + switch (type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_ENUM: + case DM_SHW_DATA_TYPE_BOOL: { + int value_int = 0; + res = dm_mgr_deprecated_get_service_output_value(devid, key, key_len, (void *)&value_int); + if (res == SUCCESS_RETURN) { + if (value) { + *(int *)value = value_int; + } + if (value_str) { + res = dm_utils_itoa_direct(value_int, value_str); + } + } + } + break; + case DM_SHW_DATA_TYPE_FLOAT: { + float value_float = 0; + res = dm_mgr_deprecated_get_service_output_value(devid, key, key_len, (void *)&value_float); + if (res == SUCCESS_RETURN) { + if (value) { + *(float *)value = value_float; + } + if (value_str) { + res = dm_utils_ftoa_direct(value_float, value_str); + } + } + } + break; + case DM_SHW_DATA_TYPE_DOUBLE: { + double value_double = 0; + res = dm_mgr_deprecated_get_service_output_value(devid, key, key_len, (void *)&value_double); + if (res == SUCCESS_RETURN) { + if (value) { + *(double *)value = value_double; + } + if (value_str) { + res = dm_utils_ftoa_direct(value_double, value_str); + } + } + } + break; + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_DATE: { + char *value_string = NULL; + res = dm_mgr_deprecated_get_service_output_value(devid, key, key_len, (void *)&value_string); + if (res == SUCCESS_RETURN) { + if (value) { + memcpy(value, value_string, strlen(value_string)); + } + if (value_str) { + *value_str = value_string; + } else { + HAL_Free(value_string); + } + } + } + break; + default: { + res = FAIL_RETURN; + } + break; + } + + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_legacy_get_pkdn_by_devid(_IN_ int devid, _OU_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _OU_ char device_name[IOTX_DEVICE_NAME_LEN + 1]) +{ + int res = 0; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1] = {0}; + + if (devid < 0 || product_key == NULL || device_name == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_search_device_by_devid(devid, product_key, device_name, device_secret); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_legacy_get_devid_by_pkdn(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], _OU_ int *devid) +{ + int res = 0; + + if (devid == NULL || product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1)) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_search_device_by_pkdn(product_key, device_name, devid); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_legacy_get_thingid_by_devid(_IN_ int devid, _OU_ void **thing_id) +{ + int res = 0; + + if (devid < 0 || thing_id == NULL || *thing_id != NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_search_device_node_by_devid(devid, thing_id); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_legacy_get_devid_by_thingid(_IN_ void *thing_id, _OU_ int *devid) +{ + int res = 0; + + if (thing_id == NULL || devid == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_deprecated_search_devid_by_device_node(thing_id, devid); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_legacy_get_pkdn_ptr_by_devid(_IN_ int devid, _OU_ char **product_key, _OU_ char **device_name) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || product_key == NULL || *product_key != NULL || + device_name == NULL || *device_name != NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + res = dm_mgr_search_device_node_by_devid(devid, (void **)&node); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + + *product_key = node->product_key; + *device_name = node->device_name; + + _dm_api_unlock(); + return SUCCESS_RETURN; +} + +int iotx_dm_deprecated_legacy_send_service_response(_IN_ int devid, _IN_ int msgid, _IN_ iotx_dm_error_code_t code, + _IN_ char *identifier, _IN_ int identifier_len, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + + _dm_api_lock(); + + res = dm_mgr_deprecated_upstream_thing_service_response(devid, msgid, code, identifier, identifier_len, payload, + payload_len); + + _dm_api_unlock(); + return res; +} + +int iotx_dm_deprecated_send_service_response(_IN_ int devid, _IN_ int msgid, _IN_ iotx_dm_error_code_t code, + _IN_ char *identifier, + _IN_ int identifier_len) +{ + int res = 0; + lite_cjson_item_t *lite = NULL; + char *payload = NULL; + + if (devid < 0 || msgid < 0 || identifier == NULL || identifier_len <= 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + lite = lite_cjson_create_object(); + if (lite == NULL) { + _dm_api_unlock(); + return DM_MEMORY_NOT_ENOUGH; + } + + res = dm_mgr_deprecated_assemble_service_output(devid, identifier, identifier_len, lite); + if (res != SUCCESS_RETURN) { + lite_cjson_delete(lite); + _dm_api_unlock(); + return FAIL_RETURN; + } + + payload = lite_cjson_print_unformatted(lite); + lite_cjson_delete(lite); + if (payload == NULL) { + _dm_api_unlock(); + return DM_MEMORY_NOT_ENOUGH; + } + + dm_log_debug("Current Service Response Payload, Length: %d, Payload: %s", strlen(payload), payload); + + res = dm_mgr_deprecated_upstream_thing_service_response(devid, msgid, code, identifier, identifier_len, payload, + strlen(payload)); + + DM_free(payload); + + _dm_api_unlock(); + return res; +} + +#ifdef DEVICE_MODEL_GATEWAY +int iotx_dm_deprecated_subdev_register(_IN_ int devid, _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1]) +{ + int res = 0; + dm_mgr_dev_node_t *search_node = NULL; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + _dm_api_lock(); + if ((device_secret != NULL) && (strlen(device_secret) > 0) && (strlen(device_secret) < IOTX_DEVICE_SECRET_LEN + 1)) { + res = dm_mgr_search_device_node_by_devid(devid, (void **)&search_node); + if (res != SUCCESS_RETURN) { + _dm_api_unlock(); + return FAIL_RETURN; + } + memset(search_node->device_secret, 0, IOTX_DEVICE_SECRET_LEN + 1); + memcpy(search_node->device_secret, device_secret, strlen(device_secret)); + _dm_api_unlock(); + return SUCCESS_RETURN; + } + + res = dm_mgr_upstream_thing_sub_register(devid); + + _dm_api_unlock(); + return res; +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_client.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_client.c new file mode 100644 index 00000000..45b71091 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_client.c @@ -0,0 +1,738 @@ +#include "iotx_dm_internal.h" + +#ifdef DEV_BIND_ENABLED + #include "dev_bind_api.h" +#endif +#ifdef LOG_REPORT_TO_CLOUD + #include "iotx_log_report.h" +#endif + +static dm_client_uri_map_t g_dm_client_uri_map[] = { +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + {DM_URI_THING_EVENT_POST_REPLY_WILDCARD, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_thing_event_post_reply }, +#ifdef DEVICE_MODEL_SHADOW + {DM_URI_THING_PROPERTY_DESIRED_DELETE_REPLY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_thing_property_desired_delete_reply}, + {DM_URI_THING_PROPERTY_DESIRED_GET_REPLY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_thing_property_desired_get_reply }, + {DM_URI_THING_SERVICE_PROPERTY_GET, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_thing_service_property_get }, +#endif + {DM_URI_THING_SERVICE_PROPERTY_SET, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_thing_service_property_set }, + {DM_URI_THING_SERVICE_REQUEST_WILDCARD, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_thing_service_request }, + {DM_URI_THING_DEVICEINFO_UPDATE_REPLY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_thing_deviceinfo_update_reply }, + {DM_URI_THING_DEVICEINFO_DELETE_REPLY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_thing_deviceinfo_delete_reply }, + {DM_URI_THING_DYNAMICTSL_GET_REPLY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_thing_dynamictsl_get_reply }, + {DM_URI_RRPC_REQUEST_WILDCARD, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_rrpc_request_wildcard }, + {DM_URI_NTP_RESPONSE, DM_URI_EXT_NTP_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_ntp_response }, + {NULL, DM_URI_EXT_ERROR_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_ext_error }, +#endif + {DM_URI_THING_MODEL_DOWN_RAW, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_thing_model_down_raw }, + {DM_URI_THING_MODEL_UP_RAW_REPLY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_ALL, (void *)dm_client_thing_model_up_raw_reply }, + +#ifdef DEVICE_MODEL_GATEWAY + {DM_URI_THING_TOPO_ADD_NOTIFY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_thing_topo_add_notify }, + {DM_URI_THING_GATEWAY_PERMIT, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_thing_gateway_permit }, + {DM_URI_THING_SUB_REGISTER_REPLY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_thing_sub_register_reply }, + {DM_URI_THING_SUB_UNREGISTER_REPLY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_thing_sub_unregister_reply }, + {DM_URI_THING_TOPO_ADD_REPLY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_thing_topo_add_reply }, + {DM_URI_THING_TOPO_DELETE_REPLY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_thing_topo_delete_reply }, + {DM_URI_THING_TOPO_GET_REPLY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_thing_topo_get_reply }, + {DM_URI_THING_LIST_FOUND_REPLY, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_thing_list_found_reply }, + {DM_URI_COMBINE_LOGIN_REPLY, DM_URI_EXT_SESSION_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_combine_login_reply }, + {DM_URI_COMBINE_LOGOUT_REPLY, DM_URI_EXT_SESSION_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_combine_logout_reply }, + {DM_URI_THING_DISABLE, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_thing_disable }, + {DM_URI_THING_ENABLE, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_thing_enable }, + {DM_URI_THING_DELETE, DM_URI_SYS_PREFIX, IOTX_DM_DEVICE_GATEWAY, (void *)dm_client_thing_delete }, +#endif +}; + +static int _dm_client_subscribe_filter(char *uri, char *uri_name, char product_key[IOTX_PRODUCT_KEY_LEN + 1], + char device_name[IOTX_DEVICE_NAME_LEN + 1]) +{ +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + int res = 0; +#endif + if (uri_name == NULL) { + return SUCCESS_RETURN; + } + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + if (strlen(uri_name) == strlen(DM_URI_THING_EVENT_POST_REPLY_WILDCARD) && + memcmp(uri_name, DM_URI_THING_EVENT_POST_REPLY_WILDCARD, strlen(uri_name)) == 0) { + int event_post_reply_opt = 0; + res = dm_opt_get(DM_OPT_DOWNSTREAM_EVENT_POST_REPLY, &event_post_reply_opt); + if (res == SUCCESS_RETURN && event_post_reply_opt == 0) { + dm_client_unsubscribe(uri); + return FAIL_RETURN; + } + } +#endif + + return SUCCESS_RETURN; +} + +int dm_client_subscribe_all(char product_key[IOTX_PRODUCT_KEY_LEN + 1], char device_name[IOTX_DEVICE_NAME_LEN + 1], + int dev_type) +{ + int res = 0, index = 0, fail_count = 0; + int number = sizeof(g_dm_client_uri_map) / sizeof(dm_client_uri_map_t); + char *uri = NULL; + uint8_t local_sub = 0; +#ifdef SUB_PERSISTENCE_ENABLED + char device_key[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 4] = {0}; +#endif + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + index = 1; + + for (fail_count = 0; fail_count < IOTX_DM_CLIENT_SUB_RETRY_MAX_COUNTS; fail_count++) { + + res = dm_utils_service_name((char *)g_dm_client_uri_map[0].uri_prefix, (char *)g_dm_client_uri_map[0].uri_name, + product_key, device_name, &uri); + if (res < SUCCESS_RETURN) { + continue; + } + res = _dm_client_subscribe_filter(uri, (char *)g_dm_client_uri_map[0].uri_name, product_key, device_name); + if (res < SUCCESS_RETURN) { + DM_free(uri); + continue; + } + + res = dm_client_subscribe(uri, (iotx_cm_data_handle_cb)g_dm_client_uri_map[0].callback, 0); + if (res < SUCCESS_RETURN) { + DM_free(uri); + continue; + } + + DM_free(uri); + break; + } +#else + index = 0; +#endif + fail_count = 0; +#ifdef SUB_PERSISTENCE_ENABLED + { + int len = 1; + HAL_Snprintf(device_key, IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN, "qub_%s%s", product_key, device_name); + HAL_Kv_Get(device_key, &local_sub, &len); + } +#endif + + for (; index < number; index++) { + if ((g_dm_client_uri_map[index].dev_type & dev_type) == 0) { + continue; + } + dm_log_info("index: %d", index); + + if (fail_count >= IOTX_DM_CLIENT_SUB_RETRY_MAX_COUNTS) { + fail_count = 0; + continue; + } + res = dm_utils_service_name((char *)g_dm_client_uri_map[index].uri_prefix, (char *)g_dm_client_uri_map[index].uri_name, + product_key, device_name, &uri); + if (res < SUCCESS_RETURN) { + index--; + continue; + } + + res = _dm_client_subscribe_filter(uri, (char *)g_dm_client_uri_map[index].uri_name, product_key, device_name); + if (res < SUCCESS_RETURN) { + DM_free(uri); + continue; + } + + res = dm_client_subscribe(uri, (iotx_cm_data_handle_cb)g_dm_client_uri_map[index].callback, &local_sub); + if (res < SUCCESS_RETURN) { + index--; + fail_count++; + DM_free(uri); + continue; + } + + fail_count = 0; + DM_free(uri); + } +#ifdef SUB_PERSISTENCE_ENABLED + local_sub = 1; + HAL_Kv_Set(device_key, &local_sub, 1, 1); +#endif + + return SUCCESS_RETURN; +} + +static void _dm_client_event_cloud_connected_handle(void) +{ + dm_log_info("IOTX_CM_EVENT_CLOUD_CONNECTED"); + +#ifdef DEV_BIND_ENABLED + awss_report_cloud(); +#endif + dm_msg_cloud_connected(); +} + +static void _dm_client_event_cloud_disconnect_handle(void) +{ + dm_log_info("IOTX_CM_EVENT_CLOUD_DISCONNECT"); + + dm_msg_cloud_disconnect(); +} + +void dm_client_event_handle(int fd, iotx_cm_event_msg_t *event, void *context) +{ + switch (event->type) { + case IOTX_CM_EVENT_CLOUD_CONNECTED: { + _dm_client_event_cloud_connected_handle(); + } + break; + case IOTX_CM_EVENT_CLOUD_CONNECT_FAILED: { + + } + break; + case IOTX_CM_EVENT_CLOUD_DISCONNECT: { + _dm_client_event_cloud_disconnect_handle(); + } + break; + default: + break; + } +} + +void dm_client_thing_model_down_raw(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_model_down_raw(&source); +} + +void dm_client_thing_model_up_raw_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_model_up_raw_reply(&source); +} +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) +void dm_client_thing_service_property_set(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + int res = 0; + dm_msg_source_t source; + dm_msg_dest_t dest; + dm_msg_request_payload_t request; + dm_msg_response_t response; + int prop_set_reply_opt = 0; + + memset(&source, 0, sizeof(dm_msg_source_t)); + memset(&dest, 0, sizeof(dm_msg_dest_t)); + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dest.uri_name = DM_URI_THING_SERVICE_PROPERTY_SET_REPLY; + + res = dm_msg_proc_thing_service_property_set(&source, &dest, &request, &response); + if (res < SUCCESS_RETURN) { + return; + } + + prop_set_reply_opt = 0; + res = dm_opt_get(DM_OPT_UPSTREAM_PROPERTY_SET_REPLY, &prop_set_reply_opt); + if (res == SUCCESS_RETURN) { + if (prop_set_reply_opt) { + dm_msg_response(DM_MSG_DEST_CLOUD, &request, &response, "{}", strlen("{}"), NULL); +#ifdef LOG_REPORT_TO_CLOUD + if (SUCCESS_RETURN == check_target_msg(request.id.value, request.id.value_length)) { + send_permance_info(request.id.value, request.id.value_length, "2", 1); + } +#endif + } + } +} + +#ifdef DEVICE_MODEL_SHADOW +void dm_client_thing_service_property_get(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + int res = 0; + dm_msg_source_t source; + dm_msg_dest_t dest; + dm_msg_request_payload_t request; + dm_msg_response_t response; + unsigned char *data = NULL; + int data_len = 0; + + memset(&source, 0, sizeof(dm_msg_source_t)); + memset(&dest, 0, sizeof(dm_msg_dest_t)); + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dest.uri_name = DM_URI_THING_SERVICE_PROPERTY_GET_REPLY; + + res = dm_msg_proc_thing_service_property_get(&source, &dest, &request, &response, &data, &data_len); + if (res < SUCCESS_RETURN) { + return; + } +} +#endif + +void dm_client_thing_service_request(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_service_request(&source); +} + +void dm_client_thing_event_post_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_event_post_reply(&source); +} +#ifdef DEVICE_MODEL_SHADOW +void dm_client_thing_property_desired_get_reply(int fd, const char *topic, const char *payload, + unsigned int payload_len, void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_property_desired_get_reply(&source); +} + +void dm_client_thing_property_desired_delete_reply(int fd, const char *topic, const char *payload, + unsigned int payload_len, void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_property_desired_delete_reply(&source); +} +#endif + +void dm_client_thing_deviceinfo_update_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_deviceinfo_update_reply(&source); +} + +void dm_client_thing_deviceinfo_delete_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_deviceinfo_delete_reply(&source); +} + +void dm_client_thing_dynamictsl_get_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_dynamictsl_get_reply(&source); +} + +void dm_client_rrpc_request_wildcard(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_rrpc_request(&source); +} + +void dm_client_ntp_response(int fd, const char *topic, const char *payload, unsigned int payload_len, void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_disp_ntp_response(&source); +} + +void dm_client_ext_error(int fd, const char *topic, const char *payload, unsigned int payload_len, void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_disp_ext_error_response(&source); +} +#endif + +#ifdef DEVICE_MODEL_GATEWAY +int dm_client_subdev_unsubscribe(char product_key[IOTX_PRODUCT_KEY_LEN + 1], char device_name[IOTX_DEVICE_NAME_LEN + 1]) +{ + int res = 0, index = 0; + int number = sizeof(g_dm_client_uri_map) / sizeof(dm_client_uri_map_t); + char *uri = NULL; + + for (index = 0; index < number; index++) { + if ((g_dm_client_uri_map[index].dev_type & IOTX_DM_DEVICE_SUBDEV) == 0) { + continue; + } + + res = dm_utils_service_name((char *)g_dm_client_uri_map[index].uri_prefix, (char *)g_dm_client_uri_map[index].uri_name, + product_key, device_name, &uri); + if (res < SUCCESS_RETURN) { + index--; + continue; + } + + dm_client_unsubscribe(uri); + DM_free(uri); + } + + return SUCCESS_RETURN; +} + +void dm_client_thing_topo_add_notify(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + int res = 0; + dm_msg_source_t source; + dm_msg_dest_t dest; + dm_msg_request_payload_t request; + dm_msg_response_t response; + + memset(&source, 0, sizeof(dm_msg_source_t)); + memset(&dest, 0, sizeof(dm_msg_dest_t)); + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dest.uri_name = DM_URI_THING_TOPO_ADD_NOTIFY_REPLY; + + res = dm_msg_proc_thing_topo_add_notify(&source, &dest, &request, &response); + if (res < SUCCESS_RETURN) { + return; + } + + dm_msg_response(DM_MSG_DEST_CLOUD, &request, &response, "{}", strlen("{}"), NULL); +} + +void dm_client_thing_disable(int fd, const char *topic, const char *payload, unsigned int payload_len, void *context) +{ + int res = 0; + dm_msg_source_t source; + dm_msg_dest_t dest; + dm_msg_request_payload_t request; + dm_msg_response_t response; + + memset(&source, 0, sizeof(dm_msg_source_t)); + memset(&dest, 0, sizeof(dm_msg_dest_t)); + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dest.uri_name = DM_URI_THING_DISABLE_REPLY; + + res = dm_msg_proc_thing_disable(&source, &dest, &request, &response); + if (res < SUCCESS_RETURN) { + return; + } + + dm_msg_response(DM_MSG_DEST_CLOUD, &request, &response, "{}", strlen("{}"), NULL); +} + +void dm_client_thing_enable(int fd, const char *topic, const char *payload, unsigned int payload_len, void *context) +{ + int res = 0; + dm_msg_source_t source; + dm_msg_dest_t dest; + dm_msg_request_payload_t request; + dm_msg_response_t response; + + memset(&source, 0, sizeof(dm_msg_source_t)); + memset(&dest, 0, sizeof(dm_msg_dest_t)); + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dest.uri_name = DM_URI_THING_ENABLE_REPLY; + + res = dm_msg_proc_thing_enable(&source, &dest, &request, &response); + if (res < SUCCESS_RETURN) { + return; + } + + dm_msg_response(DM_MSG_DEST_CLOUD, &request, &response, "{}", strlen("{}"), NULL); +} + +void dm_client_thing_delete(int fd, const char *topic, const char *payload, unsigned int payload_len, void *context) +{ + int res = 0; + dm_msg_source_t source; + dm_msg_dest_t dest; + dm_msg_request_payload_t request; + dm_msg_response_t response; + + memset(&source, 0, sizeof(dm_msg_source_t)); + memset(&dest, 0, sizeof(dm_msg_dest_t)); + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dest.uri_name = DM_URI_THING_DELETE_REPLY; + + res = dm_msg_proc_thing_delete(&source, &dest, &request, &response); + if (res < SUCCESS_RETURN) { + return; + } + + dm_msg_response(DM_MSG_DEST_CLOUD, &request, &response, "{}", strlen("{}"), NULL); +} + +void dm_client_thing_gateway_permit(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + int res = 0; + dm_msg_source_t source; + dm_msg_dest_t dest; + dm_msg_request_payload_t request; + dm_msg_response_t response; + + memset(&source, 0, sizeof(dm_msg_source_t)); + memset(&dest, 0, sizeof(dm_msg_dest_t)); + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dest.uri_name = DM_URI_THING_GATEWAY_PERMIT_REPLY; + + res = dm_msg_proc_thing_gateway_permit(&source, &dest, &request, &response); + if (res < SUCCESS_RETURN) { + return; + } + + dm_msg_response(DM_MSG_DEST_CLOUD, &request, &response, "{}", strlen("{}"), NULL); +} + +void dm_client_thing_sub_register_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_sub_register_reply(&source); +} + +void dm_client_thing_sub_unregister_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_sub_unregister_reply(&source); +} + +void dm_client_thing_topo_add_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_topo_add_reply(&source); +} + +void dm_client_thing_topo_delete_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_topo_delete_reply(&source); +} + +void dm_client_thing_topo_get_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_topo_get_reply(&source); +} + +void dm_client_thing_list_found_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_thing_list_found_reply(&source); +} + +void dm_client_combine_login_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_combine_login_reply(&source); +} + +void dm_client_combine_logout_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context) +{ + dm_msg_source_t source; + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = topic; + source.payload = (unsigned char *)payload; + source.payload_len = payload_len; + source.context = NULL; + + dm_msg_proc_combine_logout_reply(&source); +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_client.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_client.h new file mode 100644 index 00000000..08e138cc --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_client.h @@ -0,0 +1,75 @@ +#ifndef _DM_CLIENT_H_ +#define _DM_CLIENT_H_ + +typedef struct { + const char *uri_name; + const char *uri_prefix; + int dev_type; + void *callback; +} dm_client_uri_map_t; + +void dm_client_event_handle(int fd, iotx_cm_event_msg_t *event, void *context); + +int dm_client_subscribe_all(char product_key[IOTX_PRODUCT_KEY_LEN + 1], char device_name[IOTX_DEVICE_NAME_LEN + 1], int dev_type); + +void dm_client_thing_model_down_raw(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_model_up_raw_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) +void dm_client_thing_property_desired_get_reply(int fd, const char *topic, const char *payload, + unsigned int payload_len, void *context); +void dm_client_thing_property_desired_delete_reply(int fd, const char *topic, const char *payload, + unsigned int payload_len, void *context); +void dm_client_thing_service_property_set(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_service_property_get(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_service_property_post(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_event_property_post_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_deviceinfo_update_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_deviceinfo_delete_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_dynamictsl_get_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_service_request(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_event_post_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_rrpc_request_wildcard(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_ntp_response(int fd, const char *topic, const char *payload, unsigned int payload_len, void *context); +void dm_client_ext_error(int fd, const char *topic, const char *payload, unsigned int payload_len, void *context); +#endif + +#ifdef DEVICE_MODEL_GATEWAY +int dm_client_subdev_unsubscribe(char product_key[IOTX_PRODUCT_KEY_LEN + 1], char device_name[IOTX_DEVICE_NAME_LEN + 1]); +void dm_client_thing_topo_add_notify(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_disable(int fd, const char *topic, const char *payload, unsigned int payload_len, void *context); +void dm_client_thing_enable(int fd, const char *topic, const char *payload, unsigned int payload_len, void *context); +void dm_client_thing_delete(int fd, const char *topic, const char *payload, unsigned int payload_len, void *context); +void dm_client_thing_gateway_permit(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_sub_register_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_sub_unregister_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_topo_add_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_topo_delete_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_topo_get_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_thing_list_found_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_combine_login_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +void dm_client_combine_logout_reply(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_client_adapter.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_client_adapter.c new file mode 100644 index 00000000..b42197ff --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_client_adapter.c @@ -0,0 +1,145 @@ +#include "iotx_dm_internal.h" + +static dm_client_ctx_t g_dm_client_ctx = {0}; + +static dm_client_ctx_t *dm_client_get_ctx(void) +{ + return &g_dm_client_ctx; +} + +int dm_client_open(void) +{ + int res = 0; + dm_client_ctx_t *ctx = dm_client_get_ctx(); + iotx_cm_init_param_t cm_param; + + memset(ctx, 0, sizeof(dm_client_ctx_t)); + memset(&cm_param, 0, sizeof(iotx_cm_init_param_t)); + + cm_param.request_timeout_ms = IOTX_DM_CLIENT_REQUEST_TIMEOUT_MS; + cm_param.keepalive_interval_ms = IOTX_DM_CLIENT_KEEPALIVE_INTERVAL_MS; + cm_param.write_buf_size = CONFIG_MQTT_TX_MAXLEN; + cm_param.read_buf_size = CONFIG_MQTT_RX_MAXLEN; +#if defined(COAP_COMM_ENABLED) && !defined(MQTT_COMM_ENABLED) + cm_param.protocol_type = IOTX_CM_PROTOCOL_TYPE_COAP; +#else + cm_param.protocol_type = IOTX_CM_PROTOCOL_TYPE_MQTT; +#endif + cm_param.handle_event = dm_client_event_handle; + + res = iotx_cm_open(&cm_param); + + if (res < SUCCESS_RETURN) { + return res; + } + ctx->fd = res; + + dm_log_info("CM Fd: %d", ctx->fd); + + return SUCCESS_RETURN; +} + +int dm_client_connect(int timeout_ms) +{ + int res = 0; + dm_client_ctx_t *ctx = dm_client_get_ctx(); + + res = iotx_cm_connect(ctx->fd, timeout_ms); + if (res < SUCCESS_RETURN) { + return res; + } + + return SUCCESS_RETURN; +} + +int dm_client_close(void) +{ + dm_client_ctx_t *ctx = dm_client_get_ctx(); + + return iotx_cm_close(ctx->fd); +} + +int dm_client_subscribe(char *uri, iotx_cm_data_handle_cb callback, void *context) +{ + int res = 0; + uint8_t local_sub = 0; + dm_client_ctx_t *ctx = dm_client_get_ctx(); + iotx_cm_ext_params_t sub_params; + + memset(&sub_params, 0, sizeof(iotx_cm_ext_params_t)); + if (context != NULL) { + local_sub = *((uint8_t *)context); + } + + if (local_sub == 1) { + sub_params.ack_type = IOTX_CM_MESSAGE_SUB_LOCAL; + sub_params.sync_mode = IOTX_CM_ASYNC; + } else { + sub_params.ack_type = IOTX_CM_MESSAGE_NO_ACK; + sub_params.sync_mode = IOTX_CM_SYNC; + } + + sub_params.sync_timeout = IOTX_DM_CLIENT_SUB_TIMEOUT_MS; + sub_params.ack_cb = NULL; + + res = iotx_cm_sub(ctx->fd, &sub_params, (const char *)uri, callback, NULL); + dm_log_info("Subscribe Result: %d", res); + + if (res < SUCCESS_RETURN) { + return res; + } + + return SUCCESS_RETURN; +} + +int dm_client_unsubscribe(char *uri) +{ + int res = 0; + dm_client_ctx_t *ctx = dm_client_get_ctx(); + + res = iotx_cm_unsub(ctx->fd, uri); + + dm_log_info("Unsubscribe Result: %d", res); + + return res; +} + +int dm_client_publish(char *uri, unsigned char *payload, int payload_len, iotx_cm_data_handle_cb callback) +{ + int res = 0; + char *pub_uri = NULL; + dm_client_ctx_t *ctx = dm_client_get_ctx(); + iotx_cm_ext_params_t pub_param; + + memset(&pub_param, 0, sizeof(iotx_cm_ext_params_t)); + pub_param.ack_type = IOTX_CM_MESSAGE_NO_ACK; + pub_param.sync_mode = IOTX_CM_ASYNC; + pub_param.sync_timeout = 0; + pub_param.ack_cb = NULL; + +#if defined(COAP_COMM_ENABLED) && !defined(MQTT_COMM_ENABLED) + pub_param.ack_cb = callback; + res = dm_utils_uri_add_prefix("/topic", uri, &pub_uri); + if (res < SUCCESS_RETURN) { + return FAIL_RETURN; + } +#else + pub_uri = uri; +#endif + + res = iotx_cm_pub(ctx->fd, &pub_param, (const char *)pub_uri, (const char *)payload, (unsigned int)payload_len); + dm_log_info("Publish Result: %d", res); + +#if defined(COAP_COMM_ENABLED) && !defined(MQTT_COMM_ENABLED) + DM_free(pub_uri); +#endif + + return res; +} + +int dm_client_yield(unsigned int timeout) +{ + dm_client_ctx_t *ctx = dm_client_get_ctx(); + + return iotx_cm_yield(ctx->fd, timeout); +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_client_adapter.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_client_adapter.h new file mode 100644 index 00000000..bf82c90b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_client_adapter.h @@ -0,0 +1,18 @@ +#ifndef _DM_CLIENT_ADAPTER_H_ +#define _DM_CLIENT_ADAPTER_H_ + +typedef struct { + int fd; + iotx_conn_info_t *conn_info; + void *callback; +} dm_client_ctx_t; + +int dm_client_open(void); +int dm_client_connect(int timeout_ms); +int dm_client_close(void); +int dm_client_subscribe(char *uri, iotx_cm_data_handle_cb callback, void *context); +int dm_client_unsubscribe(char *uri); +int dm_client_publish(char *uri, unsigned char *payload, int payload_len, iotx_cm_data_handle_cb callback); +int dm_client_yield(unsigned int timeout); + +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_cota.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_cota.c new file mode 100644 index 00000000..ed8aeee4 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_cota.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "iotx_dm_internal.h" + +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define DM_COTA_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "dm.cota") + #define DM_COTA_FREE(ptr) LITE_free(ptr) +#else + #define DM_COTA_MALLOC(size) HAL_Malloc(size) + #define DM_COTA_FREE(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +static dm_cota_ctx_t g_dm_cota_ctx; + +static dm_cota_ctx_t *_dm_cota_get_ctx(void) +{ + return &g_dm_cota_ctx; +} + +int dm_cota_init(void) +{ + dm_cota_ctx_t *ctx = _dm_cota_get_ctx(); + + memset(ctx, 0, sizeof(dm_cota_ctx_t)); + + return SUCCESS_RETURN; +} + +int dm_cota_deinit(void) +{ + dm_cota_ctx_t *ctx = _dm_cota_get_ctx(); + + memset(ctx, 0, sizeof(dm_cota_ctx_t)); + + return SUCCESS_RETURN; +} + +static int _dm_cota_send_new_config_to_user(void *ota_handle) +{ + int res = 0, message_len = 0; + char *message = NULL; + uint32_t config_size = 0; + char *config_id = NULL, *sign = NULL, *sign_method = NULL, *url = NULL, *get_type = NULL; + const char *cota_new_config_fmt = + "{\"configId\":\"%s\",\"configSize\":%d,\"getType\":\"%s\",\"sign\":\"%s\",\"signMethod\":\"%s\",\"url\":\"%s\"}"; + + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_COTA_CONFIG_ID, (void *)&config_id, 1); + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_COTA_CONFIG_SIZE, &config_size, 4); + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_COTA_SIGN, (void *)&sign, 1); + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_COTA_SIGN_METHOD, (void *)&sign_method, 1); + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_COTA_URL, (void *)&url, 1); + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_COTA_GETTYPE, (void *)&get_type, 1); + + if (config_id == NULL || sign == NULL || sign_method == NULL || url == NULL || get_type == NULL) { + res = FAIL_RETURN; + goto ERROR; + } + + message_len = strlen(cota_new_config_fmt) + strlen(config_id) + DM_UTILS_UINT32_STRLEN + strlen(get_type) + + strlen(sign) + strlen(sign_method) + strlen(url) + 1; + + message = DM_malloc(message_len); + if (message == NULL) { + res = DM_MEMORY_NOT_ENOUGH; + goto ERROR; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, cota_new_config_fmt, config_id, config_size, get_type, sign, sign_method, url); + + dm_log_info("Send To User: %s", message); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_COTA_NEW_CONFIG, message); + if (res != SUCCESS_RETURN) { + if (message) { + DM_free(message); + } + res = FAIL_RETURN; + goto ERROR; + } + + res = SUCCESS_RETURN; +ERROR: + if (config_id) { + DM_COTA_FREE(config_id); + } + if (sign) { + DM_COTA_FREE(sign); + } + if (sign_method) { + DM_COTA_FREE(sign_method); + } + if (url) { + DM_COTA_FREE(url); + } + if (get_type) { + DM_COTA_FREE(get_type); + } + + return res; +} + +int dm_cota_perform_sync(_OU_ char *output, _IN_ int output_len) +{ + int res = 0, file_download = 0; + uint32_t file_size = 0, file_downloaded = 0; + uint32_t percent_pre = 0, percent_now = 0; + unsigned long long report_pre = 0, report_now = 0; + dm_cota_ctx_t *ctx = _dm_cota_get_ctx(); + void *ota_handle = NULL; + uint32_t ota_type = IOT_OTAT_NONE; + + if (output == NULL || output_len <= 0) { + return DM_INVALID_PARAMETER; + } + + /* Get Ota Handle */ + res = dm_ota_get_ota_handle(&ota_handle); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + if (ota_handle == NULL) { + return FAIL_RETURN; + } + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_OTA_TYPE, &ota_type, 4); + + if (ota_type != IOT_OTAT_COTA) { + return FAIL_RETURN; + } + + /* reset the size_fetched in ota_handle to be 0 */ + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_RESET_FETCHED_SIZE, ota_handle, 4); + /* Prepare Write Data To Storage */ + HAL_Firmware_Persistence_Start(); + + while (1) { + file_download = IOT_OTA_FetchYield(ota_handle, output, output_len, 1); + if (file_download < 0) { + IOT_OTA_ReportProgress(ota_handle, IOT_OTAP_FETCH_FAILED, NULL); + HAL_Firmware_Persistence_Stop(); + ctx->is_report_new_config = 0; + return FAIL_RETURN; + } + + /* Write Config File Into Stroage */ + HAL_Firmware_Persistence_Write(output, file_download); + + /* Get OTA information */ + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_FETCHED_SIZE, &file_downloaded, 4); + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_FILE_SIZE, &file_size, 4); + + /* Calculate Download Percent And Update Report Timestamp*/ + percent_now = (file_downloaded * 100) / file_size; + report_now = HAL_UptimeMs(); + + /* Report Download Process To Cloud */ + if (report_now < report_pre) { + report_pre = report_now; + } + if ((((percent_now - percent_pre) > 5) && + ((report_now - report_pre) > 50)) || (percent_now >= IOT_OTAP_FETCH_PERCENTAGE_MAX)) { + IOT_OTA_ReportProgress(ota_handle, percent_now, NULL); + percent_pre = percent_now; + report_pre = report_now; + } + + /* Check If OTA Finished */ + if (IOT_OTA_IsFetchFinish(ota_handle)) { + uint32_t file_isvalid = 0; + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_CHECK_CONFIG, &file_isvalid, 4); + if (file_isvalid == 0) { + HAL_Firmware_Persistence_Stop(); + ctx->is_report_new_config = 0; + return FAIL_RETURN; + } else { + break; + } + } + } + + HAL_Firmware_Persistence_Stop(); + ctx->is_report_new_config = 0; + + return SUCCESS_RETURN; +} + +int dm_cota_get_config(const char *config_scope, const char *get_type, const char *attribute_keys) +{ + int res = 0; + void *ota_handle = NULL; + + /* Get Ota Handle */ + res = dm_ota_get_ota_handle(&ota_handle); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return iotx_ota_get_config(ota_handle, config_scope, get_type, attribute_keys); +} + +int dm_cota_status_check(void) +{ + int res = 0; + dm_cota_ctx_t *ctx = _dm_cota_get_ctx(); + void *ota_handle = NULL; + + /* Get Ota Handle */ + res = dm_ota_get_ota_handle(&ota_handle); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + if (IOT_OTA_IsFetching(ota_handle)) { + uint32_t ota_type = IOT_OTAT_NONE; + + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_OTA_TYPE, &ota_type, 4); + + if (ota_type == IOT_OTAT_COTA) { + /* Send New Config Information To User */ + if (ctx->is_report_new_config == 0) { + dm_log_debug("Cota Status Check"); + res = _dm_cota_send_new_config_to_user(ota_handle); + if (res == SUCCESS_RETURN) { + ctx->is_report_new_config = 1; + } + } + } + } + + return SUCCESS_RETURN; +} +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_cota.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_cota.h new file mode 100644 index 00000000..c5f54d07 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_cota.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _DM_COTA_H_ +#define _DM_COTA_H_ + +typedef struct { + int is_report_new_config; +} dm_cota_ctx_t; + +int dm_cota_init(void); +int dm_cota_deinit(void); +int dm_cota_perform_sync(_OU_ char *output, _IN_ int output_len); +int dm_cota_get_config(const char *config_scope, const char *get_type, const char *attribute_keys); +int dm_cota_status_check(void); + +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_fota.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_fota.c new file mode 100644 index 00000000..ec71d056 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_fota.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "iotx_dm_internal.h" + +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + +static dm_fota_ctx_t g_dm_fota_ctx; + +static dm_fota_ctx_t *_dm_fota_get_ctx(void) +{ + return &g_dm_fota_ctx; +} + +int dm_fota_init(void) +{ + dm_fota_ctx_t *ctx = _dm_fota_get_ctx(); + + memset(ctx, 0, sizeof(dm_fota_ctx_t)); + + return SUCCESS_RETURN; +} + +int dm_fota_deinit(void) +{ + dm_fota_ctx_t *ctx = _dm_fota_get_ctx(); + + memset(ctx, 0, sizeof(dm_fota_ctx_t)); + + return SUCCESS_RETURN; +} + +static int _dm_fota_send_new_config_to_user(void *ota_handle) +{ + int res = 0, message_len = 0; + char *message = NULL; + char version[128] = {0}; + const char *fota_new_config_fmt = "{\"version\":\"%s\"}"; + + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_VERSION, version, 128); + + message_len = strlen(fota_new_config_fmt) + strlen(version) + 1; + + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, fota_new_config_fmt, version); + + dm_log_info("Send To User: %s", message); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_FOTA_NEW_FIRMWARE, message); + if (res != SUCCESS_RETURN) { + if (message) { + DM_free(message); + } + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_fota_perform_sync(_OU_ char *output, _IN_ int output_len) +{ + int res = 0, file_download = 0; + uint32_t file_size = 0, file_downloaded = 0; + uint32_t percent_pre = 0, percent_now = 0; + unsigned long long report_pre = 0, report_now = 0; + dm_fota_ctx_t *ctx = _dm_fota_get_ctx(); + void *ota_handle = NULL; + uint32_t ota_type = IOT_OTAT_NONE; + int ret = 0; + uint8_t is_header = 1; + + if (output == NULL || output_len <= 0) { + return DM_INVALID_PARAMETER; + } + + /* Get Ota Handle */ + res = dm_ota_get_ota_handle(&ota_handle); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + if (ota_handle == NULL) { + return FAIL_RETURN; + } + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_OTA_TYPE, &ota_type, 4); + + if (ota_type != IOT_OTAT_FOTA) { + return FAIL_RETURN; + } + + /* reset the size_fetched in ota_handle to be 0 */ + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_RESET_FETCHED_SIZE, ota_handle, 4); + /* Prepare Write Data To Storage */ + HAL_Firmware_Persistence_Start(); + while (1) { + file_download = IOT_OTA_FetchYield(ota_handle, output, output_len, 1); + if (file_download < 0) { + IOT_OTA_ReportProgress(ota_handle, IOT_OTAP_FETCH_FAILED, NULL); + HAL_Firmware_Persistence_Stop(); + ctx->is_report_new_config = 0; + return FAIL_RETURN; + } +#ifdef SUPPORT_SECURITY_OTA + /* Check safe upgrade word in image */ + if (is_header) { + if (HAL_Firmware_Check_Rsa_Key(output, file_download)) { + IOT_OTA_ReportProgress(ota_handle, IOT_OTAP_CHECK_FALIED, NULL); + HAL_Firmware_Persistence_Stop(); + return SUCCESS_RETURN; + } + is_header = 0; + } +#endif + /* Write Config File Into Stroage */ + ret = HAL_Firmware_Persistence_Write(output, file_download); + if (-1 == ret) { + IOT_OTA_ReportProgress(ota_handle, IOT_OTAP_BURN_FAILED, NULL); + dm_log_err("Fota write firmware failed"); + } + + /* Get OTA information */ + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_FETCHED_SIZE, &file_downloaded, 4); + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_FILE_SIZE, &file_size, 4); + + /* Calculate Download Percent And Update Report Timestamp*/ + percent_now = (file_downloaded * 100) / file_size; + report_now = HAL_UptimeMs(); + + /* Report Download Process To Cloud */ + if (report_now < report_pre) { + report_pre = report_now; + } + if ((((percent_now - percent_pre) > 5) && + ((report_now - report_pre) > 50)) || (percent_now >= IOT_OTAP_FETCH_PERCENTAGE_MAX)) { + IOT_OTA_ReportProgress(ota_handle, percent_now, NULL); + percent_pre = percent_now; + report_pre = report_now; + } + + /* Check If OTA Finished */ + if (IOT_OTA_IsFetchFinish(ota_handle)) { + uint32_t file_isvalid = 0; + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_CHECK_CONFIG, &file_isvalid, 4); + if (file_isvalid == 0) { + HAL_Firmware_Persistence_Stop(); + ctx->is_report_new_config = 0; + return FAIL_RETURN; + } else { + break; + } + } + } + + HAL_Firmware_Persistence_Stop(); + ctx->is_report_new_config = 0; + + return SUCCESS_RETURN; +} + +int dm_fota_status_check(void) +{ + int res = 0; + dm_fota_ctx_t *ctx = _dm_fota_get_ctx(); + void *ota_handle = NULL; + + /* Get Ota Handle */ + res = dm_ota_get_ota_handle(&ota_handle); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + if (IOT_OTA_IsFetching(ota_handle)) { + uint32_t ota_type = IOT_OTAT_NONE; + + IOT_OTA_Ioctl(ota_handle, IOT_OTAG_OTA_TYPE, &ota_type, 4); + + if (ota_type == IOT_OTAT_FOTA) { + /* Send New Config Information To User */ + if (ctx->is_report_new_config == 0) { + dm_log_debug("Fota Status Check"); + res = _dm_fota_send_new_config_to_user(ota_handle); + if (res == SUCCESS_RETURN) { + ctx->is_report_new_config = 1; + } + } + } + } + + return SUCCESS_RETURN; +} + +int dm_fota_request_image(const char *version, int buffer_len) +{ + int res = 0; + void *ota_handle = NULL; + char *version_str = NULL; + + if (NULL == version || buffer_len <= 0) { + dm_log_info("invalid input"); + return FAIL_RETURN; + } + + /* Get Ota Handle */ + res = dm_ota_get_ota_handle(&ota_handle); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + version_str = DM_malloc(buffer_len + 1); + if (NULL == version_str) { + dm_log_info("failed to malloc"); + return FAIL_RETURN; + } + memset(version_str, 0, buffer_len + 1); + memcpy(version_str, version, buffer_len); + + res = iotx_req_image(ota_handle, version_str); + DM_free(version_str); + return res; +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_fota.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_fota.h new file mode 100644 index 00000000..d75157a1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_fota.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _DM_FOTA_H_ +#define _DM_FOTA_H_ + +typedef struct { + int is_report_new_config; +} dm_fota_ctx_t; + +int dm_fota_init(void); +int dm_fota_deinit(void); +int dm_fota_perform_sync(_OU_ char *output, _IN_ int output_len); +int dm_fota_status_check(void); +int dm_fota_request_image(_IN_ const char *version, _IN_ int buffer_len); + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_intf.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_intf.h new file mode 100644 index 00000000..1d26f06c --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_intf.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _IOT_DM_API_H_ +#define _IOT_DM_API_H_ + +typedef struct { + void *mutex; + void *cloud_connectivity; + void *local_connectivity; + iotx_dm_event_callback event_callback; +} dm_api_ctx_t; + +#if defined(DEPRECATED_LINKKIT) +typedef struct { + void *mutex; + int devid; + lite_cjson_item_t *lite; +} dm_api_property_t; +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_ipc.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_ipc.c new file mode 100644 index 00000000..44a5126e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_ipc.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#include "iotx_dm_internal.h" + +dm_ipc_t g_dm_ipc; + +static dm_ipc_t *_dm_ipc_get_ctx(void) +{ + return &g_dm_ipc; +} + +static void _dm_ipc_lock(void) +{ + dm_ipc_t *ctx = _dm_ipc_get_ctx(); + if (ctx->mutex) { + HAL_MutexLock(ctx->mutex); + } +} + +static void _dm_ipc_unlock(void) +{ + dm_ipc_t *ctx = _dm_ipc_get_ctx(); + if (ctx->mutex) { + HAL_MutexUnlock(ctx->mutex); + } +} + +int dm_ipc_init(int max_size) +{ + dm_ipc_t *ctx = _dm_ipc_get_ctx(); + + memset(ctx, 0, sizeof(dm_ipc_t)); + + /* Create Mutex */ + ctx->mutex = HAL_MutexCreate(); + if (ctx->mutex == NULL) { + return DM_INVALID_PARAMETER; + } + + /* Init List */ + ctx->msg_list.max_size = max_size; + INIT_LIST_HEAD(&ctx->msg_list.message_list); + + return SUCCESS_RETURN; +} + +void dm_ipc_deinit(void) +{ + dm_ipc_t *ctx = _dm_ipc_get_ctx(); + dm_ipc_msg_node_t *del_node = NULL; + dm_ipc_msg_node_t *next_node = NULL; + dm_ipc_msg_t *del_msg = NULL; + + if (ctx->mutex) { + HAL_MutexDestroy(ctx->mutex); + } + + list_for_each_entry_safe(del_node, next_node, &ctx->msg_list.message_list, linked_list, dm_ipc_msg_node_t) { + /* Free Message */ + del_msg = (dm_ipc_msg_t *)del_node->data; + if (del_msg->data) { + DM_free(del_msg->data); + } + DM_free(del_msg); + del_msg = NULL; + + /* Free Node */ + list_del(&del_node->linked_list); + DM_free(del_node); + } +} + +int dm_ipc_msg_insert(void *data) +{ + dm_ipc_t *ctx = _dm_ipc_get_ctx(); + dm_ipc_msg_node_t *node = NULL; + + if (data == NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_ipc_lock(); + dm_log_debug("dm msg list size: %d, max size: %d", ctx->msg_list.size, ctx->msg_list.max_size); + if (ctx->msg_list.size >= ctx->msg_list.max_size) { + dm_log_warning("dm ipc list full"); + _dm_ipc_unlock(); + return FAIL_RETURN; + } + + node = DM_malloc(sizeof(dm_ipc_msg_node_t)); + if (node == NULL) { + _dm_ipc_unlock(); + return DM_MEMORY_NOT_ENOUGH; + } + memset(node, 0, sizeof(dm_ipc_msg_node_t)); + + node->data = data; + INIT_LIST_HEAD(&node->linked_list); + ctx->msg_list.size++; + list_add_tail(&node->linked_list, &ctx->msg_list.message_list); + + _dm_ipc_unlock(); + return SUCCESS_RETURN; +} + +int dm_ipc_msg_next(void **data) +{ + dm_ipc_t *ctx = _dm_ipc_get_ctx(); + dm_ipc_msg_node_t *node = NULL; + + if (data == NULL || *data != NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_ipc_lock(); + + if (list_empty(&ctx->msg_list.message_list)) { + _dm_ipc_unlock(); + return FAIL_RETURN; + } + + node = list_first_entry(&ctx->msg_list.message_list, dm_ipc_msg_node_t, linked_list); + list_del(&node->linked_list); + ctx->msg_list.size--; + + *data = node->data; + DM_free(node); + + _dm_ipc_unlock(); + return SUCCESS_RETURN; +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_ipc.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_ipc.h new file mode 100644 index 00000000..36ebe1b3 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_ipc.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _DM_IPC_H_ +#define _DM_IPC_H_ + +#include "iotx_dm_internal.h" + +typedef struct { + iotx_dm_event_types_t type; + char *data; +} dm_ipc_msg_t; + +typedef struct { + void *data; + struct list_head linked_list; +} dm_ipc_msg_node_t; + +typedef struct { + int max_size; + int size; + struct list_head message_list; +} dm_ipc_msg_list_t; + +typedef struct { + void *mutex; + dm_ipc_msg_list_t msg_list; +} dm_ipc_t; + +int dm_ipc_init(int max_size); +void dm_ipc_deinit(void); +int dm_ipc_msg_insert(void *data); +int dm_ipc_msg_next(void **data); + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_log_report.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_log_report.c new file mode 100644 index 00000000..bbe839ac --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_log_report.c @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "iotx_dm_internal.h" + +#ifdef LOG_REPORT_TO_CLOUD + +#include "dev_model_api.h" + +const char THING_LOG_POST_PARAMS_HEAD[] = + "\"%.*s %s %ld "; +const char THING_LOG_POST_PARAMS_BODY[] = + "%s %ld "; +const char THING_LOG_POST_PARAMS_END[] = + "%s %ld\","; + +char *g_log_poll = NULL; +static char *current_log_pos = NULL; + +int remove_log_poll() +{ + if (NULL != g_log_poll) { + HAL_Free(g_log_poll); + g_log_poll = NULL; + current_log_pos = NULL; + } + return 0; +} + + +unsigned int push_log(const char *input_log, int input_log_size) +{ + if (NULL == current_log_pos || NULL == input_log || input_log_size <= 0) { + dm_log_debug("invalid params"); + return -1; + } + memcpy(current_log_pos, input_log, input_log_size); + current_log_pos += input_log_size; + return (current_log_pos - g_log_poll); +} + +unsigned int add_tail() +{ + const char *tail = "]}"; + current_log_pos -= 1; + return push_log(tail, strlen(tail)); +} + +void add_log_header() +{ + const char *subprefix = "{\"template\": \"traceContext logContent\",\"contents\":["; + int sublen = strlen(subprefix); + push_log(subprefix, sublen); +} + +int reset_log_poll() +{ + if (NULL == g_log_poll) { + dm_log_err("log buffer is NULL"); + return -1; + } + memset(g_log_poll, 0, LOG_POLL_SIZE); + current_log_pos = g_log_poll; + add_log_header(); + return 0; +} + +int create_log_poll() +{ + int ret; + remove_log_poll(); + g_log_poll = HAL_Malloc(LOG_POLL_SIZE); + ret = reset_log_poll(); + return ret; +} + +static int switch_status = 0; /* 0 for switch off; 1 for switch on */ +static unsigned int sample_interval = 5; +static unsigned int sample_count = 1000; + +#define MSG_ID_LEN (64) +char msg_array[MSG_ID_LEN] = {0}; +int check_target_msg(const char *input, int len) +{ + /* do not upload log when swith is off */ + if (0 == switch_status) { + return -1; + } + if (NULL == input || len <= 0) { + dm_log_err("invalid params"); + return -1; + } + return strncmp(input, msg_array, len); +} + +static unsigned int msg_num = 0; +/* return 0 for success; -1 for failure */ +int set_target_msg(const char *input, int len) +{ + if (0 == switch_status) { + return -1; + } + if ((msg_num % sample_interval == 0) && (msg_num < sample_count)) { + if (NULL == input || len <= 0) { + dm_log_err("invalid params"); + return -1; + } + strncpy(msg_array, input, len); + return 0; + } + return -1; +} + +void parse_msg_id(_IN_ char *payload, _IN_ int payload_len, _OU_ dm_msg_request_payload_t *request) +{ + lite_cjson_t lite; + + if (payload == NULL || payload_len <= 0 || request == NULL) { + return; + } + + dm_utils_json_parse(payload, payload_len, cJSON_Object, &lite); + dm_utils_json_object_item(&lite, DM_MSG_KEY_ID, strlen(DM_MSG_KEY_ID), cJSON_String, &request->id); +} + +int stop_sample() +{ + if (current_log_pos > g_log_poll) { + dm_mgr_upstream_thing_log_post(0, NULL, 0, 1); + } + switch_status = 0; + dm_log_info("stop sample"); + return remove_log_poll(); +} + +void parse_switch_info(_IN_ char *payload, _IN_ int payload_len) +{ + lite_cjson_t lite, lite_sample_count, lite_sample_interval, lite_sample_target; + const char *c1 = "Count"; + const char *c2 = "Interval"; + const char *c3 = "ProfileTarget"; + char *sample_target; + int sample_target_len; + const char *target = "propSet"; + int ret = -1; + + if (payload == NULL || payload_len <= 0) { + return; + } + dm_utils_json_parse(payload, payload_len, cJSON_Object, &lite); + ret = lite_cjson_object_item(&lite, c1, strlen(c1), &lite_sample_count); + if (ret < SUCCESS_RETURN) { + return; + } + + ret = lite_cjson_object_item(&lite, c2, strlen(c2), &lite_sample_interval); + if (ret < SUCCESS_RETURN) { + return; + } + + ret = lite_cjson_object_item(&lite, c3, strlen(c3), &lite_sample_target); + if (ret < SUCCESS_RETURN) { + return; + } + + sample_count = lite_sample_count.value_int; + sample_interval = lite_sample_interval.value_int; + sample_target = lite_sample_target.value; + sample_target_len = lite_sample_target.value_length; + dm_log_info("switch count is %d, interval is %d, target is %.*s\n", sample_count, sample_interval, + sample_target_len, sample_target); + /* if the target is not property set, return */ + if (0 != strncmp(sample_target, target, sample_target_len)) { + dm_log_info("target is not propSet, return\n"); + return; + } + if (sample_interval <= 0) { + dm_log_err("invalid sample interval\n"); + return; + } + msg_num = 0; + /* when it switch off, force upload the remaining log */ + if (0 == sample_count) { + ret = stop_sample(); + } else { + switch_status = 1; + ret = create_log_poll(); + } + + dm_log_info("log switch run status is %d\n", ret); +} + +REPORT_STATE g_report_status = READY; + +void send_permance_info(char *input, int input_len, char *comments, int report_format) +{ +#define LOCAL_POST_LEN (150) + char data[LOCAL_POST_LEN] = {0}; + const char *format = NULL; + if (0 == switch_status) { + return; + } + + switch (report_format) { + case 0: + if (NULL == input || input_len <= 0) { + dm_log_err("invalid params"); + return; + } + format = THING_LOG_POST_PARAMS_HEAD; + HAL_Snprintf(data, sizeof(data), format, input_len, input, + comments, (long)HAL_UptimeMs()); + break; + case 1: + format = THING_LOG_POST_PARAMS_BODY; + HAL_Snprintf(data, sizeof(data), format, + comments, (long)HAL_UptimeMs()); + break; + case 2: + format = THING_LOG_POST_PARAMS_END; + HAL_Snprintf(data, sizeof(data), format, + comments, (long)HAL_UptimeMs()); + g_report_status = DONE; + break; + default: + return; + } + iotx_dm_log_post(0, data, strlen((const char *)data)); + if (2 == report_format) { + g_report_status = READY; + } +} + +void get_msgid(char *payload, int is_cloud) +{ + const char *interest = "\"method\":\"thing.service.property.set"; + char *found; + dm_msg_request_payload_t request; + if (0 == switch_status || NULL == payload) { + return; + } + + found = strstr(payload, interest); + if (NULL == found) { + return; + } + found = strstr(payload, "{"); + if (NULL == found) { + return; + } + msg_num++; + parse_msg_id(found, strlen(found), &request); + if (RUNNING == g_report_status) { + dm_log_info("current working on a sample, return"); + return; + } + + if (sample_count <= msg_num) { + stop_sample(); + return; + } + + /* if it does not meet the sample conditions, do NOT take sample */ + if (SUCCESS_RETURN != set_target_msg(request.id.value, request.id.value_length)) { + return; + } + + g_report_status = RUNNING; + + if (1 == is_cloud) { + send_permance_info(request.id.value, request.id.value_length, "1_cloud", 0); + } else if (0 == is_cloud) { + send_permance_info(request.id.value, request.id.value_length, "1_alcs", 0); + } +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_manager.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_manager.c new file mode 100644 index 00000000..947a564d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_manager.c @@ -0,0 +1,2261 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#include "iotx_dm_internal.h" + +static dm_mgr_ctx g_dm_mgr = {0}; + +static dm_mgr_ctx *_dm_mgr_get_ctx(void) +{ + return &g_dm_mgr; +} + +static void _dm_mgr_mutex_lock(void) +{ + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + if (ctx->mutex) { + HAL_MutexLock(ctx->mutex); + } +} + +static void _dm_mgr_mutex_unlock(void) +{ + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + if (ctx->mutex) { + HAL_MutexUnlock(ctx->mutex); + } +} + +static int _dm_mgr_next_devid(void) +{ + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + + return ctx->global_devid++; +} + +static int _dm_mgr_search_dev_by_devid(_IN_ int devid, _OU_ dm_mgr_dev_node_t **node) +{ + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + dm_mgr_dev_node_t *search_node = NULL; + + list_for_each_entry(search_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) { + if (search_node->devid == devid) { + /* dm_log_debug("Device Found, devid: %d", devid); */ + if (node) { + *node = search_node; + } + return SUCCESS_RETURN; + } + } + + dm_log_debug("Device Not Found, devid: %d", devid); + return FAIL_RETURN; +} + +static int _dm_mgr_search_dev_by_pkdn(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], _OU_ dm_mgr_dev_node_t **node) +{ + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + dm_mgr_dev_node_t *search_node = NULL; + + list_for_each_entry(search_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) { + if ((strlen(search_node->product_key) == strlen(product_key)) && + (memcmp(search_node->product_key, product_key, strlen(product_key)) == 0) && + (strlen(search_node->device_name) == strlen(device_name)) && + (memcmp(search_node->device_name, device_name, strlen(device_name)) == 0)) { + /* dm_log_debug("Device Found, Product Key: %s, Device Name: %s", product_key, device_name); */ + if (node) { + *node = search_node; + } + return SUCCESS_RETURN; + } + } + + dm_log_debug("Device Not Found, Product Key: %s, Device Name: %s", product_key, device_name); + return FAIL_RETURN; +} + +static int _dm_mgr_insert_dev(_IN_ int devid, _IN_ int dev_type, char product_key[IOTX_PRODUCT_KEY_LEN + 1], + char device_name[IOTX_DEVICE_NAME_LEN + 1]) +{ + int res = 0; + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || product_key == NULL || strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1 || + device_name == NULL || strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, NULL); + if (res == SUCCESS_RETURN) { + return FAIL_RETURN; + } + + node = DM_malloc(sizeof(dm_mgr_dev_node_t)); + if (node == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(node, 0, sizeof(dm_mgr_dev_node_t)); + + node->devid = devid; + node->dev_type = dev_type; + memcpy(node->product_key, product_key, strlen(product_key)); + memcpy(node->device_name, device_name, strlen(device_name)); + INIT_LIST_HEAD(&node->linked_list); + + list_add_tail(&node->linked_list, &ctx->dev_list); + + return SUCCESS_RETURN; +} + +static void _dm_mgr_destroy_devlist(void) +{ + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + dm_mgr_dev_node_t *del_node = NULL; + dm_mgr_dev_node_t *next_node = NULL; + + list_for_each_entry_safe(del_node, next_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) { + list_del(&del_node->linked_list); +#ifdef DEPRECATED_LINKKIT + dm_shw_destroy(&del_node->dev_shadow); +#endif + DM_free(del_node); + } +} + +#ifdef DEPRECATED_LINKKIT +static int _dm_mgr_legacy_thing_created(int devid) +{ + int res = 0, message_len = 0; + const char *thing_created_fmt = "{\"devid\":%d}"; + char *message = NULL; + + message_len = strlen(thing_created_fmt) + DM_UTILS_UINT32_STRLEN + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, thing_created_fmt, devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_LEGACY_THING_CREATED, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} +#endif + +int dm_mgr_init(void) +{ + int res = 0; + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + memset(ctx, 0, sizeof(dm_mgr_ctx)); + + /* Create Mutex */ + ctx->mutex = HAL_MutexCreate(); + if (ctx->mutex == NULL) { + goto ERROR; + } + + /* Init Device Id*/ + ctx->global_devid = IOTX_DM_LOCAL_NODE_DEVID + 1; + + /* Init Device List */ + INIT_LIST_HEAD(&ctx->dev_list); + + /* Local Node */ + HAL_GetProductKey(product_key); + HAL_GetDeviceName(device_name); + res = _dm_mgr_insert_dev(IOTX_DM_LOCAL_NODE_DEVID, IOTX_DM_DEVICE_TYPE, product_key, device_name); + if (res != SUCCESS_RETURN) { + goto ERROR; + } + +#ifdef DEPRECATED_LINKKIT + _dm_mgr_legacy_thing_created(IOTX_DM_LOCAL_NODE_DEVID); +#endif + + return SUCCESS_RETURN; + +ERROR: + if (ctx->mutex) { + HAL_MutexDestroy(ctx->mutex); + } + memset(ctx, 0, sizeof(dm_mgr_ctx)); + return FAIL_RETURN; +} + +int dm_mgr_deinit(void) +{ + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + + _dm_mgr_mutex_lock(); + _dm_mgr_destroy_devlist(); + _dm_mgr_mutex_unlock(); + + if (ctx->mutex) { + HAL_MutexDestroy(ctx->mutex); + } + + return SUCCESS_RETURN; +} + +int dm_mgr_device_create(_IN_ int dev_type, _IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1], _OU_ int *devid) +{ + int res = 0; + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + dm_mgr_dev_node_t *node = NULL; + + if (product_key == NULL || device_name == NULL || + strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1 || + strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) { + return DM_INVALID_PARAMETER; + } + + if (device_secret != NULL && strlen(device_secret) >= IOTX_DEVICE_SECRET_LEN + 1) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_pkdn(product_key, device_name, &node); + if (res == SUCCESS_RETURN) { + if (devid) { + *devid = node->devid; + } + return FAIL_RETURN; + } + + node = DM_malloc(sizeof(dm_mgr_dev_node_t)); + if (node == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(node, 0, sizeof(dm_mgr_dev_node_t)); + + node->devid = _dm_mgr_next_devid(); + node->dev_type = dev_type; +#if defined(DEPRECATED_LINKKIT) + node->dev_shadow = NULL; + node->tsl_source = IOTX_DM_TSL_SOURCE_CLOUD; +#endif + memcpy(node->product_key, product_key, strlen(product_key)); + memcpy(node->device_name, device_name, strlen(device_name)); + if (device_secret != NULL) { + memcpy(node->device_secret, device_secret, strlen(device_secret)); + } + node->dev_status = IOTX_DM_DEV_STATUS_AUTHORIZED; + INIT_LIST_HEAD(&node->linked_list); + + list_add_tail(&node->linked_list, &ctx->dev_list); + + if (devid) { + *devid = node->devid; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_device_destroy(_IN_ int devid) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + if (node->devid == IOTX_DM_LOCAL_NODE_DEVID) { + return FAIL_RETURN; + } + + list_del(&node->linked_list); + +#if defined(DEPRECATED_LINKKIT) + if (node->dev_shadow) { + dm_shw_destroy(&node->dev_shadow); + } +#endif + +#ifdef DEVICE_MODEL_GATEWAY + dm_client_subdev_unsubscribe(node->product_key,node->device_name); +#endif + + DM_free(node); + + return SUCCESS_RETURN; +} + +int dm_mgr_device_number(void) +{ + int index = 0; + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + dm_mgr_dev_node_t *search_node = NULL; + + list_for_each_entry(search_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) { + index++; + } + + return index; +} + +int dm_mgr_get_devid_by_index(_IN_ int index, _OU_ int *devid) +{ + int search_index = 0; + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + dm_mgr_dev_node_t *search_node = NULL; + + if (index < 0 || devid == NULL) { + return DM_INVALID_PARAMETER; + } + + list_for_each_entry(search_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) { + if (search_index == index) { + *devid = search_node->devid; + return SUCCESS_RETURN; + } + search_index++; + } + + return FAIL_RETURN; +} + +int dm_mgr_get_next_devid(_IN_ int devid, _OU_ int *devid_next) +{ + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + dm_mgr_dev_node_t *search_node = NULL; + dm_mgr_dev_node_t *next_node = NULL; + + if (devid < 0 || devid_next == NULL) { + return DM_INVALID_PARAMETER; + } + + list_for_each_entry(next_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) { + if (search_node && search_node->devid == devid) { + *devid_next = next_node->devid; + return SUCCESS_RETURN; + } + + if (next_node->devid == devid) { + search_node = next_node; + } + } + + return FAIL_RETURN; +} + +int dm_mgr_search_device_by_devid(_IN_ int devid, _OU_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _OU_ char device_name[IOTX_DEVICE_NAME_LEN + 1], _OU_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1]) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (product_key == NULL || device_name == NULL || device_secret == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + memcpy(product_key, node->product_key, strlen(node->product_key)); + memcpy(device_name, node->device_name, strlen(node->device_name)); + memcpy(device_secret, node->device_secret, strlen(node->device_secret)); + + return SUCCESS_RETURN; +} + +int dm_mgr_search_device_by_pkdn(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ int *devid) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (product_key == NULL || device_name == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_pkdn(product_key, device_name, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + if (devid) { + *devid = node->devid; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_search_device_node_by_devid(_IN_ int devid, _OU_ void **node) +{ + int res = 0; + dm_mgr_dev_node_t *search_node = NULL; + + res = _dm_mgr_search_dev_by_devid(devid, &search_node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + if (node) { + *node = (void *)search_node; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_get_dev_type(_IN_ int devid, _OU_ int *dev_type) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || dev_type == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + *dev_type = node->dev_type; + + return SUCCESS_RETURN; +} + +int dm_mgr_set_dev_enable(_IN_ int devid) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + node->status = IOTX_DM_DEV_AVAIL_ENABLE; + + return SUCCESS_RETURN; +} + +int dm_mgr_set_dev_disable(_IN_ int devid) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + node->status = IOTX_DM_DEV_AVAIL_DISABLE; + + return SUCCESS_RETURN; +} + +int dm_mgr_get_dev_avail(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ iotx_dm_dev_avail_t *status) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (product_key == NULL || device_name == NULL || status == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1)) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_pkdn(product_key, device_name, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + *status = node->status; + + return SUCCESS_RETURN; +} + +int dm_mgr_set_dev_status(_IN_ int devid, _IN_ iotx_dm_dev_status_t status) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + node->dev_status = status; + + return SUCCESS_RETURN; +} + +int dm_mgr_get_dev_status(_IN_ int devid, _OU_ iotx_dm_dev_status_t *status) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || status == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + *status = node->dev_status; + + return SUCCESS_RETURN; +} + +int dm_mgr_set_device_secret(_IN_ int devid, _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1]) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || device_secret == NULL || + strlen(device_secret) >= IOTX_DEVICE_SECRET_LEN + 1) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + memset(node->device_secret, 0, IOTX_DEVICE_SECRET_LEN + 1); + memcpy(node->device_secret, device_secret, strlen(device_secret)); + + return SUCCESS_RETURN; +} + +int dm_mgr_dev_initialized(int devid) +{ + int res = 0, message_len = 0; + char *message = NULL; + const char *fmt = "{\"devid\":%d}"; + + message_len = strlen(fmt) + DM_UTILS_UINT32_STRLEN + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, fmt, devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_INITIALIZED, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +#ifdef DEVICE_MODEL_GATEWAY +int dm_mgr_upstream_thing_sub_register(_IN_ int devid) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + dm_msg_request_t request; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + request.service_prefix = DM_URI_SYS_PREFIX; + request.service_name = DM_URI_THING_SUB_REGISTER; + HAL_GetProductKey(request.product_key); + HAL_GetDeviceName(request.device_name); + + /* Get Params And Method */ + res = dm_msg_thing_sub_register(node->product_key, node->device_name, &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Get Msg ID */ + request.msgid = iotx_report_id(); + + /* Get Dev ID */ + request.devid = devid; + + /* Callback */ + request.callback = dm_client_thing_sub_register_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_SUBDEV_REGISTER_REPLY, NULL); + res = request.msgid; + } +#endif + DM_free(request.params); + + return res; +} + +int dm_mgr_upstream_thing_sub_unregister(_IN_ int devid) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + dm_msg_request_t request; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + request.service_prefix = DM_URI_SYS_PREFIX; + request.service_name = DM_URI_THING_SUB_UNREGISTER; + HAL_GetProductKey(request.product_key); + HAL_GetDeviceName(request.device_name); + + /* Get Params And Method */ + res = dm_msg_thing_sub_unregister(node->product_key, node->device_name, &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Get Msg ID */ + request.msgid = iotx_report_id(); + + /* Get Dev ID */ + request.devid = devid; + + /* Callback */ + request.callback = dm_client_thing_sub_unregister_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_SUBDEV_UNREGISTER_REPLY, NULL); + res = request.msgid; + } +#endif + DM_free(request.params); + + return res; +} + +int dm_mgr_upstream_thing_topo_add(_IN_ int devid) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + dm_msg_request_t request; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + request.service_prefix = DM_URI_SYS_PREFIX; + request.service_name = DM_URI_THING_TOPO_ADD; + HAL_GetProductKey(request.product_key); + HAL_GetDeviceName(request.device_name); + + /* Get Params And Method */ + res = dm_msg_thing_topo_add(node->product_key, node->device_name, node->device_secret, &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Get Msg ID */ + request.msgid = iotx_report_id(); + + /* Get Dev ID */ + request.devid = devid; + + /* Callback */ + request.callback = dm_client_thing_topo_add_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_TOPO_ADD_REPLY, NULL); + res = request.msgid; + } +#endif + DM_free(request.params); + + return res; +} + +int dm_mgr_upstream_thing_topo_delete(_IN_ int devid) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + dm_msg_request_t request; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + request.service_prefix = DM_URI_SYS_PREFIX; + request.service_name = DM_URI_THING_TOPO_DELETE; + HAL_GetProductKey(request.product_key); + HAL_GetDeviceName(request.device_name); + + /* Get Params And Method */ + res = dm_msg_thing_topo_delete(node->product_key, node->device_name, &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Get Msg ID */ + request.msgid = iotx_report_id(); + + /* Get Dev ID */ + request.devid = devid; + + /* Callback */ + request.callback = dm_client_thing_topo_delete_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_TOPO_DELETE_REPLY, NULL); + res = request.msgid; + } +#endif + DM_free(request.params); + + return res; +} + +int dm_mgr_upstream_thing_topo_get(void) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + dm_msg_request_t request; + + memset(&request, 0, sizeof(dm_msg_request_t)); + request.service_prefix = DM_URI_SYS_PREFIX; + request.service_name = DM_URI_THING_TOPO_GET; + HAL_GetProductKey(request.product_key); + HAL_GetDeviceName(request.device_name); + + res = _dm_mgr_search_dev_by_pkdn(request.product_key, request.device_name, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Get Params And Method */ + res = dm_msg_thing_topo_get(&request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Get Msg ID */ + request.msgid = iotx_report_id(); + + /* Get Dev ID */ + request.devid = node->devid; + + /* Callback */ + request.callback = dm_client_thing_topo_get_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_TOPO_GET_REPLY, NULL); + res = request.msgid; + } +#endif + DM_free(request.params); + + return res; +} + +int dm_mgr_upstream_thing_list_found(_IN_ int devid) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + dm_msg_request_t request; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + request.service_prefix = DM_URI_SYS_PREFIX; + request.service_name = DM_URI_THING_LIST_FOUND; + HAL_GetProductKey(request.product_key); + HAL_GetDeviceName(request.device_name); + + /* Get Params And Method */ + res = dm_msg_thing_list_found(node->product_key, node->device_name, &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Get Msg ID */ + request.msgid = iotx_report_id(); + + /* Get Dev ID */ + request.devid = devid; + + /* Callback */ + request.callback = dm_client_thing_list_found_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_TOPO_ADD_NOTIFY_REPLY, NULL); + res = request.msgid; + } +#endif + DM_free(request.params); + + return res; +} + +int dm_mgr_upstream_combine_login(_IN_ int devid) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + dm_msg_request_t request; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + request.service_prefix = DM_URI_EXT_SESSION_PREFIX; + request.service_name = DM_URI_COMBINE_LOGIN; + HAL_GetProductKey(request.product_key); + HAL_GetDeviceName(request.device_name); + + /* Get Params And Method */ + res = dm_msg_combine_login(node->product_key, node->device_name, node->device_secret, &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Get Msg ID */ + request.msgid = iotx_report_id(); + + /* Get Dev ID */ + request.devid = devid; + + /* Callback */ + request.callback = dm_client_combine_login_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_COMBINE_LOGIN_REPLY, NULL); + res = request.msgid; + } +#endif + DM_free(request.params); + + return res; +} + +int dm_mgr_upstream_combine_logout(_IN_ int devid) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + dm_msg_request_t request; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + if (node->dev_status < IOTX_DM_DEV_STATUS_LOGINED) { + return FAIL_RETURN; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + request.service_prefix = DM_URI_EXT_SESSION_PREFIX; + request.service_name = DM_URI_COMBINE_LOGOUT; + HAL_GetProductKey(request.product_key); + HAL_GetDeviceName(request.device_name); + + /* Get Params And Method */ + res = dm_msg_combine_logout(node->product_key, node->device_name, &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Get Msg ID */ + request.msgid = iotx_report_id(); + + /* Get Dev ID */ + request.devid = devid; + + /* Callback */ + request.callback = dm_client_combine_logout_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_COMBINE_LOGOUT_REPLY, NULL); + res = request.msgid; + } +#endif + DM_free(request.params); + + return res; +} + +#ifdef DEVICE_MODEL_SUBDEV_OTA +int dm_mgr_upstream_thing_firmware_version_update(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0, res1 = 0; + dm_mgr_dev_node_t *node = NULL; + char *uri = NULL; + dm_msg_request_t request; + + if (devid < 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + request.service_prefix = DM_URI_OTA_DEVICE_INFORM; + request.service_name = NULL; + memcpy(request.product_key, node->product_key, strlen(node->product_key)); + memcpy(request.device_name, node->device_name, strlen(node->device_name)); + + /* Request URI */ + res = dm_utils_service_name(request.service_prefix, request.service_name, + request.product_key, request.device_name, &uri); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_info("DM Send Raw Data:"); + HEXDUMP_INFO(payload, payload_len); + + res = dm_client_publish(uri, (unsigned char *)payload, strlen(payload), dm_client_thing_model_up_raw_reply); + + if (res < SUCCESS_RETURN || res1 < SUCCESS_RETURN) { + dm_log_info("res of pub is %d:", res); + DM_free(uri); + return FAIL_RETURN; + } + + DM_free(uri); + return SUCCESS_RETURN; +} +#endif +#endif + +int dm_mgr_upstream_thing_model_up_raw(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0, res1 = 0; + dm_mgr_dev_node_t *node = NULL; + char *uri = NULL; + dm_msg_request_t request; + + if (devid < 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + request.service_prefix = DM_URI_SYS_PREFIX; + request.service_name = DM_URI_THING_MODEL_UP_RAW; + memcpy(request.product_key, node->product_key, strlen(node->product_key)); + memcpy(request.device_name, node->device_name, strlen(node->device_name)); + + /* Request URI */ + res = dm_utils_service_name(request.service_prefix, request.service_name, + request.product_key, request.device_name, &uri); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_info("DM Send Raw Data:"); + HEXDUMP_INFO(payload, payload_len); + + res = dm_client_publish(uri, (unsigned char *)payload, strlen(payload), dm_client_thing_model_up_raw_reply); +#ifdef ALCS_ENABLED + res1 = dm_server_send(uri, (unsigned char *)payload, strlen(payload), NULL); +#endif + + if (res < SUCCESS_RETURN || res1 < SUCCESS_RETURN) { + DM_free(uri); + return FAIL_RETURN; + } + + DM_free(uri); + return SUCCESS_RETURN; +} + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) +static int _dm_mgr_upstream_request_assemble(_IN_ int msgid, _IN_ int devid, _IN_ const char *service_prefix, + _IN_ const char *service_name, + _IN_ char *params, _IN_ int params_len, _IN_ char *method, _OU_ dm_msg_request_t *request) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + request->msgid = msgid; + request->devid = devid; + request->service_prefix = service_prefix; + request->service_name = service_name; + memcpy(request->product_key, node->product_key, strlen(node->product_key)); + memcpy(request->device_name, node->device_name, strlen(node->device_name)); + request->params = params; + request->params_len = params_len; + request->method = method; + + return SUCCESS_RETURN; +} +#ifdef DEVICE_MODEL_SHADOW +int dm_mgr_upstream_thing_property_desired_get(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + dm_msg_request_t request; + + if (devid < 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + res = _dm_mgr_upstream_request_assemble(iotx_report_id(), devid, DM_URI_SYS_PREFIX, DM_URI_THING_PROPERTY_DESIRED_GET, + payload, payload_len, "thing.property.desired.get", &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Callback */ + request.callback = dm_client_thing_property_desired_get_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); + /*TODO */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + int prop_desired_get_reply = 0; + res = dm_opt_get(DM_OPT_DOWNSTREAM_EVENT_PROPERTY_DESIRED_GET_REPLY, &prop_desired_get_reply); + if (res == SUCCESS_RETURN && prop_desired_get_reply) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_PROPERTY_DESIRED_GET_REPLY, NULL); + } + res = request.msgid; + } +#endif + return res; +} + +int dm_mgr_upstream_thing_property_desired_delete(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + dm_msg_request_t request; + + if (devid < 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + res = _dm_mgr_upstream_request_assemble(iotx_report_id(), devid, DM_URI_SYS_PREFIX, + DM_URI_THING_PROPERTY_DESIRED_DELETE, + payload, payload_len, "thing.property.desired.delete", &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Callback */ + request.callback = dm_client_thing_property_desired_delete_reply; + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + int prop_desired_delete_reply = 0; + res = dm_opt_get(DM_OPT_DOWNSTREAM_EVENT_PROPERTY_DESIRED_DELETE_REPLY, &prop_desired_delete_reply); + if (res == SUCCESS_RETURN && prop_desired_delete_reply) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_PROPERTY_DESIRED_DELETE_REPLY, NULL); + } + res = request.msgid; + } +#endif + return res; +} +#endif + +int dm_mgr_upstream_thing_property_post(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + dm_msg_request_t request; + + if (devid < 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + res = _dm_mgr_upstream_request_assemble(iotx_report_id(), devid, DM_URI_SYS_PREFIX, DM_URI_THING_EVENT_PROPERTY_POST, + payload, payload_len, "thing.event.property.post", &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Callback */ + request.callback = dm_client_thing_event_post_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_ALL, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + int prop_post_reply = 0; + res = dm_opt_get(DM_OPT_DOWNSTREAM_EVENT_POST_REPLY, &prop_post_reply); + if (res == SUCCESS_RETURN && prop_post_reply) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_EVENT_PROPERTY_POST_REPLY, NULL); + } + res = request.msgid; + } +#endif + return res; +} + +#ifdef LOG_REPORT_TO_CLOUD +static unsigned int log_size = 0; +int dm_mgr_upstream_thing_log_post(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len, int force_upload) +{ + int res = 0; + dm_msg_request_t request; + extern REPORT_STATE g_report_status; + extern char *g_log_poll; + + if (0 == force_upload) { + if (devid < 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + if (log_size + payload_len < OVERFLOW_LEN) { + log_size = push_log(payload, payload_len); + } else { + /* it should NOT happen; it means that it is too late to upload log files */ + reset_log_poll(); + dm_log_err("it it too late to upload log, reset pool"); + return FAIL_RETURN; + } + + dm_log_info("push log, len is %d, log_size is %d\n", payload_len, log_size); + if (!(log_size > REPORT_LEN && DONE == g_report_status)) { + return SUCCESS_RETURN; + } + } + + log_size = add_tail(); + memset(&request, 0, sizeof(dm_msg_request_t)); + res = _dm_mgr_upstream_request_assemble(iotx_report_id(), devid, DM_URI_SYS_PREFIX, DM_URI_THING_LOG_POST, + g_log_poll, log_size + 1, "thing.log.post", &request); + + if (res != SUCCESS_RETURN) { + reset_log_poll(); + return FAIL_RETURN; + } + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); + reset_log_poll(); + return res; +} +#endif + + + +int dm_mgr_upstream_thing_event_post(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len, _IN_ char *method, + _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0, service_name_len = 0; + char *service_name = NULL; + dm_msg_request_t request; + + if (devid < 0 || identifier == NULL || identifier_len <= 0 || + method == NULL || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + service_name_len = strlen(DM_URI_THING_EVENT_POST) + identifier_len + 1; + service_name = DM_malloc(service_name_len); + if (service_name == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(service_name, 0, service_name_len); + HAL_Snprintf(service_name, service_name_len, DM_URI_THING_EVENT_POST, identifier_len, identifier); + + memset(&request, 0, sizeof(dm_msg_request_t)); + res = _dm_mgr_upstream_request_assemble(iotx_report_id(), devid, DM_URI_SYS_PREFIX, service_name, + payload, payload_len, method, &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Callback */ + request.callback = dm_client_thing_event_post_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_ALL, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + int event_post_reply = 0; + res = dm_opt_get(DM_OPT_DOWNSTREAM_EVENT_POST_REPLY, &event_post_reply); + if (res == SUCCESS_RETURN && event_post_reply) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_EVENT_PROPERTY_POST_REPLY, NULL); + } + res = request.msgid; + } +#endif + DM_free(service_name); + + return res; +} + + +int dm_mgr_upstream_thing_deviceinfo_update(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + dm_msg_request_t request; + + if (devid < 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + res = _dm_mgr_upstream_request_assemble(iotx_report_id(), devid, DM_URI_SYS_PREFIX, DM_URI_THING_DEVICEINFO_UPDATE, + payload, payload_len, "thing.deviceinfo.update", &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Callback */ + request.callback = dm_client_thing_deviceinfo_update_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_DEVICEINFO_UPDATE_REPLY, NULL); + res = request.msgid; + } +#endif + return res; +} + +int dm_mgr_upstream_thing_deviceinfo_delete(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0; + dm_msg_request_t request; + + if (devid < 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + res = _dm_mgr_upstream_request_assemble(iotx_report_id(), devid, DM_URI_SYS_PREFIX, DM_URI_THING_DEVICEINFO_DELETE, + payload, payload_len, "thing.deviceinfo.delete", &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Callback */ + request.callback = dm_client_thing_deviceinfo_delete_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_DEVICEINFO_DELETE_REPLY, NULL); + res = request.msgid; + } +#endif + return res; +} + +int dm_mgr_upstream_thing_dsltemplate_get(_IN_ int devid) +{ + int res = 0; + char *params = "{}"; + int params_len = strlen(params); + dm_msg_request_t request; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + res = _dm_mgr_upstream_request_assemble(iotx_report_id(), devid, DM_URI_SYS_PREFIX, DM_URI_THING_DSLTEMPLATE_GET, + params, params_len, "thing.dsltemplate.get", &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_DSLTEMPLATE_GET_REPLY, NULL); + res = request.msgid; + } +#endif + return res; +} + +int dm_mgr_upstream_thing_dynamictsl_get(_IN_ int devid) +{ + int res = 0; + char *params = "{\"nodes\":[\"type\",\"identifier\"],\"addDefault\":false}"; + int params_len = strlen(params); + dm_msg_request_t request; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + memset(&request, 0, sizeof(dm_msg_request_t)); + res = _dm_mgr_upstream_request_assemble(iotx_report_id(), devid, DM_URI_SYS_PREFIX, DM_URI_THING_DYNAMICTSL_GET, + params, params_len, "thing.dynamicTsl.get", &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Callback */ + request.callback = dm_client_thing_dynamictsl_get_reply; + + /* Send Message To Cloud */ + res = dm_msg_request(DM_MSG_DEST_CLOUD, &request); +#if !defined(DM_MESSAGE_CACHE_DISABLED) + if (res == SUCCESS_RETURN) { + dm_msg_cache_insert(request.msgid, request.devid, IOTX_DM_EVENT_DSLTEMPLATE_GET_REPLY, NULL); + res = request.msgid; + } +#endif + return res; +} + +int dm_mgr_upstream_ntp_request(void) +{ + int res = 0; + const char *ntp_request_fmt = "{\"deviceSendTime\":\"1234\"}"; + char /* *cloud_payload = NULL, */ *uri = NULL; + dm_msg_request_t request; + + memset(&request, 0, sizeof(dm_msg_request_t)); + request.service_prefix = DM_URI_EXT_NTP_PREFIX; + request.service_name = DM_URI_NTP_REQUEST; + HAL_GetProductKey(request.product_key); + HAL_GetDeviceName(request.device_name); + + /* Request URI */ + res = dm_utils_service_name(request.service_prefix, request.service_name, + request.product_key, request.device_name, &uri); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_client_publish(uri, (unsigned char *)ntp_request_fmt, strlen(ntp_request_fmt), dm_client_ntp_response); + if (res != SUCCESS_RETURN) { + DM_free(uri); /* DM_free(cloud_payload); */ + return FAIL_RETURN; + } + + DM_free(uri); /* DM_free(cloud_payload); */ + return SUCCESS_RETURN; +} + +static int _dm_mgr_upstream_response_assemble(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, + _IN_ const char *prefix, + _IN_ const char *service_name, _IN_ int code, _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + request->id.value = msgid; + request->id.value_length = msgid_len; + + response->service_prefix = DM_URI_SYS_PREFIX; + response->service_name = service_name; + memcpy(response->product_key, node->product_key, strlen(node->product_key)); + memcpy(response->device_name, node->device_name, strlen(node->device_name)); + response->code = code; + + return SUCCESS_RETURN; +} + +int dm_mgr_upstream_thing_service_response(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, + _IN_ iotx_dm_error_code_t code, + _IN_ char *identifier, _IN_ int identifier_len, _IN_ char *payload, _IN_ int payload_len, void *ctx) +{ + int res = 0, service_name_len = 0; + char *service_name = NULL; + dm_msg_request_payload_t request; + dm_msg_response_t response; + + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + if (devid < 0 || msgid == NULL || msgid_len <= 0 || identifier == NULL || identifier_len <= 0 || + payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + /* Service Name */ + service_name_len = strlen(DM_URI_THING_SERVICE_RESPONSE) + identifier_len + 1; + service_name = DM_malloc(service_name_len); + if (service_name == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(service_name, 0, service_name_len); + HAL_Snprintf(service_name, service_name_len, DM_URI_THING_SERVICE_RESPONSE, identifier_len, identifier); + + res = _dm_mgr_upstream_response_assemble(devid, msgid, msgid_len, DM_URI_SYS_PREFIX, service_name, code, &request, + &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_debug("Current Service Name: %s", service_name); + if (ctx != NULL) { + dm_msg_response(DM_MSG_DEST_LOCAL, &request, &response, payload, payload_len, ctx); + } else { + dm_msg_response(DM_MSG_DEST_CLOUD, &request, &response, payload, payload_len, ctx); + } + + DM_free(service_name); + return SUCCESS_RETURN; +} + +int dm_mgr_upstream_thing_property_get_response(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, + _IN_ iotx_dm_error_code_t code, + _IN_ char *payload, _IN_ int payload_len, _IN_ void *ctx) +{ + int res = 0; + dm_msg_request_payload_t request; + dm_msg_response_t response; + const char *reply_service_name = NULL; + dm_msg_dest_type_t reply_msg_type; +#ifdef ALCS_ENABLED + dm_server_alcs_context_t *alcs_context = NULL; +#endif + + if (devid < 0 || msgid == NULL || msgid_len <= 0 || + payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + /* Send Property Get Response Message To Local */ + reply_service_name = DM_URI_THING_SERVICE_PROPERTY_GET; + reply_msg_type = DM_MSG_DEST_LOCAL; + + /* Send Property Get Response Message To Cloud */ + if (NULL == ctx) { + reply_service_name = DM_URI_THING_SERVICE_PROPERTY_GET_REPLY; + reply_msg_type = DM_MSG_DEST_CLOUD; + } + + res = _dm_mgr_upstream_response_assemble(devid, msgid, msgid_len, DM_URI_SYS_PREFIX, + reply_service_name, code, &request, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_debug("Current Service Name: %s", reply_service_name); + dm_msg_response(reply_msg_type, &request, &response, payload, payload_len, ctx); + +#ifdef ALCS_ENABLED + alcs_context = (dm_server_alcs_context_t *)ctx; + + if (alcs_context) { + DM_free(alcs_context->ip); + DM_free(alcs_context->token); + DM_free(alcs_context); + } +#endif + + return SUCCESS_RETURN; +} + +int dm_mgr_upstream_rrpc_response(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, _IN_ iotx_dm_error_code_t code, + _IN_ char *rrpcid, _IN_ int rrpcid_len, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0, service_name_len = 0; + const char *rrpc_response_service_name = "rrpc/response/%.*s"; + char *service_name = NULL; + dm_msg_request_payload_t request; + dm_msg_response_t response; + + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + if (devid < 0 || msgid == NULL || msgid_len <= 0 || + rrpcid == NULL || rrpcid_len <= 0 || payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + /* Service Name */ + service_name_len = strlen(rrpc_response_service_name) + rrpcid_len + 1; + service_name = DM_malloc(service_name_len); + if (service_name == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(service_name, 0, service_name_len); + HAL_Snprintf(service_name, service_name_len, rrpc_response_service_name, rrpcid_len, rrpcid); + + res = _dm_mgr_upstream_response_assemble(devid, msgid, msgid_len, DM_URI_SYS_PREFIX, service_name, code, &request, + &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_debug("Current Service Name: %s", service_name); + dm_msg_response(DM_MSG_DEST_ALL, &request, &response, payload, payload_len, NULL); + + DM_free(service_name); + + return SUCCESS_RETURN; +} +#endif + +#ifdef DEPRECATED_LINKKIT +int dm_mgr_deprecated_set_tsl_source(_IN_ int devid, _IN_ iotx_dm_tsl_source_t tsl_source) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + node->tsl_source = tsl_source; + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_get_tsl_source(_IN_ int devid, _IN_ iotx_dm_tsl_source_t *tsl_source) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || tsl_source == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + *tsl_source = node->tsl_source; + + return SUCCESS_RETURN; +} + +static int dm_mgr_deprecated_search_devid_by_node(_IN_ dm_mgr_dev_node_t *node, _OU_ int *devid) +{ + dm_mgr_ctx *ctx = _dm_mgr_get_ctx(); + dm_mgr_dev_node_t *search_node = NULL; + + list_for_each_entry(search_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) { + if (search_node == node) { + /* dm_log_debug("Device Found, node: %p", node); */ + if (devid) { + *devid = search_node->devid; + } + return SUCCESS_RETURN; + } + } + + dm_log_debug("Device Not Found, node: %p", node); + return FAIL_RETURN; +} + +int dm_mgr_deprecated_search_devid_by_device_node(_IN_ void *node, _OU_ int *devid) +{ + int res = 0; + + if (node == NULL || devid == NULL) { + return DM_INVALID_PARAMETER; + } + + res = dm_mgr_deprecated_search_devid_by_node((dm_mgr_dev_node_t *)node, devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_set_tsl(int devid, iotx_dm_tsl_type_t tsl_type, const char *tsl, int tsl_len) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (tsl == NULL || tsl_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_create(tsl_type, tsl, tsl_len, &node->dev_shadow); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_get_property_data(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_get_property_data(node->dev_shadow, key, key_len, data); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_get_service_input_data(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_get_service_input_output_data(DM_SHW_DATA_TARGET_SERVICE_INPUT_DATA, node->dev_shadow, key, key_len, data); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_get_service_output_data(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_get_service_input_output_data(DM_SHW_DATA_TARGET_SERVICE_OUTPUT_DATA, node->dev_shadow, key, key_len, + data); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_get_event_output_data(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_get_event_output_data(node->dev_shadow, key, key_len, data); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_get_data_type(_IN_ void *data, _OU_ dm_shw_data_type_e *type) +{ + if (data == NULL || type == NULL) { + return DM_INVALID_PARAMETER; + } + + return dm_shw_get_data_type(data, type); +} + +int dm_mgr_deprecated_get_property_number(_IN_ int devid, _OU_ int *number) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || number == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return dm_shw_get_property_number(node->dev_shadow, number); +} + +int dm_mgr_deprecated_get_service_number(_IN_ int devid, _OU_ int *number) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || number == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return dm_shw_get_service_number(node->dev_shadow, number); +} + +int dm_mgr_deprecated_get_event_number(_IN_ int devid, _OU_ int *number) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || number == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return dm_shw_get_event_number(node->dev_shadow, number); +} + +int dm_mgr_deprecated_get_property_by_index(_IN_ int devid, _IN_ int index, _OU_ void **property) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || index < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return dm_shw_get_property_by_index(node->dev_shadow, index, property); +} + +int dm_mgr_deprecated_get_service_by_index(_IN_ int devid, _IN_ int index, _OU_ void **service) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || index < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return dm_shw_get_service_by_index(node->dev_shadow, index, service); +} + +int dm_mgr_deprecated_get_event_by_index(_IN_ int devid, _IN_ int index, _OU_ void **event) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || index < 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return dm_shw_get_event_by_index(node->dev_shadow, index, event); +} + +int dm_mgr_deprecated_get_service_by_identifier(_IN_ int devid, _IN_ char *identifier, _OU_ void **service) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || identifier == NULL || service == NULL || *service != NULL) { + return DM_INVALID_PARAMETER; + } + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return dm_shw_get_service_by_identifier(node->dev_shadow, identifier, service); +} + +int dm_mgr_deprecated_get_event_by_identifier(_IN_ int devid, _IN_ char *identifier, _OU_ void **event) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || identifier == NULL || event == NULL || *event != NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return dm_shw_get_event_by_identifier(node->dev_shadow, identifier, event); +} + +int dm_mgr_deprecated_get_property_identifier(_IN_ void *property, _OU_ char **identifier) +{ + if (property == NULL || identifier == NULL) { + return DM_INVALID_PARAMETER; + } + + return dm_shw_get_property_identifier(property, identifier); +} + +int dm_mgr_deprecated_get_service_method(_IN_ void *service, _OU_ char **method) +{ + if (service == NULL || method == NULL || *method != NULL) { + return DM_INVALID_PARAMETER; + } + + return dm_shw_get_service_method(service, method); +} + +int dm_mgr_deprecated_get_event_method(_IN_ void *event, _OU_ char **method) +{ + if (event == NULL || method == NULL) { + return DM_INVALID_PARAMETER; + } + + return dm_shw_get_event_method(event, method); +} + +int dm_mgr_deprecated_set_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_set_property_value(node->dev_shadow, key, key_len, value, value_len); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_get_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_get_property_value(node->dev_shadow, key, key_len, value); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_set_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_set_event_output_value(node->dev_shadow, key, key_len, value, value_len); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_get_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_get_event_output_value(node->dev_shadow, key, key_len, value); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_set_service_input_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_set_service_input_output_value(DM_SHW_DATA_TARGET_SERVICE_INPUT_DATA, node->dev_shadow, key, key_len, + value, value_len); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_get_service_input_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_get_service_input_output_value(DM_SHW_DATA_TARGET_SERVICE_INPUT_DATA, node->dev_shadow, key, key_len, + value); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_set_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_set_service_input_output_value(DM_SHW_DATA_TARGET_SERVICE_OUTPUT_DATA, node->dev_shadow, key, key_len, + value, value_len); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_get_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || key == NULL || key_len <= 0 || value == NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_get_service_input_output_value(DM_SHW_DATA_TARGET_SERVICE_OUTPUT_DATA, node->dev_shadow, key, key_len, + value); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_assemble_property(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len, + _IN_ lite_cjson_item_t *lite) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || identifier == NULL || identifier_len <= 0 || lite == NULL || lite->type != cJSON_Object) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_assemble_property(node->dev_shadow, identifier, identifier_len, lite); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_assemble_event_output(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len, + _IN_ lite_cjson_item_t *lite) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || identifier == NULL || identifier_len <= 0 || lite == NULL || lite->type != cJSON_Object) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_assemble_event_output(node->dev_shadow, identifier, identifier_len, lite); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_assemble_service_output(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len, + _IN_ lite_cjson_item_t *lite) +{ + int res = 0; + dm_mgr_dev_node_t *node = NULL; + + if (devid < 0 || identifier == NULL || identifier_len <= 0 || lite == NULL || lite->type != cJSON_Object) { + return DM_INVALID_PARAMETER; + } + + res = _dm_mgr_search_dev_by_devid(devid, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_shw_assemble_service_output(node->dev_shadow, identifier, identifier_len, lite); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_mgr_deprecated_upstream_thing_service_response(_IN_ int devid, _IN_ int msgid, _IN_ iotx_dm_error_code_t code, + _IN_ char *identifier, _IN_ int identifier_len, _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0, service_name_len = 0; + char *msgid_str = NULL, *service_name = NULL; + dm_msg_request_payload_t request; + dm_msg_response_t response; + + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + if (devid < 0 || msgid < 0 || identifier == NULL || identifier_len <= 0 || + payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + /* Response Msg ID */ + res = dm_utils_itoa(msgid, &msgid_str); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + request.id.value = msgid_str; + request.id.value_length = strlen(msgid_str); + + /* Service Name */ + service_name_len = strlen(DM_URI_THING_SERVICE_RESPONSE) + identifier_len + 1; + service_name = DM_malloc(service_name_len); + if (service_name == NULL) { + DM_free(msgid_str); + return DM_MEMORY_NOT_ENOUGH; + } + memset(service_name, 0, service_name_len); + HAL_Snprintf(service_name, service_name_len, DM_URI_THING_SERVICE_RESPONSE, identifier_len, identifier); + + res = _dm_mgr_upstream_response_assemble(devid, msgid_str, strlen(msgid_str), DM_URI_SYS_PREFIX, service_name, code, + &request, + &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_debug("Current Service Name: %s", service_name); + dm_msg_response(DM_MSG_DEST_ALL, &request, &response, payload, payload_len, NULL); + + DM_free(msgid_str); + DM_free(service_name); + return SUCCESS_RETURN; +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_manager.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_manager.h new file mode 100644 index 00000000..40a222f9 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_manager.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _DM_MANAGER_H_ +#define _DM_MANAGER_H_ + +#include "iotx_dm_internal.h" + +typedef struct { + int devid; + int dev_type; +#if defined(DEPRECATED_LINKKIT) + dm_shw_t *dev_shadow; + iotx_dm_tsl_source_t tsl_source; +#endif + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1]; + iotx_dm_dev_avail_t status; + iotx_dm_dev_status_t dev_status; + struct list_head linked_list; +} dm_mgr_dev_node_t; + +typedef struct { + void *mutex; + int global_devid; + struct list_head dev_list; +} dm_mgr_ctx; + +int dm_mgr_init(void); +int dm_mgr_deinit(void); +int dm_mgr_device_create(_IN_ int dev_type, _IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1], _OU_ int *devid); +int dm_mgr_device_destroy(_IN_ int devid); +int dm_mgr_device_number(void); +int dm_mgr_get_devid_by_index(_IN_ int index, _OU_ int *devid); +int dm_mgr_get_next_devid(_IN_ int devid, _OU_ int *devid_next); +int dm_mgr_search_device_by_devid(_IN_ int devid, _OU_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _OU_ char device_name[IOTX_DEVICE_NAME_LEN + 1], _OU_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1]); +int dm_mgr_search_device_by_pkdn(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ int *devid); +int dm_mgr_search_device_node_by_devid(_IN_ int devid, _OU_ void **node); + +int dm_mgr_get_dev_type(_IN_ int devid, _OU_ int *dev_type); +int dm_mgr_set_dev_enable(_IN_ int devid); +int dm_mgr_set_dev_disable(_IN_ int devid); +int dm_mgr_get_dev_avail(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ iotx_dm_dev_avail_t *status); +int dm_mgr_set_dev_status(_IN_ int devid, _IN_ iotx_dm_dev_status_t status); +int dm_mgr_get_dev_status(_IN_ int devid, _OU_ iotx_dm_dev_status_t *status); +int dm_mgr_set_device_secret(_IN_ int devid, _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1]); +int dm_mgr_dev_initialized(int devid); +int dm_mgr_upstream_thing_property_desired_get(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); +int dm_mgr_upstream_thing_property_desired_delete(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); + +#ifdef DEVICE_MODEL_GATEWAY + int dm_mgr_upstream_thing_sub_register(_IN_ int devid); + int dm_mgr_upstream_thing_sub_unregister(_IN_ int devid); + int dm_mgr_upstream_thing_topo_add(_IN_ int devid); + int dm_mgr_upstream_thing_topo_delete(_IN_ int devid); + int dm_mgr_upstream_thing_topo_get(void); + int dm_mgr_upstream_thing_list_found(_IN_ int devid); + int dm_mgr_upstream_combine_login(_IN_ int devid); + int dm_mgr_upstream_combine_logout(_IN_ int devid); +#endif +int dm_mgr_upstream_thing_model_up_raw(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) +int dm_mgr_upstream_thing_property_post(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); +#ifdef LOG_REPORT_TO_CLOUD + int dm_mgr_upstream_thing_log_post(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len, int force_update); +#endif +int dm_mgr_upstream_thing_event_post(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len, _IN_ char *method, + _IN_ char *payload, _IN_ int payload_len); +int dm_mgr_upstream_thing_deviceinfo_update(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); +int dm_mgr_upstream_thing_deviceinfo_delete(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); +int dm_mgr_upstream_thing_dsltemplate_get(_IN_ int devid); +int dm_mgr_upstream_thing_dynamictsl_get(_IN_ int devid); +int dm_mgr_upstream_ntp_request(void); +int dm_mgr_upstream_thing_service_response(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, + _IN_ iotx_dm_error_code_t code, + _IN_ char *identifier, _IN_ int identifier_len, _IN_ char *payload, _IN_ int payload_len, void *ctx); +int dm_mgr_upstream_thing_property_get_response(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, + _IN_ iotx_dm_error_code_t code, + _IN_ char *payload, _IN_ int payload_len, _IN_ void *ctx); +int dm_mgr_upstream_rrpc_response(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, _IN_ iotx_dm_error_code_t code, + _IN_ char *rrpcid, _IN_ int rrpcid_len, _IN_ char *payload, _IN_ int payload_len); +#ifdef DEVICE_MODEL_SUBDEV_OTA + int dm_mgr_upstream_thing_firmware_version_update(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); +#endif +#endif +#ifdef DEPRECATED_LINKKIT +int dm_mgr_deprecated_set_tsl_source(_IN_ int devid, _IN_ iotx_dm_tsl_source_t tsl_source); +int dm_mgr_deprecated_get_tsl_source(_IN_ int devid, _IN_ iotx_dm_tsl_source_t *tsl_source); +int dm_mgr_deprecated_search_devid_by_device_node(_IN_ void *node, _OU_ int *devid); +int dm_mgr_deprecated_set_tsl(int devid, iotx_dm_tsl_type_t tsl_type, const char *tsl, int tsl_len); +int dm_mgr_deprecated_get_property_data(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data); +int dm_mgr_deprecated_get_service_input_data(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data); +int dm_mgr_deprecated_get_service_output_data(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data); +int dm_mgr_deprecated_get_event_output_data(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data); +int dm_mgr_deprecated_get_data_type(_IN_ void *property, _OU_ dm_shw_data_type_e *type); +int dm_mgr_deprecated_get_property_number(_IN_ int devid, _OU_ int *number); +int dm_mgr_deprecated_get_service_number(_IN_ int devid, _OU_ int *number); +int dm_mgr_deprecated_get_event_number(_IN_ int devid, _OU_ int *number); +int dm_mgr_deprecated_get_property_by_index(_IN_ int devid, _IN_ int index, _OU_ void **property); +int dm_mgr_deprecated_get_service_by_index(_IN_ int devid, _IN_ int index, _OU_ void **service); +int dm_mgr_deprecated_get_event_by_index(_IN_ int devid, _IN_ int index, _OU_ void **event); +int dm_mgr_deprecated_get_service_by_identifier(_IN_ int devid, _IN_ char *identifier, _OU_ void **service); +int dm_mgr_deprecated_get_event_by_identifier(_IN_ int devid, _IN_ char *identifier, _OU_ void **event); +int dm_mgr_deprecated_get_property_identifier(_IN_ void *property, _OU_ char **identifier); +int dm_mgr_deprecated_get_service_method(_IN_ void *service, _OU_ char **method); +int dm_mgr_deprecated_get_event_method(_IN_ void *event, _OU_ char **method); +int dm_mgr_deprecated_set_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len); +int dm_mgr_deprecated_get_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value); +int dm_mgr_deprecated_set_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len); +int dm_mgr_deprecated_get_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value); +int dm_mgr_deprecated_set_service_input_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len); +int dm_mgr_deprecated_get_service_input_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value); +int dm_mgr_deprecated_set_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len); +int dm_mgr_deprecated_get_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value); +int dm_mgr_deprecated_assemble_property(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len, + _IN_ lite_cjson_item_t *lite); +int dm_mgr_deprecated_assemble_event_output(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len, + _IN_ lite_cjson_item_t *lite); +int dm_mgr_deprecated_assemble_service_output(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len, + _IN_ lite_cjson_item_t *lite); +int dm_mgr_deprecated_upstream_thing_service_response(_IN_ int devid, _IN_ int msgid, _IN_ iotx_dm_error_code_t code, + _IN_ char *identifier, _IN_ int identifier_len, _IN_ char *payload, _IN_ int payload_len); +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_message.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_message.c new file mode 100644 index 00000000..eb66391c --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_message.c @@ -0,0 +1,2547 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "iotx_dm_internal.h" + +static dm_msg_ctx_t g_dm_msg_ctx; + +static dm_msg_ctx_t *_dm_msg_get_ctx(void) +{ + return &g_dm_msg_ctx; +} + +int dm_msg_init(void) +{ + dm_msg_ctx_t *ctx = _dm_msg_get_ctx(); + memset(ctx, 0, sizeof(dm_msg_ctx_t)); + + return SUCCESS_RETURN; +} + +int dm_msg_deinit(void) +{ + dm_msg_ctx_t *ctx = _dm_msg_get_ctx(); + memset(ctx, 0, sizeof(dm_msg_ctx_t)); + + return SUCCESS_RETURN; +} + +int _dm_msg_send_to_user(iotx_dm_event_types_t type, char *message) +{ + int res = 0; + dm_ipc_msg_t *dipc_msg = NULL; + + dipc_msg = DM_malloc(sizeof(dm_ipc_msg_t)); + if (dipc_msg == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(dipc_msg, 0, sizeof(dm_ipc_msg_t)); + + dipc_msg->type = type; + dipc_msg->data = message; + + res = dm_ipc_msg_insert((void *)dipc_msg); + if (res != SUCCESS_RETURN) { + DM_free(dipc_msg); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_SEND_MSG_TIMEOUT_FMT[] DM_READ_ONLY = "{\"id\":%d,\"code\":%d,\"devid\":%d}"; +int dm_msg_send_msg_timeout_to_user(int msg_id, int devid, iotx_dm_event_types_t type) +{ + int res = 0, message_len = 0; + char *message = NULL; + + message_len = strlen(DM_MSG_SEND_MSG_TIMEOUT_FMT) + DM_UTILS_UINT32_STRLEN * 3 + 1; + message = DM_malloc(message_len + 1); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_SEND_MSG_TIMEOUT_FMT, msg_id, IOTX_DM_ERR_CODE_TIMEOUT, devid); + + res = _dm_msg_send_to_user(type, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_msg_uri_parse_pkdn(_IN_ char *uri, _IN_ int uri_len, _IN_ int start_deli, _IN_ int end_deli, + _OU_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _OU_ char device_name[IOTX_DEVICE_NAME_LEN + 1]) +{ + int res = 0, start = 0, end = 0, slice = 0; + + if (uri == NULL || uri_len <= 0 || product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1)) { + return DM_INVALID_PARAMETER; + } + + res = dm_utils_memtok(uri, uri_len, DM_URI_SERVICE_DELIMITER, start_deli, &start); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_utils_memtok(uri, uri_len, DM_URI_SERVICE_DELIMITER, start_deli + 1, &slice); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_utils_memtok(uri, uri_len, DM_URI_SERVICE_DELIMITER, end_deli, &end); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* dm_log_debug("URI Product Key: %.*s, Device Name: %.*s", slice - start - 1, uri + start + 1, end - slice - 1, + uri + slice + 1); */ + + memcpy(product_key, uri + start + 1, slice - start - 1); + memcpy(device_name, uri + slice + 1, end - slice - 1); + + return SUCCESS_RETURN; +} + +int dm_msg_request_parse(_IN_ char *payload, _IN_ int payload_len, _OU_ dm_msg_request_payload_t *request) +{ + lite_cjson_t lite; + + if (payload == NULL || payload_len <= 0 || request == NULL) { + return DM_INVALID_PARAMETER; + } + + if (dm_utils_json_parse(payload, payload_len, cJSON_Object, &lite) != SUCCESS_RETURN || + dm_utils_json_object_item(&lite, DM_MSG_KEY_ID, strlen(DM_MSG_KEY_ID), cJSON_String, &request->id) != SUCCESS_RETURN || + dm_utils_json_object_item(&lite, DM_MSG_KEY_VERSION, strlen(DM_MSG_KEY_VERSION), cJSON_String, + &request->version) != SUCCESS_RETURN || + dm_utils_json_object_item(&lite, DM_MSG_KEY_METHOD, strlen(DM_MSG_KEY_METHOD), cJSON_String, + &request->method) != SUCCESS_RETURN || + dm_utils_json_object_item(&lite, DM_MSG_KEY_PARAMS, strlen(DM_MSG_KEY_PARAMS), cJSON_Invalid, + &request->params) != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_debug("Current Request Message ID: %.*s", request->id.value_length, request->id.value); + dm_log_debug("Current Request Message Version: %.*s", request->version.value_length, request->version.value); + dm_log_debug("Current Request Message Method: %.*s", request->method.value_length, request->method.value); + dm_log_debug("Current Request Message Params: %.*s", request->params.value_length, request->params.value); + + return SUCCESS_RETURN; +} + +int dm_msg_response_parse(_IN_ char *payload, _IN_ int payload_len, _OU_ dm_msg_response_payload_t *response) +{ + lite_cjson_t lite, lite_message; + + if (payload == NULL || payload_len <= 0 || response == NULL) { + return DM_INVALID_PARAMETER; + } + + if (dm_utils_json_parse(payload, payload_len, cJSON_Object, &lite) != SUCCESS_RETURN || + dm_utils_json_object_item(&lite, DM_MSG_KEY_ID, strlen(DM_MSG_KEY_ID), cJSON_String, &response->id) != SUCCESS_RETURN || + dm_utils_json_object_item(&lite, DM_MSG_KEY_CODE, strlen(DM_MSG_KEY_CODE), cJSON_Number, + &response->code) != SUCCESS_RETURN || + dm_utils_json_object_item(&lite, DM_MSG_KEY_DATA, strlen(DM_MSG_KEY_DATA), cJSON_Invalid, + &response->data) != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_debug("Current Request Message ID: %.*s", response->id.value_length, response->id.value); + dm_log_debug("Current Request Message Code: %d", response->code.value_int); + dm_log_debug("Current Request Message Data: %.*s", response->data.value_length, response->data.value); + + memset(&lite_message, 0, sizeof(lite_cjson_t)); + if (dm_utils_json_object_item(&lite, DM_MSG_KEY_MESSAGE, strlen(DM_MSG_KEY_MESSAGE), cJSON_Invalid, + &response->message) == SUCCESS_RETURN) { + dm_log_debug("Current Request Message Desc: %.*s", response->message.value_length, response->message.value); + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_REQUEST[] DM_READ_ONLY = "{\"id\":\"%d\",\"version\":\"%s\",\"params\":%.*s,\"method\":\"%s\"}"; +int dm_msg_request(dm_msg_dest_type_t type, _IN_ dm_msg_request_t *request) +{ + int res = 0, payload_len = 0; + char *payload = NULL, *uri = NULL; + lite_cjson_t lite; + + if (request == NULL || request->params == NULL || request->method == NULL) { + return DM_INVALID_PARAMETER; + } + + /* Request URI */ + res = dm_utils_service_name(request->service_prefix, request->service_name, + request->product_key, request->device_name, &uri); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + payload_len = strlen(DM_MSG_REQUEST) + 10 + strlen(DM_MSG_VERSION) + request->params_len + strlen( + request->method) + 1; + payload = DM_malloc(payload_len); + if (payload == NULL) { + DM_free(uri); + return DM_MEMORY_NOT_ENOUGH; + } + memset(payload, 0, payload_len); + HAL_Snprintf(payload, payload_len, DM_MSG_REQUEST, request->msgid, + DM_MSG_VERSION, request->params_len, request->params, request->method); + + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, payload_len, &lite); + if (res < SUCCESS_RETURN) { + dm_log_info("Wrong JSON Format, URI: %s, Payload: %s", uri, payload); + DM_free(uri); + DM_free(payload); + return FAIL_RETURN; + } + + dm_log_info("DM Send Message, URI: %s, Payload: %s", uri, payload); + + if (type & DM_MSG_DEST_CLOUD) { + dm_client_publish(uri, (unsigned char *)payload, strlen(payload), request->callback); + } + +#ifdef ALCS_ENABLED + if (type & DM_MSG_DEST_LOCAL) { + dm_server_send(uri, (unsigned char *)payload, strlen(payload), NULL); + } +#endif + + DM_free(uri); + DM_free(payload); + return SUCCESS_RETURN; +} + +const char DM_MSG_RESPONSE_WITH_DATA[] DM_READ_ONLY = "{\"id\":\"%.*s\",\"code\":%d,\"data\":%.*s}"; +int dm_msg_response(dm_msg_dest_type_t type, _IN_ dm_msg_request_payload_t *request, _IN_ dm_msg_response_t *response, + _IN_ char *data, _IN_ int data_len, _IN_ void *user_data) +{ + int res = 0, payload_len = 0; + char *uri = NULL, *payload = NULL; + lite_cjson_t lite; + + if (request == NULL || response == NULL || data == NULL || data_len <= 0) { + return DM_INVALID_PARAMETER; + } + + /* Response URI */ + res = dm_utils_service_name(response->service_prefix, response->service_name, + response->product_key, response->device_name, &uri); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Response Payload */ + payload_len = strlen(DM_MSG_RESPONSE_WITH_DATA) + request->id.value_length + DM_UTILS_UINT32_STRLEN + data_len + 1; + payload = DM_malloc(payload_len); + if (payload == NULL) { + DM_free(uri); + return DM_MEMORY_NOT_ENOUGH; + } + memset(payload, 0, payload_len); + HAL_Snprintf(payload, payload_len, DM_MSG_RESPONSE_WITH_DATA, + request->id.value_length, request->id.value, response->code, data_len, data); + + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, payload_len, &lite); + if (res < SUCCESS_RETURN) { + dm_log_info("Wrong JSON Format, URI: %s, Payload: %s", uri, payload); + DM_free(uri); + DM_free(payload); + return FAIL_RETURN; + } + + dm_log_info("Send URI: %s, Payload: %s", uri, payload); + + if (type & DM_MSG_DEST_CLOUD) { + dm_client_publish(uri, (unsigned char *)payload, strlen(payload), NULL); + } + +#ifdef ALCS_ENABLED + if (type & DM_MSG_DEST_LOCAL) { + char *end = NULL; + do { + if (strlen(uri) < 6) { + break; + } + end = uri + strlen(uri) - 6; + if (strstr(end, "_reply") != 0) { + *end = '\0'; + } + dm_server_send(uri, (unsigned char *)payload, strlen(payload), user_data); + } while (0); + + } +#endif + + DM_free(uri); + DM_free(payload); + + return SUCCESS_RETURN; +} + + +const char DM_MSG_THING_MODEL_DOWN_FMT[] DM_READ_ONLY = "{\"devid\":%d,\"payload\":\"%.*s\"}"; +int dm_msg_thing_model_down_raw(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _IN_ char *payload, _IN_ int payload_len) +{ + int res = 0, devid = 0, message_len = 0; + char *hexstr = NULL, *message = NULL; + + if (product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) || + payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_utils_hex_to_str((unsigned char *)payload, payload_len, &hexstr); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + message_len = strlen(DM_MSG_THING_MODEL_DOWN_FMT) + DM_UTILS_UINT32_STRLEN + strlen(hexstr) + 1; + message = DM_malloc(message_len); + if (message == NULL) { + DM_free(hexstr); + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_THING_MODEL_DOWN_FMT, devid, strlen(hexstr), hexstr); + DM_free(hexstr); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_MODEL_DOWN_RAW, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + + +const char DM_MSG_THING_MODEL_UP_RAW_REPLY_FMT[] DM_READ_ONLY = "{\"devid\":%d,\"payload\":\"%.*s\"}"; +int dm_msg_thing_model_up_raw_reply(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], char *payload, int payload_len) +{ + int res = 0, devid = 0, message_len = 0; + char *hexstr = NULL, *message = NULL; + + if (product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) || + payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_utils_hex_to_str((unsigned char *)payload, payload_len, &hexstr); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + message_len = strlen(DM_MSG_THING_MODEL_DOWN_FMT) + DM_UTILS_UINT32_STRLEN + strlen(hexstr) + 1; + message = DM_malloc(message_len); + if (message == NULL) { + DM_free(hexstr); + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_THING_MODEL_DOWN_FMT, devid, strlen(hexstr), hexstr); + DM_free(hexstr); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_MODEL_UP_RAW_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) +#ifndef DEPRECATED_LINKKIT +#ifdef LOG_REPORT_TO_CLOUD + const char DM_MSG_PROPERTY_SET_FMT[] DM_READ_ONLY = "{\"devid\":%d,\"payload\":%.*s,\"msgid\":%.*s}"; +#else + const char DM_MSG_PROPERTY_SET_FMT[] DM_READ_ONLY = "{\"devid\":%d,\"payload\":%.*s}"; +#endif +int dm_msg_property_set(int devid, dm_msg_request_payload_t *request) +{ + int res = 0, message_len = 0; + char *message = NULL; + + message_len = strlen(DM_MSG_PROPERTY_SET_FMT) + DM_UTILS_UINT32_STRLEN + request->params.value_length + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); +#ifdef LOG_REPORT_TO_CLOUD + HAL_Snprintf(message, message_len, DM_MSG_PROPERTY_SET_FMT, devid, request->params.value_length, request->params.value, + request->id.value_length, request->id.value); +#else + HAL_Snprintf(message, message_len, DM_MSG_PROPERTY_SET_FMT, devid, request->params.value_length, request->params.value); +#endif + res = _dm_msg_send_to_user(IOTX_DM_EVENT_PROPERTY_SET, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + return SUCCESS_RETURN; +} + +const char DM_MSG_THING_PROPERTY_GET_FMT[] DM_READ_ONLY = + "{\"id\":\"%.*s\",\"devid\":%d,\"payload\":%.*s,\"ctx\":\"%s\"}"; +int dm_msg_property_get(_IN_ int devid, _IN_ dm_msg_request_payload_t *request, _IN_ void *ctx) +{ + int res = 0, message_len = 0; + uintptr_t ctx_addr_num = (uintptr_t)ctx; + char *ctx_addr_str = NULL, *message = NULL; + + ctx_addr_str = DM_malloc(sizeof(uintptr_t) * 2 + 1); + if (ctx_addr_str == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(ctx_addr_str, 0, sizeof(uintptr_t) * 2 + 1); + + /* dm_log_debug("ctx: %p", ctx); + dm_log_debug("ctx_addr_num: %0x016llX", ctx_addr_num); */ + infra_hex2str((unsigned char *)&ctx_addr_num, sizeof(uintptr_t), ctx_addr_str); + /* dm_log_debug("ctx_addr_str: %s", ctx_addr_str); */ + + message_len = strlen(DM_MSG_THING_PROPERTY_GET_FMT) + request->id.value_length + DM_UTILS_UINT32_STRLEN + + request->params.value_length + strlen(ctx_addr_str) + 1; + message = DM_malloc(message_len); + if (message == NULL) { + DM_free(ctx_addr_str); + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_THING_PROPERTY_GET_FMT, request->id.value_length, request->id.value, devid, + request->params.value_length, request->params.value, ctx_addr_str); + + DM_free(ctx_addr_str); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_PROPERTY_GET, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_SERVICE_REQUEST_FMT[] DM_READ_ONLY = + "{\"id\":\"%.*s\",\"devid\":%d,\"serviceid\":\"%.*s\",\"payload\":%.*s,\"ctx\":\"%s\"}"; +int dm_msg_thing_service_request(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + char *identifier, int identifier_len, dm_msg_request_payload_t *request, _IN_ void *ctx) +{ + int res = 0, devid = 0, message_len = 0; + char *message = NULL; + uintptr_t ctx_addr_num = (uintptr_t)ctx; + char *ctx_addr_str = NULL; + + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } +#ifdef LOG_REPORT_TO_CLOUD + if (0 == strncmp(identifier, "SetProfilerOptions", identifier_len)) { + extern void parse_switch_info(const char *input, int len); + parse_switch_info(request->params.value, request->params.value_length); + return SUCCESS_RETURN; + } +#endif + + ctx_addr_str = DM_malloc(sizeof(uintptr_t) * 2 + 1); + if (ctx_addr_str == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(ctx_addr_str, 0, sizeof(uintptr_t) * 2 + 1); + infra_hex2str((unsigned char *)&ctx_addr_num, sizeof(uintptr_t), ctx_addr_str); + + message_len = strlen(DM_MSG_SERVICE_REQUEST_FMT) + request->id.value_length + DM_UTILS_UINT32_STRLEN + identifier_len + + request->params.value_length + strlen(ctx_addr_str) + 1; + message = DM_malloc(message_len); + if (message == NULL) { + DM_free(ctx_addr_str); + return DM_MEMORY_NOT_ENOUGH; + } + + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_SERVICE_REQUEST_FMT, request->id.value_length, request->id.value, devid, + identifier_len, identifier, + request->params.value_length, request->params.value, ctx_addr_str); + + DM_free(ctx_addr_str); + res = _dm_msg_send_to_user(IOTX_DM_EVENT_THING_SERVICE_REQUEST, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} +#endif + +const char DM_MSG_EVENT_RRPC_REQUEST_FMT[] DM_READ_ONLY = + "{\"id\":\"%.*s\",\"devid\":%d,\"serviceid\":\"%.*s\",\"rrpcid\":\"%.*s\",\"payload\":%.*s}"; +int dm_msg_rrpc_request(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + char *rrpcid, int rrpcid_len, dm_msg_request_payload_t *request) +{ + int res = 0, devid = 0, message_len = 0; + int service_offset = 0, serviceid_len = 0; + char *serviceid = NULL, *message = NULL; + + /* Get Devid */ + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Get Service ID */ + res = dm_utils_memtok(request->method.value, request->method.value_length, '.', 2, &service_offset); + if (res != SUCCESS_RETURN || service_offset >= request->method.value_length - 1) { + return FAIL_RETURN; + } + serviceid_len = request->method.value_length - service_offset - 1; + serviceid = request->method.value + service_offset + 1; + /* dm_log_info("Current RRPC Service ID: %.*s", serviceid_len, serviceid); */ + + /* Send Message To User */ + message_len = strlen(DM_MSG_EVENT_RRPC_REQUEST_FMT) + request->id.value_length + DM_UTILS_UINT32_STRLEN + serviceid_len + + rrpcid_len + + request->params.value_length + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_RRPC_REQUEST_FMT, request->id.value_length, request->id.value, devid, + serviceid_len, serviceid, rrpcid_len, rrpcid, + request->params.value_length, request->params.value); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_RRPC_REQUEST, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_EVENT_PROPERTY_POST_REPLY_FMT[] DM_READ_ONLY = + "{\"id\":%d,\"code\":%d,\"devid\":%d,\"payload\":%.*s}"; +int dm_msg_thing_event_property_post_reply(dm_msg_response_payload_t *response) +{ + int res = 0, devid = 0, id = 0, message_len = 0, payload_len = 0; + char *message = NULL, *payload = NULL; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_node_t *node = NULL; +#endif + + /* Message ID */ + if (response->id.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(int_id, response->id.value, response->id.value_length); + id = atoi(int_id); + + /* dm_log_debug("Current ID: %d", id); */ + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + res = dm_msg_cache_search(id, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + devid = node->devid; +#endif + + if ((strlen("success") == response->message.value_length) && + (memcmp("success", response->message.value, response->message.value_length) == 0)) { + payload = response->data.value; + payload_len = response->data.value_length; + } else { + payload = response->message.value; + payload_len = response->message.value_length; + } + + message_len = strlen(DM_MSG_EVENT_PROPERTY_POST_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 3 + payload_len + + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_PROPERTY_POST_REPLY_FMT, id, response->code.value_int, devid, + payload_len, payload); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_EVENT_PROPERTY_POST_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_EVENT_SPECIFIC_POST_REPLY_FMT[] DM_READ_ONLY = + "{\"id\":%d,\"code\":%d,\"devid\":%d,\"eventid\":\"%.*s\",\"payload\":\"%.*s\"}"; +int dm_msg_thing_event_post_reply(_IN_ char *identifier, _IN_ int identifier_len, + _IN_ dm_msg_response_payload_t *response) +{ + int res = 0, devid = 0, id = 0, message_len = 0; + char *message = NULL; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_node_t *node = NULL; +#endif + /* Message ID */ + if (response->id.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(int_id, response->id.value, response->id.value_length); + id = atoi(int_id); + + /* dm_log_debug("Current ID: %d", id); */ + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + res = dm_msg_cache_search(id, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + devid = node->devid; +#endif + + message_len = strlen(DM_MSG_EVENT_SPECIFIC_POST_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 3 + strlen( + identifier) + response->message.value_length + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_SPECIFIC_POST_REPLY_FMT, id, response->code.value_int, devid, + identifier_len, identifier, response->message.value_length, response->message.value); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_EVENT_SPECIFIC_POST_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} +#ifdef DEVICE_MODEL_SHADOW +const char DM_MSG_EVENT_PROPERTY_DESIRED_GET_REPLY_FMT[] DM_READ_ONLY = "{\"id\":%d,\"code\":%d,\"data\":%.*s}"; +int dm_msg_thing_property_desired_get_reply(dm_msg_response_payload_t *response) +{ + int res = 0, id = 0, message_len = 0; + char *message = NULL; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_node_t *node = NULL; +#endif + + /* Message ID */ + if (response->id.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(int_id, response->id.value, response->id.value_length); + id = atoi(int_id); + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + res = dm_msg_cache_search(id, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } +#endif + + message_len = strlen(DM_MSG_EVENT_PROPERTY_DESIRED_GET_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 2 + 1 + + response->data.value_length; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_PROPERTY_DESIRED_GET_REPLY_FMT, id, response->code.value_int, + response->data.value_length, response->data.value); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_PROPERTY_DESIRED_GET_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_EVENT_PROPERTY_DESIRED_DELETE_REPLY_FMT[] DM_READ_ONLY = + "{\"id\":%d,\"code\":%d,\"data\":%.*s,\"devid\":%d}"; +int dm_msg_thing_property_desired_delete_reply(dm_msg_response_payload_t *response) +{ + int res = 0, id = 0, devid = 0, message_len = 0; + char *message = NULL; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_node_t *node = NULL; +#endif + + /* Message ID */ + if (response->id.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(int_id, response->id.value, response->id.value_length); + id = atoi(int_id); + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + res = dm_msg_cache_search(id, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + devid = node->devid; +#endif + + message_len = strlen(DM_MSG_EVENT_PROPERTY_DESIRED_DELETE_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 3 + 1 + + response->data.value_length; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_PROPERTY_DESIRED_DELETE_REPLY_FMT, id, response->code.value_int, + response->data.value_length, response->data.value, devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_PROPERTY_DESIRED_DELETE_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} +#endif + + +const char DM_MSG_EVENT_DEVICEINFO_UPDATE_REPLY_FMT[] DM_READ_ONLY = "{\"id\":%d,\"code\":%d,\"devid\":%d}"; +int dm_msg_thing_deviceinfo_update_reply(dm_msg_response_payload_t *response) +{ + int res = 0, devid = 0, id = 0, message_len = 0; + char *message = NULL; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_node_t *node = NULL; +#endif + + /* Message ID */ + if (response->id.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(int_id, response->id.value, response->id.value_length); + id = atoi(int_id); + + /* dm_log_debug("Current ID: %d", id); */ + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + res = dm_msg_cache_search(id, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + devid = node->devid; +#endif + + message_len = strlen(DM_MSG_EVENT_DEVICEINFO_UPDATE_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 3 + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_DEVICEINFO_UPDATE_REPLY_FMT, id, response->code.value_int, devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_DEVICEINFO_UPDATE_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_EVENT_DEVICEINFO_DELETE_REPLY_FMT[] DM_READ_ONLY = "{\"id\":%d,\"code\":%d,\"devid\":%d}"; +int dm_msg_thing_deviceinfo_delete_reply(dm_msg_response_payload_t *response) +{ + int res = 0, devid = 0, id = 0, message_len = 0; + char *message = NULL; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_node_t *node = NULL; +#endif + + /* Message ID */ + if (response->id.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(int_id, response->id.value, response->id.value_length); + id = atoi(int_id); + + /* dm_log_debug("Current ID: %d", id); */ + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + res = dm_msg_cache_search(id, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + devid = node->devid; +#endif + + message_len = strlen(DM_MSG_EVENT_DEVICEINFO_DELETE_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 3 + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_DEVICEINFO_DELETE_REPLY_FMT, id, response->code.value_int, devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_DEVICEINFO_DELETE_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_msg_thing_dsltemplate_get_reply(dm_msg_response_payload_t *response) +{ +#ifdef DEPRECATED_LINKKIT + int res = 0, devid = 0, id = 0; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_node_t *node = NULL; +#endif + if (response == NULL) { + return DM_INVALID_PARAMETER; + } + + /* Message ID */ + if (response->id.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(int_id, response->id.value, response->id.value_length); + id = atoi(int_id); + + /* dm_log_debug("Current ID: %d", id); */ + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + res = dm_msg_cache_search(id, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + devid = node->devid; +#endif + + dm_mgr_deprecated_set_tsl(devid, IOTX_DM_TSL_TYPE_ALINK, (const char *)response->data.value, + response->data.value_length); +#endif + + return SUCCESS_RETURN; +} + +int dm_msg_thing_dynamictsl_get_reply(dm_msg_response_payload_t *response) +{ +#ifdef DEPRECATED_LINKKIT + int res = 0, devid = 0, id = 0; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_node_t *node = NULL; +#endif + if (response == NULL) { + return DM_INVALID_PARAMETER; + } + + /* Message ID */ + if (response->id.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(int_id, response->id.value, response->id.value_length); + id = atoi(int_id); + + /* dm_log_debug("Current ID: %d", id); */ + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + res = dm_msg_cache_search(id, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + devid = node->devid; +#endif + + dm_mgr_deprecated_set_tsl(devid, IOTX_DM_TSL_TYPE_ALINK, (const char *)response->data.value, + response->data.value_length); + dm_mgr_dev_initialized(devid); +#endif + return SUCCESS_RETURN; +} + +const char DM_MSG_THING_NTP_RESPONSE_FMT[] DM_READ_ONLY = "{\"utc\":\"%.*s\"}"; +int dm_msg_ntp_response(char *payload, int payload_len) +{ + int res = 0, message_len = 0; + char *message = NULL; + lite_cjson_t lite, lite_item_server_send_time; + const char *serverSendTime = "serverSendTime"; + + if (payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + if (dm_utils_json_parse(payload, payload_len, cJSON_Object, &lite) != SUCCESS_RETURN || + dm_utils_json_object_item(&lite, serverSendTime, strlen(serverSendTime), cJSON_String, + &lite_item_server_send_time) != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* dm_log_debug("NTP Time In String: %.*s", lite_item_server_send_time.value_length, lite_item_server_send_time.value); */ + + /* Send Message To User */ + message_len = strlen(DM_MSG_THING_NTP_RESPONSE_FMT) + DM_UTILS_UINT32_STRLEN + lite_item_server_send_time.value_length + + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_THING_NTP_RESPONSE_FMT, lite_item_server_send_time.value_length, + lite_item_server_send_time.value); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_NTP_RESPONSE, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_msg_ext_error_reply(dm_msg_response_payload_t *response) +{ + int res = 0, devid = 0; + lite_cjson_t lite, lite_item_pk, lite_item_dn; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + if (response == NULL) { + return DM_INVALID_PARAMETER; + } + + res = dm_utils_json_parse(response->data.value, response->data.value_length, cJSON_Invalid, &lite); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_utils_json_object_item(&lite, DM_MSG_KEY_PRODUCT_KEY, strlen(DM_MSG_KEY_PRODUCT_KEY), cJSON_Invalid, &lite_item_pk); + dm_utils_json_object_item(&lite, DM_MSG_KEY_DEVICE_NAME, strlen(DM_MSG_KEY_DEVICE_NAME), cJSON_Invalid, &lite_item_dn); + if (lite_item_pk.type != cJSON_String || lite_item_dn.type != cJSON_String) { + return FAIL_RETURN; + } + memcpy(product_key, lite_item_pk.value, lite_item_pk.value_length); + memcpy(device_name, lite_item_dn.value, lite_item_dn.value_length); + + /* Get Device Id */ + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Login again if error code is 520 */ + if (response->code.value_int == IOTX_DM_ERR_CODE_NO_ACTIVE_SESSION) { + dm_log_err("log in again test\r\n"); +#ifdef DEVICE_MODEL_GATEWAY + dm_mgr_upstream_combine_login(devid); +#endif + } + + return SUCCESS_RETURN; +} +#endif + +#ifdef DEVICE_MODEL_GATEWAY +const char DM_MSG_TOPO_ADD_NOTIFY_USER_PAYLOAD[] DM_READ_ONLY = + "{\"result\":%d,\"devid\":%d,\"product_key\":\"%s\",\"device_name\":\"%s\"}"; +int dm_msg_topo_add_notify(_IN_ char *payload, _IN_ int payload_len) +{ + int ret = SUCCESS_RETURN, res = 0, index = 0, devid = 0, message_len = 0; + lite_cjson_t lite, lite_item, lite_item_pk, lite_item_dn; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char *message = NULL; + + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, payload_len, &lite); + if (res != SUCCESS_RETURN || !lite_cjson_is_array(&lite)) { + return DM_JSON_PARSE_FAILED; + } + + for (index = 0; index < lite.size; index++) { + devid = 0; + message_len = 0; + message = NULL; + memset(&lite_item, 0, sizeof(lite_cjson_t)); + memset(&lite_item_pk, 0, sizeof(lite_cjson_t)); + memset(&lite_item_dn, 0, sizeof(lite_cjson_t)); + memset(product_key, 0, IOTX_PRODUCT_KEY_LEN + 1); + memset(device_name, 0, IOTX_DEVICE_NAME_LEN + 1); + + res = lite_cjson_array_item(&lite, index, &lite_item); + if (res != SUCCESS_RETURN) { + ret = FAIL_RETURN; + continue; + } + + res = lite_cjson_object_item(&lite_item, DM_MSG_KEY_PRODUCT_KEY, strlen(DM_MSG_KEY_PRODUCT_KEY), &lite_item_pk); + if (res != SUCCESS_RETURN) { + ret = FAIL_RETURN; + continue; + } + + res = lite_cjson_object_item(&lite_item, DM_MSG_KEY_DEVICE_NAME, strlen(DM_MSG_KEY_DEVICE_NAME), &lite_item_dn); + if (res != SUCCESS_RETURN) { + ret = FAIL_RETURN; + continue; + } + + /* dm_log_debug("Current Product Key: %.*s, Device Name: %.*s", + lite_item_pk.value_length, lite_item_pk.value, + lite_item_dn.value_length, lite_item_dn.value); */ + + if (lite_item_pk.value_length >= IOTX_PRODUCT_KEY_LEN + 1 || + lite_item_dn.value_length >= IOTX_DEVICE_NAME_LEN + 1) { + ret = FAIL_RETURN; + continue; + } + memcpy(product_key, lite_item_pk.value, lite_item_pk.value_length); + memcpy(device_name, lite_item_dn.value, lite_item_dn.value_length); + + res = dm_mgr_device_create(IOTX_DM_DEVICE_SUBDEV, product_key, device_name, NULL, &devid); + if (res != SUCCESS_RETURN) { + ret = FAIL_RETURN; + } + + /* Send To User */ + message_len = strlen(DM_MSG_TOPO_ADD_NOTIFY_USER_PAYLOAD) + 20 + + strlen(product_key) + strlen(device_name) + 1; + message = DM_malloc(message_len); + if (message == NULL) { + ret = DM_MEMORY_NOT_ENOUGH; + continue; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_TOPO_ADD_NOTIFY_USER_PAYLOAD, res, devid, product_key, device_name); + res = _dm_msg_send_to_user(IOTX_DM_EVENT_TOPO_ADD_NOTIFY, message); + if (res != SUCCESS_RETURN) { + ret = FAIL_RETURN; + DM_free(message); + } + + } + + return ret; +} + +const char DM_MSG_EVENT_THING_DISABLE_FMT[] DM_READ_ONLY = "{\"devid\":%d}"; +int dm_msg_thing_disable(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1]) +{ + int res = 0, devid = 0, message_len = 0; + char *message = NULL; + + if (product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1)) { + return DM_INVALID_PARAMETER; + } + + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_mgr_set_dev_disable(devid); + + message_len = strlen(DM_MSG_EVENT_THING_DISABLE_FMT) + DM_UTILS_UINT32_STRLEN + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_THING_DISABLE_FMT, devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_THING_DISABLE, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_EVENT_THING_ENABLE_FMT[] DM_READ_ONLY = "{\"devid\":%d}"; +int dm_msg_thing_enable(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1]) +{ + int res = 0, devid = 0, message_len = 0; + char *message = NULL; + + if (product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1)) { + return DM_INVALID_PARAMETER; + } + + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_mgr_set_dev_enable(devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + message_len = strlen(DM_MSG_EVENT_THING_ENABLE_FMT) + DM_UTILS_UINT32_STRLEN + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_THING_ENABLE_FMT, devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_THING_ENABLE, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_EVENT_THING_DELETE_FMT[] DM_READ_ONLY = + "{\"res\":%d,\"productKey\":\"%s\",\"deviceName\":\"%s\",\"devid\":%d}"; +int dm_msg_thing_delete(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1]) +{ + int res = 0, message_len = 0, devid = 0; + char *message = NULL; + + if (product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1)) { + return DM_INVALID_PARAMETER; + } + + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res == SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_mgr_device_destroy(devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + message_len = strlen(DM_MSG_EVENT_THING_DELETE_FMT) + strlen(product_key) + strlen(device_name) + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_THING_DELETE_FMT, res, product_key, device_name, devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_THING_DELETE, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_msg_thing_gateway_permit(_IN_ char *payload, _IN_ int payload_len) +{ + int res = 0, message_len = 0; + char *message = NULL; + lite_cjson_t lite; + + if (payload == NULL || payload_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = lite_cjson_parse(payload, payload_len, &lite); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite)) { + return DM_JSON_PARSE_FAILED; + } + + message_len = payload_len + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memcpy(message, payload, payload_len); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_GATEWAY_PERMIT, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_EVENT_SUBDEV_REGISTER_REPLY_FMT[] DM_READ_ONLY = "{\"id\":%d,\"code\":%d,\"devid\":%d}"; +int dm_msg_thing_sub_register_reply(dm_msg_response_payload_t *response) +{ + int res = 0, index = 0, message_len = 0, devid = 0; + lite_cjson_t lite, lite_item, lite_item_pk, lite_item_dn, lite_item_ds; + char *message = NULL; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1] = {0}; + char temp_id[DM_UTILS_UINT32_STRLEN] = {0}; + + if (response == NULL) { + return DM_INVALID_PARAMETER; + } + + res = lite_cjson_parse(response->data.value, response->data.value_length, &lite); + if (res != SUCCESS_RETURN || !lite_cjson_is_array(&lite)) { + return DM_JSON_PARSE_FAILED; + } + + for (index = 0; index < lite.size; index++) { + devid = 0; + message_len = 0; + message = NULL; + memset(temp_id, 0, DM_UTILS_UINT32_STRLEN); + memset(product_key, 0, IOTX_PRODUCT_KEY_LEN + 1); + memset(device_name, 0, IOTX_DEVICE_NAME_LEN + 1); + memset(&lite_item, 0, sizeof(lite_cjson_t)); + memset(&lite_item_pk, 0, sizeof(lite_cjson_t)); + memset(&lite_item_dn, 0, sizeof(lite_cjson_t)); + memset(&lite_item_ds, 0, sizeof(lite_cjson_t)); + + /* dm_log_debug("Current Index: %d", index); */ + /* Item */ + res = lite_cjson_array_item(&lite, index, &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite_item)) { + continue; + } + + /* Product Key */ + res = lite_cjson_object_item(&lite_item, DM_MSG_KEY_PRODUCT_KEY, strlen(DM_MSG_KEY_PRODUCT_KEY), &lite_item_pk); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item_pk)) { + continue; + } + /* dm_log_debug("Current Product Key: %.*s", lite_item_pk.value_length, lite_item_pk.value); */ + + /* Device Name */ + res = lite_cjson_object_item(&lite_item, DM_MSG_KEY_DEVICE_NAME, strlen(DM_MSG_KEY_DEVICE_NAME), &lite_item_dn); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item_dn)) { + continue; + } + /* dm_log_debug("Current Device Name: %.*s", lite_item_dn.value_length, lite_item_dn.value); */ + + /* Device Secret */ + res = lite_cjson_object_item(&lite_item, DM_MSG_KEY_DEVICE_SECRET, strlen(DM_MSG_KEY_DEVICE_SECRET), &lite_item_ds); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item_ds)) { + continue; + } + /* dm_log_debug("Current Device Secret: %.*s", lite_item_ds.value_length, lite_item_ds.value); */ + + /* Get Device ID */ + memcpy(product_key, lite_item_pk.value, lite_item_pk.value_length); + memcpy(device_name, lite_item_dn.value, lite_item_dn.value_length); + memcpy(device_secret, lite_item_ds.value, lite_item_ds.value_length); + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res != SUCCESS_RETURN) { + continue; + } + + /* Update State Machine */ + if (response->code.value_int == IOTX_DM_ERR_CODE_SUCCESS) { + dm_mgr_set_dev_status(devid, IOTX_DM_DEV_STATUS_REGISTERED); + } + + /* Set Device Secret */ + res = dm_mgr_set_device_secret(devid, device_secret); + if (res != SUCCESS_RETURN) { + continue; + } + + /* Send Message To User */ + memcpy(temp_id, response->id.value, response->id.value_length); + message_len = strlen(DM_MSG_EVENT_SUBDEV_REGISTER_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 2 + 1; + message = DM_malloc(message_len); + if (message == NULL) { + dm_log_warning("Memory Not Enough"); + continue; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_SUBDEV_REGISTER_REPLY_FMT, atoi(temp_id), response->code.value_int, + devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_SUBDEV_REGISTER_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + } + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_EVENT_SUBDEV_UNREGISTER_REPLY_FMT[] DM_READ_ONLY = "{\"id\":%d,\"code\":%d,\"devid\":%d}"; +int dm_msg_thing_sub_unregister_reply(dm_msg_response_payload_t *response) +{ + int res = 0, devid = 0, id, message_len = 0; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; + char *message = NULL; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_node_t *node = NULL; +#endif + + if (response == NULL) { + return DM_INVALID_PARAMETER; + } + + if (response->id.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(int_id, response->id.value, response->id.value_length); + id = atoi(int_id); + + /* dm_log_debug("Current ID: %d", id); */ + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + res = dm_msg_cache_search(id, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + devid = node->devid; +#endif + + message_len = strlen(DM_MSG_EVENT_SUBDEV_UNREGISTER_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 3 + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_SUBDEV_UNREGISTER_REPLY_FMT, id, response->code.value_int, devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_SUBDEV_UNREGISTER_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_EVENT_THING_TOPO_ADD_REPLY_FMT[] DM_READ_ONLY = "{\"id\":%d,\"code\":%d,\"devid\":%d}"; +int dm_msg_thing_topo_add_reply(dm_msg_response_payload_t *response) +{ + int res = 0, devid = 0, id = 0, message_len = 0; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; + char *message = NULL; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_node_t *node = NULL; +#endif + + if (response->id.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(int_id, response->id.value, response->id.value_length); + id = atoi(int_id); + + /* dm_log_debug("Current ID: %d", id); */ + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + res = dm_msg_cache_search(id, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + devid = node->devid; + + /* Update State Machine */ + if (response->code.value_int == IOTX_DM_ERR_CODE_SUCCESS) { + dm_mgr_set_dev_status(node->devid, IOTX_DM_DEV_STATUS_ATTACHED); + } + +#endif + + message_len = strlen(DM_MSG_EVENT_THING_TOPO_ADD_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 3 + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_THING_TOPO_ADD_REPLY_FMT, id, response->code.value_int, devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_TOPO_ADD_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_EVENT_THING_TOPO_DELETE_REPLY_FMT[] DM_READ_ONLY = "{\"id\":%d,\"code\":%d,\"devid\":%d}"; +int dm_msg_thing_topo_delete_reply(dm_msg_response_payload_t *response) +{ + int res = 0, devid = 0, id = 0, message_len = 0; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; + char *message = NULL; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + dm_msg_cache_node_t *node = NULL; +#endif + + if (response->id.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(int_id, response->id.value, response->id.value_length); + id = atoi(int_id); + + /* dm_log_debug("Current ID: %d", id); */ + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + res = dm_msg_cache_search(id, &node); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + devid = node->devid; + + /* Update State Machine */ + if (response->code.value_int == IOTX_DM_ERR_CODE_SUCCESS) { + dm_mgr_set_dev_status(node->devid, IOTX_DM_DEV_STATUS_ATTACHED); + } + +#endif + + message_len = strlen(DM_MSG_EVENT_THING_TOPO_DELETE_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 3 + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_THING_TOPO_DELETE_REPLY_FMT, id, response->code.value_int, devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_TOPO_DELETE_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_TOPO_GET_REPLY_FMT[] DM_READ_ONLY = "{\"id\":%d,\"code\":%d,\"devid\":%d,\"topo\":%.*s}"; +int dm_msg_topo_get_reply(dm_msg_response_payload_t *response) +{ + int res = 0, id = 0, message_len = 0; + char *message = NULL; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; + + if (response == NULL) { + return DM_INVALID_PARAMETER; + } + + /* Message ID */ + if (response->id.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(int_id, response->id.value, response->id.value_length); + id = atoi(int_id); + + /* dm_log_debug("Current ID: %d", id); */ + + message_len = strlen(DM_MSG_TOPO_GET_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 3 + response->data.value_length + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_TOPO_GET_REPLY_FMT, id, response->code.value_int, IOTX_DM_LOCAL_NODE_DEVID, + response->data.value_length, + response->data.value); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_TOPO_GET_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_msg_thing_list_found_reply(dm_msg_response_payload_t *response) +{ + return SUCCESS_RETURN; +} + +const char DM_MSG_EVENT_COMBINE_LOGIN_REPLY_FMT[] DM_READ_ONLY = "{\"id\":%d,\"code\":%d,\"devid\":%d}"; +int dm_msg_combine_login_reply(dm_msg_response_payload_t *response) +{ + int res = 0, message_len = 0, devid = 0; + char *message = NULL; + lite_cjson_t lite, lite_item_pk, lite_item_dn; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char temp_id[DM_UTILS_UINT32_STRLEN] = {0}; + + if (response == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + + /* Parse JSON */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(response->data.value, response->data.value_length, &lite); + if (res != SUCCESS_RETURN) { + return DM_JSON_PARSE_FAILED; + } + + /* Parse Product Key */ + res = lite_cjson_object_item(&lite, DM_MSG_KEY_PRODUCT_KEY, strlen(DM_MSG_KEY_PRODUCT_KEY), &lite_item_pk); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item_pk) + || lite_item_pk.value_length >= IOTX_PRODUCT_KEY_LEN + 1) { + return DM_JSON_PARSE_FAILED; + } + memcpy(product_key, lite_item_pk.value, lite_item_pk.value_length); + + /* Parse Device Name */ + res = lite_cjson_object_item(&lite, DM_MSG_KEY_DEVICE_NAME, strlen(DM_MSG_KEY_DEVICE_NAME), &lite_item_dn); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item_dn) + || lite_item_dn.value_length >= IOTX_DEVICE_NAME_LEN + 1) { + return DM_JSON_PARSE_FAILED; + } + memcpy(device_name, lite_item_dn.value, lite_item_dn.value_length); + + /* Get Device Id */ + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Update State Machine */ + if (response->code.value_int == IOTX_DM_ERR_CODE_SUCCESS) { + dm_mgr_set_dev_status(devid, IOTX_DM_DEV_STATUS_LOGINED); + } + + /* Message ID */ + memcpy(temp_id, response->id.value, response->id.value_length); + + message_len = strlen(DM_MSG_EVENT_COMBINE_LOGIN_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 3 + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_COMBINE_LOGIN_REPLY_FMT, atoi(temp_id), response->code.value_int, + devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_COMBINE_LOGIN_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + if (response->code.value_int != IOTX_DM_ERR_CODE_SUCCESS) { + return SUCCESS_RETURN; + } + + return SUCCESS_RETURN; +} + +const char DM_MSG_EVENT_COMBINE_LOGOUT_REPLY_FMT[] DM_READ_ONLY = "{\"id\":%d,\"code\":%d,\"devid\":%d}"; +int dm_msg_combine_logout_reply(dm_msg_response_payload_t *response) +{ + int res = 0, message_len = 0, devid = 0; + char *message = NULL; + lite_cjson_t lite, lite_item_pk, lite_item_dn; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char temp_id[DM_UTILS_UINT32_STRLEN] = {0}; + + if (response == NULL) { + return DM_INVALID_PARAMETER; + } + + /* Parse JSON */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(response->data.value, response->data.value_length, &lite); + if (res != SUCCESS_RETURN) { + return DM_JSON_PARSE_FAILED; + } + + /* Parse Product Key */ + res = lite_cjson_object_item(&lite, DM_MSG_KEY_PRODUCT_KEY, strlen(DM_MSG_KEY_PRODUCT_KEY), &lite_item_pk); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item_pk) + || lite_item_pk.value_length >= IOTX_PRODUCT_KEY_LEN + 1) { + return DM_JSON_PARSE_FAILED; + } + memcpy(product_key, lite_item_pk.value, lite_item_pk.value_length); + + /* Parse Device Name */ + res = lite_cjson_object_item(&lite, DM_MSG_KEY_DEVICE_NAME, strlen(DM_MSG_KEY_DEVICE_NAME), &lite_item_dn); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item_dn) + || lite_item_dn.value_length >= IOTX_DEVICE_NAME_LEN + 1) { + return DM_JSON_PARSE_FAILED; + } + memcpy(device_name, lite_item_dn.value, lite_item_dn.value_length); + + /* Get Device Id */ + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Update State Machine */ + if (response->code.value_int == IOTX_DM_ERR_CODE_SUCCESS) { + dm_mgr_set_dev_status(devid, IOTX_DM_DEV_STATUS_ATTACHED); + } + + /* Message ID */ + memcpy(temp_id, response->id.value, response->id.value_length); + + message_len = strlen(DM_MSG_EVENT_COMBINE_LOGOUT_REPLY_FMT) + DM_UTILS_UINT32_STRLEN * 3 + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_EVENT_COMBINE_LOGOUT_REPLY_FMT, atoi(temp_id), response->code.value_int, + devid); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_COMBINE_LOGOUT_REPLY, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +#endif + +#ifdef ALCS_ENABLED +const char DM_MSG_DEV_CORE_SERVICE_DEV[] DM_READ_ONLY = + "{\"devices\":{\"addr\":\"%s\",\"port\":%d,\"pal\":\"linkkit-ica\",\"profile\":%s}}"; +int dm_msg_dev_core_service_dev(char **payload, int *payload_len) +{ + int res = 0, index = 0, search_devid = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1] = {0}; + char ip_addr[16] = {0}; + char *device_array = NULL; + lite_cjson_item_t *lite_array = NULL, *lite_object = NULL; + uint16_t port = 5683; + + if (payload == NULL || *payload != NULL || payload_len == NULL) { + return DM_INVALID_PARAMETER; + } + + lite_array = lite_cjson_create_array(); + if (lite_array == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + + /* Get Product Key And Device Name Of All Device */ + for (index = 0; index < dm_mgr_device_number(); index++) { + search_devid = 0; + lite_object = NULL; + memset(product_key, 0, IOTX_PRODUCT_KEY_LEN + 1); + memset(device_name, 0, IOTX_DEVICE_NAME_LEN + 1); + memset(device_secret, 0, IOTX_DEVICE_SECRET_LEN + 1); + + res = dm_mgr_get_devid_by_index(index, &search_devid); + if (res != SUCCESS_RETURN) { + lite_cjson_delete(lite_array); + return FAIL_RETURN; + } + + res = dm_mgr_search_device_by_devid(search_devid, product_key, device_name, device_secret); + if (res != SUCCESS_RETURN) { + lite_cjson_delete(lite_array); + return FAIL_RETURN; + } + + lite_object = lite_cjson_create_object(); + if (lite_object == NULL) { + lite_cjson_delete(lite_array); + return FAIL_RETURN; + } + lite_cjson_add_string_to_object(lite_object, "productKey", product_key); + lite_cjson_add_string_to_object(lite_object, "deviceName", device_name); + lite_cjson_add_item_to_array(lite_array, lite_object); + } + + device_array = lite_cjson_print_unformatted(lite_array); + lite_cjson_delete(lite_array); + if (device_array == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + + HAL_Wifi_Get_IP(ip_addr, 0); + + *payload_len = strlen(DM_MSG_DEV_CORE_SERVICE_DEV) + strlen(ip_addr) + DM_UTILS_UINT16_STRLEN + strlen( + device_array) + 1; + *payload = DM_malloc(*payload_len); + if (*payload == NULL) { + HAL_Free(device_array); + return DM_MEMORY_NOT_ENOUGH; + } + memset(*payload, 0, *payload_len); + HAL_Snprintf(*payload, *payload_len, DM_MSG_DEV_CORE_SERVICE_DEV, ip_addr, port, device_array); + DM_free(device_array); + + return SUCCESS_RETURN; +} +#endif + +int dm_msg_cloud_connected(void) +{ + return _dm_msg_send_to_user(IOTX_DM_EVENT_CLOUD_CONNECTED, NULL); +} + +int dm_msg_cloud_disconnect(void) +{ + return _dm_msg_send_to_user(IOTX_DM_EVENT_CLOUD_DISCONNECT, NULL); +} + +int dm_msg_cloud_reconnect(void) +{ + int res = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + HAL_GetProductKey(product_key); + HAL_GetDeviceName(device_name); + + /* Send To User */ + res = _dm_msg_send_to_user(IOTX_DM_EVENT_CLOUD_RECONNECT, NULL); + + return res; +} + +#ifdef DEVICE_MODEL_GATEWAY +const char DM_MSG_THING_SUB_REGISTER_METHOD[] DM_READ_ONLY = "thing.sub.register"; +const char DM_MSG_THING_SUB_REGISTER_PARAMS[] DM_READ_ONLY = "[{\"productKey\":\"%s\",\"deviceName\":\"%s\"}]"; +int dm_msg_thing_sub_register(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ dm_msg_request_t *request) +{ + int params_len = 0; + char *params = NULL; + + if (request == NULL || product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) || + (strlen(request->product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(request->device_name) >= IOTX_DEVICE_NAME_LEN + 1)) { + return DM_INVALID_PARAMETER; + } + + params_len = strlen(DM_MSG_THING_SUB_REGISTER_PARAMS) + strlen(product_key) + strlen(device_name) + 1; + params = DM_malloc(params_len); + if (params == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(params, 0, params_len); + HAL_Snprintf(params, params_len, DM_MSG_THING_SUB_REGISTER_PARAMS, product_key, device_name); + + /* Get Params */ + request->params = params; + request->params_len = strlen(request->params); + + /* Get Method */ + request->method = (char *)DM_MSG_THING_SUB_REGISTER_METHOD; + + return SUCCESS_RETURN; +} + +const char DM_MSG_THING_SUB_UNREGISTER_METHOD[] DM_READ_ONLY = "thing.sub.unregister"; +const char DM_MSG_THING_SUB_UNREGISTER_PARAMS[] DM_READ_ONLY = "[{\"productKey\":\"%s\",\"deviceName\":\"%s\"}]"; +int dm_msg_thing_sub_unregister(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ dm_msg_request_t *request) +{ + int params_len = 0; + char *params = NULL; + + if (request == NULL || product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) || + (strlen(request->product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(request->device_name) >= IOTX_DEVICE_NAME_LEN + 1)) { + return DM_INVALID_PARAMETER; + } + + params_len = strlen(DM_MSG_THING_SUB_UNREGISTER_PARAMS) + strlen(product_key) + strlen(device_name) + 1; + params = DM_malloc(params_len); + if (params == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(params, 0, params_len); + HAL_Snprintf(params, params_len, DM_MSG_THING_SUB_UNREGISTER_PARAMS, product_key, device_name); + + /* Get Params */ + request->params = params; + request->params_len = strlen(request->params); + + /* Get Method */ + request->method = (char *)DM_MSG_THING_SUB_UNREGISTER_METHOD; + + return SUCCESS_RETURN; +} + +const char DM_MSG_THING_TOPO_ADD_SIGN_SOURCE[] DM_READ_ONLY = "clientId%sdeviceName%sproductKey%stimestamp%s"; +const char DM_MSG_THING_TOPO_ADD_METHOD[] DM_READ_ONLY = "thing.topo.add"; +const char DM_MSG_THING_TOPO_ADD_PARAMS[] DM_READ_ONLY = + "[{\"productKey\":\"%s\",\"deviceName\":\"%s\",\"signmethod\":\"%s\",\"sign\":\"%s\",\"timestamp\":\"%s\",\"clientId\":\"%s\"}]"; +int dm_msg_thing_topo_add(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1], _OU_ dm_msg_request_t *request) +{ + char *params = NULL; + int params_len = 0; + char timestamp[DM_UTILS_UINT64_STRLEN] = {0}; + char client_id[IOTX_PRODUCT_KEY_LEN + 1 + IOTX_DEVICE_NAME_LEN + 1 + 1] = {0}; + char *sign_source = NULL; + int sign_source_len = 0; + char *sign_method = DM_MSG_SIGN_METHOD_HMACSHA1; + char sign[65] = {0}; + + + if (request == NULL || product_key == NULL || + device_name == NULL || device_secret == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) || + (strlen(device_secret) >= IOTX_DEVICE_SECRET_LEN + 1) || + (strlen(request->product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(request->device_name) >= IOTX_DEVICE_NAME_LEN + 1)) { + return DM_INVALID_PARAMETER; + } + + /* TimeStamp */ + HAL_Snprintf(timestamp, DM_UTILS_UINT64_STRLEN, "%llu", (unsigned long long)HAL_UptimeMs()); + /* dm_log_debug("Time Stamp: %s", timestamp); */ + + /* Client ID */ + HAL_Snprintf(client_id, IOTX_PRODUCT_KEY_LEN + 1 + IOTX_DEVICE_NAME_LEN + 1 + 1, "%s.%s", product_key, device_name); + + /* Sign */ + sign_source_len = strlen(DM_MSG_THING_TOPO_ADD_SIGN_SOURCE) + strlen(client_id) + + strlen(device_name) + strlen(product_key) + strlen(timestamp) + 1; + sign_source = DM_malloc(sign_source_len); + if (sign_source == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(sign_source, 0, sign_source_len); + HAL_Snprintf(sign_source, sign_source_len, DM_MSG_THING_TOPO_ADD_SIGN_SOURCE, client_id, + device_name, product_key, timestamp); + + /* dm_log_debug("Sign Srouce: %s", sign_source); */ +#if 0 + if (strcmp(sign_method, DM_MSG_SIGN_METHOD_HMACMD5) == 0) { + utils_hmac_md5(sign_source, strlen(sign_source), sign, device_secret, strlen(device_secret)); + } else if (strcmp(sign_method, DM_MSG_SIGN_METHOD_HMACSHA1) == 0) { + utils_hmac_sha1(sign_source, strlen(sign_source), sign, device_secret, strlen(device_secret)); + } else if (strcmp(sign_method, DM_MSG_SIGN_METHOD_HMACSHA256) == 0) { + utils_hmac_sha256(sign_source, strlen(sign_source), sign, device_secret, strlen(device_secret)); + } else { + DM_free(sign_source); + return FAIL_RETURN; + } +#else + utils_hmac_sha1(sign_source, strlen(sign_source), sign, device_secret, strlen(device_secret)); +#endif + DM_free(sign_source); + /* dm_log_debug("Sign : %s", sign); */ + + /* Params */ + request->method = (char *)DM_MSG_THING_TOPO_ADD_METHOD; + params_len = strlen(DM_MSG_THING_TOPO_ADD_PARAMS) + strlen(product_key) + strlen(device_name) + + strlen(sign_method) + strlen(sign) + strlen(timestamp) + strlen(client_id) + 1; + params = DM_malloc(params_len); + + if (params == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(params, 0, params_len); + HAL_Snprintf(params, params_len, DM_MSG_THING_TOPO_ADD_PARAMS, product_key, device_name, + sign_method, sign, timestamp, client_id); + + request->params = params; + request->params_len = strlen(request->params); + + return SUCCESS_RETURN; +} + +const char DM_MSG_THING_TOPO_DELETE_METHOD[] DM_READ_ONLY = "thing.topo.delete"; +const char DM_MSG_THING_TOPO_DELETE_PARAMS[] DM_READ_ONLY = "[{\"productKey\":\"%s\",\"deviceName\":\"%s\"}]"; +int dm_msg_thing_topo_delete(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ dm_msg_request_t *request) +{ + char *params = NULL; + int params_len = 0; + + if (request == NULL || product_key == NULL || + device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) || + (strlen(request->product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(request->device_name) >= IOTX_DEVICE_NAME_LEN + 1)) { + return DM_INVALID_PARAMETER; + } + + /* Params */ + request->method = (char *)DM_MSG_THING_TOPO_DELETE_METHOD; + params_len = strlen(DM_MSG_THING_TOPO_DELETE_PARAMS) + strlen(product_key) + strlen(device_name) + 1; + params = DM_malloc(params_len); + if (params == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(params, 0, params_len); + HAL_Snprintf(params, params_len, DM_MSG_THING_TOPO_DELETE_PARAMS, product_key, device_name); + + request->params = params; + request->params_len = strlen(request->params); + + return SUCCESS_RETURN; +} + +const char DM_MSG_THING_TOPO_GET_METHOD[] DM_READ_ONLY = "thing.topo.get"; +const char DM_MSG_THING_TOPO_GET_PARAMS[] DM_READ_ONLY = "{}"; +int dm_msg_thing_topo_get(_OU_ dm_msg_request_t *request) +{ + char *params = NULL; + int params_len = 0; + + /* Params */ + request->method = (char *)DM_MSG_THING_TOPO_GET_METHOD; + params_len = strlen(DM_MSG_THING_TOPO_GET_PARAMS) + 1; + params = DM_malloc(params_len); + if (params == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(params, 0, params_len); + memcpy(params, DM_MSG_THING_TOPO_GET_PARAMS, strlen(DM_MSG_THING_TOPO_GET_PARAMS)); + + request->params = params; + request->params_len = strlen(request->params); + + return SUCCESS_RETURN; +} + +const char DM_MSG_THING_LIST_FOUND_METHOD[] DM_READ_ONLY = "thing.list.found"; +const char DM_MSG_THING_LIST_FOUND_PARAMS[] DM_READ_ONLY = "[{\"productKey\":\"%s\",\"deviceName\":\"%s\"}]"; +int dm_msg_thing_list_found(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ dm_msg_request_t *request) +{ + char *params = NULL; + int params_len = 0; + + if (product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) || + request == NULL) { + return DM_INVALID_PARAMETER; + } + + /* Params */ + request->method = (char *)DM_MSG_THING_LIST_FOUND_METHOD; + params_len = strlen(DM_MSG_THING_LIST_FOUND_PARAMS) + strlen(product_key) + strlen(device_name) + 1; + params = DM_malloc(params_len); + if (params == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(params, 0, params_len); + HAL_Snprintf(params, params_len, DM_MSG_THING_LIST_FOUND_PARAMS, product_key, device_name); + + request->params = params; + request->params_len = strlen(request->params); + + return SUCCESS_RETURN; +} + + +const char DM_MSG_COMBINE_LOGIN_SIGN_SOURCE[] DM_READ_ONLY = "clientId%sdeviceName%sproductKey%stimestamp%s"; +const char DM_MSG_COMBINE_LOGIN_METHOD[] DM_READ_ONLY = "combine.login"; +const char DM_MSG_COMBINE_LOGIN_PARAMS[] DM_READ_ONLY = + "{\"productKey\":\"%s\",\"deviceName\":\"%s\",\"clientId\":\"%s\",\"timestamp\":\"%s\",\"signMethod\":\"%s\",\"sign\":\"%s\",\"cleanSession\":\"%s\"}"; +int dm_msg_combine_login(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1], _OU_ dm_msg_request_t *request) +{ + char *params = NULL; + int params_len = 0; + char timestamp[DM_UTILS_UINT64_STRLEN] = {0}; + char client_id[IOTX_PRODUCT_KEY_LEN + 1 + IOTX_DEVICE_NAME_LEN + 1 + 1] = {0}; + char *sign_source = NULL; + int sign_source_len = 0; + char *sign_method = DM_MSG_SIGN_METHOD_HMACSHA1; + char sign[64] = {0}; + + + if (request == NULL || product_key == NULL || + device_name == NULL || device_secret == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) || + (strlen(device_secret) >= IOTX_DEVICE_SECRET_LEN + 1) || + (strlen(request->product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(request->device_name) >= IOTX_DEVICE_NAME_LEN + 1)) { + return DM_INVALID_PARAMETER; + } + + /* TimeStamp */ + HAL_Snprintf(timestamp, DM_UTILS_UINT64_STRLEN, "%llu", (unsigned long long)HAL_UptimeMs()); + /* dm_log_debug("Time Stamp: %s", timestamp); */ + + /* Client ID */ + HAL_Snprintf(client_id, IOTX_PRODUCT_KEY_LEN + 1 + IOTX_DEVICE_NAME_LEN + 1 + 1, "%s.%s", product_key, device_name); + + /* Sign */ + sign_source_len = strlen(DM_MSG_COMBINE_LOGIN_SIGN_SOURCE) + strlen(client_id) + + strlen(device_name) + strlen(product_key) + strlen(timestamp) + 1; + sign_source = DM_malloc(sign_source_len); + if (sign_source == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(sign_source, 0, sign_source_len); + HAL_Snprintf(sign_source, sign_source_len, DM_MSG_COMBINE_LOGIN_SIGN_SOURCE, client_id, + device_name, product_key, timestamp); + + /* dm_log_debug("Sign Srouce: %s", sign_source); */ +#if 0 + if (strcmp(sign_method, DM_MSG_SIGN_METHOD_HMACMD5) == 0) { + utils_hmac_md5(sign_source, strlen(sign_source), sign, device_secret, strlen(device_secret)); + } else if (strcmp(sign_method, DM_MSG_SIGN_METHOD_HMACSHA1) == 0) { + utils_hmac_sha1(sign_source, strlen(sign_source), sign, device_secret, strlen(device_secret)); + } else if (strcmp(sign_method, DM_MSG_SIGN_METHOD_HMACSHA256) == 0) { + utils_hmac_sha256(sign_source, strlen(sign_source), sign, device_secret, strlen(device_secret)); + } else { + DM_free(sign_source); + return FAIL_RETURN; + } +#else + utils_hmac_sha1(sign_source, strlen(sign_source), sign, device_secret, strlen(device_secret)); +#endif + DM_free(sign_source); + /* dm_log_debug("Sign : %s", sign); */ + + /* Params */ + request->method = (char *)DM_MSG_COMBINE_LOGIN_METHOD; + params_len = strlen(DM_MSG_COMBINE_LOGIN_PARAMS) + strlen(product_key) + strlen(device_name) + + strlen(sign_method) + strlen(sign) + strlen(timestamp) + strlen(client_id) + 1; + params = DM_malloc(params_len); + + if (params == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(params, 0, params_len); + HAL_Snprintf(params, params_len, DM_MSG_COMBINE_LOGIN_PARAMS, product_key, device_name, + client_id, timestamp, sign_method, sign, "true"); + + request->params = params; + request->params_len = strlen(request->params); + + return SUCCESS_RETURN; +} + +const char DM_MSG_COMBINE_LOGOUT_METHOD[] DM_READ_ONLY = "combine.logout"; +const char DM_MSG_COMBINE_LOGOUT_PARAMS[] DM_READ_ONLY = "{\"productKey\":\"%s\",\"deviceName\":\"%s\"}"; +int dm_msg_combine_logout(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ dm_msg_request_t *request) +{ + char *params = NULL; + int params_len = 0; + + if (product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) || + request == NULL) { + return DM_INVALID_PARAMETER; + } + + /* Params */ + request->method = (char *)DM_MSG_COMBINE_LOGOUT_METHOD; + params_len = strlen(DM_MSG_COMBINE_LOGOUT_PARAMS) + strlen(product_key) + strlen(device_name) + 1; + params = DM_malloc(params_len); + + if (params == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(params, 0, params_len); + HAL_Snprintf(params, params_len, DM_MSG_COMBINE_LOGOUT_PARAMS, product_key, device_name); + + request->params = params; + request->params_len = strlen(request->params); + + return SUCCESS_RETURN; +} +#endif + +#ifdef DEPRECATED_LINKKIT +typedef enum { + DM_MSG_PROPERTY_SET, + DM_MSG_SERVICE_SET +} dm_msg_set_type_t; +typedef int (*dm_get_shadow_data)(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data); +typedef int (*dm_set_shadow_data)(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len); + +static int _dm_msg_set_number(dm_msg_set_type_t type, int devid, char *key, lite_cjson_t *root); +static int _dm_msg_set_string(dm_msg_set_type_t type, int devid, char *key, lite_cjson_t *root); +static int _dm_msg_set_object(dm_msg_set_type_t type, int devid, char *key, lite_cjson_t *root); +static int _dm_msg_set_array(dm_msg_set_type_t type, int devid, char *key, lite_cjson_t *root); + + +static int _dm_msg_set_number(dm_msg_set_type_t type, int devid, char *key, lite_cjson_t *root) +{ + int res = 0; + void *data = NULL; + dm_shw_data_type_e data_type; + dm_get_shadow_data get_shadow_data_func = (type == DM_MSG_PROPERTY_SET) ? (dm_mgr_deprecated_get_property_data) : + (dm_mgr_deprecated_get_service_input_data); + dm_set_shadow_data set_shadow_data_func = (type == DM_MSG_PROPERTY_SET) ? (dm_mgr_deprecated_set_property_value) : + (dm_mgr_deprecated_set_service_input_value); + + /* dm_log_debug("Current Key: %s", key); */ + + res = get_shadow_data_func(devid, key, strlen(key), &data); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_mgr_deprecated_get_data_type(data, &data_type); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* dm_log_debug("Current Type: %d", data_type); */ + switch (data_type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_ENUM: + case DM_SHW_DATA_TYPE_BOOL: { + res = set_shadow_data_func(devid, key, strlen(key), &root->value_int, 0); + } + break; + case DM_SHW_DATA_TYPE_FLOAT: { + float value_float = (float)root->value_double; + res = set_shadow_data_func(devid, key, strlen(key), &value_float, 0); + } + break; + case DM_SHW_DATA_TYPE_DOUBLE: { + res = set_shadow_data_func(devid, key, strlen(key), &root->value_double, 0); + } + break; + default: + dm_log_warning("Unkonwn Number Type"); + break; + } + + return res; +} + +static int _dm_msg_set_string(dm_msg_set_type_t type, int devid, char *key, lite_cjson_t *root) +{ + int res = 0; + void *data = NULL; + dm_shw_data_type_e data_type; + dm_get_shadow_data get_shadow_data_func = (type == DM_MSG_PROPERTY_SET) ? (dm_mgr_deprecated_get_property_data) : + (dm_mgr_deprecated_get_service_input_data); + dm_set_shadow_data set_shadow_data_func = (type == DM_MSG_PROPERTY_SET) ? (dm_mgr_deprecated_set_property_value) : + (dm_mgr_deprecated_set_service_input_value); + + /* dm_log_debug("Current Key: %s", key); */ + + res = get_shadow_data_func(devid, key, strlen(key), &data); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_mgr_deprecated_get_data_type(data, &data_type); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* dm_log_debug("Current Type: %d", data_type); */ + + switch (data_type) { + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_DATE: { + res = set_shadow_data_func(devid, key, strlen(key), root->value, root->value_length); + } + break; + default: + dm_log_warning("Unkonwn String Type"); + break; + } + + return res; +} + +static int _dm_msg_set_object(dm_msg_set_type_t type, int devid, char *key, lite_cjson_t *root) +{ + int res = 0, index = 0; + lite_cjson_t lite_item_key; + lite_cjson_t lite_item_value; + char *new_key = NULL; + int new_key_len = 0; + + for (index = 0; index < root->size; index++) { + res = lite_cjson_object_item_by_index(root, index, &lite_item_key, &lite_item_value); + if (res != SUCCESS_RETURN) { + continue; + } + + /* dm_log_debug("Current Key: %.*s, Value: %.*s", + lite_item_key.value_length, lite_item_key.value, + lite_item_value.value_length, lite_item_value.value); */ + /* new_key_len = lite_item_key.value_length + 1; */ + new_key_len = ((key == NULL) ? (0) : (strlen(key) + 1)) + lite_item_key.value_length + 1; + /* dm_log_debug("new_key_len: %d", new_key_len); */ + new_key = DM_malloc(new_key_len); + if (new_key == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(new_key, 0, new_key_len); + if (key) { + memcpy(new_key, key, strlen(key)); + new_key[strlen(new_key)] = DM_SHW_KEY_DELIMITER; + } + memcpy(new_key + strlen(new_key), lite_item_key.value, lite_item_key.value_length); + /* dm_log_debug("New Key: %s", new_key); */ + + if (lite_cjson_is_object(&lite_item_value)) { + res = _dm_msg_set_object(type, devid, new_key, &lite_item_value); + } + if (lite_cjson_is_array(&lite_item_value)) { + res = _dm_msg_set_array(type, devid, new_key, &lite_item_value); + } + if (lite_cjson_is_number(&lite_item_value)) { + res = _dm_msg_set_number(type, devid, new_key, &lite_item_value); + } + if (lite_cjson_is_string(&lite_item_value)) { + res = _dm_msg_set_string(type, devid, new_key, &lite_item_value); + } + + DM_free(new_key); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + } + return SUCCESS_RETURN; +} + +static int _dm_msg_set_array(dm_msg_set_type_t type, int devid, char *key, lite_cjson_t *root) +{ + int res = 0, index = 0; + lite_cjson_t lite_item_value; + char *ascii_index = NULL; + char *new_key = NULL; + int new_key_len = 0; + + for (index = 0; index < root->size; index++) { + + res = lite_cjson_array_item(root, index, &lite_item_value); + if (res != SUCCESS_RETURN) { + continue; + } + + /* dm_log_debug("Current Value: %.*s", lite_item_value.value_length, lite_item_value.value); */ + + res = dm_utils_itoa(index, &ascii_index); + if (res != SUCCESS_RETURN) { + continue; + } + + /* Original Key '[' Index ']'*/ + new_key_len = ((key == NULL) ? (0) : (strlen(key) + 1)) + 1 + strlen(ascii_index) + 1 + 1; + new_key = DM_malloc(new_key_len); + if (new_key == NULL) { + DM_free(ascii_index); + return DM_MEMORY_NOT_ENOUGH; + } + memset(new_key, 0, new_key_len); + if (key) { + memcpy(new_key, key, strlen(key)); + } + new_key[strlen(new_key)] = '['; + memcpy(new_key + strlen(new_key), ascii_index, strlen(ascii_index)); + new_key[strlen(new_key)] = ']'; + /* dm_log_debug("New Key: %s", new_key); */ + DM_free(ascii_index); + + if (lite_cjson_is_object(&lite_item_value)) { + res = _dm_msg_set_object(type, devid, new_key, &lite_item_value); + } + if (lite_cjson_is_array(&lite_item_value)) { + res = _dm_msg_set_array(type, devid, new_key, &lite_item_value); + } + if (lite_cjson_is_number(&lite_item_value)) { + res = _dm_msg_set_number(type, devid, new_key, &lite_item_value); + } + if (lite_cjson_is_string(&lite_item_value)) { + res = _dm_msg_set_string(type, devid, new_key, &lite_item_value); + } + + DM_free(new_key); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + } + + return SUCCESS_RETURN; +} + +#ifdef DEVICE_MODEL_GATEWAY + const char DM_MSG_PROPERTY_SET_FMT[] DM_READ_ONLY = "{\"devid\":%d,\"payload\":%.*s}"; +#else + const char DM_MSG_PROPERTY_SET_FMT[] DM_READ_ONLY = "{\"devid\":%d,\"propertyid\":\"%.*s\"}"; +#endif +int dm_msg_property_set(int devid, dm_msg_request_payload_t *request) +{ + int res = 0, message_len = 0; + char *message = NULL; +#ifndef DEVICE_MODEL_GATEWAY + int index = 0; + lite_cjson_t lite, lite_item_key, lite_item_value; +#endif + if (request == NULL) { + return DM_INVALID_PARAMETER; + } + +#ifdef DEVICE_MODEL_GATEWAY + message_len = strlen(DM_MSG_PROPERTY_SET_FMT) + DM_UTILS_UINT32_STRLEN + request->params.value_length + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_PROPERTY_SET_FMT, devid, request->params.value_length, request->params.value); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_PROPERTY_SET, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + } +#else + /* Parse Root */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(request->params.value, request->params.value_length, &lite); + if (res != SUCCESS_RETURN || (!lite_cjson_is_object(&lite) && !lite_cjson_is_array(&lite))) { + return DM_JSON_PARSE_FAILED; + } + /* dm_log_info("Property Set, Size: %d", lite.size); */ + + if (lite_cjson_is_object(&lite)) { + res = _dm_msg_set_object(DM_MSG_PROPERTY_SET, devid, NULL, &lite); + } + + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + for (index = 0; index < lite.size; index++) { + memset(&lite_item_key, 0, sizeof(lite_cjson_t)); + memset(&lite_item_value, 0, sizeof(lite_cjson_t)); + + res = lite_cjson_object_item_by_index(&lite, index, &lite_item_key, &lite_item_value); + if (res != SUCCESS_RETURN) { + continue; + } + + message_len = strlen(DM_MSG_PROPERTY_SET_FMT) + DM_UTILS_UINT32_STRLEN + lite_item_key.value_length + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_PROPERTY_SET_FMT, devid, lite_item_key.value_length, lite_item_key.value); + + res = _dm_msg_send_to_user(IOTX_DM_EVENT_PROPERTY_SET, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + } + } +#endif + + return SUCCESS_RETURN; +} + +int dm_msg_property_get(_IN_ int devid, _IN_ dm_msg_request_payload_t *request, _IN_ char **payload, + _IN_ int *payload_len) +{ + int res = 0, index = 0; + lite_cjson_t lite, lite_item; + lite_cjson_item_t *lite_cjson_item = NULL; + + if (devid < 0 || request == NULL || payload == NULL || *payload != NULL || payload_len == NULL) { + return DM_INVALID_PARAMETER; + } + + lite_cjson_item = lite_cjson_create_object(); + if (lite_cjson_item == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + + /* Parse Root */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(request->params.value, request->params.value_length, &lite); + if (res != SUCCESS_RETURN || !lite_cjson_is_array(&lite)) { + return DM_JSON_PARSE_FAILED; + } + /* dm_log_info("Property Get, Size: %d", lite.size); */ + + /* Parse Params */ + for (index = 0; index < lite.size; index++) { + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_array_item(&lite, index, &lite_item); + if (res != SUCCESS_RETURN) { + lite_cjson_delete(lite_cjson_item); + return FAIL_RETURN; + } + + if (!lite_cjson_is_string(&lite_item)) { + lite_cjson_delete(lite_cjson_item); + return FAIL_RETURN; + } + + res = dm_mgr_deprecated_assemble_property(devid, lite_item.value, lite_item.value_length, lite_cjson_item); + if (res != SUCCESS_RETURN) { + lite_cjson_delete(lite_cjson_item); + return FAIL_RETURN; + } + } + + *payload = lite_cjson_print_unformatted(lite_cjson_item); + if (*payload == NULL) { + lite_cjson_delete(lite_cjson_item); + return FAIL_RETURN; + } + lite_cjson_delete(lite_cjson_item); + *payload_len = strlen(*payload); + + return SUCCESS_RETURN; +} + +#ifdef DEVICE_MODEL_GATEWAY + const char DM_MSG_SERVICE_REQUEST_FMT[] DM_READ_ONLY = + "{\"id\":%d,\"devid\":%d,\"serviceid\":\"%.*s\",\"payload\":%.*s}"; +#else + const char DM_MSG_SERVICE_REQUEST_FMT[] DM_READ_ONLY = "{\"id\":%d,\"devid\":%d,\"serviceid\":\"%.*s\"}"; +#endif +int dm_msg_thing_service_request(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + char *identifier, int identifier_len, dm_msg_request_payload_t *request, _IN_ void *ctx) +{ + int res = 0, id = 0, devid = 0, message_len = 0; + lite_cjson_t lite; +#ifndef DEVICE_MODEL_GATEWAY + char *key = NULL; +#endif + char *message = NULL; + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; + + if (product_key == NULL || device_name == NULL || + (strlen(product_key) >= IOTX_PRODUCT_KEY_LEN + 1) || + (strlen(device_name) >= IOTX_DEVICE_NAME_LEN + 1) || + identifier == NULL || identifier_len == 0 || request == NULL) { + return DM_INVALID_PARAMETER; + } + + /* Message ID */ + memcpy(int_id, request->id.value, request->id.value_length); + id = atoi(int_id); + + /* dm_log_debug("Current ID: %d", id); */ + + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + +#ifdef DEVICE_MODEL_GATEWAY + message_len = strlen(DM_MSG_SERVICE_REQUEST_FMT) + DM_UTILS_UINT32_STRLEN * 2 + identifier_len + + request->params.value_length + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_SERVICE_REQUEST_FMT, id, devid, identifier_len, identifier, + request->params.value_length, request->params.value); +#else + key = DM_malloc(identifier_len + 1); + if (key == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(key, 0, identifier_len + 1); + memcpy(key, identifier, identifier_len); + + /* Parse Root */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(request->params.value, request->params.value_length, &lite); + if (res != SUCCESS_RETURN || (!lite_cjson_is_object(&lite) && !lite_cjson_is_array(&lite))) { + DM_free(key); + return DM_JSON_PARSE_FAILED; + } + /* dm_log_info("Service Request, Size: %d", lite.size); */ + + if (lite_cjson_is_object(&lite)) { + res = _dm_msg_set_object(DM_MSG_SERVICE_SET, devid, key, &lite); + } + DM_free(key); + + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + message_len = strlen(DM_MSG_SERVICE_REQUEST_FMT) + DM_UTILS_UINT32_STRLEN * 2 + identifier_len + 1; + message = DM_malloc(message_len); + if (message == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(message, 0, message_len); + HAL_Snprintf(message, message_len, DM_MSG_SERVICE_REQUEST_FMT, id, devid, identifier_len, identifier); +#endif + res = _dm_msg_send_to_user(IOTX_DM_EVENT_THING_SERVICE_REQUEST, message); + if (res != SUCCESS_RETURN) { + DM_free(message); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_message.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_message.h new file mode 100644 index 00000000..a9174403 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_message.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _DM_MESSAGE_H_ +#define _DM_MESSAGE_H_ + +#include "iotx_dm_internal.h" + +#define DM_MSG_KEY_ID "id" +#define DM_MSG_KEY_VERSION "version" +#define DM_MSG_KEY_METHOD "method" +#define DM_MSG_KEY_PARAMS "params" +#define DM_MSG_KEY_CODE "code" +#define DM_MSG_KEY_DATA "data" +#define DM_MSG_KEY_MESSAGE "message" + +#define DM_MSG_VERSION "1.0" + +#define DM_MSG_KEY_PRODUCT_KEY "productKey" +#define DM_MSG_KEY_DEVICE_NAME "deviceName" +#define DM_MSG_KEY_DEVICE_SECRET "deviceSecret" +#define DM_MSG_KEY_TIME "time" + +#define DM_MSG_SIGN_METHOD_SHA256 "Sha256" +#define DM_MSG_SIGN_METHOD_HMACMD5 "hmacMd5" +#define DM_MSG_SIGN_METHOD_HMACSHA1 "hmacSha1" +#define DM_MSG_SIGN_METHOD_HMACSHA256 "hmacSha256" + +typedef enum { + DM_MSG_DEST_CLOUD = 0x01, + DM_MSG_DEST_LOCAL = 0x02, + DM_MSG_DEST_ALL = 0x03 +} dm_msg_dest_type_t; + +typedef struct { + const char *uri; + unsigned char *payload; + unsigned int payload_len; + void *context; +} dm_msg_source_t; + +typedef struct { + const char *uri_name; +} dm_msg_dest_t; + +typedef struct { + lite_cjson_t id; + lite_cjson_t version; + lite_cjson_t method; + lite_cjson_t params; +} dm_msg_request_payload_t; + +typedef struct { + lite_cjson_t id; + lite_cjson_t code; + lite_cjson_t data; + lite_cjson_t message; +} dm_msg_response_payload_t; + +typedef struct { + int msgid; + int devid; + const char *service_prefix; + const char *service_name; + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + char *params; + int params_len; + char *method; + iotx_cm_data_handle_cb callback; +} dm_msg_request_t; + +typedef struct { + const char *service_prefix; + const char *service_name; + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + iotx_dm_error_code_t code; +} dm_msg_response_t; + +typedef struct { + int id; +} dm_msg_ctx_t; + + +int dm_msg_init(void); +int dm_msg_deinit(void); +int _dm_msg_send_to_user(iotx_dm_event_types_t type, char *message); +int dm_msg_send_msg_timeout_to_user(int msg_id, int devid, iotx_dm_event_types_t type); +int dm_msg_uri_parse_pkdn(_IN_ char *uri, _IN_ int uri_len, _IN_ int start_deli, _IN_ int end_deli, + _OU_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _OU_ char device_name[IOTX_DEVICE_NAME_LEN + 1]); +int dm_msg_request_parse(_IN_ char *payload, _IN_ int payload_len, _OU_ dm_msg_request_payload_t *request); +int dm_msg_response_parse(_IN_ char *payload, _IN_ int payload_len, _OU_ dm_msg_response_payload_t *response); +int dm_msg_request(dm_msg_dest_type_t type, _IN_ dm_msg_request_t *request); +int dm_msg_response(dm_msg_dest_type_t type, _IN_ dm_msg_request_payload_t *request, _IN_ dm_msg_response_t *response, + _IN_ char *data, _IN_ int data_len, _IN_ void *user_data); +int dm_msg_thing_model_down_raw(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _IN_ char *payload, _IN_ int payload_len); +int dm_msg_thing_model_up_raw_reply(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], char *payload, int payload_len); +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) +int dm_msg_property_set(int devid, dm_msg_request_payload_t *request); +#ifndef DEPRECATED_LINKKIT +int dm_msg_property_get(_IN_ int devid, _IN_ dm_msg_request_payload_t *request, _IN_ void *ctx); +#else +int dm_msg_property_get(_IN_ int devid, _IN_ dm_msg_request_payload_t *request, _IN_ char **payload, + _IN_ int *payload_len); +#endif +int dm_msg_thing_service_request(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + char *identifier, int identifier_len, dm_msg_request_payload_t *request, _IN_ void *ctx); +int dm_msg_rrpc_request(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + char *messageid, int messageid_len, dm_msg_request_payload_t *request); +int dm_msg_thing_event_property_post_reply(dm_msg_response_payload_t *response); +int dm_msg_thing_event_post_reply(_IN_ char *identifier, _IN_ int identifier_len, + _IN_ dm_msg_response_payload_t *response); +int dm_msg_thing_deviceinfo_update_reply(dm_msg_response_payload_t *response); +int dm_msg_thing_property_desired_get_reply(dm_msg_response_payload_t *response); +int dm_msg_thing_property_desired_delete_reply(dm_msg_response_payload_t *response); +int dm_msg_thing_deviceinfo_delete_reply(dm_msg_response_payload_t *response); +int dm_msg_thing_dsltemplate_get_reply(dm_msg_response_payload_t *response); +int dm_msg_thing_dynamictsl_get_reply(dm_msg_response_payload_t *response); +int dm_msg_ntp_response(char *payload, int payload_len); +int dm_msg_ext_error_reply(dm_msg_response_payload_t *response); +#endif + +#ifdef DEVICE_MODEL_GATEWAY + int dm_msg_topo_add_notify(_IN_ char *payload, _IN_ int payload_len); + int dm_msg_thing_disable(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1]); + int dm_msg_thing_enable(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1]); + int dm_msg_thing_delete(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1]); + int dm_msg_thing_gateway_permit(_IN_ char *payload, _IN_ int payload_len); + int dm_msg_thing_sub_register_reply(dm_msg_response_payload_t *response); + int dm_msg_thing_sub_unregister_reply(dm_msg_response_payload_t *response); + int dm_msg_thing_topo_add_reply(dm_msg_response_payload_t *response); + int dm_msg_thing_topo_delete_reply(dm_msg_response_payload_t *response); + int dm_msg_topo_get_reply(dm_msg_response_payload_t *response); + int dm_msg_thing_list_found_reply(dm_msg_response_payload_t *response); + int dm_msg_combine_login_reply(dm_msg_response_payload_t *response); + int dm_msg_combine_logout_reply(dm_msg_response_payload_t *response); +#endif +#ifdef ALCS_ENABLED + int dm_msg_dev_core_service_dev(char **payload, int *payload_len); +#endif +int dm_msg_cloud_connected(void); +int dm_msg_cloud_disconnect(void); +int dm_msg_cloud_reconnect(void); +#if 0 + int dm_msg_found_device(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1]); + int dm_msg_remove_device(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1]); + int dm_msg_unregister_result(_IN_ char *uri, _IN_ int result); + int dm_msg_send_result(_IN_ char *uri, _IN_ int result); + int dm_msg_add_service_result(_IN_ char *uri, _IN_ int result); + int dm_msg_remove_service_result(_IN_ char *uri, _IN_ int result); +#endif +int dm_msg_register_result(_IN_ char *uri, _IN_ int result); + +#ifdef DEVICE_MODEL_GATEWAY +int dm_msg_thing_sub_register(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ dm_msg_request_t *request); +int dm_msg_thing_sub_unregister(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ dm_msg_request_t *request); +int dm_msg_thing_topo_add(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1], _OU_ dm_msg_request_t *request); +int dm_msg_thing_topo_delete(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ dm_msg_request_t *request); +int dm_msg_thing_topo_get(_OU_ dm_msg_request_t *request); +int dm_msg_thing_list_found(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ dm_msg_request_t *request); +int dm_msg_combine_login(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1], _OU_ dm_msg_request_t *request); +int dm_msg_combine_logout(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _OU_ dm_msg_request_t *request); +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_message_cache.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_message_cache.c new file mode 100644 index 00000000..7c599130 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_message_cache.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "iotx_dm_internal.h" + +#if !defined(DM_MESSAGE_CACHE_DISABLED) + +dm_msg_cache_ctx_t g_dm_msg_cache_ctx; + +dm_msg_cache_ctx_t *_dm_msg_cache_get_ctx(void) +{ + return &g_dm_msg_cache_ctx; +} + +static void _dm_msg_cache_mutex_lock(void) +{ + dm_msg_cache_ctx_t *ctx = _dm_msg_cache_get_ctx(); + if (ctx->mutex) { + HAL_MutexLock(ctx->mutex); + } +} + +static void _dm_msg_cache_mutex_unlock(void) +{ + dm_msg_cache_ctx_t *ctx = _dm_msg_cache_get_ctx(); + if (ctx->mutex) { + HAL_MutexUnlock(ctx->mutex); + } +} + +int dm_msg_cache_init(void) +{ + dm_msg_cache_ctx_t *ctx = _dm_msg_cache_get_ctx(); + + memset(ctx, 0, sizeof(dm_msg_cache_ctx_t)); + + /* Create Mutex */ + ctx->mutex = HAL_MutexCreate(); + if (ctx->mutex == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + + /* Init Message Cache List */ + INIT_LIST_HEAD(&ctx->dmc_list); + + return SUCCESS_RETURN; +} + +int dm_msg_cache_deinit(void) +{ + dm_msg_cache_ctx_t *ctx = _dm_msg_cache_get_ctx(); + dm_msg_cache_node_t *node = NULL; + dm_msg_cache_node_t *next = NULL; + + _dm_msg_cache_mutex_lock(); + list_for_each_entry_safe(node, next, &ctx->dmc_list, linked_list, dm_msg_cache_node_t) { + list_del(&node->linked_list); + if (node->data) { + DM_free(node->data); + } + DM_free(node); + _dm_msg_cache_mutex_unlock(); + } + _dm_msg_cache_mutex_unlock(); + + if (ctx->mutex) { + HAL_MutexDestroy(ctx->mutex); + } + + return SUCCESS_RETURN; +} + +int dm_msg_cache_insert(int msgid, int devid, iotx_dm_event_types_t type, char *data) +{ + dm_msg_cache_ctx_t *ctx = _dm_msg_cache_get_ctx(); + dm_msg_cache_node_t *node = NULL; + + dm_log_debug("dmc list size: %d", ctx->dmc_list_size); + if (ctx->dmc_list_size >= CONFIG_MSGCACHE_QUEUE_MAXLEN) { + return FAIL_RETURN; + } + + node = DM_malloc(sizeof(dm_msg_cache_node_t)); + if (node == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(node, 0, sizeof(dm_msg_cache_node_t)); + + node->msgid = msgid; + node->devid = devid; + node->response_type = type; + node->data = data; + node->ctime = HAL_UptimeMs(); + INIT_LIST_HEAD(&node->linked_list); + + _dm_msg_cache_mutex_lock(); + list_add_tail(&node->linked_list, &ctx->dmc_list); + ctx->dmc_list_size++; + _dm_msg_cache_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int dm_msg_cache_search(_IN_ int msgid, _OU_ dm_msg_cache_node_t **node) +{ + dm_msg_cache_ctx_t *ctx = _dm_msg_cache_get_ctx(); + dm_msg_cache_node_t *search_node = NULL; + + if (msgid <= 0 || node == NULL || *node != NULL) { + return DM_INVALID_PARAMETER; + } + + _dm_msg_cache_mutex_lock(); + list_for_each_entry(search_node, &ctx->dmc_list, linked_list, dm_msg_cache_node_t) { + if (search_node->msgid == msgid) { + *node = search_node; + _dm_msg_cache_mutex_unlock(); + return SUCCESS_RETURN; + } + } + + _dm_msg_cache_mutex_unlock(); + return FAIL_RETURN; +} + +int dm_msg_cache_remove(int msgid) +{ + dm_msg_cache_ctx_t *ctx = _dm_msg_cache_get_ctx(); + dm_msg_cache_node_t *node = NULL; + dm_msg_cache_node_t *next = NULL; + + _dm_msg_cache_mutex_lock(); + list_for_each_entry_safe(node, next, &ctx->dmc_list, linked_list, dm_msg_cache_node_t) { + if (node->msgid == msgid) { + list_del(&node->linked_list); + if (node->data) { + DM_free(node->data); + } + ctx->dmc_list_size--; + DM_free(node); + dm_log_debug("Remove Message ID: %d", msgid); + _dm_msg_cache_mutex_unlock(); + return SUCCESS_RETURN; + } + } + + _dm_msg_cache_mutex_unlock(); + return FAIL_RETURN; +} + +void dm_msg_cache_tick(void) +{ + dm_msg_cache_ctx_t *ctx = _dm_msg_cache_get_ctx(); + dm_msg_cache_node_t *node = NULL; + dm_msg_cache_node_t *next = NULL; + uint64_t current_time = HAL_UptimeMs(); + + _dm_msg_cache_mutex_lock(); + list_for_each_entry_safe(node, next, &ctx->dmc_list, linked_list, dm_msg_cache_node_t) { + if (current_time < node->ctime) { + node->ctime = current_time; + } + if (current_time - node->ctime >= DM_MSG_CACHE_TIMEOUT_MS_DEFAULT) { + dm_log_debug("Message ID Timeout: %d", node->msgid); + /* Send Timeout Message To User */ + dm_msg_send_msg_timeout_to_user(node->msgid, node->devid, node->response_type); + list_del(&node->linked_list); + if (node->data) { + DM_free(node->data); + } + DM_free(node); + ctx->dmc_list_size--; + } + } + _dm_msg_cache_mutex_unlock(); +} +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_message_cache.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_message_cache.h new file mode 100644 index 00000000..d4892018 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_message_cache.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#if !defined(DM_MESSAGE_CACHE_DISABLED) +#ifndef _DM_MESSAGE_CACHE_H_ +#define _DM_MESSAGE_CACHE_H_ + +#include "iotx_dm_internal.h" + +#define DM_MSG_CACHE_TIMEOUT_MS_DEFAULT (10000) + +typedef struct { + int msgid; + int devid; + iotx_dm_event_types_t response_type; + char *data; + uint64_t ctime; + struct list_head linked_list; +} dm_msg_cache_node_t; + +typedef struct { + void *mutex; + int dmc_list_size; + struct list_head dmc_list; +} dm_msg_cache_ctx_t; + +int dm_msg_cache_init(void); +int dm_msg_cache_deinit(void); +int dm_msg_cache_insert(int msg_id, int devid, iotx_dm_event_types_t type, char *data); +int dm_msg_cache_search(_IN_ int msg_id, _OU_ dm_msg_cache_node_t **node); +int dm_msg_cache_remove(int msg_id); +void dm_msg_cache_tick(void); + +#endif +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_msg_process.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_msg_process.c new file mode 100644 index 00000000..f0ed9ce3 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_msg_process.c @@ -0,0 +1,974 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#include "iotx_dm_internal.h" + +const char DM_URI_SYS_PREFIX[] DM_READ_ONLY = "/sys/%s/%s/"; +const char DM_URI_EXT_SESSION_PREFIX[] DM_READ_ONLY = "/ext/session/%s/%s/"; +const char DM_URI_EXT_NTP_PREFIX[] DM_READ_ONLY = "/ext/ntp/%s/%s/"; +const char DM_URI_EXT_ERROR_PREFIX[] DM_READ_ONLY = "/ext/error/%s/%s"; +const char DM_URI_REPLY_SUFFIX[] DM_READ_ONLY = "_reply"; +const char DM_URI_OTA_DEVICE_INFORM[] DM_READ_ONLY = "/ota/device/inform/%s/%s"; + +/* From Cloud To Local Request And Response*/ +const char DM_URI_THING_MODEL_DOWN_RAW[] DM_READ_ONLY = "thing/model/down_raw"; +const char DM_URI_THING_MODEL_DOWN_RAW_REPLY[] DM_READ_ONLY = "thing/model/down_raw_reply"; + +/* From Local To Cloud Request And Response*/ +const char DM_URI_THING_MODEL_UP_RAW[] DM_READ_ONLY = "thing/model/up_raw"; +const char DM_URI_THING_MODEL_UP_RAW_REPLY[] DM_READ_ONLY = "thing/model/up_raw_reply"; + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + const char DM_URI_RRPC_REQUEST_WILDCARD[] DM_READ_ONLY = "rrpc/request/+"; + + /* From Cloud To Local Request And Response*/ + const char DM_URI_THING_SERVICE_PROPERTY_SET[] DM_READ_ONLY = "thing/service/property/set"; + const char DM_URI_THING_SERVICE_PROPERTY_SET_REPLY[] DM_READ_ONLY = "thing/service/property/set_reply"; + const char DM_URI_THING_SERVICE_PROPERTY_GET[] DM_READ_ONLY = "thing/service/property/get"; + const char DM_URI_THING_SERVICE_PROPERTY_GET_REPLY[] DM_READ_ONLY = "thing/service/property/get_reply"; + const char DM_URI_THING_SERVICE_REQUEST_WILDCARD[] DM_READ_ONLY = "thing/service/+"; + const char DM_URI_THING_SERVICE_REQUEST_WILDCARD2[] DM_READ_ONLY = "thing/service/#"; + const char DM_URI_THING_SERVICE_REQUEST[] DM_READ_ONLY = "thing/service/%s"; + const char DM_URI_THING_SERVICE_RESPONSE[] DM_READ_ONLY = "thing/service/%.*s_reply"; + #ifdef DEVICE_MODEL_SHADOW + const char DM_URI_THING_PROPERTY_DESIRED_GET[] DM_READ_ONLY = "thing/property/desired/get"; + const char DM_URI_THING_PROPERTY_DESIRED_DELETE[] DM_READ_ONLY = "thing/property/desired/delete"; + const char DM_URI_THING_PROPERTY_DESIRED_GET_REPLY[] DM_READ_ONLY = "thing/property/desired/get_reply"; + const char DM_URI_THING_PROPERTY_DESIRED_DELETE_REPLY[] DM_READ_ONLY = "thing/property/desired/delete_reply"; + #endif + /* From Local To Cloud Request And Response*/ + #ifdef LOG_REPORT_TO_CLOUD + const char DM_URI_THING_LOG_POST[] DM_READ_ONLY = "thing/log/post"; + #endif + const char DM_URI_THING_EVENT_PROPERTY_POST[] DM_READ_ONLY = "thing/event/property/post"; + const char DM_URI_THING_EVENT_PROPERTY_POST_REPLY[] DM_READ_ONLY = "thing/event/property/post_reply"; + const char DM_URI_THING_EVENT_POST[] DM_READ_ONLY = "thing/event/%.*s/post"; + const char DM_URI_THING_EVENT_POST_REPLY[] DM_READ_ONLY = "thing/event/%s/post_reply"; + const char DM_URI_THING_EVENT_POST_REPLY_WILDCARD[] DM_READ_ONLY = "thing/event/+/post_reply"; + const char DM_URI_THING_DEVICEINFO_UPDATE[] DM_READ_ONLY = "thing/deviceinfo/update"; + const char DM_URI_THING_DEVICEINFO_UPDATE_REPLY[] DM_READ_ONLY = "thing/deviceinfo/update_reply"; + const char DM_URI_THING_DEVICEINFO_DELETE[] DM_READ_ONLY = "thing/deviceinfo/delete"; + const char DM_URI_THING_DEVICEINFO_DELETE_REPLY[] DM_READ_ONLY = "thing/deviceinfo/delete_reply"; + const char DM_URI_THING_DSLTEMPLATE_GET[] DM_READ_ONLY = "thing/dsltemplate/get"; + const char DM_URI_THING_DSLTEMPLATE_GET_REPLY[] DM_READ_ONLY = "thing/dsltemplate/get_reply"; + const char DM_URI_THING_DYNAMICTSL_GET[] DM_READ_ONLY = "thing/dynamicTsl/get"; + const char DM_URI_THING_DYNAMICTSL_GET_REPLY[] DM_READ_ONLY = "thing/dynamicTsl/get_reply"; + const char DM_URI_NTP_REQUEST[] DM_READ_ONLY = "request"; + const char DM_URI_NTP_RESPONSE[] DM_READ_ONLY = "response"; +#endif + +const char DM_URI_DEV_CORE_SERVICE_DEV[] DM_READ_ONLY = "/dev/core/service/dev"; + +#ifdef DEVICE_MODEL_GATEWAY + /* From Cloud To Local Request And Response*/ + const char DM_URI_THING_TOPO_ADD_NOTIFY[] DM_READ_ONLY = "thing/topo/add/notify"; + const char DM_URI_THING_TOPO_ADD_NOTIFY_REPLY[] DM_READ_ONLY = "thing/topo/add/notify_reply"; + const char DM_URI_THING_DELETE[] DM_READ_ONLY = "thing/delete"; + const char DM_URI_THING_DELETE_REPLY[] DM_READ_ONLY = "thing/delete_reply"; + const char DM_URI_THING_DISABLE[] DM_READ_ONLY = "thing/disable"; + const char DM_URI_THING_DISABLE_REPLY[] DM_READ_ONLY = "thing/disable_reply"; + const char DM_URI_THING_ENABLE[] DM_READ_ONLY = "thing/enable"; + const char DM_URI_THING_ENABLE_REPLY[] DM_READ_ONLY = "thing/enable_reply"; + const char DM_URI_THING_GATEWAY_PERMIT[] DM_READ_ONLY = "thing/gateway/permit"; + const char DM_URI_THING_GATEWAY_PERMIT_REPLY[] DM_READ_ONLY = "thing/gateway/permit_reply"; + + /* From Local To Cloud Request And Response*/ + const char DM_URI_THING_SUB_REGISTER[] DM_READ_ONLY = "thing/sub/register"; + const char DM_URI_THING_SUB_REGISTER_REPLY[] DM_READ_ONLY = "thing/sub/register_reply"; + const char DM_URI_THING_SUB_UNREGISTER[] DM_READ_ONLY = "thing/sub/unregister"; + const char DM_URI_THING_SUB_UNREGISTER_REPLY[] DM_READ_ONLY = "thing/sub/unregister_reply"; + const char DM_URI_THING_TOPO_ADD[] DM_READ_ONLY = "thing/topo/add"; + const char DM_URI_THING_TOPO_ADD_REPLY[] DM_READ_ONLY = "thing/topo/add_reply"; + const char DM_URI_THING_TOPO_DELETE[] DM_READ_ONLY = "thing/topo/delete"; + const char DM_URI_THING_TOPO_DELETE_REPLY[] DM_READ_ONLY = "thing/topo/delete_reply"; + const char DM_URI_THING_TOPO_GET[] DM_READ_ONLY = "thing/topo/get"; + const char DM_URI_THING_TOPO_GET_REPLY[] DM_READ_ONLY = "thing/topo/get_reply"; + const char DM_URI_THING_LIST_FOUND[] DM_READ_ONLY = "thing/list/found"; + const char DM_URI_THING_LIST_FOUND_REPLY[] DM_READ_ONLY = "thing/list/found_reply"; + const char DM_URI_COMBINE_LOGIN[] DM_READ_ONLY = "combine/login"; + const char DM_URI_COMBINE_LOGIN_REPLY[] DM_READ_ONLY = "combine/login_reply"; + const char DM_URI_COMBINE_LOGOUT[] DM_READ_ONLY = "combine/logout"; + const char DM_URI_COMBINE_LOGOUT_REPLY[] DM_READ_ONLY = "combine/logout_reply"; +#endif + +int dm_msg_proc_thing_model_down_raw(_IN_ dm_msg_source_t *source) +{ + int res = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + /* Parse Product Key And Device Name */ + res = dm_msg_uri_parse_pkdn((char *)source->uri, strlen(source->uri), 2 + DM_URI_OFFSET, 4 + DM_URI_OFFSET, product_key, + device_name); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return dm_msg_thing_model_down_raw(product_key, device_name, (char *)source->payload, source->payload_len); +} + +int dm_msg_proc_thing_model_up_raw_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + dm_log_info(DM_URI_THING_MODEL_UP_RAW_REPLY); + + res = dm_msg_uri_parse_pkdn((char *)source->uri, strlen(source->uri), 2 + DM_URI_OFFSET, 4 + DM_URI_OFFSET, product_key, + device_name); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + res = dm_msg_thing_model_up_raw_reply(product_key, device_name, (char *)source->payload, source->payload_len); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) +int dm_msg_proc_thing_service_property_set(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response) +{ + int res = 0, devid = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + dm_log_info(DM_URI_THING_SERVICE_PROPERTY_SET); + + /* Request */ + res = dm_msg_uri_parse_pkdn((char *)source->uri, strlen(source->uri), 2 + DM_URI_OFFSET, 4 + DM_URI_OFFSET, product_key, + device_name); + if (res < SUCCESS_RETURN) { + return res; + } + + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res < SUCCESS_RETURN) { + return res; + } + + res = dm_msg_request_parse((char *)source->payload, source->payload_len, request); + if (res < SUCCESS_RETURN) { + return res ; + } + + /* Operation */ + res = dm_msg_property_set(devid, request); + + /* Response */ + response->service_prefix = DM_URI_SYS_PREFIX; + response->service_name = dest->uri_name; + memcpy(response->product_key, product_key, strlen(product_key)); + memcpy(response->device_name, device_name, strlen(device_name)); + response->code = (res == SUCCESS_RETURN) ? (IOTX_DM_ERR_CODE_SUCCESS) : (IOTX_DM_ERR_CODE_REQUEST_ERROR); + + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_service_property_get(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response, + _OU_ unsigned char **data, int *data_len) +{ + int res = 0, devid = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + dm_log_info(DM_URI_THING_SERVICE_PROPERTY_GET); + + /* Request */ + res = dm_msg_uri_parse_pkdn((char *)source->uri, strlen(source->uri), 2 + DM_URI_OFFSET, 4 + DM_URI_OFFSET, product_key, + device_name); + if (res < SUCCESS_RETURN) { + return res; + } + + res = dm_mgr_search_device_by_pkdn(product_key, device_name, &devid); + if (res < SUCCESS_RETURN) { + return res; + } + + res = dm_msg_request_parse((char *)source->payload, source->payload_len, request); + if (res < SUCCESS_RETURN) { + return res ; + } + + /* Operation */ +#ifndef DEPRECATED_LINKKIT + res = dm_msg_property_get(devid, request, source->context); +#else + res = dm_msg_property_get(devid, request, (char **)data, data_len); +#endif + +#ifdef DEPRECATED_LINKKIT + /* Response */ + response->service_prefix = DM_URI_SYS_PREFIX; + response->service_name = dest->uri_name; + memcpy(response->product_key, product_key, strlen(product_key)); + memcpy(response->device_name, device_name, strlen(device_name)); + response->code = (res == SUCCESS_RETURN) ? (IOTX_DM_ERR_CODE_SUCCESS) : (IOTX_DM_ERR_CODE_REQUEST_ERROR); + + if (res != SUCCESS_RETURN) { + *data = DM_malloc(strlen("{}") + 1); + if (*data == NULL) { + return FAIL_RETURN; + } + memset(*data, 0, strlen("{}") + 1); + memcpy(*data, "{}", strlen("{}")); + + *data_len = strlen((char *)*data); + } +#endif + + if (res != SUCCESS_RETURN) { + dm_log_err("DM Property Get Failed"); + } + + return res; +} + +int dm_msg_proc_thing_service_property_post(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response) +{ + int res = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + dm_log_info(DM_URI_THING_EVENT_PROPERTY_POST); + + /* Request */ + res = dm_msg_uri_parse_pkdn((char *)source->uri, strlen(source->uri), 2 + DM_URI_OFFSET, 4 + DM_URI_OFFSET, product_key, + device_name); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_msg_request_parse((char *)source->payload, source->payload_len, request); + + /* Response */ + response->service_prefix = DM_URI_SYS_PREFIX; + response->service_name = dest->uri_name; + memcpy(response->product_key, product_key, strlen(product_key)); + memcpy(response->device_name, device_name, strlen(device_name)); + response->code = (res == SUCCESS_RETURN) ? (IOTX_DM_ERR_CODE_SUCCESS) : (IOTX_DM_ERR_CODE_REQUEST_ERROR); + + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_service_request(_IN_ dm_msg_source_t *source) +{ + int res = 0, serviceid_pos = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + dm_msg_request_payload_t request; + + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + + res = dm_utils_memtok((char *)source->uri, strlen(source->uri), DM_URI_SERVICE_DELIMITER, 6, &serviceid_pos); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_info("Service Identifier: %.*s", (int)(strlen(source->uri) - serviceid_pos - 1), + source->uri + serviceid_pos + 1); + + /* Parse Product Key And Device Name */ + res = dm_msg_uri_parse_pkdn((char *)source->uri, strlen(source->uri), 2 + DM_URI_OFFSET, 4 + DM_URI_OFFSET, product_key, + device_name); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Request */ + res = dm_msg_request_parse((char *)source->payload, source->payload_len, &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + return dm_msg_thing_service_request(product_key, device_name, (char *)source->uri + serviceid_pos + 1, + strlen(source->uri) - serviceid_pos - 1, &request, source->context); +} + +int dm_msg_proc_thing_event_post_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0, eventid_start_pos = 0, eventid_end_pos = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + res = dm_utils_memtok((char *)source->uri, strlen(source->uri), DM_URI_SERVICE_DELIMITER, 6 + DM_URI_OFFSET, + &eventid_start_pos); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + res = dm_utils_memtok((char *)source->uri, strlen(source->uri), DM_URI_SERVICE_DELIMITER, 7 + DM_URI_OFFSET, + &eventid_end_pos); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_info("Event Id: %.*s", eventid_end_pos - eventid_start_pos - 1, source->uri + eventid_start_pos + 1); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + if ((strlen("property") == eventid_end_pos - eventid_start_pos - 1) && + (memcmp("property", source->uri + eventid_start_pos + 1, eventid_end_pos - eventid_start_pos - 1) == 0)) { + dm_msg_thing_event_property_post_reply(&response); + } else { + dm_msg_thing_event_post_reply((char *)source->uri + eventid_start_pos + 1, eventid_end_pos - eventid_start_pos - 1, + &response); + } + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} + +#ifdef DEVICE_MODEL_SHADOW +int dm_msg_proc_thing_property_desired_get_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_PROPERTY_DESIRED_GET_REPLY); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + res = dm_msg_thing_property_desired_get_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_property_desired_delete_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_PROPERTY_DESIRED_DELETE_REPLY); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + res = dm_msg_thing_property_desired_delete_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} +#endif + +int dm_msg_proc_thing_deviceinfo_update_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_DEVICEINFO_UPDATE_REPLY); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + dm_msg_thing_deviceinfo_update_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_deviceinfo_delete_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_DEVICEINFO_DELETE_REPLY); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + dm_msg_thing_deviceinfo_delete_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_dynamictsl_get_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_DYNAMICTSL_GET_REPLY); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + dm_msg_thing_dynamictsl_get_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} + +int dm_msg_proc_rrpc_request(_IN_ dm_msg_source_t *source) +{ + int res = 0, rrpcid_pos = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + dm_msg_request_payload_t request; + + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + + res = dm_utils_memtok((char *)source->uri, strlen(source->uri), DM_URI_SERVICE_DELIMITER, 6, &rrpcid_pos); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_info("Rrpc Id: %.*s", (int)(strlen(source->uri) - rrpcid_pos - 1), source->uri + rrpcid_pos + 1); + + /* Parse Product Key And Device Name */ + res = dm_msg_uri_parse_pkdn((char *)source->uri, strlen(source->uri), 2 + DM_URI_OFFSET, 4 + DM_URI_OFFSET, product_key, + device_name); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Request */ + res = dm_msg_request_parse((char *)source->payload, source->payload_len, &request); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + return dm_msg_rrpc_request(product_key, device_name, (char *)source->uri + rrpcid_pos + 1, + strlen(source->uri) - rrpcid_pos - 1, &request); +} + +int dm_disp_ntp_response(_IN_ dm_msg_source_t *source) +{ + dm_log_info(DM_URI_NTP_RESPONSE); + + /* Operation */ + return dm_msg_ntp_response((char *)source->payload, source->payload_len); +} + +int dm_disp_ext_error_response(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; + /* char int_id[DM_UTILS_UINT32_STRLEN] = {0}; */ + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + return dm_msg_ext_error_reply(&response); +} +#endif + +#ifdef DEVICE_MODEL_GATEWAY +int dm_msg_proc_thing_topo_add_notify(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response) +{ + int res = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + dm_log_info(DM_URI_THING_TOPO_ADD_NOTIFY); + + /* Request */ + res = dm_msg_uri_parse_pkdn((char *)source->uri, strlen(source->uri), 2 + DM_URI_OFFSET, 4 + DM_URI_OFFSET, product_key, + device_name); + if (res < SUCCESS_RETURN) { + return res; + } + + res = dm_msg_request_parse((char *)source->payload, source->payload_len, request); + if (res < SUCCESS_RETURN) { + return res ; + } + + /* Operation */ + res = dm_msg_topo_add_notify(request->params.value, request->params.value_length); + if (res < SUCCESS_RETURN) { + return res ; + } + + /* Response */ + response->service_prefix = DM_URI_SYS_PREFIX; + response->service_name = dest->uri_name; + memcpy(response->product_key, product_key, strlen(product_key)); + memcpy(response->device_name, device_name, strlen(device_name)); + response->code = (res == SUCCESS_RETURN) ? (IOTX_DM_ERR_CODE_SUCCESS) : (IOTX_DM_ERR_CODE_REQUEST_ERROR); + + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_disable(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response) +{ + int res = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + dm_log_info(DM_URI_THING_DISABLE); + + /* Request */ + res = dm_msg_uri_parse_pkdn((char *)source->uri, strlen(source->uri), 2 + DM_URI_OFFSET, 4 + DM_URI_OFFSET, product_key, + device_name); + if (res < SUCCESS_RETURN) { + return res; + } + + res = dm_msg_request_parse((char *)source->payload, source->payload_len, request); + if (res != SUCCESS_RETURN) { + return res; + } + + /* Operation */ + res = dm_msg_thing_disable(product_key, device_name); + + /* Response */ + response->service_prefix = DM_URI_SYS_PREFIX; + response->service_name = dest->uri_name; + memcpy(response->product_key, product_key, strlen(product_key)); + memcpy(response->device_name, device_name, strlen(device_name)); + response->code = (res == SUCCESS_RETURN) ? (IOTX_DM_ERR_CODE_SUCCESS) : (IOTX_DM_ERR_CODE_REQUEST_ERROR); + + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_enable(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response) +{ + int res = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + dm_log_info(DM_URI_THING_DISABLE); + + /* Request */ + res = dm_msg_uri_parse_pkdn((char *)source->uri, strlen(source->uri), 2 + DM_URI_OFFSET, 4 + DM_URI_OFFSET, product_key, + device_name); + if (res < SUCCESS_RETURN) { + return res; + } + + res = dm_msg_request_parse((char *)source->payload, source->payload_len, request); + if (res != SUCCESS_RETURN) { + return res; + } + + /* Operation */ + res = dm_msg_thing_enable(product_key, device_name); + + /* Response */ + response->service_prefix = DM_URI_SYS_PREFIX; + response->service_name = dest->uri_name; + memcpy(response->product_key, product_key, strlen(product_key)); + memcpy(response->device_name, device_name, strlen(device_name)); + response->code = (res == SUCCESS_RETURN) ? (IOTX_DM_ERR_CODE_SUCCESS) : (IOTX_DM_ERR_CODE_REQUEST_ERROR); + + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_delete(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response) +{ + int res = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + dm_log_info(DM_URI_THING_DELETE); + + /* Request */ + res = dm_msg_uri_parse_pkdn((char *)source->uri, strlen(source->uri), 2 + DM_URI_OFFSET, 4 + DM_URI_OFFSET, product_key, + device_name); + if (res < SUCCESS_RETURN) { + return res; + } + + res = dm_msg_request_parse((char *)source->payload, source->payload_len, request); + if (res != SUCCESS_RETURN) { + return res; + } + + /* Operation */ + res = dm_msg_thing_delete(product_key, device_name); + + /* Response */ + response->service_prefix = DM_URI_SYS_PREFIX; + response->service_name = dest->uri_name; + memcpy(response->product_key, product_key, strlen(product_key)); + memcpy(response->device_name, device_name, strlen(device_name)); + response->code = (res == SUCCESS_RETURN) ? (IOTX_DM_ERR_CODE_SUCCESS) : (IOTX_DM_ERR_CODE_REQUEST_ERROR); + + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_gateway_permit(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response) +{ + int res = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + dm_log_info(DM_URI_THING_DELETE); + + /* Request */ + res = dm_msg_uri_parse_pkdn((char *)source->uri, strlen(source->uri), 2 + DM_URI_OFFSET, 4 + DM_URI_OFFSET, product_key, + device_name); + if (res < SUCCESS_RETURN) { + return res; + } + + res = dm_msg_request_parse((char *)source->payload, source->payload_len, request); + if (res != SUCCESS_RETURN) { + return res; + } + + /* Operation */ + res = dm_msg_thing_gateway_permit(request->params.value, request->params.value_length); + + /* Response */ + response->service_prefix = DM_URI_SYS_PREFIX; + response->service_name = dest->uri_name; + memcpy(response->product_key, product_key, strlen(product_key)); + memcpy(response->device_name, device_name, strlen(device_name)); + response->code = (res == SUCCESS_RETURN) ? (IOTX_DM_ERR_CODE_SUCCESS) : (IOTX_DM_ERR_CODE_REQUEST_ERROR); + + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_sub_register_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_SUB_REGISTER_REPLY); + + memset(&response, 0, sizeof(dm_msg_response_payload_t)); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + dm_msg_thing_sub_register_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_sub_unregister_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_SUB_UNREGISTER_REPLY); + + memset(&response, 0, sizeof(dm_msg_response_payload_t)); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + dm_msg_thing_sub_unregister_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_topo_add_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_TOPO_ADD_REPLY); + + memset(&response, 0, sizeof(dm_msg_response_payload_t)); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + dm_msg_thing_topo_add_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_topo_delete_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_TOPO_DELETE_REPLY); + + memset(&response, 0, sizeof(dm_msg_response_payload_t)); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + dm_msg_thing_topo_delete_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_topo_get_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_TOPO_GET_REPLY); + + memset(&response, 0, sizeof(dm_msg_response_payload_t)); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + dm_msg_topo_get_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} + +int dm_msg_proc_thing_list_found_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_TOPO_GET_REPLY); + + memset(&response, 0, sizeof(dm_msg_response_payload_t)); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + dm_msg_thing_list_found_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} + +int dm_msg_proc_combine_login_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_TOPO_GET_REPLY); + + memset(&response, 0, sizeof(dm_msg_response_payload_t)); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + dm_msg_combine_login_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} + +int dm_msg_proc_combine_logout_reply(_IN_ dm_msg_source_t *source) +{ + int res = 0; + dm_msg_response_payload_t response; +#if !defined(DM_MESSAGE_CACHE_DISABLED) + char int_id[DM_UTILS_UINT32_STRLEN] = {0}; +#endif + + dm_log_info(DM_URI_THING_TOPO_GET_REPLY); + + memset(&response, 0, sizeof(dm_msg_response_payload_t)); + + /* Response */ + res = dm_msg_response_parse((char *)source->payload, source->payload_len, &response); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Operation */ + dm_msg_combine_logout_reply(&response); + + /* Remove Message From Cache */ +#if !defined(DM_MESSAGE_CACHE_DISABLED) + memcpy(int_id, response.id.value, response.id.value_length); + dm_msg_cache_remove(atoi(int_id)); +#endif + return SUCCESS_RETURN; +} +#endif + +#ifdef ALCS_ENABLED +int dm_msg_proc_thing_dev_core_service_dev(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response, + _OU_ unsigned char **data, int *data_len) +{ + int res = 0; + + dm_log_info(DM_URI_DEV_CORE_SERVICE_DEV); + + /* Request */ + res = dm_msg_request_parse((char *)source->payload, source->payload_len, request); + if (res < SUCCESS_RETURN) { + return res ; + } + + /* Operation */ + res = dm_msg_dev_core_service_dev((char **)data, data_len); + if (res < SUCCESS_RETURN) { + return res; + } + + /* Response */ + response->service_prefix = NULL; + response->service_name = dest->uri_name; + response->code = (res == SUCCESS_RETURN) ? (IOTX_DM_ERR_CODE_SUCCESS) : (IOTX_DM_ERR_CODE_REQUEST_ERROR); + + return SUCCESS_RETURN; +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_msg_process.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_msg_process.h new file mode 100644 index 00000000..911949b8 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_msg_process.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _DM_MSG_PROCESS_H_ +#define _DM_MSG_PROCESS_H_ + +#define DM_URI_SERVICE_DELIMITER '/' + +extern const char DM_URI_SYS_PREFIX[] DM_READ_ONLY; +extern const char DM_URI_EXT_SESSION_PREFIX[] DM_READ_ONLY; +extern const char DM_URI_EXT_NTP_PREFIX[] DM_READ_ONLY; +extern const char DM_URI_EXT_ERROR_PREFIX[] DM_READ_ONLY; +extern const char DM_URI_REPLY_SUFFIX[] DM_READ_ONLY; +extern const char DM_URI_OTA_DEVICE_INFORM[] DM_READ_ONLY; +extern const char DM_URI_THING_PROPERTY_DESIRED_GET[] DM_READ_ONLY; +extern const char DM_URI_THING_PROPERTY_DESIRED_DELETE[] DM_READ_ONLY; +extern const char DM_URI_THING_PROPERTY_DESIRED_GET_REPLY[] DM_READ_ONLY; +extern const char DM_URI_THING_PROPERTY_DESIRED_DELETE_REPLY[] DM_READ_ONLY; +/* From Cloud To Local Request And Response*/ +extern const char DM_URI_THING_MODEL_DOWN_RAW[] DM_READ_ONLY; +extern const char DM_URI_THING_MODEL_DOWN_RAW_REPLY[] DM_READ_ONLY; + +/* From Local To Cloud Request And Response*/ +extern const char DM_URI_THING_MODEL_UP_RAW[] DM_READ_ONLY; +extern const char DM_URI_THING_MODEL_UP_RAW_REPLY[] DM_READ_ONLY; + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + extern const char DM_URI_RRPC_REQUEST_WILDCARD[] DM_READ_ONLY; + /* From Cloud To Local Request And Response*/ + extern const char DM_URI_THING_SERVICE_PROPERTY_SET[] DM_READ_ONLY; + extern const char DM_URI_THING_SERVICE_PROPERTY_SET_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_SERVICE_PROPERTY_GET[] DM_READ_ONLY; + extern const char DM_URI_THING_SERVICE_PROPERTY_GET_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_SERVICE_REQUEST_WILDCARD[] DM_READ_ONLY; + extern const char DM_URI_THING_SERVICE_REQUEST_WILDCARD2[] DM_READ_ONLY; + extern const char DM_URI_THING_SERVICE_REQUEST[] DM_READ_ONLY; + extern const char DM_URI_THING_SERVICE_RESPONSE[] DM_READ_ONLY; + + + /* From Local To Cloud Request And Response*/ + extern const char DM_URI_THING_EVENT_PROPERTY_POST[] DM_READ_ONLY; + extern const char DM_URI_THING_EVENT_PROPERTY_POST_REPLY[] DM_READ_ONLY; + #ifdef LOG_REPORT_TO_CLOUD + extern const char DM_URI_THING_LOG_POST[] DM_READ_ONLY; + #endif + extern const char DM_URI_THING_EVENT_POST[] DM_READ_ONLY; + extern const char DM_URI_THING_EVENT_POST_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_EVENT_POST_REPLY_WILDCARD[] DM_READ_ONLY; + extern const char DM_URI_THING_DEVICEINFO_UPDATE[] DM_READ_ONLY; + extern const char DM_URI_THING_DEVICEINFO_UPDATE_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_DEVICEINFO_DELETE[] DM_READ_ONLY; + extern const char DM_URI_THING_DEVICEINFO_DELETE_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_DSLTEMPLATE_GET[] DM_READ_ONLY; + extern const char DM_URI_THING_DSLTEMPLATE_GET_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_DYNAMICTSL_GET[] DM_READ_ONLY; + extern const char DM_URI_THING_DYNAMICTSL_GET_REPLY[] DM_READ_ONLY; + extern const char DM_URI_NTP_REQUEST[] DM_READ_ONLY; + extern const char DM_URI_NTP_RESPONSE[] DM_READ_ONLY; +#endif + +extern const char DM_URI_DEV_CORE_SERVICE_DEV[] DM_READ_ONLY; + +#ifdef DEVICE_MODEL_GATEWAY + /* From Cloud To Local Request And Response*/ + extern const char DM_URI_THING_TOPO_ADD_NOTIFY[] DM_READ_ONLY; + extern const char DM_URI_THING_TOPO_ADD_NOTIFY_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_DISABLE[] DM_READ_ONLY; + extern const char DM_URI_THING_DISABLE_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_ENABLE[] DM_READ_ONLY; + extern const char DM_URI_THING_ENABLE_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_DELETE[] DM_READ_ONLY; + extern const char DM_URI_THING_DELETE_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_GATEWAY_PERMIT[] DM_READ_ONLY; + extern const char DM_URI_THING_GATEWAY_PERMIT_REPLY[] DM_READ_ONLY; + + /* From Local To Cloud Request And Response*/ + extern const char DM_URI_THING_SUB_REGISTER[] DM_READ_ONLY; + extern const char DM_URI_THING_SUB_REGISTER_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_SUB_UNREGISTER[] DM_READ_ONLY; + extern const char DM_URI_THING_SUB_UNREGISTER_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_TOPO_ADD[] DM_READ_ONLY; + extern const char DM_URI_THING_TOPO_ADD_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_TOPO_DELETE[] DM_READ_ONLY; + extern const char DM_URI_THING_TOPO_DELETE_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_TOPO_GET[] DM_READ_ONLY; + extern const char DM_URI_THING_TOPO_GET_REPLY[] DM_READ_ONLY; + extern const char DM_URI_THING_LIST_FOUND[] DM_READ_ONLY; + extern const char DM_URI_THING_LIST_FOUND_REPLY[] DM_READ_ONLY; + extern const char DM_URI_COMBINE_LOGIN[] DM_READ_ONLY; + extern const char DM_URI_COMBINE_LOGIN_REPLY[] DM_READ_ONLY; + extern const char DM_URI_COMBINE_LOGOUT[] DM_READ_ONLY; + extern const char DM_URI_COMBINE_LOGOUT_REPLY[] DM_READ_ONLY; +#endif + +int dm_disp_uri_prefix_split(_IN_ const char *prefix, _IN_ char *uri, _IN_ int uri_len, _OU_ int *start, _OU_ int *end); +int dm_disp_uri_pkdn_split(_IN_ char *uri, _IN_ int uri_len, _OU_ int *start, _OU_ int *end); +int dm_disp_uri_service_specific_split(_IN_ char *uri, _IN_ int uri_len, _OU_ int *start, _OU_ int *end); +int dm_disp_uri_rrpc_request_split(_IN_ char *uri, _IN_ int uri_len, _OU_ int *start, _OU_ int *end); +int dm_disp_uri_event_specific_split(_IN_ char *uri, _IN_ int uri_len, _OU_ int *start, _OU_ int *end); + +int dm_msg_proc_thing_model_down_raw(_IN_ dm_msg_source_t *source); +int dm_msg_proc_thing_model_up_raw_reply(_IN_ dm_msg_source_t *source); + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) +int dm_msg_proc_thing_service_property_set(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response); +int dm_msg_proc_thing_service_property_get(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response, + _OU_ unsigned char **data, int *data_len); +int dm_msg_proc_thing_property_desired_get_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_thing_property_desired_delete_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_thing_service_property_post(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response); +int dm_msg_proc_thing_service_request(_IN_ dm_msg_source_t *source); +int dm_msg_proc_thing_event_post_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_thing_deviceinfo_update_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_thing_deviceinfo_delete_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_thing_dynamictsl_get_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_rrpc_request(_IN_ dm_msg_source_t *source); +int dm_disp_ntp_response(_IN_ dm_msg_source_t *source); +int dm_disp_ext_error_response(_IN_ dm_msg_source_t *source); +#endif + +#ifdef DEVICE_MODEL_GATEWAY +int dm_msg_proc_thing_topo_add_notify(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response); +int dm_msg_proc_thing_disable(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response); +int dm_msg_proc_thing_enable(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response); +int dm_msg_proc_thing_delete(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response); +int dm_msg_proc_thing_gateway_permit(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response); +int dm_msg_proc_thing_sub_register_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_thing_sub_unregister_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_thing_topo_add_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_thing_topo_delete_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_thing_topo_get_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_thing_list_found_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_combine_login_reply(_IN_ dm_msg_source_t *source); +int dm_msg_proc_combine_logout_reply(_IN_ dm_msg_source_t *source); +#endif + +#ifdef ALCS_ENABLED +int dm_msg_proc_thing_dev_core_service_dev(_IN_ dm_msg_source_t *source, _IN_ dm_msg_dest_t *dest, + _OU_ dm_msg_request_payload_t *request, _OU_ dm_msg_response_t *response, + _OU_ unsigned char **data, int *data_len); +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_opt.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_opt.c new file mode 100644 index 00000000..75ffa8f7 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_opt.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "iotx_dm_internal.h" + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + +static dm_opt_ctx g_dm_opt = { + 0, 0, 1, 1, 1 +}; + +int dm_opt_set(dm_opt_t opt, void *data) +{ + int res = SUCCESS_RETURN; + + if (data == NULL) { + return FAIL_RETURN; + } + + switch (opt) { + case DM_OPT_DOWNSTREAM_PROPERTY_POST_REPLY: { + int opt = *(int *)(data); + g_dm_opt.prop_post_reply_opt = opt; + } + break; + case DM_OPT_DOWNSTREAM_EVENT_POST_REPLY: { + int opt = *(int *)(data); + g_dm_opt.event_post_reply_opt = opt; + } + break; + case DM_OPT_UPSTREAM_PROPERTY_SET_REPLY: { + int opt = *(int *)(data); + g_dm_opt.prop_set_reply_opt = opt; + } + break; +#ifdef DEVICE_MODEL_SHADOW + case DM_OPT_DOWNSTREAM_EVENT_PROPERTY_DESIRED_GET_REPLY: { + int opt = *(int *)(data); + g_dm_opt.prop_desired_get_reply_opt = opt; + } + break; + case DM_OPT_DOWNSTREAM_EVENT_PROPERTY_DESIRED_DELETE_REPLY: { + int opt = *(int *)(data); + g_dm_opt.prop_desired_delete_reply_opt = opt; + } + break; +#endif + default: { + res = FAIL_RETURN; + } + break; + } + + return res; +} + +int dm_opt_get(dm_opt_t opt, void *data) +{ + int res = SUCCESS_RETURN; + + if (data == NULL) { + return FAIL_RETURN; + } + + switch (opt) { + case DM_OPT_DOWNSTREAM_PROPERTY_POST_REPLY: { + *(int *)(data) = g_dm_opt.prop_post_reply_opt; + } + break; + case DM_OPT_DOWNSTREAM_EVENT_POST_REPLY: { + *(int *)(data) = g_dm_opt.event_post_reply_opt; + } + break; + case DM_OPT_UPSTREAM_PROPERTY_SET_REPLY: { + *(int *)(data) = g_dm_opt.prop_set_reply_opt; + } + break; +#ifdef DEVICE_MODEL_SHADOW + case DM_OPT_DOWNSTREAM_EVENT_PROPERTY_DESIRED_DELETE_REPLY: { + *(int *)(data) = g_dm_opt.prop_desired_delete_reply_opt; + } + break; + case DM_OPT_DOWNSTREAM_EVENT_PROPERTY_DESIRED_GET_REPLY: { + *(int *)(data) = g_dm_opt.prop_desired_get_reply_opt; + } + break; +#endif + default: { + res = FAIL_RETURN; + } + break; + } + + return res; +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_opt.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_opt.h new file mode 100644 index 00000000..552d846c --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_opt.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) +#ifndef _DM_OPT_H +#define _DM_OPT_H + +typedef enum { + DM_OPT_DOWNSTREAM_PROPERTY_POST_REPLY, + DM_OPT_DOWNSTREAM_EVENT_POST_REPLY, + DM_OPT_UPSTREAM_PROPERTY_SET_REPLY, + DM_OPT_DOWNSTREAM_EVENT_PROPERTY_DESIRED_DELETE_REPLY, + DM_OPT_DOWNSTREAM_EVENT_PROPERTY_DESIRED_GET_REPLY +} dm_opt_t; + +typedef struct { + int prop_post_reply_opt; + int event_post_reply_opt; + int prop_set_reply_opt; + int prop_desired_get_reply_opt; + int prop_desired_delete_reply_opt; +} dm_opt_ctx; + +int dm_opt_set(dm_opt_t opt, void *data); +int dm_opt_get(dm_opt_t opt, void *data); + +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_ota.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_ota.c new file mode 100644 index 00000000..6a974dab --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_ota.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "iotx_dm_internal.h" + +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + +static dm_ota_ctx_t g_dm_ota_ctx; + +static dm_ota_ctx_t *_dm_ota_get_ctx(void) +{ + return &g_dm_ota_ctx; +} + +int dm_ota_init(void) +{ + dm_ota_ctx_t *ctx = _dm_ota_get_ctx(); + memset(ctx, 0, sizeof(dm_ota_ctx_t)); + + HAL_GetProductKey(ctx->product_key); + HAL_GetDeviceName(ctx->device_name); + + return SUCCESS_RETURN; +} + +int dm_ota_sub(void) +{ + dm_ota_ctx_t *ctx = _dm_ota_get_ctx(); + void *handle = NULL; + + /* Init OTA Handle */ + handle = IOT_OTA_Init(ctx->product_key, ctx->device_name, NULL); + if (handle == NULL) { + return FAIL_RETURN; + } + + ctx->ota_handle = handle; + + return SUCCESS_RETURN; +} + +int dm_ota_deinit(void) +{ + dm_ota_ctx_t *ctx = _dm_ota_get_ctx(); + + if (ctx->ota_handle) { + IOT_OTA_Deinit(ctx->ota_handle); + ctx->ota_handle = NULL; + } + + return SUCCESS_RETURN; +} +#ifdef DEVICE_MODEL_GATEWAY +#ifdef DEVICE_MODEL_SUBDEV_OTA +int dm_ota_switch_device(int devid) +{ + char pk[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char dn[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char ds[IOTX_DEVICE_SECRET_LEN + 1] = {0}; + int ret = dm_mgr_search_device_by_devid(devid, pk, dn, ds); + void *ota_handle = NULL; + int res = -1; + dm_ota_ctx_t *ctx = NULL; + + if (SUCCESS_RETURN != ret) { + dm_log_err("could not find device by id, ret is %d", ret); + return FAIL_RETURN; + } + dm_log_info("do subdevice ota, pk, dn is %s, %s", pk, dn); + + ota_handle = NULL; + res = dm_ota_get_ota_handle(&ota_handle); + + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* if currently a device is doing OTA, do not interrupt */ + if (IOT_OTA_IsFetching(ota_handle)) { + dm_log_info("OTA is processing, can not switch to another device"); + return FAIL_RETURN; + } + + dm_ota_deinit(); + ctx = _dm_ota_get_ctx(); + memset(ctx, 0, sizeof(dm_ota_ctx_t)); + + memcpy(ctx->product_key, pk, strlen(pk) + 1); + memcpy(ctx->device_name, dn, strlen(dn) + 1); + ret = dm_ota_sub(); + if (ret < 0) { + dm_log_err("dm_ota_sub ret is %d, %s, %s\n", ret, pk, dn); + } + return ret; +} +#endif +#endif + +int dm_ota_get_ota_handle(void **handle) +{ + dm_ota_ctx_t *ctx = _dm_ota_get_ctx(); + + if (handle == NULL || *handle != NULL) { + return FAIL_RETURN; + } + + if (ctx->ota_handle == NULL) { + return FAIL_RETURN; + } + + *handle = ctx->ota_handle; + + return SUCCESS_RETURN; +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_ota.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_ota.h new file mode 100644 index 00000000..8d25e46b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_ota.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _DM_OTA_H_ +#define _DM_OTA_H_ + +typedef struct { + void *ota_handle; + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; +} dm_ota_ctx_t; + +int dm_ota_init(void); +int dm_ota_sub(void); +int dm_ota_deinit(void); +int dm_ota_get_ota_handle(void **handle); +#ifdef DEVICE_MODEL_GATEWAY + #ifdef DEVICE_MODEL_SUBDEV_OTA + int dm_ota_switch_device(int devid); + #endif +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_server.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_server.c new file mode 100644 index 00000000..5735d9fd --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_server.c @@ -0,0 +1,284 @@ +#include "iotx_dm_internal.h" + +#ifdef ALCS_ENABLED + +#ifdef LOG_REPORT_TO_CLOUD + #include "iotx_log_report.h" +#endif +static int _dm_server_malloc_context(_IN_ NetworkAddr *remote, _IN_ CoAPMessage *message, + _OU_ dm_server_alcs_context_t **context) +{ + dm_server_alcs_context_t *alcs_context = NULL; + + alcs_context = DM_malloc(sizeof(dm_server_alcs_context_t)); + if (alcs_context == NULL) { + return FAIL_RETURN; + } + memset(alcs_context, 0, sizeof(dm_server_alcs_context_t)); + + alcs_context->ip = DM_malloc(strlen((char *)remote->addr) + 1); + if (alcs_context->ip == NULL) { + DM_free(alcs_context); + return FAIL_RETURN; + } + memset(alcs_context->ip, 0, strlen((char *)remote->addr) + 1); + memcpy(alcs_context->ip, (char *)remote->addr, strlen((char *)remote->addr) + 1); + + alcs_context->port = remote->port; + dm_log_info("alcs_context->ip: %s", alcs_context->ip); + dm_log_info("alcs_context->port: %d", alcs_context->port); + + alcs_context->token = DM_malloc(message->header.tokenlen); + if (alcs_context->token == NULL) { + DM_free(alcs_context->ip); + DM_free(alcs_context); + return FAIL_RETURN; + } + memset(alcs_context->token, 0, message->header.tokenlen); + memcpy(alcs_context->token, message->token, message->header.tokenlen); + + alcs_context->token_len = message->header.tokenlen; + + *context = alcs_context; + + return SUCCESS_RETURN; +} + +void dm_server_free_context(_IN_ void *ctx) +{ + dm_server_alcs_context_t *context = (dm_server_alcs_context_t *)ctx; + DM_free(context->ip); + DM_free(context->token); + DM_free(context); +} + +static dm_server_uri_map_t g_dm_server_uri_map[] = { +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + {DM_URI_THING_SERVICE_PROPERTY_SET, DM_URI_SYS_PREFIX, IOTX_DM_LOCAL_AUTH, dm_server_thing_service_property_set }, + {DM_URI_THING_SERVICE_PROPERTY_GET, DM_URI_SYS_PREFIX, IOTX_DM_LOCAL_AUTH, dm_server_thing_service_property_get }, + {DM_URI_THING_EVENT_PROPERTY_POST, DM_URI_SYS_PREFIX, IOTX_DM_LOCAL_AUTH, dm_server_thing_service_property_post }, + {DM_URI_THING_SERVICE_REQUEST_WILDCARD2, DM_URI_SYS_PREFIX, IOTX_DM_LOCAL_AUTH, dm_server_thing_service_request }, +#endif + {DM_URI_DEV_CORE_SERVICE_DEV, NULL, IOTX_DM_LOCAL_NO_AUTH, dm_server_thing_dev_core_service_dev }, +}; + +int dm_server_subscribe_all(char product_key[IOTX_PRODUCT_KEY_LEN + 1], char device_name[IOTX_DEVICE_NAME_LEN + 1]) +{ + int res = 0, index = 0, auth = 0; + int number = sizeof(g_dm_server_uri_map) / sizeof(dm_server_uri_map_t); + char *uri = NULL; + + for (index = 0; index < number; index++) { + res = dm_utils_service_name((char *)g_dm_server_uri_map[index].uri_prefix, (char *)g_dm_server_uri_map[index].uri_name, + product_key, device_name, &uri); + if (res < SUCCESS_RETURN) { + index--; + continue; + } + + auth = (g_dm_server_uri_map[index].auth_type & IOTX_DM_SERVICE_LOCAL_AUTH) ? (IOTX_DM_MESSAGE_AUTH) : + (IOTX_DM_MESSAGE_NO_AUTH); + res = dm_server_subscribe(uri, (void *)g_dm_server_uri_map[index].callback, auth); + if (res < SUCCESS_RETURN) { + index--; + DM_free(uri); + continue; + } + DM_free(uri); + } + + return SUCCESS_RETURN; +} + +void dm_server_alcs_event_handler(void *pcontext, void *phandle, iotx_alcs_event_msg_t *msg) +{ + +} + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) +void dm_server_thing_service_property_set(CoAPContext *context, const char *paths, NetworkAddr *remote, + CoAPMessage *message) +{ + int res = 0; + dm_msg_source_t source; + dm_msg_dest_t dest; + dm_msg_request_payload_t request; + dm_msg_response_t response; + dm_server_alcs_context_t *alcs_context = NULL; + + res = _dm_server_malloc_context(remote, message, &alcs_context); + if (res != SUCCESS_RETURN) { + return; + } + + memset(&source, 0, sizeof(dm_msg_source_t)); + memset(&dest, 0, sizeof(dm_msg_dest_t)); + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + source.uri = paths; + source.payload = (unsigned char *)message->payload; + source.payload_len = message->payloadlen; + source.context = alcs_context; + + dest.uri_name = DM_URI_THING_SERVICE_PROPERTY_SET; + + res = dm_msg_proc_thing_service_property_set(&source, &dest, &request, &response); + if (res < SUCCESS_RETURN) { + dm_server_free_context(alcs_context); + return; + } + +#ifdef LOG_REPORT_TO_CLOUD + { + extern void send_permance_info(char *input, int input_len, char *comments, int report_format); + if (SUCCESS_RETURN == check_target_msg(request.id.value, request.id.value_length)) { + send_permance_info(request.id.value, request.id.value_length, "2", 1); + } + } +#endif + + dm_msg_response(DM_MSG_DEST_LOCAL, &request, &response, "{}", strlen("{}"), (void *)alcs_context); + dm_server_free_context(alcs_context); +} + +void dm_server_thing_service_request(CoAPContext *context, const char *paths, NetworkAddr *remote, + CoAPMessage *message) +{ + int res = 0; + dm_msg_source_t source; + + dm_server_alcs_context_t *alcs_context = NULL; + + res = _dm_server_malloc_context(remote, message, &alcs_context); + if (res != SUCCESS_RETURN) { + return; + } + + memset(&source, 0, sizeof(dm_msg_source_t)); + + source.uri = paths; + source.payload = (unsigned char *)message->payload; + source.payload_len = message->payloadlen; + source.context = alcs_context; + + if (dm_msg_proc_thing_service_request(&source) < 0) { + dm_server_free_context(alcs_context); + } +} + +void dm_server_thing_service_property_get(CoAPContext *context, const char *paths, NetworkAddr *remote, + CoAPMessage *message) +{ + int res = 0; + dm_server_alcs_context_t *alcs_context = NULL; + dm_msg_source_t source; + dm_msg_dest_t dest; + dm_msg_request_payload_t request; + dm_msg_response_t response; + unsigned char *data = NULL; + int data_len = 0; + + res = _dm_server_malloc_context(remote, message, &alcs_context); + if (res != SUCCESS_RETURN) { + return; + } + + memset(&source, 0, sizeof(dm_msg_source_t)); + memset(&dest, 0, sizeof(dm_msg_dest_t)); + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + source.uri = paths; + source.payload = (unsigned char *)message->payload; + source.payload_len = message->payloadlen; + source.context = alcs_context; + + dest.uri_name = DM_URI_THING_SERVICE_PROPERTY_GET; + + dm_msg_proc_thing_service_property_get(&source, &dest, &request, &response, &data, &data_len); + +#ifdef DEPRECATED_LINKKIT + dm_msg_response(DM_MSG_DEST_LOCAL, &request, &response, (char *)data, data_len, alcs_context); + DM_free(data); + dm_server_free_context(alcs_context); +#endif +} + +void dm_server_thing_service_property_post(CoAPContext *context, const char *paths, NetworkAddr *remote, + CoAPMessage *message) +{ + int res = 0; + dm_server_alcs_context_t *alcs_context = NULL; + dm_msg_source_t source; + dm_msg_dest_t dest; + dm_msg_request_payload_t request; + dm_msg_response_t response; + + res = _dm_server_malloc_context(remote, message, &alcs_context); + if (res != SUCCESS_RETURN) { + return; + } + + memset(&source, 0, sizeof(dm_msg_source_t)); + memset(&dest, 0, sizeof(dm_msg_dest_t)); + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + source.uri = paths; + source.payload = (unsigned char *)message->payload; + source.payload_len = message->payloadlen; + source.context = alcs_context; + + dest.uri_name = DM_URI_THING_EVENT_PROPERTY_POST; + + dm_msg_proc_thing_service_property_post(&source, &dest, &request, &response); + + dm_msg_response(DM_MSG_DEST_LOCAL, &request, &response, "{}", strlen("{}"), alcs_context); + dm_server_free_context(alcs_context); +} + +#endif +void dm_server_thing_dev_core_service_dev(CoAPContext *context, const char *paths, NetworkAddr *remote, + CoAPMessage *message) +{ + int res = 0; + dm_server_alcs_context_t *alcs_context = NULL; + dm_msg_source_t source; + dm_msg_dest_t dest; + dm_msg_request_payload_t request; + dm_msg_response_t response; + unsigned char *data = NULL; + int data_len = 0; + + res = _dm_server_malloc_context(remote, message, &alcs_context); + if (res != SUCCESS_RETURN) { + return; + } + + memset(&source, 0, sizeof(dm_msg_source_t)); + memset(&dest, 0, sizeof(dm_msg_dest_t)); + memset(&request, 0, sizeof(dm_msg_request_payload_t)); + memset(&response, 0, sizeof(dm_msg_response_t)); + + source.uri = paths; + source.payload = (unsigned char *)message->payload; + source.payload_len = message->payloadlen; + source.context = alcs_context; + + dest.uri_name = DM_URI_DEV_CORE_SERVICE_DEV; + + res = dm_msg_proc_thing_dev_core_service_dev(&source, &dest, &request, &response, &data, &data_len); + if (res < SUCCESS_RETURN) { + dm_server_free_context(alcs_context); + return; + } + + dm_msg_response(DM_MSG_DEST_LOCAL, &request, &response, (char *)data, data_len, alcs_context); + + if (response.code == IOTX_DM_ERR_CODE_SUCCESS) { + DM_free(data); + } + dm_server_free_context(alcs_context); +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_server.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_server.h new file mode 100644 index 00000000..2ada9788 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_server.h @@ -0,0 +1,29 @@ +#ifndef _DM_SERVER_H_ +#define _DM_SERVER_H_ + +#ifdef ALCS_ENABLED +typedef struct { + const char *uri_name; + const char *uri_prefix; + int auth_type; + CoAPRecvMsgHandler callback; +} dm_server_uri_map_t; + +#define DM_SERVER_ALCS_NO_AUTH (0) +#define DM_SERVER_ALCS_AUTH (1) + +void dm_server_alcs_event_handler(void *pcontext, void *phandle, iotx_alcs_event_msg_t *msg); + +int dm_server_subscribe_all(char product_key[IOTX_PRODUCT_KEY_LEN + 1], char device_name[IOTX_DEVICE_NAME_LEN + 1]); +void dm_server_thing_service_property_set(CoAPContext *context, const char *paths, NetworkAddr *remote, + CoAPMessage *message); +void dm_server_thing_service_property_get(CoAPContext *context, const char *paths, NetworkAddr *remote, + CoAPMessage *message); +void dm_server_thing_service_property_post(CoAPContext *context, const char *paths, NetworkAddr *remote, + CoAPMessage *message); +void dm_server_thing_dev_core_service_dev(CoAPContext *context, const char *paths, NetworkAddr *remote, + CoAPMessage *message); +void dm_server_thing_service_request(CoAPContext *context, const char *paths, NetworkAddr *remote, + CoAPMessage *message); +#endif +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_server_adapter.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_server_adapter.c new file mode 100644 index 00000000..dc827706 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_server_adapter.c @@ -0,0 +1,140 @@ +#include "iotx_dm_internal.h" + +#ifdef ALCS_ENABLED + +static dm_server_ctx_t g_dm_server_ctx = {0}; + +static dm_server_ctx_t *dm_server_get_ctx(void) +{ + return &g_dm_server_ctx; +} + +int dm_server_open(void) +{ + dm_server_ctx_t *ctx = dm_server_get_ctx(); + iotx_alcs_param_t alcs_param; + iotx_alcs_event_handle_t event_handle; + + memset(&alcs_param, 0x0, sizeof(iotx_alcs_param_t)); + memset(&event_handle, 0x0, sizeof(iotx_alcs_event_handle_t)); + + alcs_param.group = (char *)DM_SERVER_ALCS_ADDR; + alcs_param.port = DM_SERVER_ALCS_PORT; + alcs_param.send_maxcount = DM_SERVER_ALCS_SEND_MAXCOUNT; + alcs_param.waittime = DM_SERVER_ALCS_WAITTIME; + alcs_param.obs_maxcount = DM_SERVER_ALCS_OBS_MAXCOUNT; + alcs_param.res_maxcount = DM_SERVER_ALCS_RES_MAXCOUNT; + alcs_param.role = IOTX_ALCS_ROLE_CLIENT | IOTX_ALCS_ROLE_SERVER; + event_handle.h_fp = dm_server_alcs_event_handler; + event_handle.pcontext = NULL; + + alcs_param.handle_event = &event_handle; + + ctx->conn_handle = iotx_alcs_construct(&alcs_param); + if (ctx->conn_handle == NULL) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_server_connect(void) +{ + + dm_server_ctx_t *ctx = dm_server_get_ctx(); + + return iotx_alcs_cloud_init(ctx->conn_handle); +} + +int dm_server_close(void) +{ + dm_server_ctx_t *ctx = dm_server_get_ctx(); + + return iotx_alcs_destroy(&ctx->conn_handle); +} + +int dm_server_send(char *uri, unsigned char *payload, int payload_len, void *context) +{ + int res = 0; + dm_server_ctx_t *ctx = dm_server_get_ctx(); + iotx_alcs_msg_t alcs_msg; + dm_server_alcs_context_t *alcs_context = (dm_server_alcs_context_t *)context; + + memset(&alcs_msg, 0, sizeof(iotx_alcs_msg_t)); + + alcs_msg.group_id = 0; + alcs_msg.ip = alcs_context ? alcs_context->ip : NULL; + alcs_msg.port = alcs_context ? alcs_context->port : 0; + alcs_msg.msg_code = (alcs_context && alcs_context->token_len + && alcs_context->token) ? ITOX_ALCS_COAP_MSG_CODE_205_CONTENT : ITOX_ALCS_COAP_MSG_CODE_GET; + alcs_msg.msg_type = IOTX_ALCS_MESSAGE_TYPE_CON; + alcs_msg.uri = uri; + alcs_msg.payload = payload; + alcs_msg.payload_len = payload_len; + + if (alcs_context == NULL) { + res = iotx_alcs_observe_notify(ctx->conn_handle, alcs_msg.uri, alcs_msg.payload_len, alcs_msg.payload); + dm_log_info("Send Observe Notify Result %d", res); + } else if (alcs_context->ip && alcs_context->port && NULL == alcs_context->token) { + res = iotx_alcs_send(ctx->conn_handle, &alcs_msg); + dm_log_info("Send Result %d", res); + } else if (alcs_context->ip && alcs_context->port && alcs_context->token_len && alcs_context->token) { + res = iotx_alcs_send_Response(ctx->conn_handle, &alcs_msg, (uint8_t)alcs_context->token_len, + (uint8_t *)alcs_context->token); + dm_log_info("Send Response Result %d", res); + } + + return res; +} + +int dm_server_subscribe(char *uri, CoAPRecvMsgHandler callback, int auth_type) +{ + int res = 0; + dm_server_ctx_t *ctx = dm_server_get_ctx(); + iotx_alcs_res_t alcs_res; + + memset(&alcs_res, 0, sizeof(iotx_alcs_res_t)); + + alcs_res.uri = uri; + alcs_res.msg_ct = IOTX_ALCS_MESSAGE_CT_APP_JSON; + alcs_res.msg_perm = IOTX_ALCS_MESSAGE_PERM_GET; + alcs_res.maxage = 60; + alcs_res.need_auth = auth_type; + alcs_res.callback = callback; + + res = iotx_alcs_register_resource(ctx->conn_handle, &alcs_res); + + dm_log_info("Register Resource Result: %d", res); + + return res; +} + +int dm_server_add_device(char product_key[IOTX_PRODUCT_KEY_LEN + 1], char device_name[IOTX_DEVICE_NAME_LEN + 1]) +{ + int res = 0; + dm_server_ctx_t *ctx = dm_server_get_ctx(); + + res = iotx_alcs_add_sub_device(ctx->conn_handle, (const char *)product_key, (const char *)device_name); + dm_log_info("Add Device Result: %d, Product Key: %s, Device Name: %s", res, product_key, device_name); + + return res; +} + +int dm_server_del_device(char product_key[IOTX_PRODUCT_KEY_LEN + 1], char device_name[IOTX_DEVICE_NAME_LEN + 1]) +{ + int res = 0; + dm_server_ctx_t *ctx = dm_server_get_ctx(); + + res = iotx_alcs_remove_sub_device(ctx->conn_handle, (const char *)product_key, (const char *)device_name); + dm_log_info("Del Device Result: %d, Product Key: %s, Device Name: %s", res, product_key, device_name); + + return res; +} + +int dm_server_yield(void) +{ + dm_server_ctx_t *ctx = dm_server_get_ctx(); + + return iotx_alcs_yield(ctx->conn_handle); +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_server_adapter.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_server_adapter.h new file mode 100644 index 00000000..bfb49a75 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_server_adapter.h @@ -0,0 +1,34 @@ +#ifndef _DM_SERVER_ADAPTER_H_ +#define _DM_SERVER_ADAPTER_H_ + +#ifdef ALCS_ENABLED + +#define DM_SERVER_ALCS_ADDR "224.0.1.187" +#define DM_SERVER_ALCS_PORT (5863) +#define DM_SERVER_ALCS_SEND_MAXCOUNT (16) +#define DM_SERVER_ALCS_WAITTIME (200) +#define DM_SERVER_ALCS_OBS_MAXCOUNT (16) +#define DM_SERVER_ALCS_RES_MAXCOUNT (255) + +typedef struct { + void *conn_handle; +} dm_server_ctx_t; + +typedef struct { + char *ip; + uint16_t port; + char *token; + int token_len; +} dm_server_alcs_context_t; + +int dm_server_open(void); +int dm_server_connect(void); +int dm_server_close(void); +int dm_server_send(char *uri, unsigned char *payload, int payload_len, void *context); +int dm_server_subscribe(char *uri, CoAPRecvMsgHandler callback, int auth_type); +int dm_server_add_device(char product_key[IOTX_PRODUCT_KEY_LEN + 1], char device_name[IOTX_DEVICE_NAME_LEN + 1]); +int dm_server_del_device(char product_key[IOTX_PRODUCT_KEY_LEN + 1], char device_name[IOTX_DEVICE_NAME_LEN + 1]); +int dm_server_yield(void); + +#endif +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_shadow.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_shadow.c new file mode 100644 index 00000000..0bffa7f1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_shadow.c @@ -0,0 +1,2535 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "iotx_dm_internal.h" + +#ifdef DEPRECATED_LINKKIT + +/* #define IOTX_DM_TSL_DEVELOP_TEST */ + +/*****************************Internal Definition*****************************/ + +typedef int (*dm_shw_data_set)(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len); +typedef int (*dm_shw_array_set)(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index); +typedef int (*dm_shw_data_get)(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value); +typedef int (*dm_shw_array_get)(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index); +typedef void (*dm_shw_data_free)(_IN_ dm_shw_data_value_t *data_value); +typedef void (*dm_shw_array_free)(_IN_ dm_shw_data_value_t *data_value); +typedef void (*dm_shw_data_print)(_IN_ dm_shw_data_value_t *data_value); + +typedef struct { + dm_shw_data_type_e type; + const char *name; + dm_shw_data_set func_set; + dm_shw_array_set func_array_set; + dm_shw_data_get func_get; + dm_shw_array_get func_array_get; + dm_shw_data_free func_free; + dm_shw_array_free func_array_free; +} dm_shw_data_type_mapping_t; + +/* Data Set */ +static int _dm_shw_int_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len); +static int _dm_shw_float_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len); +static int _dm_shw_double_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len); +static int _dm_shw_text_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len); +static int _dm_shw_enum_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len); +static int _dm_shw_date_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len); +static int _dm_shw_bool_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len); + +/* Array Data Set */ +static int _dm_shw_array_int_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index); +static int _dm_shw_array_float_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index); +static int _dm_shw_array_double_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index); +static int _dm_shw_array_text_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index); +static int _dm_shw_array_enum_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index); +static int _dm_shw_array_date_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index); +static int _dm_shw_array_bool_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index); + +/* Data Get */ +static int _dm_shw_int_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value); +static int _dm_shw_float_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value); +static int _dm_shw_double_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value); +static int _dm_shw_text_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value); +static int _dm_shw_enum_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value); +static int _dm_shw_date_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value); +static int _dm_shw_bool_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value); + +/* Array Data Get */ +static int _dm_shw_array_int_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index); +static int _dm_shw_array_float_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index); +static int _dm_shw_array_double_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index); +static int _dm_shw_array_text_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index); +static int _dm_shw_array_enum_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index); +static int _dm_shw_array_date_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index); +static int _dm_shw_array_bool_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index); + +/* Data Free */ +static void _dm_shw_int_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_float_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_double_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_text_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_enum_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_date_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_bool_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_array_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_struct_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_property_free(_IN_ dm_shw_data_t *property); + +/* Array Data Free */ +static void _dm_shw_array_int_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_array_float_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_array_double_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_array_text_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_array_enum_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_array_date_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_array_bool_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_array_array_free(_IN_ dm_shw_data_value_t *data_value); +static void _dm_shw_array_struct_free(_IN_ dm_shw_data_value_t *data_value); + +#if 0 + /* Data Print */ + static void _dm_shw_int_print(_IN_ dm_shw_data_value_t *data_value); + static void _dm_shw_float_print(_IN_ dm_shw_data_value_t *data_value); + static void _dm_shw_double_print(_IN_ dm_shw_data_value_t *data_value); + static void _dm_shw_text_print(_IN_ dm_shw_data_value_t *data_value); + static void _dm_shw_enum_print(_IN_ dm_shw_data_value_t *data_value); + static void _dm_shw_date_print(_IN_ dm_shw_data_value_t *data_value); + static void _dm_shw_bool_print(_IN_ dm_shw_data_value_t *data_value); + static void _dm_shw_array_print(_IN_ dm_shw_data_value_t *data_value); + static void _dm_shw_struct_print(_IN_ dm_shw_data_value_t *data_value); + static void _dm_shw_property_print(_IN_ dm_shw_data_t *property); +#endif + +/* Data Search */ +static int _dm_shw_data_struct_search(_IN_ dm_shw_data_t *input, _IN_ char *key, _IN_ int key_len, + _OU_ dm_shw_data_t **output, _OU_ int *index); + +static dm_shw_data_type_mapping_t g_iotx_data_type_mapping[] = { + {DM_SHW_DATA_TYPE_NONE, "none", NULL, NULL, NULL, NULL, NULL, NULL }, + {DM_SHW_DATA_TYPE_INT, "int", _dm_shw_int_set, _dm_shw_array_int_set, _dm_shw_int_get, _dm_shw_array_int_get, _dm_shw_int_free, _dm_shw_array_int_free }, + {DM_SHW_DATA_TYPE_FLOAT, "float", _dm_shw_float_set, _dm_shw_array_float_set, _dm_shw_float_get, _dm_shw_array_float_get, _dm_shw_float_free, _dm_shw_array_float_free, }, + {DM_SHW_DATA_TYPE_DOUBLE, "double", _dm_shw_double_set, _dm_shw_array_double_set, _dm_shw_double_get, _dm_shw_array_double_get, _dm_shw_double_free, _dm_shw_array_double_free, }, + {DM_SHW_DATA_TYPE_TEXT, "text", _dm_shw_text_set, _dm_shw_array_text_set, _dm_shw_text_get, _dm_shw_array_text_get, _dm_shw_text_free, _dm_shw_array_text_free, }, + {DM_SHW_DATA_TYPE_ENUM, "enum", _dm_shw_enum_set, _dm_shw_array_enum_set, _dm_shw_enum_get, _dm_shw_array_enum_get, _dm_shw_enum_free, _dm_shw_array_enum_free, }, + {DM_SHW_DATA_TYPE_DATE, "date", _dm_shw_date_set, _dm_shw_array_date_set, _dm_shw_date_get, _dm_shw_array_date_get, _dm_shw_date_free, _dm_shw_array_date_free, }, + {DM_SHW_DATA_TYPE_BOOL, "bool", _dm_shw_bool_set, _dm_shw_array_bool_set, _dm_shw_bool_get, _dm_shw_array_bool_get, _dm_shw_bool_free, _dm_shw_array_bool_free, }, + {DM_SHW_DATA_TYPE_ARRAY, "array", NULL, NULL, NULL, NULL, _dm_shw_array_free, _dm_shw_array_array_free, }, + {DM_SHW_DATA_TYPE_STRUCT, "struct", NULL, NULL, NULL, NULL, _dm_shw_struct_free, _dm_shw_array_struct_free, } +}; + +/*****************************************************************************/ + +static int _dm_shw_data_array_search(_IN_ dm_shw_data_t *input, _IN_ int input_index, _IN_ char *key, + _IN_ int key_len, _OU_ dm_shw_data_t **output, _OU_ int *output_index) +{ + int res = 0, deli_offset = 0; + + dm_shw_data_value_complex_t *complex_struct = (dm_shw_data_value_complex_t *)input->data_value.value; + /* dm_log_debug("Current Key: %s, Len: %d",key,key_len); + dm_log_debug("Current Item Identifier: %s",input->identifier); */ + res = dm_utils_memtok(key, key_len, DM_SHW_KEY_DELIMITER, 1, &deli_offset); + if (res != SUCCESS_RETURN) { + deli_offset = key_len; + } + + switch (complex_struct->type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_FLOAT: + case DM_SHW_DATA_TYPE_DOUBLE: + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_ENUM: + case DM_SHW_DATA_TYPE_DATE: + case DM_SHW_DATA_TYPE_BOOL: { + if (deli_offset != key_len) { + return FAIL_RETURN; + } + if (output) { + *output = input; + } + if (output_index) { + *output_index = input_index; + } + return SUCCESS_RETURN; + } + break; + case DM_SHW_DATA_TYPE_STRUCT: { + dm_shw_data_t *search_data = NULL; + if (complex_struct->value == NULL) { + return FAIL_RETURN; + } + search_data = (dm_shw_data_t *)complex_struct->value + input_index; + return _dm_shw_data_struct_search(search_data, key, deli_offset, output, output_index); + } + break; + default: + dm_log_err("Unknown Data Type: %d", complex_struct->type); + break; + } + + return FAIL_RETURN; +} + +static int _dm_shw_data_struct_search(_IN_ dm_shw_data_t *input, _IN_ char *key, + _IN_ int key_len, _OU_ dm_shw_data_t **output, _OU_ int *index) +{ + int res = 0, item_index = 0, deli_offset = 0, partial_offset = 0; + int partial_input_len = 0, array_input_len = 0, array_index = 0; + dm_shw_data_t *data_item = NULL; + + /* dm_log_debug("Current Key: %.*s",key_len,key); */ + + dm_shw_data_value_complex_t *complex_struct = (dm_shw_data_value_complex_t *)input->data_value.value; + + res = dm_utils_memtok(key, key_len, DM_SHW_KEY_DELIMITER, 1, &deli_offset); + if (res != SUCCESS_RETURN) { + deli_offset = key_len; + } + + partial_offset = deli_offset; + res = dm_utils_strarr_index(key, deli_offset, &partial_input_len, &array_input_len, &array_index); + if (res == SUCCESS_RETURN) { + /* dm_log_debug("Current Index: %d",array_index); */ + partial_offset = partial_input_len; + } + + for (item_index = 0; item_index < complex_struct->size; item_index++) { + data_item = (dm_shw_data_t *)complex_struct->value + item_index; + if (strlen(data_item->identifier) != partial_offset || + memcmp(data_item->identifier, key, partial_offset) != 0) { + continue; + } + + switch (data_item->data_value.type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_FLOAT: + case DM_SHW_DATA_TYPE_DOUBLE: + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_ENUM: + case DM_SHW_DATA_TYPE_DATE: + case DM_SHW_DATA_TYPE_BOOL: { + if (partial_input_len != 0 || deli_offset != key_len) { + return FAIL_RETURN; + } + if (output) { + *output = data_item; + } + return SUCCESS_RETURN; + } + break; + case DM_SHW_DATA_TYPE_ARRAY: { + int key_offset = (deli_offset == key_len) ? (deli_offset - 1) : (deli_offset + 1); + int key_len_offset = (deli_offset == key_len) ? (key_len) : (deli_offset + 1); + if ((partial_input_len == 0) && (deli_offset == key_len)) { + if (output) { + *output = data_item; + } + return SUCCESS_RETURN; + } + if (partial_input_len == 0) { + return FAIL_RETURN; + } + return _dm_shw_data_array_search(data_item, array_index, key + key_offset, key_len - key_len_offset, output, index); + } + case DM_SHW_DATA_TYPE_STRUCT: { + if (deli_offset == key_len) { + if (output) { + *output = data_item; + } + return SUCCESS_RETURN; + } + if (partial_input_len != 0) { + return FAIL_RETURN; + } + return _dm_shw_data_struct_search(data_item, key + deli_offset + 1, key_len - deli_offset - 1, output, index); + } + default: + dm_log_err("Unknown Data Type"); + break; + } + } + + return FAIL_RETURN; +} + +static int _dm_shw_data_search(_IN_ dm_shw_data_t *input, _IN_ char *key, + _IN_ int key_len, _OU_ dm_shw_data_t **output, _OU_ int *index) +{ + int res = 0, deli_offset = 0, partial_offset = 0; + int partial_input_len = 0, array_input_len = 0, array_index = 0; + + if (input == NULL || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = dm_utils_memtok(key, key_len, DM_SHW_KEY_DELIMITER, 1, &deli_offset); + if (res != SUCCESS_RETURN) { + deli_offset = key_len; + } + + partial_offset = deli_offset; + res = dm_utils_strarr_index(key, deli_offset, &partial_input_len, &array_input_len, &array_index); + if (res == SUCCESS_RETURN) { + /* dm_log_debug("Current Index: %d",array_index); */ + partial_offset = partial_input_len; + } + + /* dm_log_debug("Current Input Identifier: %s",input->identifier); + dm_log_debug("Current Compare Key: %.*s",partial_offset,key); */ + + if (strlen(input->identifier) != partial_offset || + memcmp(input->identifier, key, partial_offset) != 0) { + return FAIL_RETURN; + } + dm_log_debug("Identifier Found: %s", input->identifier); + + switch (input->data_value.type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_FLOAT: + case DM_SHW_DATA_TYPE_DOUBLE: + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_ENUM: + case DM_SHW_DATA_TYPE_DATE: + case DM_SHW_DATA_TYPE_BOOL: { + if (partial_input_len != 0 || deli_offset != key_len) { + return FAIL_RETURN; + } + if (output) { + *output = input; + } + return SUCCESS_RETURN; + } + break; + case DM_SHW_DATA_TYPE_ARRAY: { + int key_offset = (deli_offset == key_len) ? (deli_offset - 1) : (deli_offset + 1); + int key_len_offset = (deli_offset == key_len) ? (key_len) : (deli_offset + 1); + if ((partial_input_len == 0) && (deli_offset == key_len)) { + if (output) { + *output = input; + } + return SUCCESS_RETURN; + } + if (partial_input_len == 0) { + return FAIL_RETURN; + } + return _dm_shw_data_array_search(input, array_index, key + key_offset, key_len - key_len_offset, output, index); + } + break; + case DM_SHW_DATA_TYPE_STRUCT: { + if (deli_offset == key_len) { + if (output) { + *output = input; + } + return SUCCESS_RETURN; + } + if (partial_input_len != 0) { + return FAIL_RETURN; + } + return _dm_shw_data_struct_search(input, key + deli_offset + 1, key_len - deli_offset - 1, output, index); + } + break; + default: + dm_log_err("Unknow Data Type"); + break; + } + + return FAIL_RETURN; +} + +static int _dm_shw_property_search(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, + _OU_ dm_shw_data_t **property, _OU_ int *index) +{ + int res = 0, item_index = 0; + dm_shw_data_t *property_item = NULL; + + if (shadow == NULL || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + if (shadow->property_number == 0 || shadow->properties == NULL) { + return DM_TSL_PROPERTY_NOT_EXIST; + } + + for (item_index = 0; item_index < shadow->property_number; item_index++) { + property_item = shadow->properties + item_index; + res = _dm_shw_data_search(property_item, key, key_len, property, index); + if (res == SUCCESS_RETURN) { + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +static int _dm_shw_event_output_search(_IN_ dm_shw_data_t *outputdatas, _IN_ int number, _IN_ char *key, + _IN_ int key_len, _OU_ dm_shw_data_t **event_data, _OU_ int *index) +{ + int res = 0, item_index = 0; + dm_shw_data_t *outputdata = NULL; + + if (outputdatas == NULL || number <= 0 || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + for (item_index = 0; item_index < number; item_index++) { + outputdata = outputdatas + item_index; + res = _dm_shw_data_search(outputdata, key, key_len, event_data, index); + if (res == SUCCESS_RETURN) { + return SUCCESS_RETURN; + } + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_event_search(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _OU_ dm_shw_event_t **event) +{ + int index = 0; + dm_shw_event_t *dtsl_event = NULL; + + if (shadow == NULL || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + for (index = 0; index < shadow->event_number; index++) { + dtsl_event = shadow->events + index; + if ((strlen(dtsl_event->identifier) == key_len) && + (memcmp(dtsl_event->identifier, key, key_len) == 0)) { + /* dm_log_debug("TSL Event Found: %s",dtsl_event->identifier); */ + if (event) { + *event = dtsl_event; + } + return SUCCESS_RETURN; + } + } + + /* dm_log_debug("TSL Event Not Found: %.*s",key_len,key); */ + + return FAIL_RETURN; +} + +static int _dm_shw_service_input_output_search(_IN_ dm_shw_data_target_e type, _IN_ dm_shw_service_t *service, + _IN_ char *key, _IN_ int key_len, _OU_ dm_shw_data_t **service_data, _OU_ int *index) +{ + int res = 0, item_index = 0, datas_number = 0; + dm_shw_data_t *datas = NULL; + dm_shw_data_t *data = NULL; + + if (type == DM_SHW_DATA_TARGET_SERVICE_INPUT_DATA) { + datas = service->input_datas; + datas_number = service->input_data_number; + } else { + datas = service->output_datas; + datas_number = service->output_data_number; + } + + for (item_index = 0; item_index < datas_number; item_index++) { + data = datas + item_index; + res = _dm_shw_data_search(data, key, key_len, service_data, index); + if (res == SUCCESS_RETURN) { + return SUCCESS_RETURN; + } + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_service_search(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, + _OU_ dm_shw_service_t **service) +{ + int index = 0; + dm_shw_service_t *dtsl_service = NULL; + + if (shadow == NULL || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + for (index = 0; index < shadow->service_number; index++) { + dtsl_service = shadow->services + index; + if ((strlen(dtsl_service->identifier) == key_len) && + (memcmp(dtsl_service->identifier, key, key_len) == 0)) { + /* dm_log_debug("TSL Service Found: %s",dtsl_service->identifier); */ + if (service) { + *service = dtsl_service; + } + return SUCCESS_RETURN; + } + } + + /* dm_log_debug("TSL Service Not Found: %.*s",key_len,key); */ + + return FAIL_RETURN; +} + +int dm_shw_create(_IN_ iotx_dm_tsl_type_t type, _IN_ const char *tsl, _IN_ int tsl_len, _OU_ dm_shw_t **shadow) +{ + int res = 0; + + if (shadow == NULL || *shadow != NULL || tsl == NULL || tsl_len <= 0) { + return DM_INVALID_PARAMETER; + } + + switch (type) { + case IOTX_DM_TSL_TYPE_ALINK: { + res = dm_tsl_alink_create(tsl, tsl_len, shadow); + } + break; + case IOTX_DM_TSL_TYPE_TLV: { + /* TODO for yusan*/ + res = FAIL_RETURN; + } + break; + default: + dm_log_err("Unknown TSL Type"); + res = FAIL_RETURN; + break; + } + + return res; +} + +int dm_shw_get_property_data(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **data) +{ + int res = 0; + + if (shadow == NULL || key == NULL || key_len <= 0 || data == NULL || *data != NULL) { + return DM_INVALID_PARAMETER; + } + + res = _dm_shw_property_search(shadow, key, key_len, (dm_shw_data_t **)data, NULL); + if (res != SUCCESS_RETURN) { + return DM_TSL_PROPERTY_NOT_EXIST; + } + + return SUCCESS_RETURN; +} + +int dm_shw_get_service_input_output_data(_IN_ dm_shw_data_target_e type, _IN_ dm_shw_t *shadow, _IN_ char *key, + _IN_ int key_len, _OU_ void **data) +{ + int res = 0; + int offset = 0, array_index = 0; + char *pos = NULL; + dm_shw_service_t *service = NULL; + dm_shw_data_t *service_data = NULL; + + if (type < DM_SHW_DATA_TARGET_SERVICE_INPUT_DATA || type > DM_SHW_DATA_TARGET_SERVICE_OUTPUT_DATA || shadow == NULL + || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = dm_utils_memtok(key, key_len, DM_SHW_KEY_DELIMITER, 1, &offset); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_debug("Key: %.*s", key_len, key); + + res = _dm_shw_service_search(shadow, key, offset, &service); + if (res != SUCCESS_RETURN) { + return DM_TSL_EVENT_NOT_EXIST; + } + + pos = key + offset + 1; + dm_log_debug("TSL Service input/output Data Search, Event Data ID: %s", pos); + + res = _dm_shw_service_input_output_search(type, service, pos, strlen(pos), &service_data, &array_index); + if (res != SUCCESS_RETURN) { + return DM_TSL_EVENT_NOT_EXIST; + } + + if (data) { + *data = (void *)service_data; + } + + return SUCCESS_RETURN; +} + +int dm_shw_get_event_output_data(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **data) +{ + int res = 0; + int offset = 0, array_index = 0; + char *pos = NULL; + dm_shw_event_t *event = NULL; + dm_shw_data_t *event_data = NULL; + + if (shadow == NULL || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = dm_utils_memtok(key, key_len, DM_SHW_KEY_DELIMITER, 1, &offset); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_debug("Key: %.*s", key_len, key); + + res = _dm_shw_event_search(shadow, key, offset, &event); + if (res != SUCCESS_RETURN) { + return DM_TSL_EVENT_NOT_EXIST; + } + + pos = key + offset + 1; + /* dm_log_debug("TSL Event Output Data Search, Event Data ID: %s",pos); */ + + res = _dm_shw_event_output_search(event->output_datas, event->output_data_number, pos, strlen(pos), &event_data, + &array_index); + if (res != SUCCESS_RETURN) { + return DM_TSL_EVENT_NOT_EXIST; + } + + if (data) { + *data = (void *)event_data; + } + + return SUCCESS_RETURN; +} + +int dm_shw_get_data_type(_IN_ void *data, _OU_ dm_shw_data_type_e *type) +{ + dm_shw_data_t *data_item = (dm_shw_data_t *)data; + + if (data_item == NULL || type == NULL) { + return DM_INVALID_PARAMETER; + } + + if (data_item->data_value.type == DM_SHW_DATA_TYPE_ARRAY) { + dm_shw_data_value_complex_t *complex_value = (dm_shw_data_value_complex_t *)data_item->data_value.value; + *type = complex_value->type; + } else { + *type = data_item->data_value.type; + } + + return SUCCESS_RETURN; +} + +int dm_shw_get_event(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **event) +{ + int index = 0; + dm_shw_event_t *dtsl_event = NULL; + + if (shadow == NULL || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + for (index = 0; index < shadow->event_number; index++) { + dtsl_event = shadow->events + index; + if ((strlen(dtsl_event->identifier) == key_len) && + (memcmp(dtsl_event->identifier, key, key_len) == 0)) { + if (event) { + *event = (dm_shw_event_t *)dtsl_event; + } + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +int dm_shw_get_service(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **service) +{ + int index = 0; + dm_shw_service_t *dtsl_service = NULL; + + if (shadow == NULL || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + for (index = 0; index < shadow->event_number; index++) { + dtsl_service = shadow->services + index; + if ((strlen(dtsl_service->identifier) == key_len) && + (memcmp(dtsl_service->identifier, key, key_len) == 0)) { + if (service) { + *service = (dm_shw_service_t *)dtsl_service; + } + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +int dm_shw_get_property_number(_IN_ dm_shw_t *shadow, _OU_ int *number) +{ + if (shadow == NULL || number == NULL) { + return DM_INVALID_PARAMETER; + } + + *number = shadow->property_number; + + return SUCCESS_RETURN; +} + +int dm_shw_get_service_number(_IN_ dm_shw_t *shadow, _OU_ int *number) +{ + if (shadow == NULL || number == NULL) { + return DM_INVALID_PARAMETER; + } + + *number = shadow->service_number; + + return SUCCESS_RETURN; +} + +int dm_shw_get_event_number(_IN_ dm_shw_t *shadow, _OU_ int *number) +{ + if (shadow == NULL || number == NULL) { + return DM_INVALID_PARAMETER; + } + + *number = shadow->event_number; + + return SUCCESS_RETURN; +} + +int dm_shw_get_property_by_index(_IN_ dm_shw_t *shadow, _IN_ int index, _OU_ void **property) +{ + if (shadow == NULL || index < 0 || index >= shadow->property_number || + property == NULL || *property != NULL) { + return DM_INVALID_PARAMETER; + } + + *property = (void *)(shadow->properties + index); + + return SUCCESS_RETURN; +} + +int dm_shw_get_service_by_index(_IN_ dm_shw_t *shadow, _IN_ int index, _OU_ void **service) +{ + if (shadow == NULL || index < 0 || index >= shadow->service_number || + service == NULL || *service != NULL) { + return DM_INVALID_PARAMETER; + } + + *service = (void *)(shadow->services + index); + + return SUCCESS_RETURN; +} + +int dm_shw_get_event_by_index(_IN_ dm_shw_t *shadow, _IN_ int index, _OU_ void **event) +{ + if (shadow == NULL || index < 0 || index >= shadow->event_number || + event == NULL || *event != NULL) { + return DM_INVALID_PARAMETER; + } + + *event = (void *)(shadow->events + index); + + return SUCCESS_RETURN; +} + +int dm_shw_get_service_by_identifier(_IN_ dm_shw_t *shadow, _IN_ char *identifier, _OU_ void **service) +{ + int index = 0; + dm_shw_service_t *search_service = NULL; + + if (shadow == NULL || identifier == NULL || + service == NULL || *service != NULL) { + return DM_INVALID_PARAMETER; + } + + for (index = 0; index < shadow->service_number; index++) { + search_service = shadow->services + index; + if ((strlen(search_service->identifier) == strlen(identifier)) && + (memcmp(search_service->identifier, identifier, strlen(identifier)) == 0)) { + *service = (void *)search_service; + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +int dm_shw_get_event_by_identifier(_IN_ dm_shw_t *shadow, _IN_ char *identifier, _OU_ void **event) +{ + int index = 0; + dm_shw_event_t *search_event = NULL; + + if (shadow == NULL || identifier == NULL || + event == NULL || *event != NULL) { + return DM_INVALID_PARAMETER; + } + + for (index = 0; index < shadow->event_number; index++) { + search_event = shadow->events + index; + if ((strlen(search_event->identifier) == strlen(identifier)) && + (memcmp(search_event->identifier, identifier, strlen(identifier)) == 0)) { + *event = (void *)search_event; + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +int dm_shw_get_property_identifier(_IN_ void *property, _OU_ char **identifier) +{ + dm_shw_data_t *property_item = (dm_shw_data_t *)property; + + if (property_item == NULL || identifier == NULL || *identifier != NULL) { + return DM_INVALID_PARAMETER; + } + + *identifier = property_item->identifier; + + return SUCCESS_RETURN; +} + +int dm_shw_get_service_method(_IN_ void *service, _OU_ char **method) +{ + int service_method_len = 0; + const char *service_method_fmt = "thing.service.%s"; + dm_shw_service_t *service_item = (dm_shw_service_t *)service; + + if (service_item == NULL || method == NULL || *method != NULL) { + return DM_INVALID_PARAMETER; + } + + service_method_len = (strlen(service_method_fmt) + strlen(service_item->identifier) + 1); + *method = DM_malloc(service_method_len); + if (*method == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*method, 0, service_method_len); + HAL_Snprintf(*method, service_method_len, service_method_fmt, service_item->identifier); + + return SUCCESS_RETURN; +} + +int dm_shw_get_event_method(_IN_ void *event, _OU_ char **method) +{ + int event_method_len = 0; + const char *post_identifier = "post"; + const char *property_identifier = "property"; + const char *identifier = NULL; + const char *event_method_fmt = "thing.event.%s.post"; + dm_shw_event_t *event_item = (dm_shw_event_t *)event; + + if (event_item == NULL || method == NULL || *method != NULL) { + return DM_INVALID_PARAMETER; + } + + /* God Damn It Special Case! */ + if ((strlen(event_item->identifier) == strlen(post_identifier)) && + (memcmp(event_item->identifier, post_identifier, strlen(post_identifier)) == 0)) { + identifier = property_identifier; + } else { + identifier = (const char *)event_item->identifier; + } + + event_method_len = (strlen(event_method_fmt) + strlen(identifier) + 1); + *method = DM_malloc(event_method_len); + if (*method == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*method, 0, event_method_len); + HAL_Snprintf(*method, event_method_len, event_method_fmt, identifier); + + return SUCCESS_RETURN; +} + +static int _dm_shw_int_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len) +{ + int int_set = (value == NULL) ? (0) : (*(int *)value); + + data_value->value_int = int_set; + dm_log_debug("Current Int Value Be Set(Int): %d", data_value->value_int); + + return SUCCESS_RETURN; +} + +static int _dm_shw_float_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len) +{ + float float_set = (value == NULL) ? (0) : (*(float *)value); + + data_value->value_float = float_set; + dm_log_debug("Current Float Value Be Set(Float): %f", data_value->value_float); + + return SUCCESS_RETURN; +} + +static int _dm_shw_double_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len) +{ + double double_set = (value == NULL) ? (0) : (*(double *)value); + + data_value->value_double = double_set; + dm_log_debug("Current Double Value Be Set(Double): %f", data_value->value_double); + + return SUCCESS_RETURN; +} + +static int _dm_shw_text_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len) +{ + int res = 0; + char *value_set = (value == NULL) ? ("NULL") : ((char *)value); + int value_set_len = (value == NULL) ? (strlen("NULL")) : (value_len); + + if (data_value->value) { + DM_free(data_value->value); + data_value->value = NULL; + } + res = dm_utils_copy(value_set, value_set_len, &data_value->value, value_set_len + 1); + if (res != SUCCESS_RETURN) { + return DM_MEMORY_NOT_ENOUGH; + } + dm_log_debug("Current Text Value Be Set(String): %s", data_value->value); + + return SUCCESS_RETURN; +} + +static int _dm_shw_enum_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len) +{ + int enum_set = (value == NULL) ? (0) : (*(int *)value); + + enum_set = (enum_set < 0) ? (0) : (enum_set); + + data_value->value_int = enum_set; + dm_log_debug("Current Enum Value Be Set(Enum): %d", data_value->value_int); + + return SUCCESS_RETURN; +} + +static int _dm_shw_date_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len) +{ + int res = 0; + char *value_set = (value == NULL) ? ("NULL") : ((char *)value); + int value_set_len = (value == NULL) ? (strlen("NULL")) : (value_len); + + if (data_value->value) { + DM_free(data_value->value); + data_value->value = NULL; + } + res = dm_utils_copy(value_set, value_set_len, &data_value->value, value_set_len + 1); + if (res != SUCCESS_RETURN) { + return DM_MEMORY_NOT_ENOUGH; + } + dm_log_debug("Current Date Value Be Set(String): %s", data_value->value); + + return SUCCESS_RETURN; +} + +static int _dm_shw_bool_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len) +{ + int int_set = (value == NULL) ? (0) : (*(int *)value); + + int_set = (int_set == 0) ? (int_set) : ((int_set == 1) ? (int_set) : (0)); + + data_value->value_int = int_set; + dm_log_debug("Current Bool Value Be Set(Bool): %d", data_value->value_int); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_int_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + int int_set = (value == NULL) ? (0) : (*(int *)value); + + *((int *)(complex_array->value) + index) = int_set; + dm_log_debug("Current Array Value Be Set(Int), Index: %d, Value: %d", index, *((int *)(complex_array->value) + index)); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_float_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + float float_set = (value == NULL) ? (0) : (*(float *)value); + + *((float *)(complex_array->value) + index) = float_set; + dm_log_debug("Current Array Value Be Set(Float), Index: %d, Value: %f", index, + *((float *)(complex_array->value) + index)); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_double_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + double double_set = (value == NULL) ? (0) : (*(double *)value); + + *((double *)(complex_array->value) + index) = double_set; + dm_log_debug("Current Array Value Be Set(Double), Index: %d, Value: %f", index, + *((double *)(complex_array->value) + index)); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_text_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index) +{ + int res = 0; + dm_shw_data_value_complex_t *complex_array = data_value->value; + char *text_set = (value == NULL) ? ("NULL") : ((char *)value); + int value_set_len = (value == NULL) ? (strlen("NULL")) : (value_len); + + if (*((char **)(complex_array->value) + index)) { + DM_free(*((char **)(complex_array->value) + index)); + *((char **)(complex_array->value) + index) = NULL; + } + + res = dm_utils_copy(text_set, value_set_len, (void **)((char **)(complex_array->value) + index), value_set_len + 1); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_debug("Current Array Value Be Set(Text String), Index: %d, Value: %s", index, + *((char **)(complex_array->value) + index)); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_enum_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + int int_set = (value == NULL) ? (0) : (*(int *)value); + + *((int *)(complex_array->value) + index) = int_set; + dm_log_debug("Current Array Value Be Set(Enum), Index: %d, Value: %d", index, *((int *)(complex_array->value) + index)); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_date_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index) +{ + int res = 0; + dm_shw_data_value_complex_t *complex_array = data_value->value; + char *text_set = (value == NULL) ? ("NULL") : ((char *)value); + int value_set_len = (value == NULL) ? (strlen("NULL")) : (value_len); + + if (*((char **)(complex_array->value) + index)) { + DM_free(*((char **)(complex_array->value) + index)); + *((char **)(complex_array->value) + index) = NULL; + } + + res = dm_utils_copy(text_set, value_set_len, (void **)((char **)(complex_array->value) + index), value_set_len + 1); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_debug("Current Array Value Be Set(Date String), Index: %d, Value: %s", index, + *((char **)(complex_array->value) + index)); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_bool_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + int int_set = (value == NULL) ? (0) : (*(int *)value); + + *((int *)(complex_array->value) + index) = int_set; + dm_log_debug("Current Array Value Be Set(Bool), Index: %d, Value: %d", index, *((int *)(complex_array->value) + index)); + + return SUCCESS_RETURN; +} + + +static int _dm_shw_data_array_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len, + _IN_ int index) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + + if (complex_array == NULL || index < 0 || index >= complex_array->size) { + return DM_INVALID_PARAMETER; + } + + if (g_iotx_data_type_mapping[complex_array->type].func_array_set == NULL) { + return FAIL_RETURN; + } + + return g_iotx_data_type_mapping[complex_array->type].func_array_set(data_value, value, value_len, index); +} + +static int _dm_shw_data_set(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int value_len) +{ + if (g_iotx_data_type_mapping[data_value->type].func_set == NULL) { + return FAIL_RETURN; + } + + return g_iotx_data_type_mapping[data_value->type].func_set(data_value, value, value_len); +} + +int dm_shw_set_property_value(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len) +{ + int res = 0, array_index = 0; + dm_shw_data_t *data = NULL; + + if (shadow == NULL || key == NULL || key_len <= 0) { + return FAIL_RETURN; + } + + dm_log_debug("Key:%d %s", key_len, key); + res = _dm_shw_property_search(shadow, key, key_len, &data, &array_index); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + if (data->data_value.type == DM_SHW_DATA_TYPE_ARRAY) { + dm_log_debug("Current Found Data Index: %d", array_index); + res = _dm_shw_data_array_set(&data->data_value, value, value_len, array_index); + if (res != SUCCESS_RETURN) { + return DM_TSL_PROPERTY_SET_FAILED; + } + } else { + res = _dm_shw_data_set(&data->data_value, value, value_len); + if (res != SUCCESS_RETURN) { + return DM_TSL_PROPERTY_SET_FAILED; + } + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_int_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value) +{ + *(int *)(value) = data_value->value_int; + return SUCCESS_RETURN; +} + +static int _dm_shw_float_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value) +{ + *(float *)(value) = data_value->value_float; + return SUCCESS_RETURN; +} + +static int _dm_shw_double_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value) +{ + *(double *)(value) = data_value->value_double; + return SUCCESS_RETURN; +} + +static int _dm_shw_text_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value) +{ + int res = 0; + + if (*(char **)value != NULL || data_value->value == NULL) { + return FAIL_RETURN; + } + + res = dm_utils_copy_direct(data_value->value, strlen(data_value->value), (void **)value, strlen(data_value->value) + 1); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_enum_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value) +{ + *(int *)(value) = data_value->value_int; + return SUCCESS_RETURN; +} + +static int _dm_shw_date_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value) +{ + int res = 0; + + if (*(char **)value != NULL || data_value->value == NULL) { + return FAIL_RETURN; + } + + res = dm_utils_copy_direct(data_value->value, strlen(data_value->value), (void **)value, strlen(data_value->value) + 1); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_bool_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value) +{ + *(int *)(value) = data_value->value_int; + return SUCCESS_RETURN; +} + +static int _dm_shw_array_int_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + + if (complex_array->value == NULL || ((int *)(complex_array->value) + index) == NULL) { + return DM_INVALID_PARAMETER; + } + + *((int *)value) = *((int *)(complex_array->value) + index); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_float_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + + if (complex_array->value == NULL || ((float *)(complex_array->value) + index) == NULL) { + return DM_INVALID_PARAMETER; + } + + *((float *)value) = *((float *)(complex_array->value) + index); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_double_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + + if (complex_array->value == NULL || ((double *)(complex_array->value) + index) == NULL) { + return DM_INVALID_PARAMETER; + } + + *((double *)value) = *((double *)(complex_array->value) + index); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_text_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index) +{ + int res = 0; + dm_shw_data_value_complex_t *complex_array = data_value->value; + + if (complex_array->value == NULL || *((char **)(complex_array->value) + index) == NULL || *(char **)value != NULL) { + return DM_INVALID_PARAMETER; + } + + res = dm_utils_copy_direct(*((char **)(complex_array->value) + index), + strlen(*((char **)(complex_array->value) + index)), + (void **)value, strlen(*((char **)(complex_array->value) + index)) + 1); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_enum_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + + if (complex_array->value == NULL || ((int *)(complex_array->value) + index) == NULL) { + return DM_INVALID_PARAMETER; + } + + *((int *)value) = *((int *)(complex_array->value) + index); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_date_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index) +{ + int res = 0; + dm_shw_data_value_complex_t *complex_array = data_value->value; + + if (complex_array->value == NULL || *((char **)(complex_array->value) + index) == NULL || *(char **)value != NULL) { + return DM_INVALID_PARAMETER; + } + + res = dm_utils_copy_direct(*((char **)(complex_array->value) + index), + strlen(*((char **)(complex_array->value) + index)), + (void **)value, strlen(*((char **)(complex_array->value) + index)) + 1); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_bool_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + + if (complex_array->value == NULL || ((int *)(complex_array->value) + index) == NULL) { + return DM_INVALID_PARAMETER; + } + + *((int *)value) = *((int *)(complex_array->value) + index); + + return SUCCESS_RETURN; +} + +static int _dm_shw_data_array_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value, _IN_ int index) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + + if (complex_array == NULL || index < 0 || index >= complex_array->size) { + return FAIL_RETURN; + } + + if (g_iotx_data_type_mapping[complex_array->type].func_array_get == NULL) { + return FAIL_RETURN; + } + + return g_iotx_data_type_mapping[complex_array->type].func_array_get(data_value, value, index); +} + +static int _dm_shw_data_get(_IN_ dm_shw_data_value_t *data_value, _IN_ void *value) +{ + if (g_iotx_data_type_mapping[data_value->type].func_get == NULL) { + return FAIL_RETURN; + } + + return g_iotx_data_type_mapping[data_value->type].func_get(data_value, value); +} + +int dm_shw_get_property_value(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _OU_ void *value) +{ + int res = 0, array_index = 0; + dm_shw_data_t *data = NULL; + + if (shadow == NULL || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = _dm_shw_property_search(shadow, key, key_len, &data, &array_index); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_debug("Current Found Data: %s", data->identifier); + if (data->data_value.type == DM_SHW_DATA_TYPE_ARRAY) { + dm_log_debug("Current Found Data Index: %d", array_index); + res = _dm_shw_data_array_get(&data->data_value, value, array_index); + if (res != SUCCESS_RETURN) { + return DM_TSL_PROPERTY_GET_FAILED; + } + } else { + res = _dm_shw_data_get(&data->data_value, value); + if (res != SUCCESS_RETURN) { + return DM_TSL_PROPERTY_GET_FAILED; + } + } + + return SUCCESS_RETURN; +} + +int dm_shw_set_event_output_value(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len) +{ + int res = 0, array_index = 0; + int offset = 0; + char *pos = NULL; + dm_shw_event_t *event = NULL; + dm_shw_data_t *event_data = NULL; + + if (shadow == NULL || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = dm_utils_memtok(key, key_len, DM_SHW_KEY_DELIMITER, 1, &offset); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_debug("Key: %.*s", key_len, key); + + res = _dm_shw_event_search(shadow, key, offset, &event); + if (res != SUCCESS_RETURN) { + return DM_TSL_EVENT_NOT_EXIST; + } + + pos = key + offset + 1; + /* dm_log_debug("TSL Event Output Data Search, Event Data ID: %s",pos); */ + + res = _dm_shw_event_output_search(event->output_datas, event->output_data_number, pos, strlen(pos), &event_data, + &array_index); + if (res != SUCCESS_RETURN) { + return DM_TSL_EVENT_NOT_EXIST; + } + + if (event_data->data_value.type == DM_SHW_DATA_TYPE_ARRAY) { + res = _dm_shw_data_array_set(&event_data->data_value, value, value_len, array_index); + if (res != SUCCESS_RETURN) { + return DM_TSL_EVENT_SET_FAILED; + } + } else { + res = _dm_shw_data_set(&event_data->data_value, value, value_len); + if (res != SUCCESS_RETURN) { + return DM_TSL_EVENT_SET_FAILED; + } + } + + return SUCCESS_RETURN; +} + +int dm_shw_get_event_output_value(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _IN_ void *value) +{ + int res = 0; + int offset = 0, array_index = 0; + char *pos = NULL; + dm_shw_event_t *event = NULL; + dm_shw_data_t *event_data = NULL; + + if (shadow == NULL || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = dm_utils_memtok(key, key_len, DM_SHW_KEY_DELIMITER, 1, &offset); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_debug("Key: %.*s", key_len, key); + + res = _dm_shw_event_search(shadow, key, offset, &event); + if (res != SUCCESS_RETURN) { + return DM_TSL_EVENT_NOT_EXIST; + } + + pos = key + offset + 1; + dm_log_debug("TSL Event Output Data Search, Event Data ID: %s", pos); + + res = _dm_shw_event_output_search(event->output_datas, event->output_data_number, pos, strlen(pos), &event_data, + &array_index); + if (res != SUCCESS_RETURN) { + return DM_TSL_EVENT_NOT_EXIST; + } + + if (event_data->data_value.type == DM_SHW_DATA_TYPE_ARRAY) { + res = _dm_shw_data_array_get(&event_data->data_value, value, array_index); + if (res != SUCCESS_RETURN) { + return DM_TSL_EVENT_GET_FAILED; + } + } else { + res = _dm_shw_data_get(&event_data->data_value, value); + if (res != SUCCESS_RETURN) { + return DM_TSL_EVENT_GET_FAILED; + } + } + + return SUCCESS_RETURN; +} + +int dm_shw_set_service_input_output_value(_IN_ dm_shw_data_target_e type, _IN_ dm_shw_t *shadow, _IN_ char *key, + _IN_ int key_len, _IN_ void *value, _IN_ int value_len) +{ + int res = 0, array_index = 0; + int offset = 0; + char *pos = NULL; + dm_shw_service_t *service = NULL; + dm_shw_data_t *service_data = NULL; + + if (type < DM_SHW_DATA_TARGET_SERVICE_INPUT_DATA || type > DM_SHW_DATA_TARGET_SERVICE_OUTPUT_DATA || shadow == NULL + || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = dm_utils_memtok(key, key_len, DM_SHW_KEY_DELIMITER, 1, &offset); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_debug("Key: %.*s", key_len, key); + + res = _dm_shw_service_search(shadow, key, offset, &service); + if (res != SUCCESS_RETURN) { + return DM_TSL_SERVICE_NOT_EXIST; + } + + pos = key + offset + 1; + dm_log_debug("TSL Service Input/Output Data Search, Event Data ID: %s", pos); + + res = _dm_shw_service_input_output_search(type, service, pos, strlen(pos), &service_data, &array_index); + if (res != SUCCESS_RETURN) { + return DM_TSL_SERVICE_NOT_EXIST; + } + + if (service_data->data_value.type == DM_SHW_DATA_TYPE_ARRAY) { + res = _dm_shw_data_array_set(&service_data->data_value, value, value_len, array_index); + if (res != SUCCESS_RETURN) { + return DM_TSL_SERVICE_SET_FAILED; + } + } else { + res = _dm_shw_data_set(&service_data->data_value, value, value_len); + if (res != SUCCESS_RETURN) { + return DM_TSL_SERVICE_SET_FAILED; + } + } + + return SUCCESS_RETURN; +} + +int dm_shw_get_service_input_output_value(_IN_ dm_shw_data_target_e type, _IN_ dm_shw_t *shadow, _IN_ char *key, + _IN_ int key_len, _IN_ void *value) +{ + int res = 0; + int offset = 0, array_index = 0; + char *pos = NULL; + dm_shw_service_t *service = NULL; + dm_shw_data_t *service_data = NULL; + + if (shadow == NULL || key == NULL || key_len <= 0) { + return DM_INVALID_PARAMETER; + } + + res = dm_utils_memtok(key, key_len, DM_SHW_KEY_DELIMITER, 1, &offset); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_debug("key: %.*s", key_len, key); + + res = _dm_shw_service_search(shadow, key, offset, &service); + if (res != SUCCESS_RETURN) { + return DM_TSL_SERVICE_NOT_EXIST; + } + + pos = key + offset + 1; + dm_log_debug("TSL Service Input/Output Data Search, Event Data ID: %s", pos); + + res = _dm_shw_service_input_output_search(type, service, pos, strlen(pos), &service_data, &array_index); + if (res != SUCCESS_RETURN) { + return DM_TSL_SERVICE_NOT_EXIST; + } + + if (service_data->data_value.type == DM_SHW_DATA_TYPE_ARRAY) { + res = _dm_shw_data_array_get(&service_data->data_value, value, array_index); + if (res != SUCCESS_RETURN) { + return DM_TSL_SERVICE_GET_FAILED; + } + } else { + res = _dm_shw_data_get(&service_data->data_value, value); + if (res != SUCCESS_RETURN) { + return DM_TSL_SERVICE_GET_FAILED; + } + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_int_insert_json_item(_IN_ dm_shw_data_t *data, _IN_ lite_cjson_item_t *lite) +{ + lite_cjson_add_number_to_object(lite, data->identifier, data->data_value.value_int); + + return SUCCESS_RETURN; +} + +static int _dm_shw_float_insert_json_item(_IN_ dm_shw_data_t *data, _IN_ lite_cjson_item_t *lite) +{ + lite_cjson_add_number_to_object(lite, data->identifier, data->data_value.value_float); + + return SUCCESS_RETURN; +} + +static int _dm_shw_double_insert_json_item(_IN_ dm_shw_data_t *data, _IN_ lite_cjson_item_t *lite) +{ + lite_cjson_add_number_to_object(lite, data->identifier, data->data_value.value_double); + + return SUCCESS_RETURN; +} + +static int _dm_shw_string_insert_json_item(_IN_ dm_shw_data_t *data, _IN_ lite_cjson_item_t *lite) +{ + char *value = (data->data_value.value == NULL) ? ("") : (data->data_value.value); + lite_cjson_add_string_to_object(lite, data->identifier, value); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_insert_json_item(_IN_ dm_shw_data_t *data, _IN_ lite_cjson_item_t *lite); +static int _dm_shw_struct_insert_json_item(_IN_ dm_shw_data_t *data, _IN_ lite_cjson_item_t *lite); +static int _dm_shw_data_insert_json_item(_IN_ dm_shw_data_t *data, _IN_ lite_cjson_item_t *lite); + +static int _dm_shw_array_insert_json_item(_IN_ dm_shw_data_t *data, _IN_ lite_cjson_item_t *lite) +{ + int res = SUCCESS_RETURN, index = 0; + lite_cjson_item_t *array = NULL, *array_item = NULL; + dm_shw_data_value_complex_t *complex_array = NULL; + + if (data == NULL || lite == NULL) { + return DM_INVALID_PARAMETER; + } + + complex_array = data->data_value.value; + + if (lite->type == cJSON_Array) { + array = lite_cjson_create_object(); + if (array == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + } + + array_item = lite_cjson_create_array(); + if (array_item == NULL) { + if (array) { + lite_cjson_delete(array); + } + return DM_MEMORY_NOT_ENOUGH; + } + + switch (complex_array->type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_BOOL: + case DM_SHW_DATA_TYPE_ENUM: { + int value = 0; + for (index = 0; index < complex_array->size; index++) { + value = *((int *)(complex_array->value) + index); + lite_cjson_add_item_to_array(array_item, lite_cjson_create_number((double)value)); + } + if (lite->type == cJSON_Array) { + lite_cjson_add_item_to_object(array, data->identifier, array_item); + lite_cjson_add_item_to_array(lite, array); + } else { + lite_cjson_add_item_to_object(lite, data->identifier, array_item); + lite_cjson_delete(array); + } + } + break; + case DM_SHW_DATA_TYPE_FLOAT: { + float value = 0; + for (index = 0; index < complex_array->size; index++) { + value = *((float *)(complex_array->value) + index); + lite_cjson_add_item_to_array(array_item, lite_cjson_create_number((double)value)); + } + if (lite->type == cJSON_Array) { + lite_cjson_add_item_to_object(array, data->identifier, array_item); + lite_cjson_add_item_to_array(lite, array); + } else { + lite_cjson_add_item_to_object(lite, data->identifier, array_item); + lite_cjson_delete(array); + } + } + break; + case DM_SHW_DATA_TYPE_DOUBLE: { + double value = 0; + for (index = 0; index < complex_array->size; index++) { + value = *((double *)(complex_array->value) + index); + lite_cjson_add_item_to_array(array_item, lite_cjson_create_number(value)); + } + if (lite->type == cJSON_Array) { + lite_cjson_add_item_to_object(array, data->identifier, array_item); + lite_cjson_add_item_to_array(lite, array); + } else { + lite_cjson_add_item_to_object(lite, data->identifier, array_item); + lite_cjson_delete(array); + } + } + break; + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_DATE: { + char *value = NULL; + for (index = 0; index < complex_array->size; index++) { + value = *((char **)(complex_array->value) + index); + value = (value == NULL) ? ("") : (value); + lite_cjson_add_item_to_array(array_item, lite_cjson_create_string((const char *)value)); + } + if (lite->type == cJSON_Array) { + lite_cjson_add_item_to_object(array, data->identifier, array_item); + lite_cjson_add_item_to_array(lite, array); + } else { + lite_cjson_add_item_to_object(lite, data->identifier, array_item); + lite_cjson_delete(array); + } + } + break; + case DM_SHW_DATA_TYPE_ARRAY: { + /* TODO */ + } + break; + case DM_SHW_DATA_TYPE_STRUCT: { + dm_shw_data_t *array_data = NULL; + for (index = 0; index < complex_array->size; index++) { + array_data = (dm_shw_data_t *)(complex_array->value) + index; + if (array_data) { + _dm_shw_struct_insert_json_item(array_data, array_item); + } + } + + if (lite->type == cJSON_Array) { + lite_cjson_add_item_to_object(array, data->identifier, array_item); + lite_cjson_add_item_to_array(lite, array); + } else { + lite_cjson_add_item_to_object(lite, data->identifier, array_item); + lite_cjson_delete(array); + } + } + break; + default: { + lite_cjson_delete(array_item); + lite_cjson_delete(array); + } + break; + } + + return res; +} + +static int _dm_shw_struct_insert_json_item(_IN_ dm_shw_data_t *data, _IN_ lite_cjson_item_t *lite) +{ + int res = 0, index = 0; + lite_cjson_item_t *lite_object = NULL, *lite_item = NULL; + dm_shw_data_t *current_data = NULL; + dm_shw_data_value_complex_t *complex_struct = NULL; + + if (data == NULL || lite == NULL) { + return DM_INVALID_PARAMETER; + } + + if (lite->type == cJSON_Array) { + lite_object = lite_cjson_create_object(); + if (lite_object == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + } + + lite_item = lite_cjson_create_object(); + if (lite_item == NULL) { + lite_cjson_delete(lite_object); + return DM_MEMORY_NOT_ENOUGH; + } + + complex_struct = data->data_value.value; + + for (index = 0; index < complex_struct->size; index++) { + current_data = (dm_shw_data_t *)complex_struct->value + index; + _dm_shw_data_insert_json_item(current_data, lite_item); + } + if (lite->type == cJSON_Array) { + if (data->identifier) { + lite_cjson_add_item_to_object(lite_object, data->identifier, lite_item); + lite_cjson_add_item_to_array(lite, lite_object); + } else { + lite_cjson_add_item_to_array(lite, lite_item); + lite_cjson_delete(lite_object); + } + } else { + if (data->identifier) { + lite_cjson_add_item_to_object(lite, data->identifier, lite_item); + lite_cjson_delete(lite_object); + } else { + res = FAIL_RETURN; + lite_cjson_delete(lite_item); + lite_cjson_delete(lite_object); + } + } + + return res; +} + +static int _dm_shw_data_insert_json_item(_IN_ dm_shw_data_t *data, _IN_ lite_cjson_item_t *lite) +{ + int res = 0; + lite_cjson_item_t *data_object = NULL; + + if (data == NULL || lite == NULL) { + return DM_INVALID_PARAMETER; + } + + if (lite->type == cJSON_Array) { + data_object = lite_cjson_create_object(); + if (data_object == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + } + + switch (data->data_value.type) { + case DM_SHW_DATA_TYPE_INT: + case DM_SHW_DATA_TYPE_BOOL: + case DM_SHW_DATA_TYPE_ENUM: { + if (lite->type == cJSON_Array) { + res = _dm_shw_int_insert_json_item(data, data_object); + if (res == SUCCESS_RETURN) { + lite_cjson_add_item_to_array(lite, data_object); + } + } else { + res = _dm_shw_int_insert_json_item(data, lite); + lite_cjson_delete(data_object); + } + } + break; + case DM_SHW_DATA_TYPE_FLOAT: { + if (lite->type == cJSON_Array) { + res = _dm_shw_float_insert_json_item(data, data_object); + if (res == SUCCESS_RETURN) { + lite_cjson_add_item_to_array(lite, data_object); + } + } else { + res = _dm_shw_float_insert_json_item(data, lite); + lite_cjson_delete(data_object); + } + } + break; + case DM_SHW_DATA_TYPE_DOUBLE: { + if (lite->type == cJSON_Array) { + res = _dm_shw_double_insert_json_item(data, data_object); + if (res == SUCCESS_RETURN) { + lite_cjson_add_item_to_array(lite, data_object); + } + } else { + res = _dm_shw_double_insert_json_item(data, lite); + lite_cjson_delete(data_object); + } + } + break; + case DM_SHW_DATA_TYPE_TEXT: + case DM_SHW_DATA_TYPE_DATE: { + if (lite->type == cJSON_Array) { + res = _dm_shw_string_insert_json_item(data, data_object); + if (res == SUCCESS_RETURN) { + lite_cjson_add_item_to_array(lite, data_object); + } + } else { + res = _dm_shw_string_insert_json_item(data, lite); + lite_cjson_delete(data_object); + } + } + break; + case DM_SHW_DATA_TYPE_ARRAY: { + /* dm_log_debug("DM_SHW_DATA_TYPE_ARRAY"); */ + if (lite->type == cJSON_Array) { + res = _dm_shw_array_insert_json_item(data, data_object); + if (res == SUCCESS_RETURN) { + lite_cjson_add_item_to_array(lite, data_object); + } + } else { + res = _dm_shw_array_insert_json_item(data, lite); + lite_cjson_delete(data_object); + } + } + break; + case DM_SHW_DATA_TYPE_STRUCT: { + /* dm_log_debug("DM_SHW_DATA_TYPE_STRUCT"); */ + if (lite->type == cJSON_Array) { + res = _dm_shw_struct_insert_json_item(data, data_object); + if (res == SUCCESS_RETURN) { + lite_cjson_add_item_to_array(lite, data_object); + } + } else { + res = _dm_shw_struct_insert_json_item(data, lite); + lite_cjson_delete(data_object); + } + } + break; + default: + lite_cjson_delete(data_object); + res = FAIL_RETURN; + break; + } + + return res; +} + +int dm_shw_assemble_property(_IN_ dm_shw_t *shadow, _IN_ char *identifier, _IN_ int identifier_len, + _IN_ lite_cjson_item_t *lite) +{ + int res = 0, index = 0; + dm_shw_data_t *property = NULL; + + if (shadow == NULL || identifier == NULL || identifier_len <= 0 || lite == NULL || lite->type != cJSON_Object) { + return DM_INVALID_PARAMETER; + } + + for (index = 0; index < shadow->property_number; index++) { + property = shadow->properties + index; + if ((strlen(property->identifier) == identifier_len) && + (memcmp(property->identifier, identifier, identifier_len) == 0)) { + /* dm_log_debug("Property Found: %.*s",identifier_len,identifier); */ + break; + } + } + + if (index == shadow->property_number) { + dm_log_debug("Property Not Found: %.*s", identifier_len, identifier); + return FAIL_RETURN; + } + + res = _dm_shw_data_insert_json_item(property, lite); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_shw_assemble_event_output(_IN_ dm_shw_t *shadow, _IN_ char *identifier, _IN_ int identifier_len, + _IN_ lite_cjson_item_t *lite) +{ + int res = 0, index = 0; + dm_shw_data_t *event_outputdata = NULL; + dm_shw_event_t *event = NULL; + + if (shadow == NULL || identifier == NULL || identifier_len <= 0 || lite == NULL || lite->type != cJSON_Object) { + return DM_INVALID_PARAMETER; + } + + for (index = 0; index < shadow->event_number; index++) { + event = shadow->events + index; + if ((strlen(event->identifier) == identifier_len) && + (memcmp(event->identifier, identifier, identifier_len) == 0)) { + /* dm_log_debug("Event Found: %.*s",identifier_len,identifier); */ + break; + } + } + + if (index == shadow->event_number) { + dm_log_debug("Event Not Found: %.*s", identifier_len, identifier); + return FAIL_RETURN; + } + + for (index = 0; index < event->output_data_number; index++) { + event_outputdata = event->output_datas + index; + + res = _dm_shw_data_insert_json_item(event_outputdata, lite); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + } + + return SUCCESS_RETURN; +} + +int dm_shw_assemble_service_output(_IN_ dm_shw_t *shadow, _IN_ char *identifier, _IN_ int identifier_len, + _IN_ lite_cjson_item_t *lite) +{ + int res = 0, index = 0; + dm_shw_data_t *service_outputdata = NULL; + dm_shw_service_t *service = NULL; + + if (shadow == NULL || identifier == NULL || identifier_len <= 0 || lite == NULL || lite->type != cJSON_Object) { + return DM_INVALID_PARAMETER; + } + + for (index = 0; index < shadow->service_number; index++) { + service = shadow->services + index; + if ((strlen(service->identifier) == identifier_len) && + (memcmp(service->identifier, identifier, identifier_len) == 0)) { + /* dm_log_debug("Service Found: %.*s",identifier_len,identifier); */ + break; + } + } + + if (index == shadow->service_number) { + dm_log_debug("Service Not Found: %.*s", identifier_len, identifier); + return FAIL_RETURN; + } + + for (index = 0; index < service->output_data_number; index++) { + service_outputdata = service->output_datas + index; + + res = _dm_shw_data_insert_json_item(service_outputdata, lite); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + } + + return SUCCESS_RETURN; +} + +static void _dm_shw_int_free(_IN_ dm_shw_data_value_t *data_value) +{ + /* Free Value */ + /* if (data_value->value) {DM_free(data_value->value);data_value->value = NULL;} */ +} + +static void _dm_shw_float_free(_IN_ dm_shw_data_value_t *data_value) +{ + /* Free Value */ + /* if (data_value->value) {DM_free(data_value->value);data_value->value = NULL;} */ +} + +static void _dm_shw_double_free(_IN_ dm_shw_data_value_t *data_value) +{ + /* Free Value */ + /* if (data_value->value) {DM_free(data_value->value);data_value->value = NULL;} */ +} + +static void _dm_shw_text_free(_IN_ dm_shw_data_value_t *data_value) +{ + /* Free Value */ + if (data_value->value) { + DM_free(data_value->value); + data_value->value = NULL; + } +} + +static void _dm_shw_enum_free(_IN_ dm_shw_data_value_t *data_value) +{ + /* Free Value */ + /* if (data_value->value) {DM_free(data_value->value);data_value->value = NULL;} */ +} + +static void _dm_shw_date_free(_IN_ dm_shw_data_value_t *data_value) +{ + /* Free Value */ + if (data_value->value) { + DM_free(data_value->value); + data_value->value = NULL; + } +} + +static void _dm_shw_bool_free(_IN_ dm_shw_data_value_t *data_value) +{ + /* Free Value */ + /* if (data_value->value) {DM_free(data_value->value);data_value->value = NULL;} */ +} + +static void _dm_shw_array_int_free(_IN_ dm_shw_data_value_t *data_value) +{ + +} + +static void _dm_shw_array_float_free(_IN_ dm_shw_data_value_t *data_value) +{ + +} + +static void _dm_shw_array_double_free(_IN_ dm_shw_data_value_t *data_value) +{ + +} + +static void _dm_shw_array_text_free(_IN_ dm_shw_data_value_t *data_value) +{ + int index = 0; + dm_shw_data_value_complex_t *complex_array = data_value->value; + + /* Free Value */ + if (complex_array) { + for (index = 0; index < complex_array->size; index++) { + if (*((char **)(complex_array->value) + index)) { + DM_free(*((char **)(complex_array->value) + index)); + *((char **)(complex_array->value) + index) = NULL; + } + } + } +} + +static void _dm_shw_array_enum_free(_IN_ dm_shw_data_value_t *data_value) +{ + +} + +static void _dm_shw_array_date_free(_IN_ dm_shw_data_value_t *data_value) +{ + int index = 0; + dm_shw_data_value_complex_t *complex_array = data_value->value; + + /* Free Value */ + if (complex_array) { + for (index = 0; index < complex_array->size; index++) { + if (*((char **)(complex_array->value) + index)) { + DM_free(*((char **)(complex_array->value) + index)); + *((char **)(complex_array->value) + index) = NULL; + } + } + } +} + +static void _dm_shw_array_bool_free(_IN_ dm_shw_data_value_t *data_value) +{ + +} + +static void _dm_shw_array_array_free(_IN_ dm_shw_data_value_t *data_value) +{ + +} + +static void _dm_shw_array_struct_free(_IN_ dm_shw_data_value_t *data_value) +{ + int index = 0; + dm_shw_data_t *data = NULL; + + dm_shw_data_value_complex_t *complex_struct = (dm_shw_data_value_complex_t *)data_value->value; + + if (complex_struct) { + for (index = 0; index < complex_struct->size; index++) { + data = (dm_shw_data_t *)complex_struct->value + index; + _dm_shw_property_free(data); + } + } +} + +static void _dm_shw_array_free(_IN_ dm_shw_data_value_t *data_value) +{ + dm_shw_data_value_complex_t *complex_array = data_value->value; + + /* Free Value */ + if (complex_array) { + /* dm_log_err("complex_array->type: %d",complex_array->type); */ + if (g_iotx_data_type_mapping[complex_array->type].func_array_free != NULL) { + g_iotx_data_type_mapping[complex_array->type].func_array_free(data_value); + } + if (complex_array->value) { + DM_free(complex_array->value); + } + DM_free(complex_array); + data_value->value = NULL; + } +} + +static void _dm_shw_struct_free(_IN_ dm_shw_data_value_t *data_value) +{ + int index = 0; + dm_shw_data_t *property = NULL; + dm_shw_data_value_complex_t *complex_array = data_value->value; + + /* Free Value */ + if (complex_array) { + for (index = 0; index < complex_array->size; index++) { + property = (dm_shw_data_t *)(complex_array->value) + index; + _dm_shw_property_free(property); + } + if (complex_array->value) { + DM_free(complex_array->value); + } + DM_free(complex_array); + data_value->value = NULL; + } +} + +static void _dm_shw_data_free(dm_shw_data_value_t *data_value) +{ + if (g_iotx_data_type_mapping[data_value->type].func_free == NULL) { + return; + } + g_iotx_data_type_mapping[data_value->type].func_free(data_value); +} + +static void _dm_shw_property_free(_IN_ dm_shw_data_t *property) +{ + if (property->identifier) { + DM_free(property->identifier); + } + _dm_shw_data_free(&property->data_value); +} + +static void _dm_shw_properties_free(_IN_ dm_shw_data_t *properties, _IN_ int number) +{ + int index = 0; + dm_shw_data_t *property = NULL; + + for (index = 0; index < number; index++) { + property = properties + index; + _dm_shw_property_free(property); + } +} + +static void _dm_shw_event_outputdata_free(_IN_ dm_shw_data_t *outputdata) +{ + if (outputdata->identifier) { + DM_free(outputdata->identifier); + outputdata->identifier = NULL; + } + _dm_shw_data_free(&outputdata->data_value); +} + +static void _dm_shw_event_outputdatas_free(_IN_ dm_shw_data_t *outputdatas, _IN_ int number) +{ + int index = 0; + dm_shw_data_t *outputdata = NULL; + + for (index = 0; index < number; index++) { + outputdata = outputdatas + index; + _dm_shw_event_outputdata_free(outputdata); + } +} + +static void _dm_shw_event_free(_IN_ dm_shw_event_t *event) +{ + if (event->identifier) { + DM_free(event->identifier); + event->identifier = NULL; + } + if (event->output_datas) { + _dm_shw_event_outputdatas_free(event->output_datas, event->output_data_number); + DM_free(event->output_datas); + event->output_datas = NULL; + } +} + +static void _dm_shw_events_free(_IN_ dm_shw_event_t *events, _IN_ int number) +{ + int index = 0; + dm_shw_event_t *event = NULL; + + for (index = 0; index < number; index++) { + event = events + index; + _dm_shw_event_free(event); + } +} + +static void _dm_shw_service_outputdata_free(_IN_ dm_shw_data_t *outputdata) +{ + if (outputdata->identifier) { + DM_free(outputdata->identifier); + outputdata->identifier = NULL; + } + _dm_shw_data_free(&outputdata->data_value); +} + +static void _dm_shw_service_outputdatas_free(_IN_ dm_shw_data_t *outputdatas, _IN_ int number) +{ + int index = 0; + dm_shw_data_t *outputdata = NULL; + + for (index = 0; index < number; index++) { + outputdata = outputdatas + index; + _dm_shw_service_outputdata_free(outputdata); + } +} + +static void _dm_shw_service_inputdata_free(_IN_ dm_shw_data_t *inputdata) +{ + if (inputdata->identifier) { + DM_free(inputdata->identifier); + inputdata->identifier = NULL; + } + _dm_shw_data_free(&inputdata->data_value); +} + +static void _dm_shw_service_inputdatas_free(_IN_ dm_shw_data_t *inputdatas, _IN_ int number) +{ + int index = 0; + dm_shw_data_t *inputdata = NULL; + + for (index = 0; index < number; index++) { + inputdata = inputdatas + index; + _dm_shw_service_inputdata_free(inputdata); + } +} + +static void _dm_shw_service_free(_IN_ dm_shw_service_t *service) +{ + if (service->identifier) { + DM_free(service->identifier); + service->identifier = NULL; + } + if (service->output_datas) { + _dm_shw_service_outputdatas_free(service->output_datas, service->output_data_number); + DM_free(service->output_datas); + service->output_datas = NULL; + } + if (service->input_datas) { + _dm_shw_service_inputdatas_free(service->input_datas, service->input_data_number); + DM_free(service->input_datas); + service->input_datas = NULL; + } +} + +static void _dm_shw_services_free(_IN_ dm_shw_service_t *services, _IN_ int number) +{ + int index = 0; + dm_shw_service_t *service = NULL; + + for (index = 0; index < number; index++) { + service = services + index; + _dm_shw_service_free(service); + } +} + +void dm_shw_destroy(_IN_ dm_shw_t **shadow) +{ + if (shadow == NULL || *shadow == NULL) { + return; + } + + /* Free Properties */ + if ((*shadow)->properties) { + _dm_shw_properties_free((*shadow)->properties, (*shadow)->property_number); + DM_free((*shadow)->properties); + (*shadow)->properties = NULL; + } + + /* Free Events */ + if ((*shadow)->events) { + _dm_shw_events_free((*shadow)->events, (*shadow)->event_number); + DM_free((*shadow)->events); + (*shadow)->events = NULL; + } + + /* Free Services */ + if ((*shadow)->services) { + _dm_shw_services_free((*shadow)->services, (*shadow)->service_number); + DM_free((*shadow)->services); + (*shadow)->services = NULL; + } + + DM_free(*shadow); + *shadow = NULL; +} + +#if 0 +static void _dm_shw_int_print(_IN_ dm_shw_data_value_t *data_value) +{ + dm_log_debug("TSL Property Value : %d", data_value->value_int); +} + +static void _dm_shw_float_print(_IN_ dm_shw_data_value_t *data_value) +{ + dm_log_debug("TSL Property Value : %f", data_value->value_float); +} + +static void _dm_shw_double_print(_IN_ dm_shw_data_value_t *data_value) +{ + dm_log_debug("TSL Property Value : %f", data_value->value_double); +} + +static void _dm_shw_text_print(_IN_ dm_shw_data_value_t *data_value) +{ + dm_log_debug("TSL Property Value : %s", + ((char *)data_value->value == NULL) ? ("NULL") : ((char *)data_value->value)); +} + +static void _dm_shw_enum_print(_IN_ dm_shw_data_value_t *data_value) +{ + dm_log_debug("TSL Property Value : %d", data_value->value_int); +} + +static void _dm_shw_date_print(_IN_ dm_shw_data_value_t *data_value) +{ + dm_log_debug("TSL Property Value : %s", + ((char *)data_value->value == NULL) ? ("NULL") : ((char *)data_value->value)); +} + +static void _dm_shw_bool_print(_IN_ dm_shw_data_value_t *data_value) +{ + dm_log_debug("TSL Property Value : %d", data_value->value_int); +} + +static void _dm_shw_array_print(_IN_ dm_shw_data_value_t *data_value) +{ + int index = 0; + dm_shw_data_value_complex_t *complex_array = data_value->value; + + if (complex_array == NULL) { + dm_log_debug("TSL Property Complex Array Not Exist"); + return; + } + + dm_log_debug("TSL Property Size: %d", complex_array->size); + dm_log_debug("TSL Property Type: %s", g_iotx_data_type_mapping[complex_array->type].name); + + for (index = 0; index < complex_array->size; index++) { + dm_log_debug("TSL Property Array Value Index : %d", index); + switch (complex_array->type) { + case DM_SHW_DATA_TYPE_INT: { + dm_log_debug("TSL Property Value: %d", *((int *)(complex_array->value) + index)); + } + break; + case DM_SHW_DATA_TYPE_FLOAT: { + dm_log_debug("TSL Property Value: %f", *((float *)(complex_array->value) + index)); + } + break; + case DM_SHW_DATA_TYPE_DOUBLE: { + dm_log_debug("TSL Property Value: %f", *((double *)(complex_array->value) + index)); + } + break; + case DM_SHW_DATA_TYPE_TEXT: { + dm_log_debug("TSL Property Value: %s", + (*((char **)(complex_array->value) + index) == NULL) ? "NULL" : * ((char **)(data_value->value) + index)); + } + break; + default: + dm_log_err("Execute Should Not Be Here!"); + break; + } + } +} + +static void _dm_shw_struct_print(_IN_ dm_shw_data_value_t *data_value) +{ + int index = 0; + dm_shw_data_t *property = NULL; + dm_shw_data_value_complex_t *complex_array = data_value->value; + + dm_log_debug("TSL Property Struct Size: %d", complex_array->size); + if (complex_array->size == 0) { + return; + } + + for (index = 0; index < complex_array->size; index++) { + dm_log_debug("TSL Property Struct Index: %d", index); + property = (dm_shw_data_t *)complex_array->value + index; + _dm_shw_property_print(property); + dm_log_debug("\n"); + } +} + +static void _dm_shw_data_print(_IN_ dm_shw_data_value_t *data_value) +{ + dm_log_debug("TSL Property Type: %s", g_iotx_data_type_mapping[data_value->type].name); + + if (g_iotx_data_type_mapping[data_value->type].func_print == NULL) { + return; + } + g_iotx_data_type_mapping[data_value->type].func_print(data_value); +} + +static void _dm_shw_property_print(_IN_ dm_shw_data_t *property) +{ + dm_log_debug("TSL Property Identifier : %s", (property->identifier == NULL) ? ("NULL") : (property->identifier)); + _dm_shw_data_print(&property->data_value); +} + +static void _dm_shw_properties_print(_IN_ dm_shw_data_t *properties, _IN_ int number) +{ + int index = 0; + dm_shw_data_t *property = NULL; + + if (!properties) { + dm_log_debug("TSL Propertie Not Exist"); + } + + dm_log_debug("TSL Property Number: %d", number); + for (index = 0; index < number; index++) { + property = properties + index; + dm_log_debug("TSL Property Index : %d", index); + _dm_shw_property_print(property); + dm_log_debug("\n"); + } +} + +static void _dm_shw_event_outputdata_print(_IN_ dm_shw_data_t *outputdata) +{ + dm_log_debug("TSL Event Output Data Identifier : %s", + (outputdata->identifier == NULL) ? ("NULL") : (outputdata->identifier)); + _dm_shw_data_print(&outputdata->data_value); +} + +static void _dm_shw_event_outputdatas_print(_IN_ dm_shw_data_t *outputdatas, _IN_ int number) +{ + int index = 0; + dm_shw_data_t *outputdata = NULL; + + if (!outputdatas) { + dm_log_debug("TSL Event Output Data Not Exist"); + } + + dm_log_debug("TSL Event Output Data Number: %d", number); + for (index = 0; index < number; index++) { + outputdata = outputdatas + index; + dm_log_debug("TSL Event Output Data Index: %d", index); + _dm_shw_event_outputdata_print(outputdata); + dm_log_debug("\n"); + } +} + +static void _dm_shw_event_print(_IN_ dm_shw_event_t *event) +{ + dm_log_debug("TSL Event Identifier : %s", (event->identifier == NULL) ? ("NULL") : (event->identifier)); + _dm_shw_event_outputdatas_print(event->output_datas, event->output_data_number); +} + +static void _dm_shw_events_print(_IN_ dm_shw_event_t *events, _IN_ int number) +{ + int index = 0; + dm_shw_event_t *event = NULL; + if (!events) { + dm_log_debug("TSL Events: NULL"); + } + + dm_log_debug("TSL Event Number: %d", number); + for (index = 0; index < number; index++) { + event = events + index; + dm_log_debug("TSL Event Index : %d", index); + _dm_shw_event_print(event); + dm_log_debug("\n"); + } +} + +static void _dm_shw_service_outputdata_print(_IN_ dm_shw_data_t *outputdata) +{ + dm_log_debug("TSL Service Output Data Identifier : %s", + (outputdata->identifier == NULL) ? ("NULL") : (outputdata->identifier)); + _dm_shw_data_print(&outputdata->data_value); +} + +static void _dm_shw_service_outputdatas_print(_IN_ dm_shw_data_t *outputdatas, _IN_ int number) +{ + int index = 0; + dm_shw_data_t *outputdata = NULL; + + if (!outputdatas) { + dm_log_debug("TSL Service Output Data Not Exist"); + } + + dm_log_debug("TSL Service Output Data Number: %d", number); + for (index = 0; index < number; index++) { + outputdata = outputdatas + index; + dm_log_debug("TSL Service Output Data Index: %d", index); + _dm_shw_service_outputdata_print(outputdata); + dm_log_debug("\n"); + } +} + +static void _dm_shw_service_inputdata_get_print(_IN_ dm_shw_data_t *inputdata) +{ + dm_log_debug("TSL Service Input Data Identifier : %s", + (inputdata->identifier == NULL) ? ("NULL") : (inputdata->identifier)); +} + +static void _dm_shw_service_inputdata_print(_IN_ dm_shw_data_t *inputdata) +{ + dm_log_debug("TSL Service Input Data Identifier : %s", + (inputdata->identifier == NULL) ? ("NULL") : (inputdata->identifier)); + _dm_shw_data_print(&inputdata->data_value); +} + +static void _dm_shw_service_inputdatas_print(_IN_ dm_shw_service_t *service, _IN_ int number) +{ + int index = 0; + dm_shw_data_t *inputdata = NULL; + + if (!service->input_datas) { + dm_log_debug("TSL Service Output Data Not Exist"); + } + + dm_log_debug("TSL Service Output Data Number: %d", number); + for (index = 0; index < number; index++) { + inputdata = service->input_datas + index; + dm_log_debug("TSL Service Output Data Index: %d", index); + /* There Is A God-Damned Special Case For thing.service.property.get(method)/get(identifier) */ + if (strcmp(service->identifier, DM_SHW_SPECIAL_SERVICE_GET_IDENTIFIER) == 0) { + _dm_shw_service_inputdata_get_print(inputdata); + } else { + _dm_shw_service_inputdata_print(inputdata); + } + dm_log_debug("\n"); + } +} + +static void _dm_shw_service_print(_IN_ dm_shw_service_t *service) +{ + dm_log_debug("TSL Service Identifier : %s", (service->identifier == NULL) ? ("NULL") : (service->identifier)); + _dm_shw_service_outputdatas_print(service->output_datas, service->output_data_number); + _dm_shw_service_inputdatas_print(service, service->input_data_number); +} + +static void _dm_shw_services_print(_IN_ dm_shw_service_t *services, _IN_ int number) +{ + int index = 0; + dm_shw_service_t *service = NULL; + if (!services) { + dm_log_debug("TSL Serivces: NULL"); + } + + dm_log_debug("TSL Service Number: %d", number); + for (index = 0; index < number; index++) { + service = services + index; + dm_log_debug("TSL Service Index: %d", index); + _dm_shw_service_print(service); + dm_log_debug("\n"); + } +} + +void dm_shw_print(_IN_ dm_shw_t *shadow) +{ + dm_log_debug("TSL Profile, Product Key: %s, Device Name: %s", shadow->profile.product_key, shadow->profile.device_name); + _dm_shw_properties_print(shadow->properties, shadow->property_number); + _dm_shw_events_print(shadow->events, shadow->event_number); + _dm_shw_services_print(shadow->services, shadow->service_number); +} +#endif +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_shadow.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_shadow.h new file mode 100644 index 00000000..3320a8ff --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_shadow.h @@ -0,0 +1,533 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#if defined(DEPRECATED_LINKKIT) +#ifndef _DM_SHADOW_H_ +#define _DM_SHADOW_H_ + +#include "iotx_dm_internal.h" + +#define DM_SHW_KEY_SCHEMA "schema" +#define DM_SHW_KEY_LINK "link" +#define DM_SHW_KEY_PROFILE "profile" +#define DM_SHW_KEY_PROPERTIES "properties" +#define DM_SHW_KEY_EVENTS "events" +#define DM_SHW_KEY_SERVICES "services" + +#define DM_SHW_KEY_PROFILE_PK "productKey" +#define DM_SHW_KEY_PROFILE_DN "deviceName" +#define DM_SHW_KEY_IDENTIFIER "identifier" +#define DM_SHW_KEY_NAME "name" +#define DM_SHW_KEY_DESC "desc" +#define DM_SHW_KEY_ACCESS_MODE "accessMode" +#define DM_SHW_KEY_REQUIRED "required" +#define DM_SHW_KEY_METHOD "method" +#define DM_SHW_KEY_CALLTYPE "callType" +#define DM_SHW_KEY_OUTPUTDATA "outputData" +#define DM_SHW_KEY_INPUTDATA "inputData" +#define DM_SHW_KEY_DATATYPE "dataType" +#define DM_SHW_KEY_TYPE "type" +#define DM_SHW_KEY_SPECS "specs" +#define DM_SHW_KEY_UNIT "unit" +#define DM_SHW_KEY_UNITNAME "unitName" +#define DM_SHW_KEY_MIN "min" +#define DM_SHW_KEY_MAX "max" +#define DM_SHW_KEY_LENGTH "length" +#define DM_SHW_KEY_SIZE "size" +#define DM_SHW_KEY_ITEM "item" + +/* Special Service And Event */ +#define DM_SHW_SPECIAL_SERVICE_SET_IDENTIFIER "set" +#define DM_SHW_SPECIAL_SERVICE_SET_METHOD "thing.service.property.set" +#define DM_SHW_SPECIAL_SERVICE_GET_IDENTIFIER "get" +#define DM_SHW_SPECIAL_SERVICE_GET_METHOD "thing.service.property.get" +#define DM_SHW_SPECIAL_EVENT_POST_IDENTIFIER "post" +#define DM_SHW_SPECIAL_EVENT_POST_METHOD "thing.event.property.post" + +#define DM_SHW_KEY_DELIMITER '.' + +typedef enum { + DM_SHW_DATA_TYPE_NONE, /* none */ + DM_SHW_DATA_TYPE_INT, /* int */ + DM_SHW_DATA_TYPE_FLOAT, /* float */ + DM_SHW_DATA_TYPE_DOUBLE, /* double */ + DM_SHW_DATA_TYPE_TEXT, /* string */ + DM_SHW_DATA_TYPE_ENUM, /* int */ + DM_SHW_DATA_TYPE_DATE, /* string */ + DM_SHW_DATA_TYPE_BOOL, /* bool,0 or 1 */ + DM_SHW_DATA_TYPE_ARRAY, /* support int, float, double, text */ + DM_SHW_DATA_TYPE_STRUCT, /* support above 8 data types */ +} dm_shw_data_type_e; + +typedef enum { + DM_SHW_DATA_TARGET_SERVICE_INPUT_DATA, + DM_SHW_DATA_TARGET_SERVICE_OUTPUT_DATA +} dm_shw_data_target_e; + +typedef struct { + dm_shw_data_type_e type; + int size; + void *value; +} dm_shw_data_value_complex_t; + +typedef struct { + dm_shw_data_type_e type; + union { + int value_int; + float value_float; + double value_double; + void *value; /* string or complex type accroding to data type */ + }; +} dm_shw_data_value_t; + +typedef struct { + dm_shw_data_type_e type; + int specs_number; /* used when type is enum and struct */ + void *specs; /* nerver be used by struct */ +} dm_shw_data_type_t; + +typedef struct { + char *identifier; + dm_shw_data_value_t data_value; +} dm_shw_data_t; + +typedef struct { + char *identifier; + int input_data_number; /* input_data Number */ + dm_shw_data_t *input_datas; /* input_data array, type is dm_shw_data_t */ + int output_data_number; /* ouput_data Number */ + dm_shw_data_t *output_datas; /* output_data array, type is dm_shw_data_t */ +} dm_shw_event_t; + +typedef struct { + char *identifier; /* synchronized or asynchronized */ + int input_data_number; /* input_data_number */ + dm_shw_data_t *input_datas; /* input_data array, type is dm_shw_data_t */ + int output_data_number; /* ouput_data Number */ + dm_shw_data_t *output_datas; /* output_data array, type is dm_shw_data_t */ +} dm_shw_service_t; + +typedef struct { + int property_number; + dm_shw_data_t *properties; /* property array, type is dm_shw_data_t */ + int event_number; + dm_shw_event_t *events; /* event array, type is dm_shw_event_t */ + int service_number; + dm_shw_service_t *services; /* service array, type is dm_shw_service_t */ +} dm_shw_t; + +/** + * @brief Create TSL struct from TSL string. + * This function used to parse TSL string into TSL struct. + * + * @param tsl. The TSL string in JSON format. + * @param tsl_len. The length of tsl + * @param shadow. The pointer of TSL Struct pointer, will be malloc memory. + * This memory should be free by dm_shw_destroy. + * + * @return success or fail. + * + */ +int dm_shw_create(_IN_ iotx_dm_tsl_type_t type, _IN_ const char *tsl, _IN_ int tsl_len, _OU_ dm_shw_t **shadow); + +/** + * @brief Get property from TSL struct. + * This function used to get property from TSL struct. + * + * @param shadow. The pointer of TSL Struct. + * @param key. The property compound string, format decided by data type of property as follows: + * int,float,double,text,enum,date,bool type: property_id + * array type: property_id(array)[index] + * struct type: property_id(struct).property_id or property_id(struct).property_id[index] + * + * @param key_len. The length of key. + * @param property. The property in TSL Struct. + * + * @return success or fail. + * + */ +int dm_shw_get_property_data(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **data); + +int dm_shw_get_service_input_output_data(_IN_ dm_shw_data_target_e type, _IN_ dm_shw_t *shadow, _IN_ char *key, + _IN_ int key_len, _OU_ void **data); + +/** + * @brief Get event output data from TSL struct. + * This function used to get event output data from TSL struct. + * + * @param shadow. The pointer of TSL Struct. + * @param key. The property compound string, format decided by data type of property as follows: + * int,float,double,text,enum,date,bool type: property_id + * array type: property_id(array)[index] + * struct type: property_id(struct).property_id or property_id(struct).property_id[index] + * + * @param key_len. The length of key. + * @param property. The property in TSL Struct. + * + * @return success or fail. + * + */ +int dm_shw_get_event_output_data(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **data); + +/** + * @brief Get property type from TSL struct. + * This function used to get property type from TSL struct. + * + * @param property. The handle of property. + * @param type. The data type of property + * + * + * @return success or fail. + * + */ +int dm_shw_get_data_type(_IN_ void *data, _OU_ dm_shw_data_type_e *type); + +/** + * @brief Get event from TSL struct. + * This function used to get property from TSL struct. + * + * @param service. The handle of event. + * @param key. The property compound string, format decided by data type of property as follows: + * int,float,double,text,enum,date,bool type: event_id + * + * @param key_len. The length of key. + * @param property. The event in TSL Struct. + * + * @return success or fail. + * + */ +int dm_shw_get_event(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **event); + +/** + * @brief Get service from TSL struct. + * This function used to get property from TSL struct. + * + * @param shadow. The pointer of TSL Struct. + * @param key. The property compound string, format decided by data type of property as follows: + * int,float,double,text,enum,date,bool type: service_id + * + * @param key_len. The length of key. + * @param property. The service in TSL Struct. + * + * @return success or fail. + * + */ +int dm_shw_get_service(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **service); + +/** + * @brief Get property number from TSL struct. + * This function used to get property number from TSL struct. + * + * @param shadow. The pointer of TSL Struct. + * @param number. The property number in TSL Struct. + * + * @return success or fail. + * + */ +int dm_shw_get_property_number(_IN_ dm_shw_t *shadow, _OU_ int *number); + +/** + * @brief Get service number from TSL struct. + * This function used to get property number from TSL struct. + * + * @param shadow. The pointer of TSL Struct. + * @param number. The service number in TSL Struct. + * + * @return success or fail. + * + */ +int dm_shw_get_service_number(_IN_ dm_shw_t *shadow, _OU_ int *number); + +/** + * @brief Get event number from TSL struct. + * This function used to get property number from TSL struct. + * + * @param shadow. The pointer of TSL Struct. + * @param number. The event number in TSL Struct. + * + * @return success or fail. + * + */ +int dm_shw_get_event_number(_IN_ dm_shw_t *shadow, _OU_ int *number); + +/** + * @brief Get property reference from TSL struct by index. + * This function used to get property reference from TSL struct by index. + * + * @param shadow. The pointer of TSL Struct. + * @param index. The index of property + * @param property. The property reference in TSL Struct. + * + * @return success or fail. + * + */ +int dm_shw_get_property_by_index(_IN_ dm_shw_t *shadow, _IN_ int index, _OU_ void **property); + +/** + * @brief Get service reference from TSL struct by index. + * This function used to get service reference from TSL struct by index. + * + * @param shadow. The pointer of TSL Struct. + * @param index. The index of service + * @param service. The service reference in TSL Struct. + * + * @return success or fail. + * + */ +int dm_shw_get_service_by_index(_IN_ dm_shw_t *shadow, _IN_ int index, _OU_ void **service); + +/** + * @brief Get event reference from TSL struct by index. + * This function used to get event reference from TSL struct by index. + * + * @param shadow. The pointer of TSL Struct. + * @param index. The index of event + * @param event. The event reference in TSL Struct. + * + * @return success or fail. + * + */ +int dm_shw_get_event_by_index(_IN_ dm_shw_t *shadow, _IN_ int index, _OU_ void **event); + +/** + * @brief Get service reference from TSL struct by identifier. + * This function used to get service reference from TSL struct by identifier. + * + * @param shadow. The pointer of TSL Struct. + * @param identifier. The identifier of event + * @param service. The service reference in TSL Struct. + * + * @return success or fail. + * + */ +int dm_shw_get_service_by_identifier(_IN_ dm_shw_t *shadow, _IN_ char *identifier, _OU_ void **service); + +/** + * @brief Get event reference from TSL struct by identifier. + * This function used to get event reference from TSL struct by identifier. + * + * @param shadow. The pointer of TSL Struct. + * @param identifier. The identifier of event + * @param event. The event reference in TSL Struct. + * + * @return success or fail. + * + */ +int dm_shw_get_event_by_identifier(_IN_ dm_shw_t *shadow, _IN_ char *identifier, _OU_ void **event); + +/** + * @brief Get property identifier from TSL struct by service handle. + * This function used to get property identifier from TSL struct by service handle. + * + * @param service. The handle of property. + * @param method. The reference to property identifier in TSL Struct + * + * @return success or fail. + * + */ +int dm_shw_get_property_identifier(_IN_ void *property, _OU_ char **identifier); + +/** + * @brief Get service method from TSL struct by service handle. + * This function used to get service method from TSL struct by service handle. + * + * @param service. The handle of service. + * @param method. Generate method from service identifier + * + * @return success or fail. + * + */ +int dm_shw_get_service_method(_IN_ void *service, _OU_ char **method); + +/** + * @brief Get event method from TSL struct by event handle. + * This function used to get event method from TSL struct by event handle. + * + * @param service. The handle of event. + * @param method. Generate method from event identifier + * + * @return success or fail. + * + */ +int dm_shw_get_event_method(_IN_ void *event, _OU_ char **method); + +/** + * @brief Set Property Value Into TSL Struct. + * This function used to set property value into TSL Struct. + * + * @param tsl. The pointer of TSL Struct. + * @param key. The property compound string, format decided by data type of property as follows: + * int,float,double,text,enum,date,bool type: property_id + * array type: property_id(array)[index] + * struct type: property_id(struct).property_id or property_id(struct).property_id[index] + * + * @param key_len. The length of key + * @param value. The value to be set, data type decided by data type of property as follows: + * int: int*, float: float*, double: double*, + * text: char*, enum: int*, date: char*, bool: int* + * attention! value can be NULL to clear property value + * @param value_len. The length of value, only be used when type is text or data + * + * @return success or fail. + * + */ +int dm_shw_set_property_value(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len); + +/** + * @brief Get Property Value From TSL Struct. + * This function used to get property value from TSL Struct. + * + * @param tsl. The pointer of TSL Struct. + * @param key. The property compound string, format decided by data type of property as follows: + * int,float,double,text,enum,date,bool type: property_id + * array type: property_id(array)[index] + * struct type: property_id(struct).property_id or property_id(struct).property_id[index] + * + * @param key_len. The length of key + * @param value. The variable to store value, data type decided by data type of property as follows: + * int: int*, float: float*, double: double*, + * text: char**, enum: int*, date: char**, bool: int* + * attention! value can not be NULL + * + * @warning if data type is text or date, *value well be end with '\0'. + * the memory allocated to *value must be free by user. + * + * @return success or fail. + * + */ +int dm_shw_get_property_value(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _OU_ void *value); + +/** + * @brief Set event output value into TSL struct. + * This function used to set event output value into TSL struct. + * + * @param tsl. The pointer of TSL Struct. + * @param key. The property compound string, format decided by data type of property as follows: + * int,float,double,text,enum,date,bool type: event_id.event_data_id + * array type: event_id.event_data_id(array)[index] + * struct type: event_id.event_data_id(struct).property_id + * or event_id.event_data_id(struct).property_id[index] + * + * @param key_len. The length of key + * @param value. The value to be set, data type decided by data type of property as follows: + * int: int*, float: float*, double: double*, + * text: char*, enum: int*, date: char*, bool: int* + * attention! value can be NULL to clear property value + * @param value_len. The length of value, only be used when type is text or data + * + * @return success or fail. + * + */ +int dm_shw_set_event_output_value(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len); + +/** + * @brief Get event output value from TSL struct. + * This function used to get event output value from TSL struct. + * + * @param tsl. The pointer of TSL Struct. + * @param key. The property compound string, format decided by data type of property as follows: + * int,float,double,text,enum,date,bool type: event_id.event_data_id + * array type: event_id.event_data_id(array)[index] + * struct type: event_id.event_data_id(struct).property_id + * or event_id.event_data_id(struct).property_id[index] + * + * @param key_len. The length of key + * @param value. The variable to store value, data type decided by data type of property as follows: + * int: int*, float: float*, double: double*, + * text: char**, enum: int*, date: char**, bool: int* + * attention! value can not be NULL + * + * @warning if data type is text or date, *value well be end with '\0'. + * the memory allocated to *value must be free by user. + * + * @return success or fail. + * + */ +int dm_shw_get_event_output_value(_IN_ dm_shw_t *shadow, _IN_ char *key, _IN_ int key_len, _IN_ void *value); + +int dm_shw_set_service_input_output_value(_IN_ dm_shw_data_target_e type, _IN_ dm_shw_t *shadow, _IN_ char *key, + _IN_ int key_len, _IN_ void *value, _IN_ int value_len); +int dm_shw_get_service_input_output_value(_IN_ dm_shw_data_target_e type, _IN_ dm_shw_t *shadow, _IN_ char *key, + _IN_ int key_len, _IN_ void *value); + +/** + * @brief Get property payload from TSL struct. + * This function used to get property payload from TSL struct. + * + * @param shadow. The pointer of TSL Struct + * @param identifier. The Property Identifier + * @param identifier_len. The Property Identifier Length + * @param lite. The pointer to json array where to store property value + * + * @warning The payload malloc by this function and need to be free manully. + * + * @return success or fail. + * + */ +int dm_shw_assemble_property(_IN_ dm_shw_t *shadow, _IN_ char *identifier, _IN_ int identifier_len, + _IN_ lite_cjson_item_t *lite); + +/** + * @brief Get event output payload from TSL struct. + * This function used to get event output payload from TSL struct. + * + * @param shadow. The pointer of TSL Struct + * @param identifier. The Event Identifier + * @param identifier_len. The Event Identifier Length + * @param lite. The pointer to json array where to store event output value + * + * @warning The payload malloc by this function and need to be free manully. + * + * @return success or fail. + * + */ +int dm_shw_assemble_event_output(_IN_ dm_shw_t *shadow, _IN_ char *identifier, _IN_ int identifier_len, + _IN_ lite_cjson_item_t *lite); + +/** + * @brief Get service output payload from TSL struct. + * This function used to get service output payload from TSL struct. + * + * @param shadow. The pointer of TSL Struct + * @param identifier. The Service Identifier + * @param identifier_len. The Service Identifier Length + * @param lite. The pointer to json array where to store service output value + * + * @warning The payload malloc by this function and need to be free manully. + * + * @return success or fail. + * + */ +int dm_shw_assemble_service_output(_IN_ dm_shw_t *shadow, _IN_ char *identifier, _IN_ int identifier_len, + _IN_ lite_cjson_item_t *lite); + +/** + * @brief Free TSL struct. + * This function used to free TSL struct. + * + * @param shadow. The pointer of TSL Struct. + * + * @return success or fail. + * + */ +void dm_shw_destroy(_IN_ dm_shw_t **shadow); + +#if 0 + /** + * @brief Print detailed information of TSL struct. + * This function used to print detailed information of TSL struct. + * + * @param shadow. The pointer of TSL Struct. + * + * @return success or fail. + * + */ + void dm_shw_print(_IN_ dm_shw_t *shadow); +#endif + +#endif +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_tsl_alink.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_tsl_alink.c new file mode 100644 index 00000000..cf306b85 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_tsl_alink.c @@ -0,0 +1,1023 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "iotx_dm_internal.h" + +#ifdef DEPRECATED_LINKKIT + +typedef int (*dm_shw_data_parse)(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +typedef int (*dm_shw_array_parse)(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); + +typedef struct { + dm_shw_data_type_e type; + const char *name; + dm_shw_data_parse func_parse; + dm_shw_array_parse func_array_parse; +} dm_tsl_alink_mapping_t; + +/* Data Parse */ +static int _dm_shw_int_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_float_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_double_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_text_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_enum_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_date_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_bool_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_array_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_struct_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_property_parse(_IN_ dm_shw_data_t *property, _IN_ lite_cjson_t *root); + +/* Array Data Parse */ +static int _dm_shw_array_int_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_array_float_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_array_double_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_array_text_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_array_enum_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_array_date_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_array_bool_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_array_array_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); +static int _dm_shw_array_struct_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root); + +static dm_tsl_alink_mapping_t g_dm_tsl_alink_mapping[] = { + {DM_SHW_DATA_TYPE_NONE, "none", NULL, NULL }, + {DM_SHW_DATA_TYPE_INT, "int", _dm_shw_int_parse, _dm_shw_array_int_parse }, + {DM_SHW_DATA_TYPE_FLOAT, "float", _dm_shw_float_parse, _dm_shw_array_float_parse }, + {DM_SHW_DATA_TYPE_DOUBLE, "double", _dm_shw_double_parse, _dm_shw_array_double_parse }, + {DM_SHW_DATA_TYPE_TEXT, "text", _dm_shw_text_parse, _dm_shw_array_text_parse }, + {DM_SHW_DATA_TYPE_ENUM, "enum", _dm_shw_enum_parse, _dm_shw_array_enum_parse }, + {DM_SHW_DATA_TYPE_DATE, "date", _dm_shw_date_parse, _dm_shw_array_date_parse }, + {DM_SHW_DATA_TYPE_BOOL, "bool", _dm_shw_bool_parse, _dm_shw_array_bool_parse }, + {DM_SHW_DATA_TYPE_ARRAY, "array", _dm_shw_array_parse, _dm_shw_array_array_parse }, + {DM_SHW_DATA_TYPE_STRUCT, "struct", _dm_shw_struct_parse, _dm_shw_array_struct_parse } +}; + +static int _dm_shw_get_type(_IN_ const char *name, _IN_ int name_len, _OU_ dm_shw_data_type_e *type) +{ + int index = 0; + + if (name == NULL || name_len <= 0 || type == NULL) { + return DM_INVALID_PARAMETER; + } + + for (index = 0; index < sizeof(g_dm_tsl_alink_mapping) / sizeof(dm_tsl_alink_mapping_t); index++) { + if (strlen(g_dm_tsl_alink_mapping[index].name) == name_len && + memcmp(g_dm_tsl_alink_mapping[index].name, name, name_len) == 0) { + *type = g_dm_tsl_alink_mapping[index].type; + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +static int _dm_shw_int_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + return SUCCESS_RETURN; +} + +static int _dm_shw_float_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + return SUCCESS_RETURN; +} + +static int _dm_shw_double_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + return SUCCESS_RETURN; +} + +static int _dm_shw_text_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + return SUCCESS_RETURN; +} + +static int _dm_shw_enum_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + return SUCCESS_RETURN; +} + +static int _dm_shw_date_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + return SUCCESS_RETURN; +} + +static int _dm_shw_bool_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + return SUCCESS_RETURN; +} + +static int _dm_shw_array_int_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + dm_shw_data_value_complex_t *complex_array = (dm_shw_data_value_complex_t *)data_value->value; + + complex_array->value = DM_malloc((complex_array->size) * (sizeof(int))); + if (complex_array->value == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(complex_array->value, 0, (complex_array->size) * (sizeof(int))); + + /* Just For Test */ +#ifdef IOTX_DM_TSL_DEVELOP_TEST + int index = 0; + for (index = 0; index < complex_array->size; index++) { + *((int *)(complex_array->value) + index) = index + 1; + } +#endif + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_float_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + dm_shw_data_value_complex_t *complex_array = (dm_shw_data_value_complex_t *)data_value->value; + + complex_array->value = DM_malloc((complex_array->size) * (sizeof(float))); + if (complex_array->value == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(complex_array->value, 0, (complex_array->size) * (sizeof(float))); + + /* Just For Test */ +#ifdef IOTX_DM_TSL_DEVELOP_TEST + int index = 0; + for (index = 0; index < complex_array->size; index++) { + *((float *)(complex_array->value) + index) = (float)index + 0.2; + } +#endif + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_double_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + dm_shw_data_value_complex_t *complex_array = (dm_shw_data_value_complex_t *)data_value->value; + + complex_array->value = DM_malloc((complex_array->size) * (sizeof(double))); + if (complex_array->value == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(complex_array->value, 0, (complex_array->size) * (sizeof(double))); + + /* Just For Test */ +#ifdef IOTX_DM_TSL_DEVELOP_TEST + int index = 0; + for (index = 0; index < complex_array->size; index++) { + *((double *)(complex_array->value) + index) = (double)index + 0.2; + } +#endif + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_text_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + dm_shw_data_value_complex_t *complex_array = (dm_shw_data_value_complex_t *)data_value->value; + + complex_array->value = DM_malloc((complex_array->size) * (sizeof(char *))); + if (complex_array->value == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(complex_array->value, 0, (complex_array->size) * (sizeof(char *))); + +#ifdef IOTX_DM_TSL_DEVELOP_TEST + int index = 0; + char temp[10] = {0}; + for (index = 0; index < complex_array->size; index++) { + memset(temp, 0, sizeof(temp)); + HAL_Snprintf(temp, sizeof(temp), "%d", index + 1); + *((char **)(complex_array->value) + index) = DM_malloc(strlen(temp) + 1); + if (*((char **)(complex_array->value) + index) != NULL) { + memset(*((char **)(complex_array->value) + index), 0, strlen(temp) + 1); + memcpy(*((char **)(complex_array->value) + index), temp, strlen(temp)); + } + } +#endif + return SUCCESS_RETURN; +} + +static int _dm_shw_array_enum_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + dm_shw_data_value_complex_t *complex_array = (dm_shw_data_value_complex_t *)data_value->value; + + complex_array->value = DM_malloc((complex_array->size) * (sizeof(int))); + if (complex_array->value == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(complex_array->value, 0, (complex_array->size) * (sizeof(int))); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_date_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + dm_shw_data_value_complex_t *complex_array = (dm_shw_data_value_complex_t *)data_value->value; + + complex_array->value = DM_malloc((complex_array->size) * (sizeof(char *))); + if (complex_array->value == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(complex_array->value, 0, (complex_array->size) * (sizeof(char *))); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_bool_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + dm_shw_data_value_complex_t *complex_array = (dm_shw_data_value_complex_t *)data_value->value; + + complex_array->value = DM_malloc((complex_array->size) * (sizeof(int))); + if (complex_array->value == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(complex_array->value, 0, (complex_array->size) * (sizeof(int))); + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_array_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ +#if 0 + int res = 0; + char size_str[DM_UTILS_UINT32_STRLEN] = {0}; + lite_cjson_t lite_item, lite_type, lite_specs; + dm_shw_data_value_complex_t *complex_array = (dm_shw_data_value_complex_t *)data_value->value; + dm_shw_data_value_t *data_value_next_level; + dm_shw_data_value_complex_t *complex_array_next_level = NULL; + + if (!lite_cjson_is_object(root)) { + return DM_INVALID_PARAMETER; + } + + /* Allocate Memory For Next Level Data Value And Next Level Complex Array */ + data_value_next_level = DM_malloc(sizeof(dm_shw_data_value_t)); + if (data_value_next_level == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(data_value_next_level, 0, sizeof(dm_shw_data_value_t)); + data_value_next_level->type = DM_SHW_DATA_TYPE_ARRAY; + + complex_array_next_level = DM_malloc(sizeof(dm_shw_data_value_complex_t)); + if (complex_array_next_level == NULL) { + DM_free(data_value_next_level); + return DM_MEMORY_NOT_ENOUGH; + } + memset(complex_array_next_level, 0, sizeof(dm_shw_data_value_complex_t)); + complex_array->value = (void *)data_value_next_level; + data_value_next_level->value = complex_array_next_level; + + /* Parse Size (Mandatory) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_SIZE, strlen(DM_SHW_KEY_SIZE), &lite_item); + if (res != SUCCESS_RETURN && !lite_cjson_is_string(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + if (lite_item.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(size_str, lite_item.value, lite_item.value_length); + complex_array_next_level->size = atoi(size_str); + + dm_log_debug("TSL Property Array Array Size: %d", complex_array_next_level->size); + + /* Parse Item And Type (Mandatory) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_ITEM, strlen(DM_SHW_KEY_ITEM), &lite_item); + if (res != SUCCESS_RETURN && !lite_cjson_is_object(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + memset(&lite_type, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite_item, DM_SHW_KEY_TYPE, strlen(DM_SHW_KEY_TYPE), &lite_type); + if (res != SUCCESS_RETURN && !lite_cjson_is_string(&lite_type)) { + return DM_JSON_PARSE_FAILED; + } + res = _dm_shw_get_type(lite_type.value, lite_type.value_length, &complex_array_next_level->type); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Parse Specs (Optional) */ + memset(&lite_specs, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite_item, DM_SHW_KEY_SPECS, strlen(DM_SHW_KEY_SPECS), &lite_specs); + if ((complex_array_next_level->type == DM_SHW_DATA_TYPE_ARRAY + || complex_array_next_level->type == DM_SHW_DATA_TYPE_STRUCT) && + (res != SUCCESS_RETURN)) { + return DM_JSON_PARSE_FAILED; + } + + if (g_dm_tsl_alink_mapping[complex_array_next_level->type].func_array_parse == NULL) { + return FAIL_RETURN; + } + dm_log_debug("TSL Property Specs Type: %s", g_dm_tsl_alink_mapping[complex_array_next_level->type].name); + + /* Parse Array Type */ + res = g_dm_tsl_alink_mapping[complex_array->type].func_array_parse(data_value_next_level, &lite_specs); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } +#endif + return SUCCESS_RETURN; +} + +static int _dm_shw_array_struct_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + int res = 0, index = 0; + dm_shw_data_value_complex_t *complex_array = (dm_shw_data_value_complex_t *)data_value->value; + dm_shw_data_t *data = NULL; + + if (!lite_cjson_is_array(root) || root->size <= 0) { + return DM_INVALID_PARAMETER; + } + + dm_log_debug("Array Struct Size: %d", complex_array->size); + complex_array->value = DM_malloc((complex_array->size) * (sizeof(dm_shw_data_t))); + if (complex_array->value == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(complex_array->value, 0, (complex_array->size) * (sizeof(dm_shw_data_t))); + + dm_log_debug("Array Struct Spec Size: %d", root->size); + for (index = 0; index < complex_array->size; index++) { + data = (dm_shw_data_t *)complex_array->value + index; + + data->data_value.type = DM_SHW_DATA_TYPE_STRUCT; + + res = _dm_shw_struct_parse(&data->data_value, root); + if (res != SUCCESS_RETURN) { + continue; + } + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_array_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + int res = 0; + char size_str[DM_UTILS_UINT32_STRLEN] = {0}; + lite_cjson_t lite_item, lite_type, lite_specs; + dm_shw_data_value_complex_t *complex_array = NULL; + + /* dm_log_debug("DM_SHW_DATA_TYPE_ARRAY"); */ + + if (root == NULL || !lite_cjson_is_object(root)) { + return DM_INVALID_PARAMETER; + } + + /* Allocate Memory For Data Type Specs */ + complex_array = DM_malloc(sizeof(dm_shw_data_value_complex_t)); + if (complex_array == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(complex_array, 0, sizeof(dm_shw_data_value_complex_t)); + data_value->value = (void *)complex_array; + + /* Parse Size (Mandatory) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_SIZE, strlen(DM_SHW_KEY_SIZE), &lite_item); + if (res != SUCCESS_RETURN && !lite_cjson_is_string(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + if (lite_item.value_length > DM_UTILS_UINT32_STRLEN) { + return FAIL_RETURN; + } + memcpy(size_str, lite_item.value, lite_item.value_length); + complex_array->size = atoi(size_str); + + /* dm_log_debug("TSL Property Array Size: %d",complex_array->size); */ + + /* Parse Item And Type (Mandatory) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_ITEM, strlen(DM_SHW_KEY_ITEM), &lite_item); + if (res != SUCCESS_RETURN && !lite_cjson_is_object(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + memset(&lite_type, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite_item, DM_SHW_KEY_TYPE, strlen(DM_SHW_KEY_TYPE), &lite_type); + if (res != SUCCESS_RETURN && !lite_cjson_is_string(&lite_type)) { + return DM_JSON_PARSE_FAILED; + } + res = _dm_shw_get_type(lite_type.value, lite_type.value_length, &complex_array->type); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + /* dm_log_debug("TSL Property Array Type: %d",complex_array->type); */ + + /* Parse Specs (Optional) */ + memset(&lite_specs, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite_item, DM_SHW_KEY_SPECS, strlen(DM_SHW_KEY_SPECS), &lite_specs); + if ((complex_array->type == DM_SHW_DATA_TYPE_ARRAY || complex_array->type == DM_SHW_DATA_TYPE_STRUCT) && + (res != SUCCESS_RETURN)) { + return DM_JSON_PARSE_FAILED; + } + + if (g_dm_tsl_alink_mapping[complex_array->type].func_array_parse == NULL) { + return FAIL_RETURN; + } + /* dm_log_debug("TSL Property Specs Type: %s",g_dm_tsl_alink_mapping[complex_array->type].name); */ + + /* Parse Array Type */ + res = g_dm_tsl_alink_mapping[complex_array->type].func_array_parse(data_value, &lite_specs); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_struct_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + int res = 0, index = 0; + lite_cjson_t lite_item; + dm_shw_data_t *property = NULL; + dm_shw_data_value_complex_t *complex_struct = NULL; + + /* dm_log_debug("DM_SHW_DATA_TYPE_STRUCT"); */ + + if (root == NULL || !lite_cjson_is_array(root) || root->size == 0) { + return DM_INVALID_PARAMETER; + } + + /* dm_log_debug("TSL Property Struct Size: %d",root->size); */ + + /* Allocate Memory For Data Type Specs */ + complex_struct = DM_malloc(sizeof(dm_shw_data_value_complex_t)); + if (complex_struct == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(complex_struct, 0, sizeof(dm_shw_data_value_complex_t)); + data_value->value = (void *)complex_struct; + + complex_struct->size = root->size; + + /* Allocate Memory For Multi Identifier */ + complex_struct->value = DM_malloc((complex_struct->size) * (sizeof(dm_shw_data_t))); + if (complex_struct->value == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(complex_struct->value, 0, (complex_struct->size) * (sizeof(dm_shw_data_t))); + + for (index = 0; index < complex_struct->size; index++) { + memset(&lite_item, 0, sizeof(lite_cjson_t)); + property = (dm_shw_data_t *)complex_struct->value + index; + /* dm_log_debug("TSL Property Struct Index: %d",index); */ + + res = lite_cjson_array_item(root, index, &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + /* dm_log_debug("TSL Property Struct Property: %.*s",lite_item.value_length,lite_item.value); */ + res = _dm_shw_property_parse(property, &lite_item); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_data_parse(_IN_ dm_shw_data_value_t *data_value, _IN_ lite_cjson_t *root) +{ + int res = 0; + lite_cjson_t lite_item; + + memset(data_value, 0, sizeof(dm_shw_data_value_t)); + + /* Parse Type */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_TYPE, strlen(DM_SHW_KEY_TYPE), &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + dm_log_debug("TSL Data Type: %.*s", lite_item.value_length, lite_item.value); + res = _dm_shw_get_type(lite_item.value, lite_item.value_length, &data_value->type); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Parse Specs */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_SPECS, strlen(DM_SHW_KEY_SPECS), &lite_item); + if (res == SUCCESS_RETURN) { + /* dm_log_debug("TSL Data Specs: %.*s",lite_item.value_length,lite_item.value); */ + } + + /* Parse Type And Value */ + if (g_dm_tsl_alink_mapping[data_value->type].func_parse == NULL) { + return FAIL_RETURN; + } + res = g_dm_tsl_alink_mapping[data_value->type].func_parse(data_value, &lite_item); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_property_parse(_IN_ dm_shw_data_t *property, _IN_ lite_cjson_t *root) +{ + int res = 0; + lite_cjson_t lite_item; + + /* Parse Identifier (Mandatory) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_IDENTIFIER, strlen(DM_SHW_KEY_IDENTIFIER), &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + res = dm_utils_copy(lite_item.value, lite_item.value_length, (void **)(&property->identifier), + lite_item.value_length + 1); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_debug("Identifier: %s", property->identifier); + + /* Parse DataType */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_DATATYPE, strlen(DM_SHW_KEY_DATATYPE), &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + /* dm_log_debug("TSL Property Data Type: %.*s",lite_item.value_length,lite_item.value); */ + res = _dm_shw_data_parse(&property->data_value, &lite_item); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_properties_parse(_IN_ dm_shw_t *shadow, _IN_ lite_cjson_t *root) +{ + int res = 0, index = 0; + lite_cjson_t lite_properties, lite_property; + + memset(&lite_properties, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_PROPERTIES, strlen(DM_SHW_KEY_PROPERTIES), &lite_properties); + if (res == SUCCESS_RETURN) { + if (!lite_cjson_is_array(&lite_properties)) { + return DM_JSON_PARSE_FAILED; + } + } else { + return SUCCESS_RETURN; + } + + dm_log_debug("Number: %d", lite_properties.size); + if (lite_properties.size == 0) { + return SUCCESS_RETURN; + } + + /* Allocate Memory For TSL Properties Struct */ + shadow->property_number = lite_properties.size; + shadow->properties = DM_malloc(sizeof(dm_shw_data_t) * (lite_properties.size)); + if (shadow->properties == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(shadow->properties, 0, sizeof(dm_shw_data_t) * (lite_properties.size)); + + for (index = 0; index < lite_properties.size; index++) { + memset(&lite_property, 0, sizeof(lite_cjson_t)); + res = lite_cjson_array_item(&lite_properties, index, &lite_property); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite_property)) { + return FAIL_RETURN; + } + + dm_log_debug("Index: %d", index); + _dm_shw_property_parse(shadow->properties + index, &lite_property); + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_event_outputdata_parse(_IN_ dm_shw_t *shadow, _IN_ dm_shw_data_t *event_data, + _IN_ lite_cjson_t *root) +{ + int res = 0; + lite_cjson_t lite_item; + + /* Parse Identifier (Madantory) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_IDENTIFIER, strlen(DM_SHW_KEY_IDENTIFIER), &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + res = dm_utils_copy(lite_item.value, lite_item.value_length, (void **) & (event_data->identifier), + lite_item.value_length + 1); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_debug("Identifier: %s", event_data->identifier); + + /* Parse DataType */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_DATATYPE, strlen(DM_SHW_KEY_DATATYPE), &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + /* dm_log_debug("TSL Output Event Data Type: %.*s",lite_item.value_length,lite_item.value); */ + res = _dm_shw_data_parse(&event_data->data_value, &lite_item); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_event_outputdatas_parse(_IN_ dm_shw_t *shadow, _IN_ dm_shw_event_t *event, _IN_ lite_cjson_t *root) +{ + int res = 0, index = 0; + lite_cjson_t lite_item; + dm_shw_data_t *output_data = NULL; + + dm_log_debug("Number: %d", event->output_data_number); + if (event->output_data_number == 0) { + return SUCCESS_RETURN; + } + + /* Allocate Memory For Output Datas */ + event->output_datas = DM_malloc((event->output_data_number) * (sizeof(dm_shw_data_t))); + if (event->output_datas == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(event->output_datas, 0, (event->output_data_number) * (sizeof(dm_shw_data_t))); + + for (index = 0; index < event->output_data_number; index++) { + memset(&lite_item, 0, sizeof(lite_cjson_t)); + output_data = event->output_datas + index; + + res = lite_cjson_array_item(root, index, &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite_item)) { + return FAIL_RETURN; + } + + dm_log_debug("Index: %d", index); + _dm_shw_event_outputdata_parse(shadow, output_data, &lite_item); + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_event_parse(_IN_ dm_shw_t *shadow, _IN_ dm_shw_event_t *event, _IN_ lite_cjson_t *root) +{ + int res = 0; + lite_cjson_t lite_item; + + /* Parse Identifier (Mandatory) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_IDENTIFIER, strlen(DM_SHW_KEY_IDENTIFIER), &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + res = dm_utils_copy(lite_item.value, lite_item.value_length, (void **)(&event->identifier), lite_item.value_length + 1); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_debug("Identifier: %s", event->identifier); + + /* Check If Current Event Id Is Post */ + if (((strlen(event->identifier) == strlen(DM_SHW_SPECIAL_EVENT_POST_IDENTIFIER)) && + (memcmp(event->identifier, DM_SHW_SPECIAL_EVENT_POST_IDENTIFIER, strlen(DM_SHW_SPECIAL_EVENT_POST_IDENTIFIER)) == 0))) { + /* dm_log_info("TSL Special Event Identifier: %s, Ignore It",event->identifier); */ + return SUCCESS_RETURN; + } + + /* Parse Output Data (Madantory) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_OUTPUTDATA, strlen(DM_SHW_KEY_OUTPUTDATA), &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_array(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + event->output_data_number = lite_item.size; + res = _dm_shw_event_outputdatas_parse(shadow, event, &lite_item); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_events_parse(_IN_ dm_shw_t *shadow, _IN_ lite_cjson_t *root) +{ + int res = 0, index = 0; + lite_cjson_t lite_events, lite_event; + + memset(&lite_events, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_EVENTS, strlen(DM_SHW_KEY_EVENTS), &lite_events); + if (res == SUCCESS_RETURN) { + if (!lite_cjson_is_array(&lite_events)) { + return DM_JSON_PARSE_FAILED; + } + } else { + return SUCCESS_RETURN; + } + + dm_log_debug("Number: %d", lite_events.size); + if (lite_events.size == 0) { + return SUCCESS_RETURN; + } + + /* Allocate Memory For TSL Events Struct */ + shadow->event_number = lite_events.size; + shadow->events = DM_malloc(sizeof(dm_shw_event_t) * (lite_events.size)); + if (shadow->events == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(shadow->events, 0, sizeof(dm_shw_event_t) * (lite_events.size)); + + for (index = 0; index < lite_events.size; index++) { + memset(&lite_event, 0, sizeof(lite_cjson_t)); + res = lite_cjson_array_item(&lite_events, index, &lite_event); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite_event)) { + return FAIL_RETURN; + } + + dm_log_debug("Index: %d", index); + _dm_shw_event_parse(shadow, shadow->events + index, &lite_event); + } + return SUCCESS_RETURN; +} + +static int _dm_shw_service_outputdata_parse(_IN_ dm_shw_t *shadow, _IN_ dm_shw_data_t *service_data, + _IN_ lite_cjson_t *root) +{ + int res = 0; + lite_cjson_t lite_item; + + /* Parse Identifier (Madantory) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_IDENTIFIER, strlen(DM_SHW_KEY_IDENTIFIER), &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + res = dm_utils_copy(lite_item.value, lite_item.value_length, (void **) & (service_data->identifier), + lite_item.value_length + 1); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_debug("Identifier: %s", service_data->identifier); + + /* Parse DataType */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_DATATYPE, strlen(DM_SHW_KEY_DATATYPE), &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + /* dm_log_debug("TSL Output Service Data Type: %.*s",lite_item.value_length,lite_item.value); */ + res = _dm_shw_data_parse(&service_data->data_value, &lite_item); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_service_outputdatas_parse(_IN_ dm_shw_t *shadow, _IN_ dm_shw_service_t *service, + _IN_ lite_cjson_t *root) +{ + int res = 0, index = 0; + lite_cjson_t lite_item; + dm_shw_data_t *output_data = NULL; + + dm_log_debug("Number: %d", service->output_data_number); + if (service->output_data_number == 0) { + return SUCCESS_RETURN; + } + + /* Allocate Memory For Output Datas */ + service->output_datas = DM_malloc((service->output_data_number) * (sizeof(dm_shw_data_t))); + if (service->output_datas == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(service->output_datas, 0, (service->output_data_number) * (sizeof(dm_shw_data_t))); + + for (index = 0; index < service->output_data_number; index++) { + memset(&lite_item, 0, sizeof(lite_cjson_t)); + output_data = service->output_datas + index; + + res = lite_cjson_array_item(root, index, &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite_item)) { + return FAIL_RETURN; + } + + dm_log_debug("Index: %d", index); + _dm_shw_service_outputdata_parse(shadow, output_data, &lite_item); + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_service_inputdata_parse(_IN_ dm_shw_t *shadow, _IN_ dm_shw_data_t *input_data, + _IN_ lite_cjson_t *root) +{ + int res = 0; + lite_cjson_t lite_item; + + if (!lite_cjson_is_object(root)) { + return DM_INVALID_PARAMETER; + } + + /* Parse Identifier (Madantory) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_IDENTIFIER, strlen(DM_SHW_KEY_IDENTIFIER), &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + res = dm_utils_copy(lite_item.value, lite_item.value_length, (void **) & (input_data->identifier), + lite_item.value_length + 1); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_debug("Identifier: %s", input_data->identifier); + + /* Parse DataType */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_DATATYPE, strlen(DM_SHW_KEY_DATATYPE), &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + /* dm_log_debug("TSL Input Service Data Type: %.*s",lite_item.value_length,lite_item.value); */ + res = _dm_shw_data_parse(&input_data->data_value, &lite_item); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_service_inputdatas_parse(_IN_ dm_shw_t *shadow, _IN_ dm_shw_service_t *service, + _IN_ lite_cjson_t *root) +{ + int res = 0, index = 0; + lite_cjson_t lite_item; + dm_shw_data_t *input_data = NULL; + + dm_log_debug("Number: %d", service->input_data_number); + if (service->input_data_number == 0) { + return SUCCESS_RETURN; + } + + /* Allocate Memory For Output Datas */ + service->input_datas = DM_malloc((service->input_data_number) * (sizeof(dm_shw_data_t))); + if (service->input_datas == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(service->input_datas, 0, (service->input_data_number) * (sizeof(dm_shw_data_t))); + + for (index = 0; index < service->input_data_number; index++) { + memset(&lite_item, 0, sizeof(lite_cjson_t)); + input_data = service->input_datas + index; + + res = lite_cjson_array_item(root, index, &lite_item); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + dm_log_debug("Index: %d", index); + _dm_shw_service_inputdata_parse(shadow, input_data, &lite_item); + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_service_parse(_IN_ dm_shw_t *shadow, _IN_ dm_shw_service_t *service, _IN_ lite_cjson_t *root) +{ + int res = 0; + lite_cjson_t lite_item; + + /* Parse Identifier (Mandatory) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_IDENTIFIER, strlen(DM_SHW_KEY_IDENTIFIER), &lite_item); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item)) { + return DM_JSON_PARSE_FAILED; + } + res = dm_utils_copy(lite_item.value, lite_item.value_length, (void **)(&service->identifier), + lite_item.value_length + 1); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + dm_log_debug("Identifier: %s", service->identifier); + + /* Check If Current Service Id Is Set Or Get */ + if (((strlen(service->identifier) == strlen(DM_SHW_SPECIAL_SERVICE_SET_IDENTIFIER)) && + (memcmp(service->identifier, DM_SHW_SPECIAL_SERVICE_SET_IDENTIFIER, + strlen(DM_SHW_SPECIAL_SERVICE_SET_IDENTIFIER)) == 0)) || + ((strlen(service->identifier) == strlen(DM_SHW_SPECIAL_SERVICE_GET_IDENTIFIER)) && + (memcmp(service->identifier, DM_SHW_SPECIAL_SERVICE_GET_IDENTIFIER, + strlen(DM_SHW_SPECIAL_SERVICE_GET_IDENTIFIER)) == 0))) { + /* dm_log_info("TSL Special Service Identifier: %s, Ignore It",service->identifier); */ + return SUCCESS_RETURN; + } + + /* Parse Output Data (Optional) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_OUTPUTDATA, strlen(DM_SHW_KEY_OUTPUTDATA), &lite_item); + if (res == SUCCESS_RETURN && lite_cjson_is_array(&lite_item)) { + service->output_data_number = lite_item.size; + res = _dm_shw_service_outputdatas_parse(shadow, service, &lite_item); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + } + + /* Parse Input Data (Optional) */ + memset(&lite_item, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_INPUTDATA, strlen(DM_SHW_KEY_INPUTDATA), &lite_item); + if (res == SUCCESS_RETURN && lite_cjson_is_array(&lite_item)) { + service->input_data_number = lite_item.size; + res = _dm_shw_service_inputdatas_parse(shadow, service, &lite_item); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + } + + return SUCCESS_RETURN; +} + +static int _dm_shw_services_parse(_IN_ dm_shw_t *shadow, _IN_ lite_cjson_t *root) +{ + int res = 0, index = 0; + lite_cjson_t lite_services, lite_service; + dm_shw_service_t *service = NULL; + + memset(&lite_services, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(root, DM_SHW_KEY_SERVICES, strlen(DM_SHW_KEY_SERVICES), &lite_services); + if (res == SUCCESS_RETURN) { + if (!lite_cjson_is_array(&lite_services)) { + return DM_JSON_PARSE_FAILED; + } + } else { + return SUCCESS_RETURN; + } + + dm_log_debug("Number: %d", lite_services.size); + if (lite_services.size == 0) { + return SUCCESS_RETURN; + } + + /* Allocate Memory For TSL Services Struct */ + shadow->service_number = lite_services.size; + shadow->services = DM_malloc(sizeof(dm_shw_service_t) * (lite_services.size)); + if (shadow->services == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(shadow->services, 0, sizeof(dm_shw_service_t) * (lite_services.size)); + + for (index = 0; index < lite_services.size; index++) { + memset(&lite_service, 0, sizeof(lite_cjson_t)); + service = shadow->services + index; + + res = lite_cjson_array_item(&lite_services, index, &lite_service); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite_service)) { + return FAIL_RETURN; + } + + dm_log_debug("Index: %d", index); + _dm_shw_service_parse(shadow, service, &lite_service); + } + + return SUCCESS_RETURN; +} + +int dm_tsl_alink_create(_IN_ const char *tsl, _IN_ int tsl_len, _OU_ dm_shw_t **shadow) +{ + int res = 0; + lite_cjson_t lite_root; + + if (shadow == NULL || *shadow != NULL || tsl == NULL || tsl_len <= 0) { + return DM_INVALID_PARAMETER; + } + + *shadow = DM_malloc(sizeof(dm_shw_t)); + if (*shadow == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*shadow, 0, sizeof(dm_shw_t)); + + /* Parse Root */ + memset(&lite_root, 0, sizeof(lite_root)); + res = lite_cjson_parse(tsl, tsl_len, &lite_root); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite_root)) { + DM_free(*shadow); + return DM_JSON_PARSE_FAILED; + } + + /* Parse Properties (Mandatory) */ + res = _dm_shw_properties_parse(*shadow, &lite_root); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Parse Events (Mandatory) */ + res = _dm_shw_events_parse(*shadow, &lite_root); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + /* Parse Services (Mandatory) */ + res = _dm_shw_services_parse(*shadow, &lite_root); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_tsl_alink.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_tsl_alink.h new file mode 100644 index 00000000..f73adfae --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_tsl_alink.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#if defined(DEPRECATED_LINKKIT) + #ifndef _DM_TSL_ALINK_H_ + #define _DM_TSL_ALINK_H_ + + /** + * @brief Create TSL struct from TSL string. + * This function used to parse TSL string into TSL struct. + * + * @param tsl. The TSL string in JSON format. + * @param tsl_len. The length of tsl + * @param shadow. The pointer of TSL Struct pointer, will be malloc memory. + * This memory should be free by dm_shw_destroy. + * + * @return success or fail. + * + */ + int dm_tsl_alink_create(_IN_ const char *tsl, _IN_ int tsl_len, _OU_ dm_shw_t **shadow); + + #endif +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_utils.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_utils.c new file mode 100644 index 00000000..fb1f4aec --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_utils.c @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#include "iotx_dm_internal.h" + +int dm_utils_copy_direct(_IN_ void *input, _IN_ int input_len, _OU_ void **output, _IN_ int output_len) +{ + if (input == NULL || output == NULL || *output != NULL) { + return DM_INVALID_PARAMETER; + } + + *output = HAL_Malloc(output_len); + if (*output == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*output, 0, output_len); + memcpy(*output, input, input_len); + + return SUCCESS_RETURN; +} + +int dm_utils_copy(_IN_ void *input, _IN_ int input_len, _OU_ void **output, _IN_ int output_len) +{ + if (input == NULL || output == NULL || *output != NULL) { + return DM_INVALID_PARAMETER; + } + + *output = DM_malloc(output_len); + if (*output == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*output, 0, output_len); + memcpy(*output, input, input_len); + + return SUCCESS_RETURN; +} + +int dm_utils_strarr_index(_IN_ char *input, _IN_ int input_len, + _OU_ int *partial_input_len, _OU_ int *array_input_len, _OU_ int *array_index) +{ + int index = 0; + int deep = 0; + char *bracket_pre = NULL; + char *bracket_suf = NULL; + char array_index_str[10] = {0}; + + if (input == NULL || input_len <= 1 || array_index == NULL) { + return DM_INVALID_PARAMETER; + } + + for (index = 0; index < input_len; index++) { + switch (input[index]) { + case '[': { + if (deep != 0) { + return FAIL_RETURN; + } + deep++; + if (!bracket_pre) { + bracket_pre = (char *)&input[index]; + } + } + break; + case ']': { + if (deep != 1) { + return FAIL_RETURN; + } + deep--; + if (input[index - 1] == '[') { + return FAIL_RETURN; + } + if (!bracket_suf) { + bracket_suf = (char *)&input[index]; + } + } + break; + default: + break; + } + } + + if (bracket_pre && bracket_suf && ((bracket_suf - input + 1) == input_len)) { + if (partial_input_len) { + *partial_input_len = bracket_pre - input; + } + if (array_input_len) { + *array_input_len = bracket_suf - input + 1; + } + + /* Get Index */ + memcpy(array_index_str, bracket_pre + 1, bracket_suf - bracket_pre - 1); + *array_index = atoi(array_index_str); + return SUCCESS_RETURN; + } + + return FAIL_RETURN; +} + +int dm_utils_itoa_direct(_IN_ int input, _OU_ char **output) +{ + int res = 0; + char temp_output[10 + 1] = {0}; + + if (output == NULL || *output != NULL) { + return DM_INVALID_PARAMETER; + } + + res = HAL_Snprintf(temp_output, 10, "%d", input); + if (res < 0) { + return FAIL_RETURN; + } + + *output = HAL_Malloc(strlen(temp_output) + 1); + if (*output == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*output, 0, strlen(temp_output) + 1); + memcpy(*output, temp_output, strlen(temp_output)); + + return SUCCESS_RETURN; +} + +int dm_utils_itoa(_IN_ int input, _OU_ char **output) +{ + int res = 0; + char temp_output[10 + 1] = {0}; + + if (output == NULL || *output != NULL) { + return DM_INVALID_PARAMETER; + } + + res = HAL_Snprintf(temp_output, 10, "%d", input); + if (res < 0) { + return FAIL_RETURN; + } + + *output = DM_malloc(strlen(temp_output) + 1); + if (*output == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*output, 0, strlen(temp_output) + 1); + memcpy(*output, temp_output, strlen(temp_output)); + + return SUCCESS_RETURN; +} + +int dm_utils_ftoa_direct(_IN_ double input, _OU_ char **output) +{ + int res = 0; + char temp_output[30 + 1] = {0}; + + if (output == NULL || *output != NULL) { + return DM_INVALID_PARAMETER; + } + + res = HAL_Snprintf(temp_output, 30, "%f", input); + if (res < 0) { + return FAIL_RETURN; + } + + *output = HAL_Malloc(strlen(temp_output) + 1); + if (*output == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*output, 0, strlen(temp_output) + 1); + memcpy(*output, temp_output, strlen(temp_output)); + + return SUCCESS_RETURN; +} + +int dm_utils_ftoa(_IN_ double input, _OU_ char **output) +{ + int res = 0; + char temp_output[30 + 1] = {0}; + + if (output == NULL || *output != NULL) { + return DM_INVALID_PARAMETER; + } + + res = HAL_Snprintf(temp_output, 30, "%f", input); + if (res < 0) { + return FAIL_RETURN; + } + + *output = DM_malloc(strlen(temp_output) + 1); + if (*output == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*output, 0, strlen(temp_output) + 1); + memcpy(*output, temp_output, strlen(temp_output)); + + return SUCCESS_RETURN; +} + +int dm_utils_hex_to_str(_IN_ unsigned char *input, _IN_ int input_len, _OU_ char **output) +{ + int index = 0, output_len = 0; + unsigned char iter_char = 0; + + if (input == NULL || input_len <= 0 || output == NULL || *output != NULL) { + return DM_INVALID_PARAMETER; + } + + output_len = input_len * 2; + *output = DM_malloc(output_len + 1); + if (*output == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*output, 0, output_len + 1); + + for (index = 0; index < input_len; index++) { + iter_char = (input[index] >> 4) & 0x0F; + if (iter_char <= 0x09) { + iter_char += '0'; + } else if (iter_char >= 0x0A && iter_char <= 0x0F) { + iter_char += 'A' - 0x0A; + } + (*output)[index * 2] = iter_char; + + iter_char = (input[index]) & 0x0F; + if (iter_char <= 0x09) { + iter_char += '0'; + } else if (iter_char >= 0x0A && iter_char <= 0x0F) { + iter_char += 'A' - 0x0A; + } + (*output)[index * 2 + 1] = iter_char; + } + + return SUCCESS_RETURN; +} + +int dm_utils_str_to_hex(_IN_ char *input, _IN_ int input_len, _OU_ unsigned char **output, _OU_ int *output_len) +{ + int index = 0; + char iter_char = 0; + + if (input == NULL || input_len <= 0 || input_len % 2 != 0 || + output == NULL || *output != NULL || output_len == NULL) { + return DM_INVALID_PARAMETER; + } + + *output_len = input_len / 2; + *output = DM_malloc(*output_len); + if (*output == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*output, 0, *output_len); + + for (index = 0; index < input_len; index += 2) { + if (input[index] >= '0' && input[index] <= '9') { + iter_char = input[index] - '0'; + } else if (input[index] >= 'A' && input[index] <= 'F') { + iter_char = input[index] - 'A' + 0x0A; + } + (*output)[index / 2] |= (iter_char << 4) & 0xF0; + + if (input[index + 1] >= '0' && input[index + 1] <= '9') { + iter_char = input[index + 1] - '0'; + } else if (input[index + 1] >= 'A' && input[index + 1] <= 'F') { + iter_char = input[index + 1] - 'A' + 0x0A; + } + (*output)[index / 2] |= (iter_char) & 0x0F; + } + + return SUCCESS_RETURN; +} + +int dm_utils_memtok(_IN_ char *input, _IN_ int input_len, _IN_ char delimiter, _IN_ int index, _OU_ int *offset) +{ + int item_index = 0; + int count = 0; + + if (input == NULL || input_len <= 0 || offset == NULL) { + return DM_INVALID_PARAMETER; + } + + for (item_index = 0; item_index < input_len; item_index++) { + if (input[item_index] == delimiter && (item_index + 1) < input_len) { + count++; + if (count == index) { + *offset = item_index; + return SUCCESS_RETURN; + } + } + } + + return FAIL_RETURN; +} + +int dm_utils_replace_char(_IN_ char *input, _IN_ int input_len, _IN_ char src, _IN_ char dest) +{ + int index = 0; + + if (input == NULL || input_len <= 0) { + return DM_INVALID_PARAMETER; + } + + for (index = 0; index < input_len; index++) { + if (input[index] == src) { + input[index] = dest; + } + } + + return SUCCESS_RETURN; +} + +int dm_utils_service_name(_IN_ const char *prefix, _IN_ const char *name, _IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], _OU_ char **service_name) +{ + int prefix_len = (prefix == NULL) ? (0) : (strlen(prefix)); + int name_len = (name == NULL) ? (0) : (strlen(name)); + int service_name_len = 0; + if ((prefix == NULL && name == NULL) || product_key == NULL || device_name == NULL || + service_name == NULL || *service_name != NULL) { + return DM_INVALID_PARAMETER; + } + + service_name_len = prefix_len + name_len + strlen(product_key) + strlen(device_name) + 1; + *service_name = DM_malloc(service_name_len); + if (*service_name == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*service_name, 0, service_name_len); + + if (prefix != NULL) { + HAL_Snprintf(*service_name, service_name_len, prefix, product_key, device_name); + } + + if (name != NULL) { + memcpy(*service_name + strlen(*service_name), name, name_len); + } + + return SUCCESS_RETURN; +} + +int dm_utils_uri_add_prefix(_IN_ const char *prefix, _IN_ char *uri, _OU_ char **new_uri) +{ + int new_uri_len = 0; + + if (prefix == NULL || uri == NULL || new_uri == NULL || *new_uri != NULL) { + return DM_INVALID_PARAMETER; + } + + new_uri_len = strlen(prefix) + strlen(uri) + 1; + *new_uri = DM_malloc(new_uri_len); + if (*new_uri == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*new_uri, 0, new_uri_len); + + memcpy(*new_uri, prefix, strlen(prefix)); + memcpy(*new_uri + strlen(*new_uri), uri, strlen(uri)); + + return SUCCESS_RETURN; +} + +int dm_utils_json_parse(_IN_ const char *payload, _IN_ int payload_len, _IN_ int type, _OU_ lite_cjson_t *lite) +{ + int res = 0; + + if (payload == NULL || payload_len <= 0 || type < 0 || lite == NULL) { + return DM_INVALID_PARAMETER; + } + memset(lite, 0, sizeof(lite_cjson_t)); + + res = lite_cjson_parse(payload, payload_len, lite); + if (res != SUCCESS_RETURN) { + memset(lite, 0, sizeof(lite_cjson_t)); + return FAIL_RETURN; + } + + if (type != cJSON_Invalid && lite->type != type) { + memset(lite, 0, sizeof(lite_cjson_t)); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int dm_utils_json_object_item(_IN_ lite_cjson_t *lite, _IN_ const char *key, _IN_ int key_len, _IN_ int type, + _OU_ lite_cjson_t *lite_item) +{ + int res = 0; + + if (lite == NULL || lite->type != cJSON_Object || key == NULL || key_len <= 0 || type < 0 || lite_item == NULL) { + return DM_INVALID_PARAMETER; + } + + if (lite->type != cJSON_Object) { + dm_log_err("lite->type != cJSON_Object, %d", lite->type); + } + + memset(lite_item, 0, sizeof(lite_cjson_t)); + + res = lite_cjson_object_item(lite, key, key_len, lite_item); + if (res != SUCCESS_RETURN) { + /* dm_log_err(DM_UTILS_LOG_JSON_PARSE_FAILED, lite->value_length, lite->value); */ + memset(lite_item, 0, sizeof(lite_cjson_t)); + return FAIL_RETURN; + } + + if (type != cJSON_Invalid && lite_item->type != type) { + memset(lite_item, 0, sizeof(lite_cjson_t)); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +void *dm_utils_malloc(unsigned int size) +{ +#ifdef INFRA_MEM_STATS + return LITE_malloc(size, MEM_MAGIC, "lite_cjson"); +#else + return HAL_Malloc(size); +#endif +} + +void dm_utils_free(void *ptr) +{ +#ifdef INFRA_MEM_STATS + LITE_free(ptr); +#else + HAL_Free((void *)ptr); +#endif +} \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_utils.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_utils.h new file mode 100644 index 00000000..e84b9ac5 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_utils.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _DM_UTILS_H_ +#define _DM_UTILS_H_ + +#define DM_UTILS_UINT16_STRLEN (5) +#define DM_UTILS_UINT32_STRLEN (10) +#define DM_UTILS_UINT64_STRLEN (20) + +int dm_utils_copy_direct(void *input, int input_len, void **output, int output_len); + +int dm_utils_copy(void *input, int input_len, void **output, int output_len); + +/** + * @brief search array index in a string. + * This function used to search array index in a string. + * + * @param input. The string to be searched + * @param input_len. The length of input + * @param partial_input_len. The length of input except [xx] + * @param array_input_len. The length of input include [xx] + * @param array_index. The array index in [xx] + * + * @warning input must be type of "xxxxx[xx]" + * @return success or fail. + * + */ +int dm_utils_strarr_index(char *input, int input_len, + int *partial_input_len, int *array_input_len, int *array_index); + +int dm_utils_itoa_direct(int input, char **output); +int dm_utils_itoa(int input, char **output); +int dm_utils_ftoa_direct(double input, char **output); +int dm_utils_ftoa(double input, char **output); +int dm_utils_hex_to_str(unsigned char *input, int input_len, char **output); +int dm_utils_str_to_hex(char *input, int input_len, unsigned char **output, int *output_len); +int dm_utils_memtok(char *input, int input_len, char delimiter, int index, int *offset); +int dm_utils_replace_char(char *input, int input_len, char src, char dest); +int dm_utils_service_name(const char *prefix, const char *name, char product_key[IOTX_PRODUCT_KEY_LEN + 1], + char device_name[IOTX_DEVICE_NAME_LEN + 1], char **service_name); +int dm_utils_uri_add_prefix(const char *prefix, char *uri, char **new_uri); +int dm_utils_json_parse(const char *payload, int payload_len, int type, lite_cjson_t *lite); +int dm_utils_json_object_item(lite_cjson_t *lite, const char *key, int key_len, int type, + lite_cjson_t *lite_item); +void *dm_utils_malloc(unsigned int size); +void dm_utils_free(void *ptr); +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_wrapper.h new file mode 100644 index 00000000..2828a3bc --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/dm_wrapper.h @@ -0,0 +1,81 @@ +#ifndef _DM_WRAPPER_H_ +#define _DM_WRAPPER_H_ + +#include "infra_compat.h" +#include "wrappers_defs.h" + +int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN + 1]); +int HAL_GetProductSecret(char product_secret[IOTX_PRODUCT_SECRET_LEN + 1]); +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN + 1]); +int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN + 1]); + +void *HAL_MutexCreate(void); +void HAL_MutexDestroy(void *mutex); +void HAL_MutexLock(void *mutex); +void HAL_MutexUnlock(void *mutex); + +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); +uint64_t HAL_UptimeMs(void); +void HAL_SleepMs(uint32_t ms); +void HAL_Srandom(uint32_t seed); +uint32_t HAL_Random(uint32_t region); +void HAL_Printf(const char *fmt, ...); +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); + +#ifdef INFRA_LOG +#include +int HAL_Vsnprintf(char *str, const int len, const char *format, va_list ap); +#endif + +int HAL_ThreadCreate( + void **thread_handle, + void *(*work_routine)(void *), + void *arg, + hal_os_thread_param_t *hal_os_thread_param, + int *stack_used); +void HAL_ThreadDelete(void *thread_handle); + +void *HAL_SemaphoreCreate(void); +void HAL_SemaphoreDestroy(void *sem); +void HAL_SemaphorePost(void *sem); +int HAL_SemaphoreWait(void *sem, uint32_t timeout_ms); +int HAL_Kv_Set(const char *key, const void *val, int len, int sync); +int HAL_Kv_Get(const char *key, void *val, int *buffer_len); +int HAL_Kv_Del(const char *key); +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + void HAL_Firmware_Persistence_Start(void); + int HAL_Firmware_Persistence_Write(char *buffer, uint32_t length); + int HAL_Firmware_Persistence_Stop(void); +#ifdef SUPPORT_SECURITY_OTA + int HAL_Firmware_Check_Rsa_Key(char *buffer, uint32_t length); +#endif +#endif + +//#ifdef DEPRECATED_LINKKIT +#if 1 +int HAL_SetProductKey(char *product_key); +int HAL_SetProductSecret(char *product_secret); +int HAL_SetDeviceName(char *device_name); +int HAL_SetDeviceSecret(char *device_secret); +#endif + +#ifdef ALCS_ENABLED +p_HAL_Aes128_t HAL_Aes128_Init( + const uint8_t *key, + const uint8_t *iv, + AES_DIR_t dir); +int HAL_Aes128_Cbc_Encrypt( + p_HAL_Aes128_t aes, + const void *src, + size_t blockNum, + void *dst); +int HAL_Aes128_Destroy(p_HAL_Aes128_t aes); +int HAL_Aes128_Cbc_Decrypt( + p_HAL_Aes128_t aes, + const void *src, + size_t blockNum, + void *dst); +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_gateway.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_gateway.c new file mode 100644 index 00000000..8f38be42 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_gateway.c @@ -0,0 +1,2532 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "iotx_dm_internal.h" + +#if defined(DEPRECATED_LINKKIT) && defined(DEVICE_MODEL_GATEWAY) + +#include "impl_gateway.h" + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define IMPL_GATEWAY_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "impl.gateway") + #define IMPL_GATEWAY_FREE(ptr) IMPL_GATEWAY_FREE(ptr) +#else + #define IMPL_GATEWAY_MALLOC(size) HAL_Malloc(size) + #define IMPL_GATEWAY_FREE(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#ifdef INFRA_LOG + #include "infra_log.h" + #define impl_gateway_err(...) log_err("impl.gateway", __VA_ARGS__) + #define impl_gateway_info(...) log_info("impl.gateway", __VA_ARGS__) + #define impl_gateway_debug(...) log_debug("impl.gateway", __VA_ARGS__) +#else + #define impl_gateway_err(...) + #define impl_gateway_info(...) + #define impl_gateway_debug(...) +#endif + +static linkkit_gateway_legacy_ctx_t g_linkkit_gateway_legacy_ctx = {0}; + +static linkkit_gateway_legacy_ctx_t *_linkkit_gateway_legacy_get_ctx(void) +{ + return &g_linkkit_gateway_legacy_ctx; +} + +static void _linkkit_gateway_mutex_lock(void) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + if (linkkit_gateway_ctx->mutex) { + HAL_MutexLock(linkkit_gateway_ctx->mutex); + } +} + +static void _linkkit_gateway_mutex_unlock(void) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + if (linkkit_gateway_ctx->mutex) { + HAL_MutexUnlock(linkkit_gateway_ctx->mutex); + } +} + +static void _linkkit_gateway_upstream_mutex_lock(void) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + if (linkkit_gateway_ctx->upstream_mutex) { + HAL_MutexLock(linkkit_gateway_ctx->upstream_mutex); + } +} + +static void _linkkit_gateway_upstream_mutex_unlock(void) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + if (linkkit_gateway_ctx->upstream_mutex) { + HAL_MutexUnlock(linkkit_gateway_ctx->upstream_mutex); + } +} + +static int _linkkit_gateway_callback_list_insert(int devid, linkkit_cbs_t *callback, void *context) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_dev_callback_node_t *search_node = NULL, *node = NULL; + + list_for_each_entry(search_node, &linkkit_gateway_ctx->dev_callback_list, linked_list, + linkkit_gateway_dev_callback_node_t) { + if (search_node->devid == devid) { + impl_gateway_info("Device Already Exist: %d", devid); + return SUCCESS_RETURN; + } + } + + node = IMPL_GATEWAY_MALLOC(sizeof(linkkit_gateway_dev_callback_node_t)); + if (node == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(node, 0, sizeof(linkkit_gateway_dev_callback_node_t)); + node->devid = devid; + node->callback = callback; + node->callback_ctx = context; + INIT_LIST_HEAD(&node->linked_list); + + list_add(&node->linked_list, &linkkit_gateway_ctx->dev_callback_list); + + return SUCCESS_RETURN; +} + +static int _linkkit_gateway_callback_list_remove(int devid) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_dev_callback_node_t *search_node = NULL; + + list_for_each_entry(search_node, &linkkit_gateway_ctx->dev_callback_list, linked_list, + linkkit_gateway_dev_callback_node_t) { + if (search_node->devid == devid) { + impl_gateway_info("Device Found: %d, Delete It", devid); + list_del(&search_node->linked_list); + IMPL_GATEWAY_FREE(search_node); + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +static int _linkkit_gateway_callback_list_search(int devid, linkkit_gateway_dev_callback_node_t **node) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_dev_callback_node_t *search_node = NULL; + + if (devid < 0 || node == NULL || *node != NULL) { + return FAIL_RETURN; + } + + list_for_each_entry(search_node, &linkkit_gateway_ctx->dev_callback_list, linked_list, + linkkit_gateway_dev_callback_node_t) { + if (search_node->devid == devid) { + impl_gateway_info("Device Found: %d", devid); + *node = search_node; + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +static void _linkkit_gateway_callback_list_destroy(void) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_dev_callback_node_t *search_node = NULL; + linkkit_gateway_dev_callback_node_t *next_node = NULL; + + list_for_each_entry_safe(search_node, next_node, &linkkit_gateway_ctx->dev_callback_list, linked_list, + linkkit_gateway_dev_callback_node_t) { + list_del(&search_node->linked_list); + IMPL_GATEWAY_FREE(search_node); + } +} + +static int _linkkit_gateway_upstream_sync_callback_list_insert(int msgid, void *semaphore, + linkkit_gateway_upstream_sync_callback_node_t **node) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_upstream_sync_callback_node_t *search_node = NULL; + + list_for_each_entry(search_node, &linkkit_gateway_ctx->upstream_sync_callback_list, linked_list, + linkkit_gateway_upstream_sync_callback_node_t) { + if (search_node->msgid == msgid) { + impl_gateway_info("Message Already Exist: %d", msgid); + return FAIL_RETURN; + } + } + + search_node = IMPL_GATEWAY_MALLOC(sizeof(linkkit_gateway_upstream_sync_callback_node_t)); + if (search_node == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(search_node, 0, sizeof(linkkit_gateway_upstream_sync_callback_node_t)); + search_node->msgid = msgid; + search_node->semaphore = semaphore; + INIT_LIST_HEAD(&search_node->linked_list); + + list_add(&search_node->linked_list, &linkkit_gateway_ctx->upstream_sync_callback_list); + impl_gateway_info("New Message, msgid: %d", msgid); + + *node = search_node; + return SUCCESS_RETURN; +} + +static int _linkkit_gateway_upstream_sync_callback_list_remove(int msgid) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_upstream_sync_callback_node_t *search_node = NULL; + + list_for_each_entry(search_node, &linkkit_gateway_ctx->upstream_sync_callback_list, linked_list, + linkkit_gateway_upstream_sync_callback_node_t) { + if (search_node->msgid == msgid) { + impl_gateway_info("Message Found: %d, Delete It", msgid); + HAL_SemaphoreDestroy(search_node->semaphore); + list_del(&search_node->linked_list); + IMPL_GATEWAY_FREE(search_node); + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +static int _linkkit_gateway_upstream_sync_callback_list_search(int msgid, + linkkit_gateway_upstream_sync_callback_node_t **node) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_upstream_sync_callback_node_t *search_node = NULL; + + if (node == NULL || *node != NULL) { + return FAIL_RETURN; + } + + list_for_each_entry(search_node, &linkkit_gateway_ctx->upstream_sync_callback_list, linked_list, + linkkit_gateway_upstream_sync_callback_node_t) { + if (search_node->msgid == msgid) { + impl_gateway_info("Sync Message Found: %d", msgid); + *node = search_node; + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +static void _linkkit_gateway_upstream_sync_callback_list_destroy(void) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_upstream_sync_callback_node_t *search_node = NULL, *next_node = NULL; + + list_for_each_entry_safe(search_node, next_node, &linkkit_gateway_ctx->upstream_sync_callback_list, linked_list, + linkkit_gateway_upstream_sync_callback_node_t) { + list_del(&search_node->linked_list); + HAL_SemaphoreDestroy(search_node->semaphore); + IMPL_GATEWAY_FREE(search_node); + } +} + +static int _linkkit_gateway_upstream_async_callback_list_insert(int msgid, int timeout_ms, + linkkit_gateway_upstream_async_callback callback, void *context) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_upstream_async_callback_node_t *search_node = NULL, *node = NULL; + + list_for_each_entry(search_node, &linkkit_gateway_ctx->upstream_async_callback_list, linked_list, + linkkit_gateway_upstream_async_callback_node_t) { + if (search_node->msgid == msgid) { + impl_gateway_info("Async Message Already Exist: %d", msgid); + return FAIL_RETURN; + } + } + + node = IMPL_GATEWAY_MALLOC(sizeof(linkkit_gateway_upstream_async_callback_node_t)); + if (node == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(node, 0, sizeof(linkkit_gateway_upstream_async_callback_node_t)); + node->msgid = msgid; + node->timeout_ms = timeout_ms; + node->timestamp_ms = HAL_UptimeMs(); + node->callback = callback; + node->callback_ctx = context; + + INIT_LIST_HEAD(&node->linked_list); + + list_add(&node->linked_list, &linkkit_gateway_ctx->upstream_async_callback_list); + + return SUCCESS_RETURN; +} + +static int _linkkit_gateway_upstream_async_callback_list_remove(int msgid) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_upstream_async_callback_node_t *search_node = NULL; + + list_for_each_entry(search_node, &linkkit_gateway_ctx->upstream_async_callback_list, linked_list, + linkkit_gateway_upstream_async_callback_node_t) { + if (search_node->msgid == msgid) { + impl_gateway_info("Async Message Found: %d, Delete It", msgid); + list_del(&search_node->linked_list); + IMPL_GATEWAY_FREE(search_node); + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +static int _linkkit_gateway_upstream_async_callback_list_search(int msgid, + linkkit_gateway_upstream_async_callback_node_t **node) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_upstream_async_callback_node_t *search_node = NULL; + + if (node == NULL || *node != NULL) { + return FAIL_RETURN; + } + + list_for_each_entry(search_node, &linkkit_gateway_ctx->upstream_async_callback_list, linked_list, + linkkit_gateway_upstream_async_callback_node_t) { + if (search_node->msgid == msgid) { + impl_gateway_info("Async Message Found: %d", msgid); + *node = search_node; + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +static void _linkkit_gateway_upstream_async_callback_list_destroy(void) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_upstream_async_callback_node_t *search_node = NULL, *next_node = NULL; + + list_for_each_entry_safe(search_node, next_node, &linkkit_gateway_ctx->upstream_async_callback_list, linked_list, + linkkit_gateway_upstream_async_callback_node_t) { + list_del(&search_node->linked_list); + IMPL_GATEWAY_FREE(search_node); + } +} + +static void _linkkit_gateway_upstream_callback_remove(int msgid, int code) +{ + int res = 0; + linkkit_gateway_upstream_sync_callback_node_t *sync_node = NULL; + res = _linkkit_gateway_upstream_sync_callback_list_search(msgid, &sync_node); + if (res != SUCCESS_RETURN) { + linkkit_gateway_upstream_async_callback_node_t *node = NULL; + res = _linkkit_gateway_upstream_async_callback_list_search(msgid, &node); + if (res == SUCCESS_RETURN) { + uint64_t current_time = HAL_UptimeMs(); + if (current_time - node->timestamp_ms > node->timeout_ms) { + if (node->callback) { + node->callback(FAIL_RETURN, node->callback_ctx); + } + } else { + if (node->callback) { + int return_value = (code == IOTX_DM_ERR_CODE_SUCCESS) ? (SUCCESS_RETURN) : (FAIL_RETURN); + impl_gateway_info("Async Message %d Result: %d", msgid, return_value); + node->callback(return_value, node->callback_ctx); + } + } + _linkkit_gateway_upstream_async_callback_list_remove(msgid); + } + } else { + sync_node->code = (code == IOTX_DM_ERR_CODE_SUCCESS) ? (SUCCESS_RETURN) : (FAIL_RETURN); + impl_gateway_info("Sync Message %d Result: %d", msgid, sync_node->code); + HAL_SemaphorePost(sync_node->semaphore); + } +} + +linkkit_params_t *linkkit_gateway_get_default_params(void) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + /* Legacy Parameter */ + linkkit_gateway_ctx->init_params.maxMsgSize = 20 * 1024; + linkkit_gateway_ctx->init_params.maxMsgQueueSize = 16; + linkkit_gateway_ctx->init_params.threadPoolSize = 4; + linkkit_gateway_ctx->init_params.threadStackSize = 8 * 1024; + + return &linkkit_gateway_ctx->init_params; +} + +int linkkit_gateway_setopt(linkkit_params_t *params, int option, void *value, int value_len) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (params == NULL || value == NULL) { + return FAIL_RETURN; + } + + switch (option) { + case LINKKIT_OPT_MAX_MSG_SIZE: { + if (value_len != sizeof(int)) { + return FAIL_RETURN; + } + if (*((int *)value) < 256) { + impl_gateway_err("maxMsgSize should not less than 256 bytes\n"); + return FAIL_RETURN; + } + linkkit_gateway_ctx->init_params.maxMsgSize = *((int *)value); + } + break; + case LINKKIT_OPT_MAX_MSG_QUEUE_SIZE: { + if (value_len != sizeof(int)) { + return FAIL_RETURN; + } + if (*((int *)value) < 1) { + impl_gateway_err("maxMsgQueueSize should not less than 1\n"); + return FAIL_RETURN; + } + linkkit_gateway_ctx->init_params.maxMsgQueueSize = *((int *)value); + } + break; + case LINKKIT_OPT_THREAD_POOL_SIZE: { + if (value_len != sizeof(int)) { + return FAIL_RETURN; + } + if (*((int *)value) < 1) { + impl_gateway_err("threadPoolSize should not less than 1\n"); + return FAIL_RETURN; + } + linkkit_gateway_ctx->init_params.threadPoolSize = *((int *)value); + } + break; + case LINKKIT_OPT_THREAD_STACK_SIZE: { + if (value_len != sizeof(int)) { + return FAIL_RETURN; + } + if (*((int *)value) < 1024) { + impl_gateway_err("threadStackSize should not less than 1024\n"); + return FAIL_RETURN; + } + linkkit_gateway_ctx->init_params.threadStackSize = *((int *)value); + } + break; + case LINKKIT_OPT_PROPERTY_POST_REPLY: + iotx_dm_set_opt(0, value); + break; + case LINKKIT_OPT_EVENT_POST_REPLY: + iotx_dm_set_opt(1, value); + break; + case LINKKIT_OPT_PROPERTY_SET_REPLY: + iotx_dm_set_opt(2, value); + break; + default: + impl_gateway_err("unknow option: %d\n", option); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int linkkit_gateway_set_event_callback(linkkit_params_t *params, int (*event_cb)(linkkit_event_t *ev, void *ctx), + void *ctx) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (params == NULL || event_cb == NULL) { + return FAIL_RETURN; + } + + linkkit_gateway_ctx->init_params.event_cb = event_cb; + linkkit_gateway_ctx->init_params.ctx = ctx; + + return SUCCESS_RETURN; +} + +int linkkit_gateway_init(linkkit_params_t *initParams) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (initParams == NULL) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_inited == 1) { + return FAIL_RETURN; + } + + if (initParams->maxMsgSize < 256 || + initParams->maxMsgQueueSize < 1 || + initParams->threadPoolSize < 1 || + initParams->threadStackSize < 1024) { + return FAIL_RETURN; + } + linkkit_gateway_ctx->is_inited = 1; + + return SUCCESS_RETURN; +} + +int linkkit_gateway_exit(void) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (linkkit_gateway_ctx->is_inited == 0) { + return FAIL_RETURN; + } + linkkit_gateway_ctx->is_inited = 0; + + return SUCCESS_RETURN; +} + +static void _linkkit_gateway_event_callback(iotx_dm_event_types_t type, char *payload) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + impl_gateway_info("Receive Message Type: %d", type); + if (payload) { + impl_gateway_info("Receive Message: %s", payload); + } + + switch (type) { + case IOTX_DM_EVENT_CLOUD_CONNECTED: { + if (linkkit_gateway_ctx->init_params.event_cb) { + linkkit_event_t event; + + memset(&event, 0, sizeof(linkkit_event_t)); + event.event_type = LINKKIT_EVENT_CLOUD_CONNECTED; + linkkit_gateway_ctx->init_params.event_cb(&event, linkkit_gateway_ctx->init_params.ctx); + } + } + break; + case IOTX_DM_EVENT_CLOUD_DISCONNECT: { + if (linkkit_gateway_ctx->init_params.event_cb) { + linkkit_event_t event; + + memset(&event, 0, sizeof(linkkit_event_t)); + event.event_type = LINKKIT_EVENT_CLOUD_DISCONNECTED; + linkkit_gateway_ctx->init_params.event_cb(&event, linkkit_gateway_ctx->init_params.ctx); + } + } + break; + case IOTX_DM_EVENT_SUBDEV_REGISTER_REPLY: { + int res = 0; + lite_cjson_t lite, lite_item_id, lite_item_code, lite_item_devid; + + if (payload == NULL) { + return; + } + + /* Parse JSON */ + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite)) { + return; + } + + /* Parse Message ID */ + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_ID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_ID), + &lite_item_id); + if (res != SUCCESS_RETURN || !lite_cjson_is_number(&lite_item_id)) { + return; + } + impl_gateway_info("Current Msg ID: %d", lite_item_id.value_int); + + /* Parse Message Code */ + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_CODE, strlen(LINKKIT_GATEWAY_LEGACY_KEY_CODE), + &lite_item_code); + if (res != SUCCESS_RETURN || !lite_cjson_is_number(&lite_item_code)) { + return; + } + impl_gateway_info("Current Code: %d", lite_item_code.value_int); + + /* Parse Devid */ + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN || !lite_cjson_is_number(&lite_item_devid)) { + return; + } + impl_gateway_info("Current devid: %d", lite_item_devid.value_int); + + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_callback_remove(lite_item_id.value_int, lite_item_code.value_int); + _linkkit_gateway_upstream_mutex_unlock(); + } + break; + case IOTX_DM_EVENT_SUBDEV_UNREGISTER_REPLY: { + + } + break; + case IOTX_DM_EVENT_TOPO_ADD_REPLY: { + int res = 0; + lite_cjson_t lite, lite_item_id, lite_item_code, lite_item_devid; + + if (payload == NULL) { + return; + } + + /* Parse JSON */ + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite)) { + return; + } + + /* Parse Message ID */ + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_ID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_ID), + &lite_item_id); + if (res != SUCCESS_RETURN || !lite_cjson_is_number(&lite_item_id)) { + return; + } + impl_gateway_info("Current Msg ID: %d", lite_item_id.value_int); + + /* Parse Message Code */ + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_CODE, strlen(LINKKIT_GATEWAY_LEGACY_KEY_CODE), + &lite_item_code); + if (res != SUCCESS_RETURN || !lite_cjson_is_number(&lite_item_code)) { + return; + } + impl_gateway_info("Current Code: %d", lite_item_code.value_int); + + /* Parse Devid */ + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN || !lite_cjson_is_number(&lite_item_devid)) { + return; + } + impl_gateway_info("Current devid: %d", lite_item_devid.value_int); + + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_callback_remove(lite_item_id.value_int, lite_item_code.value_int); + _linkkit_gateway_upstream_mutex_unlock(); + } + break; + case IOTX_DM_EVENT_TOPO_DELETE_REPLY: { + int res = 0; + lite_cjson_t lite, lite_item_id, lite_item_code, lite_item_devid; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Id */ + memset(&lite_item_id, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_ID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_ID), + &lite_item_id); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Id: %d", lite_item_id.value_int); + + /* Parse Code */ + memset(&lite_item_code, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_CODE, strlen(LINKKIT_GATEWAY_LEGACY_KEY_CODE), + &lite_item_code); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Code: %d", lite_item_code.value_int); + + /* Parse Devid */ + memset(&lite_item_devid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Devid: %d", lite_item_devid.value_int); + + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_callback_remove(lite_item_id.value_int, lite_item_code.value_int); + _linkkit_gateway_upstream_mutex_unlock(); + } + break; + case IOTX_DM_EVENT_COMBINE_LOGIN_REPLY: { + int res = 0; + lite_cjson_t lite, lite_item_id, lite_item_code, lite_item_devid; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Id */ + memset(&lite_item_id, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_ID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_ID), + &lite_item_id); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Id: %d", lite_item_id.value_int); + + /* Parse Code */ + memset(&lite_item_code, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_CODE, strlen(LINKKIT_GATEWAY_LEGACY_KEY_CODE), + &lite_item_code); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Code: %d", lite_item_code.value_int); + + /* Parse Devid */ + memset(&lite_item_devid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Devid: %d", lite_item_devid.value_int); + + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_callback_remove(lite_item_id.value_int, lite_item_code.value_int); + _linkkit_gateway_upstream_mutex_unlock(); + } + break; + case IOTX_DM_EVENT_COMBINE_LOGOUT_REPLY: { + int res = 0; + lite_cjson_t lite, lite_item_id, lite_item_code, lite_item_devid; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Id */ + memset(&lite_item_id, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_ID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_ID), + &lite_item_id); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Id: %d", lite_item_id.value_int); + + /* Parse Code */ + memset(&lite_item_code, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_CODE, strlen(LINKKIT_GATEWAY_LEGACY_KEY_CODE), + &lite_item_code); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Code: %d", lite_item_code.value_int); + + /* Parse Devid */ + memset(&lite_item_devid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Devid: %d", lite_item_devid.value_int); + + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_callback_remove(lite_item_id.value_int, lite_item_code.value_int); + _linkkit_gateway_upstream_mutex_unlock(); + } + break; + case IOTX_DM_EVENT_PROPERTY_SET: { + int res = 0; + linkkit_gateway_dev_callback_node_t *node = NULL; + lite_cjson_t lite, lite_item_devid, lite_item_payload; + char *params = NULL; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Devid */ + memset(&lite_item_devid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Devid: %d", lite_item_devid.value_int); + + /* Parse Payload */ + memset(&lite_item_payload, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_PAYLOAD, strlen(LINKKIT_GATEWAY_LEGACY_KEY_PAYLOAD), + &lite_item_payload); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Payload: %.*", lite_item_payload.value_length, lite_item_payload.value); + + params = IMPL_GATEWAY_MALLOC(lite_item_payload.value_length + 1); + if (params == NULL) { + return; + } + memset(params, 0, lite_item_payload.value_length + 1); + memcpy(params, lite_item_payload.value, lite_item_payload.value_length); + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_callback_list_search(lite_item_devid.value_int, &node); + _linkkit_gateway_upstream_mutex_unlock(); + if (res == SUCCESS_RETURN) { + if (node->callback->set_property) { + node->callback->set_property(params, node->callback_ctx); + } + } + + IMPL_GATEWAY_FREE(params); + } + break; + case IOTX_DM_EVENT_GATEWAY_PERMIT: { + int res = 0; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + lite_cjson_t lite, lite_item_pk, lite_item_timeout; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Product Key */ + memset(&lite_item_pk, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_PRODUCT_KEY, + strlen(LINKKIT_GATEWAY_LEGACY_KEY_PRODUCT_KEY), &lite_item_pk); + if (res != SUCCESS_RETURN || lite_item_pk.value_length >= IOTX_PRODUCT_KEY_LEN + 1) { + return; + } + impl_gateway_debug("Current Product Key: %.*s", lite_item_pk.value_length, lite_item_pk.value); + + /* Parse Timeout */ + memset(&lite_item_timeout, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_TIME, strlen(LINKKIT_GATEWAY_LEGACY_KEY_TIME), + &lite_item_timeout); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Timeout: %d", lite_item_timeout.value_int); + + memcpy(product_key, lite_item_pk.value, lite_item_pk.value_length); + + if (linkkit_gateway_ctx->init_params.event_cb) { + linkkit_event_t event; + + memset(&event, 0, sizeof(linkkit_event_t)); + event.event_type = LINKKIT_EVENT_SUBDEV_PERMITED; + event.event_data.subdev_permited.productKey = product_key; + event.event_data.subdev_permited.timeoutSec = lite_item_timeout.value_int; + linkkit_gateway_ctx->init_params.event_cb(&event, linkkit_gateway_ctx->init_params.ctx); + } + } + break; + case IOTX_DM_EVENT_THING_SERVICE_REQUEST: { + int res = 0; + linkkit_gateway_dev_callback_node_t *node = NULL; + lite_cjson_t lite, lite_item_id, lite_item_devid, lite_item_serviceid, lite_item_paylaod; + char *identifier = NULL, *input = NULL, *output = NULL; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Id */ + memset(&lite_item_id, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_ID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_ID), + &lite_item_id); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Id: %d", lite_item_id.value_int); + + /* Parse Devid */ + memset(&lite_item_devid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Devid: %d", lite_item_devid.value_int); + + /* Parse Serviceid */ + memset(&lite_item_serviceid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_SERVICEID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_SERVICEID), + &lite_item_serviceid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current ServiceID: %.*s", lite_item_serviceid.value_length, lite_item_serviceid.value); + + /* Parse Payload */ + memset(&lite_item_paylaod, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_PAYLOAD, strlen(LINKKIT_GATEWAY_LEGACY_KEY_PAYLOAD), + &lite_item_paylaod); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Payload: %.*s", lite_item_paylaod.value_length, lite_item_paylaod.value); + + identifier = IMPL_GATEWAY_MALLOC(lite_item_serviceid.value_length + 1); + if (identifier == NULL) { + return; + } + memset(identifier, 0, lite_item_serviceid.value_length + 1); + memcpy(identifier, lite_item_serviceid.value, lite_item_serviceid.value_length); + + input = IMPL_GATEWAY_MALLOC(lite_item_paylaod.value_length + 1); + if (input == NULL) { + IMPL_GATEWAY_FREE(identifier); + return; + } + memset(input, 0, lite_item_paylaod.value_length + 1); + memcpy(input, lite_item_paylaod.value, lite_item_paylaod.value_length); + + + output = IMPL_GATEWAY_MALLOC(linkkit_gateway_ctx->init_params.maxMsgSize + 1); + if (output == NULL) { + IMPL_GATEWAY_FREE(identifier); + IMPL_GATEWAY_FREE(input); + return; + } + memset(output, 0, linkkit_gateway_ctx->init_params.maxMsgSize + 1); + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_callback_list_search(lite_item_devid.value_int, &node); + _linkkit_gateway_upstream_mutex_unlock(); + if (res == SUCCESS_RETURN) { + if (node->callback->call_service) { + res = node->callback->call_service(identifier, input, output, linkkit_gateway_ctx->init_params.maxMsgSize, + node->callback_ctx); + if (res == SUCCESS_RETURN) { + iotx_dm_deprecated_legacy_send_service_response(lite_item_devid.value_int, lite_item_id.value_int, 200, + lite_item_serviceid.value, + lite_item_serviceid.value_length, output, strlen(output)); + } else { + iotx_dm_deprecated_legacy_send_service_response(lite_item_devid.value_int, lite_item_id.value_int, 202, + lite_item_serviceid.value, + lite_item_serviceid.value_length, "{}", strlen("{}")); + } + } + } + + IMPL_GATEWAY_FREE(identifier); + IMPL_GATEWAY_FREE(input); + IMPL_GATEWAY_FREE(output); + } + break; + case IOTX_DM_EVENT_MODEL_DOWN_RAW: { + int res = 0; + linkkit_gateway_dev_callback_node_t *node = NULL; + lite_cjson_t lite, lite_item_devid, lite_item_rawdata; + char *output = NULL; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Devid */ + memset(&lite_item_devid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Devid: %d", lite_item_devid.value_int); + + /* Parse Raw Data */ + memset(&lite_item_rawdata, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_PAYLOAD, strlen(LINKKIT_GATEWAY_LEGACY_KEY_PAYLOAD), + &lite_item_rawdata); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Raw Data: %.*s", lite_item_rawdata.value_length, lite_item_rawdata.value); + + output = IMPL_GATEWAY_MALLOC(linkkit_gateway_ctx->init_params.maxMsgSize + 1); + if (output == NULL) { + return; + } + memset(output, 0, linkkit_gateway_ctx->init_params.maxMsgSize + 1); + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_callback_list_search(lite_item_devid.value_int, &node); + _linkkit_gateway_upstream_mutex_unlock(); + if (res == SUCCESS_RETURN) { + if (node->callback->down_rawdata) { + res = node->callback->down_rawdata(lite_item_rawdata.value, lite_item_rawdata.value_length, output, + linkkit_gateway_ctx->init_params.maxMsgSize, node->callback_ctx); + if (res > 0) { + iotx_dm_post_rawdata(lite_item_devid.value_int, output, res); + } + } + } + + IMPL_GATEWAY_FREE(output); + } + break; + case IOTX_DM_EVENT_MODEL_UP_RAW_REPLY: { + int res = 0; + linkkit_gateway_dev_callback_node_t *node = NULL; + lite_cjson_t lite, lite_item_devid, lite_item_rawdata; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Devid */ + memset(&lite_item_devid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Devid: %d", lite_item_devid.value_int); + + /* Parse Raw Data */ + memset(&lite_item_rawdata, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_PAYLOAD, strlen(LINKKIT_GATEWAY_LEGACY_KEY_PAYLOAD), + &lite_item_rawdata); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Raw Data: %.*s", lite_item_rawdata.value_length, lite_item_rawdata.value); + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_callback_list_search(lite_item_devid.value_int, &node); + _linkkit_gateway_upstream_mutex_unlock(); + if (res == SUCCESS_RETURN) { + if (node->callback->post_rawdata_reply) { + node->callback->post_rawdata_reply(lite_item_rawdata.value, lite_item_rawdata.value_length, node->callback_ctx); + } + } + } + break; + case IOTX_DM_EVENT_INITIALIZED: { + int res = 0; + linkkit_gateway_dev_callback_node_t *node = NULL; + lite_cjson_t lite, lite_item_devid; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Devid */ + memset(&lite_item_devid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Devid: %d", lite_item_devid.value_int); + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_callback_list_search(lite_item_devid.value_int, &node); + _linkkit_gateway_upstream_mutex_unlock(); + if (res == SUCCESS_RETURN) { + if (node->callback->register_complete) { + node->callback->register_complete(node->callback_ctx); + } + } + } + break; + case IOTX_DM_EVENT_EVENT_PROPERTY_POST_REPLY: { + int res = 0; + lite_cjson_t lite, lite_item_id, lite_item_code, lite_item_devid; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Id */ + memset(&lite_item_id, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_ID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_ID), + &lite_item_id); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Id: %d", lite_item_id.value_int); + + /* Parse Code */ + memset(&lite_item_code, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_CODE, strlen(LINKKIT_GATEWAY_LEGACY_KEY_CODE), + &lite_item_code); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Code: %d", lite_item_code.value_int); + + /* Parse Devid */ + memset(&lite_item_devid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Devid: %d", lite_item_devid.value_int); + + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_callback_remove(lite_item_id.value_int, lite_item_code.value_int); + _linkkit_gateway_upstream_mutex_unlock(); + } + break; + case IOTX_DM_EVENT_EVENT_SPECIFIC_POST_REPLY: { + int res = 0; + char *eventid = NULL; + lite_cjson_t lite, lite_item_id, lite_item_code, lite_item_devid, lite_item_eventid; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Id */ + memset(&lite_item_id, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_ID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_ID), + &lite_item_id); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Id: %d", lite_item_id.value_int); + + /* Parse Code */ + memset(&lite_item_code, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_CODE, strlen(LINKKIT_GATEWAY_LEGACY_KEY_CODE), + &lite_item_code); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Code: %d", lite_item_code.value_int); + + /* Parse Devid */ + memset(&lite_item_devid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Devid: %d", lite_item_devid.value_int); + + /* Parse Property ID */ + memset(&lite_item_eventid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_EVENTID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_EVENTID), + &lite_item_eventid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current EventID: %.*s", lite_item_eventid.value_length, lite_item_eventid.value); + + eventid = IMPL_GATEWAY_MALLOC(lite_item_eventid.value_length + 1); + if (eventid == NULL) { + return; + } + memset(eventid, 0, lite_item_eventid.value_length + 1); + memcpy(eventid, lite_item_eventid.value, lite_item_eventid.value_length); + + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_callback_remove(lite_item_id.value_int, lite_item_code.value_int); + _linkkit_gateway_upstream_mutex_unlock(); + + IMPL_GATEWAY_FREE(eventid); + } + break; + case IOTX_DM_EVENT_FOTA_NEW_FIRMWARE: { + int res = 0; + lite_cjson_t lite, lite_item_version; + char *version = NULL; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite)) { + return; + } + + /* Parse Version */ + memset(&lite_item_version, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_VERSION, strlen(LINKKIT_GATEWAY_LEGACY_KEY_VERSION), + &lite_item_version); + if (res != SUCCESS_RETURN || !lite_cjson_is_string(&lite_item_version)) { + return; + } + impl_gateway_debug("Current Firmware Version: %.*s", lite_item_version.value_length, lite_item_version.value); + + version = IMPL_GATEWAY_MALLOC(lite_item_version.value_length + 1); + if (version == NULL) { + return; + } + memset(version, 0, lite_item_version.value_length + 1); + memcpy(version, lite_item_version.value, lite_item_version.value_length); + + if (linkkit_gateway_ctx->fota_callback) { + linkkit_gateway_ctx->fota_callback(service_fota_callback_type_new_version_detected, version); + } + + if (version) { + IMPL_GATEWAY_FREE(version); + } + } + break; + case IOTX_DM_EVENT_DEVICEINFO_UPDATE_REPLY: { + int res = 0; + lite_cjson_t lite, lite_item_id, lite_item_code, lite_item_devid; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Id */ + memset(&lite_item_id, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_ID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_ID), + &lite_item_id); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Id: %d", lite_item_id.value_int); + + /* Parse Code */ + memset(&lite_item_code, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_CODE, strlen(LINKKIT_GATEWAY_LEGACY_KEY_CODE), + &lite_item_code); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Code: %d", lite_item_code.value_int); + + /* Parse Devid */ + memset(&lite_item_devid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Devid: %d", lite_item_devid.value_int); + + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_callback_remove(lite_item_id.value_int, lite_item_code.value_int); + _linkkit_gateway_upstream_mutex_unlock(); + } + break; + case IOTX_DM_EVENT_DEVICEINFO_DELETE_REPLY: { + int res = 0; + lite_cjson_t lite, lite_item_id, lite_item_code, lite_item_devid; + + if (payload == NULL) { + return; + } + + /* Parse Payload */ + memset(&lite, 0, sizeof(lite_cjson_t)); + res = lite_cjson_parse(payload, strlen(payload), &lite); + if (res != SUCCESS_RETURN) { + return; + } + + /* Parse Id */ + memset(&lite_item_id, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_ID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_ID), + &lite_item_id); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Id: %d", lite_item_id.value_int); + + /* Parse Code */ + memset(&lite_item_code, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_CODE, strlen(LINKKIT_GATEWAY_LEGACY_KEY_CODE), + &lite_item_code); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Code: %d", lite_item_code.value_int); + + /* Parse Devid */ + memset(&lite_item_devid, 0, sizeof(lite_cjson_t)); + res = lite_cjson_object_item(&lite, LINKKIT_GATEWAY_LEGACY_KEY_DEVID, strlen(LINKKIT_GATEWAY_LEGACY_KEY_DEVID), + &lite_item_devid); + if (res != SUCCESS_RETURN) { + return; + } + impl_gateway_debug("Current Devid: %d", lite_item_devid.value_int); + + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_callback_remove(lite_item_id.value_int, lite_item_code.value_int); + _linkkit_gateway_upstream_mutex_unlock(); + } + break; + default: { + impl_gateway_info("Not Found Type For Now, Smile"); + } + break; + } +} + +static void *_linkkit_gateway_dispatch(void *params) +{ + while (1) { + iotx_dm_dispatch(); + HAL_SleepMs(20); + } + return NULL; +} + +int linkkit_gateway_start(linkkit_cbs_t *cbs, void *ctx) +{ + int res = 0, stack_used = 0; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + iotx_dm_init_params_t dm_init_params; + linkkit_gateway_dev_callback_node_t *node = NULL; + + if (cbs == NULL) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_inited == 0) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started) { + impl_gateway_info("Linkkit Gateway Already Started"); + return SUCCESS_RETURN; + } + + linkkit_gateway_ctx->is_inited = 1; + linkkit_gateway_ctx->is_started = 1; + + /* Create Mutex */ + linkkit_gateway_ctx->mutex = HAL_MutexCreate(); + if (linkkit_gateway_ctx->mutex == NULL) { + linkkit_gateway_ctx->is_started = 0; + return FAIL_RETURN; + } + + linkkit_gateway_ctx->upstream_mutex = HAL_MutexCreate(); + if (linkkit_gateway_ctx->upstream_mutex == NULL) { + HAL_MutexDestroy(linkkit_gateway_ctx->mutex); + linkkit_gateway_ctx->is_started = 0; + return FAIL_RETURN; + } + + /* Initialize Device Manager */ + memset(&dm_init_params, 0, sizeof(iotx_dm_init_params_t)); + dm_init_params.secret_type = IOTX_DM_DEVICE_SECRET_DEVICE; + dm_init_params.domain_type = IOTX_DM_CLOUD_DOMAIN_SHANGHAI; + dm_init_params.event_callback = _linkkit_gateway_event_callback; + + res = iotx_dm_open(); + if (res != SUCCESS_RETURN) { + HAL_MutexDestroy(linkkit_gateway_ctx->mutex); + HAL_MutexDestroy(linkkit_gateway_ctx->upstream_mutex); + linkkit_gateway_ctx->is_started = 0; + return FAIL_RETURN; + } + + res = iotx_dm_connect(&dm_init_params); + if (res != SUCCESS_RETURN) { + HAL_MutexDestroy(linkkit_gateway_ctx->mutex); + HAL_MutexDestroy(linkkit_gateway_ctx->upstream_mutex); + linkkit_gateway_ctx->is_started = 0; + return FAIL_RETURN; + } + + res = iotx_dm_subscribe(IOTX_DM_LOCAL_NODE_DEVID); + if (res != SUCCESS_RETURN) { + HAL_MutexDestroy(linkkit_gateway_ctx->mutex); + HAL_MutexDestroy(linkkit_gateway_ctx->upstream_mutex); + iotx_dm_close(); + linkkit_gateway_ctx->is_started = 0; + return FAIL_RETURN; + } + + res = HAL_ThreadCreate(&linkkit_gateway_ctx->dispatch_thread, _linkkit_gateway_dispatch, NULL, NULL, &stack_used); + if (res != SUCCESS_RETURN) { + HAL_MutexDestroy(linkkit_gateway_ctx->mutex); + HAL_MutexDestroy(linkkit_gateway_ctx->upstream_mutex); + iotx_dm_close(); + linkkit_gateway_ctx->is_started = 0; + return FAIL_RETURN; + } + + /* Insert Gateway Callback And Callback Context Into Device Callback Linkked List */ + INIT_LIST_HEAD(&linkkit_gateway_ctx->dev_callback_list); + + res = _linkkit_gateway_callback_list_insert(IOTX_DM_LOCAL_NODE_DEVID, cbs, ctx); + if (res != SUCCESS_RETURN) { + HAL_MutexDestroy(linkkit_gateway_ctx->mutex); + HAL_MutexDestroy(linkkit_gateway_ctx->upstream_mutex); + iotx_dm_close(); + HAL_ThreadDelete(linkkit_gateway_ctx->dispatch_thread); + linkkit_gateway_ctx->is_started = 0; + return FAIL_RETURN; + } + + /* Init Upstream Callback List */ + INIT_LIST_HEAD(&linkkit_gateway_ctx->upstream_sync_callback_list); + INIT_LIST_HEAD(&linkkit_gateway_ctx->upstream_async_callback_list); + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_callback_list_search(IOTX_DM_LOCAL_NODE_DEVID, &node); + _linkkit_gateway_upstream_mutex_unlock(); + if (res == SUCCESS_RETURN) { + if (node->callback->register_complete) { + node->callback->register_complete(node->callback_ctx); + } + } + + return SUCCESS_RETURN; +} + +int linkkit_gateway_stop(int devid) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + if (devid != IOTX_DM_LOCAL_NODE_DEVID) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + _linkkit_gateway_upstream_mutex_lock(); + linkkit_gateway_ctx->is_started = 0; + HAL_ThreadDelete(linkkit_gateway_ctx->dispatch_thread); + iotx_dm_close(); + HAL_SleepMs(200); + _linkkit_gateway_callback_list_destroy(); + _linkkit_gateway_upstream_sync_callback_list_destroy(); + _linkkit_gateway_upstream_async_callback_list_destroy(); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + + HAL_MutexDestroy(linkkit_gateway_ctx->upstream_mutex); + HAL_MutexDestroy(linkkit_gateway_ctx->mutex); + + linkkit_gateway_ctx->mutex = NULL; + linkkit_gateway_ctx->upstream_mutex = NULL; + memset(&linkkit_gateway_ctx->init_params, 0, sizeof(linkkit_params_t)); + linkkit_gateway_ctx->dispatch_thread = NULL; + linkkit_gateway_ctx->fota_callback = NULL; + INIT_LIST_HEAD(&linkkit_gateway_ctx->dev_callback_list); + INIT_LIST_HEAD(&linkkit_gateway_ctx->upstream_sync_callback_list); + INIT_LIST_HEAD(&linkkit_gateway_ctx->upstream_async_callback_list); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_subdev_register(char *productKey, char *deviceName, char *deviceSecret) +{ + int res = 0, msgid = 0, code = 0, devid = 0; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + linkkit_gateway_upstream_sync_callback_node_t *node = NULL; + void *semaphore = NULL; + linkkit_gateway_dev_callback_node_t *dev_callback_node = NULL; + + if (productKey == NULL || strlen(productKey) >= IOTX_PRODUCT_KEY_LEN + 1 || + deviceName == NULL || strlen(deviceName) >= IOTX_DEVICE_NAME_LEN + 1) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + res = iotx_dm_deprecated_legacy_get_devid_by_pkdn(productKey, deviceName, &devid); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + /* Subdev Delete Topo */ + res = iotx_dm_subdev_topo_del(devid); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + msgid = res; + + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, LINKKIT_GATEWAY_LEGACY_SYNC_DEFAULT_TIMEOUT_MS); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + code = node->code; + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + /* Subdev Register */ + res = iotx_dm_deprecated_subdev_register(devid, deviceSecret); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + if (res > SUCCESS_RETURN) { + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + msgid = res; + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, LINKKIT_GATEWAY_LEGACY_SYNC_DEFAULT_TIMEOUT_MS); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + code = node->code; + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + } + + /* Subdev Add Topo */ + res = iotx_dm_subdev_topo_add(devid); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + msgid = res; + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, LINKKIT_GATEWAY_LEGACY_SYNC_DEFAULT_TIMEOUT_MS); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + code = node->code; + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_callback_list_search(devid, &dev_callback_node); + _linkkit_gateway_upstream_mutex_unlock(); + if (res == SUCCESS_RETURN) { + if (dev_callback_node->callback->register_complete) { + dev_callback_node->callback->register_complete(dev_callback_node->callback_ctx); + } + } + + _linkkit_gateway_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_subdev_unregister(char *productKey, char *deviceName) +{ + int res = 0, msgid = 0, code = 0, devid = 0; + linkkit_gateway_upstream_sync_callback_node_t *node = NULL; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + void *semaphore = NULL; + + if (productKey == NULL || strlen(productKey) >= IOTX_PRODUCT_KEY_LEN + 1 || + deviceName == NULL || strlen(deviceName) >= IOTX_DEVICE_NAME_LEN + 1) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + res = iotx_dm_deprecated_legacy_get_devid_by_pkdn(productKey, deviceName, &devid); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + /* Subdev Delete Topo */ + res = iotx_dm_subdev_topo_del(devid); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + msgid = res; + + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, LINKKIT_GATEWAY_LEGACY_SYNC_DEFAULT_TIMEOUT_MS); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + code = node->code; + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_subdev_create(char *productKey, char *deviceName, linkkit_cbs_t *cbs, void *ctx) +{ + int res = 0, devid = 0; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (productKey == NULL || strlen(productKey) >= IOTX_PRODUCT_KEY_LEN + 1 || + deviceName == NULL || strlen(deviceName) >= IOTX_DEVICE_NAME_LEN + 1 || cbs == NULL) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + res = iotx_dm_subdev_create(productKey, deviceName, NULL, &devid); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_callback_list_insert(devid, cbs, ctx); + if (res != SUCCESS_RETURN) { + iotx_dm_subdev_destroy(devid); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + + return devid; +} + +int linkkit_gateway_subdev_destroy(int devid) +{ + int res = 0; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + if (devid <= 0) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_callback_list_remove(devid); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + res = iotx_dm_subdev_destroy(devid); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_subdev_login(int devid) +{ + int res = 0, msgid = 0, code = 0; + linkkit_gateway_upstream_sync_callback_node_t *node = NULL; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + void *semaphore = NULL; + + if (devid <= 0) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + res = iotx_dm_subdev_login(devid); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + msgid = res; + + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, LINKKIT_GATEWAY_LEGACY_SYNC_DEFAULT_TIMEOUT_MS); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + code = node->code; + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + res = iotx_dm_subscribe(devid); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_subdev_logout(int devid) +{ + int res = 0, msgid = 0, code = 0; + linkkit_gateway_upstream_sync_callback_node_t *node = NULL; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + void *semaphore = NULL; + + if (devid <= 0) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + res = iotx_dm_subdev_logout(devid); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + msgid = res; + + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, LINKKIT_GATEWAY_LEGACY_SYNC_DEFAULT_TIMEOUT_MS); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + code = node->code; + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_get_devinfo(int devid, linkkit_devinfo_t *devinfo) +{ + int res = 0, type = 0; + iotx_dm_dev_status_t status; + iotx_dm_dev_avail_t available; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (devid < 0 || devinfo == NULL) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + memset(devinfo, 0, sizeof(linkkit_devinfo_t)); + res = iotx_dm_deprecated_legacy_get_pkdn_ptr_by_devid(devid, &(devinfo->productKey), &(devinfo->deviceName)); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + res = iotx_dm_get_device_type(devid, &type); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + if (type == IOTX_DM_DEVICE_GATEWAY) { + devinfo->devtype = 0; + } else if (type == IOTX_DM_DEVICE_SUBDEV) { + devinfo->devtype = 1; + } else { + impl_gateway_info("wrong device type\n"); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + res = iotx_dm_get_device_status(devid, &status); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + if (status >= IOTX_DM_DEV_STATUS_LOGINED) { + devinfo->login = 1; + } + if (status == IOTX_DM_DEV_STATUS_ONLINE) { + devinfo->online = 1; + } + + res = iotx_dm_get_device_avail_status(devid, &available); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + devinfo->state = available; + _linkkit_gateway_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_trigger_event_json_sync(int devid, char *identifier, char *event, int timeout_ms) +{ + int res = 0, msgid = 0, code = 0, event_reply_value = 0; + linkkit_gateway_upstream_sync_callback_node_t *node = NULL; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + void *semaphore = NULL; + + if (devid < 0 || identifier == NULL || event == NULL || timeout_ms < 0) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + res = iotx_dm_get_opt(1, (void *)&event_reply_value); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + if (timeout_ms == 0 || event_reply_value == 0) { + res = iotx_dm_post_event(devid, identifier, strlen(identifier), event, strlen(event)); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } else { + _linkkit_gateway_mutex_unlock(); + return SUCCESS_RETURN; + } + } + + res = iotx_dm_post_event(devid, identifier, strlen(identifier), event, strlen(event)); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + msgid = res; + + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, timeout_ms); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + code = node->code; + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_trigger_event_json(int devid, char *identifier, char *event, int timeout_ms, + void (*func)(int retval, void *ctx), void *ctx) +{ + int res = 0, event_reply_value = 0; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (devid < 0 || identifier == NULL || event == NULL || timeout_ms < 0) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + res = iotx_dm_get_opt(1, (void *)&event_reply_value); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + impl_gateway_info("event_reply_value: %d", event_reply_value); + + if (timeout_ms == 0 || event_reply_value == 0) { + res = iotx_dm_post_event(devid, identifier, strlen(identifier), event, strlen(event)); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } else { + _linkkit_gateway_mutex_unlock(); + return SUCCESS_RETURN; + } + } + + res = iotx_dm_post_event(devid, identifier, strlen(identifier), event, strlen(event)); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_upstream_async_callback_list_insert(res, timeout_ms, func, ctx); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_post_property_json_sync(int devid, char *property, int timeout_ms) +{ + int res = 0, msgid = 0, code = 0, property_reply_value = 0; + linkkit_gateway_upstream_sync_callback_node_t *node = NULL; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + void *semaphore = NULL; + + if (devid < 0 || property == NULL || timeout_ms < 0) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + res = iotx_dm_get_opt(0, (void *)&property_reply_value); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + if (timeout_ms == 0 || property_reply_value == 0) { + res = iotx_dm_post_property(devid, property, strlen(property)); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } else { + _linkkit_gateway_mutex_unlock(); + return SUCCESS_RETURN; + } + } + + res = iotx_dm_post_property(devid, property, strlen(property)); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + msgid = res; + + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, timeout_ms); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + code = node->code; + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_post_property_json(int devid, char *property, int timeout_ms, void (*func)(int retval, void *ctx), + void *ctx) +{ + int res = 0, property_reply_value = 0; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (devid < 0 || property == NULL || timeout_ms < 0) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + res = iotx_dm_get_opt(0, (void *)&property_reply_value); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + if (timeout_ms == 0 || property_reply_value == 0) { + res = iotx_dm_post_property(devid, property, strlen(property)); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } else { + _linkkit_gateway_mutex_unlock(); + return SUCCESS_RETURN; + } + } + + res = iotx_dm_post_property(devid, property, strlen(property)); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_upstream_async_callback_list_insert(res, timeout_ms, func, ctx); + if (res != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_post_rawdata(int devid, void *data, int len) +{ + int res = 0; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (devid < 0 || data == NULL || len <= 0) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + res = iotx_dm_post_rawdata(devid, data, len); + _linkkit_gateway_mutex_unlock(); + + return res; +} + +int linkkit_gateway_fota_init(handle_service_fota_callback_fp_t callback_fp) +{ + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + linkkit_gateway_ctx->fota_callback = callback_fp; + + return SUCCESS_RETURN; +} + +int linkkit_gateway_invoke_fota_service(void *data_buf, int data_buf_length) +{ + int res = 0; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + res = iotx_dm_fota_perform_sync(data_buf, data_buf_length); + _linkkit_gateway_mutex_unlock(); + + return res; +} + +int linkkit_gateway_post_extinfos(int devid, linkkit_extinfo_t *extinfos, int nb_extinfos, int timeout_ms) +{ + int res = 0, index = 0, msgid = 0, code = 0; + linkkit_gateway_upstream_sync_callback_node_t *node = NULL; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + void *semaphore = NULL; + char *payload = NULL; + lite_cjson_item_t *lite_array = NULL, *lite_array_item = NULL; + + if (devid < 0 || extinfos == NULL || nb_extinfos <= 0 || timeout_ms < 0) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + lite_array = lite_cjson_create_array(); + if (lite_array == NULL) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + for (index = 0; index < nb_extinfos; index++) { + if (extinfos[index].attrKey == NULL || extinfos[index].attrValue == NULL) { + lite_cjson_delete(lite_array); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + lite_array_item = lite_cjson_create_object(); + if (lite_array_item == NULL) { + lite_cjson_delete(lite_array); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + lite_cjson_add_string_to_object(lite_array_item, "attrKey", extinfos[index].attrKey); + lite_cjson_add_string_to_object(lite_array_item, "attrValue", extinfos[index].attrValue); + lite_cjson_add_item_to_array(lite_array, lite_array_item); + } + + payload = lite_cjson_print_unformatted(lite_array); + if (payload == NULL) { + lite_cjson_delete(lite_array); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + lite_cjson_delete(lite_array); + + if (timeout_ms == 0) { + res = iotx_dm_deviceinfo_update(devid, payload, strlen(payload)); + IMPL_GATEWAY_FREE(payload); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } else { + _linkkit_gateway_mutex_unlock(); + return SUCCESS_RETURN; + } + } + + res = iotx_dm_deviceinfo_update(devid, payload, strlen(payload)); + if (res < SUCCESS_RETURN) { + IMPL_GATEWAY_FREE(payload); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + msgid = res; + IMPL_GATEWAY_FREE(payload); + + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, timeout_ms); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + code = node->code; + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_delete_extinfos(int devid, linkkit_extinfo_t *extinfos, int nb_extinfos, int timeout_ms) +{ + int res = 0, index = 0, msgid = 0, code = 0; + linkkit_gateway_upstream_sync_callback_node_t *node = NULL; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + void *semaphore = NULL; + char *payload = NULL; + lite_cjson_item_t *lite_array = NULL, *lite_array_item = NULL; + + if (devid < 0 || extinfos == NULL || nb_extinfos <= 0 || timeout_ms < 0) { + return FAIL_RETURN; + } + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + lite_array = lite_cjson_create_array(); + if (lite_array == NULL) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + for (index = 0; index < nb_extinfos; index++) { + if (extinfos[index].attrKey == NULL || extinfos[index].attrValue == NULL) { + lite_cjson_delete(lite_array); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + lite_array_item = lite_cjson_create_object(); + if (lite_array_item == NULL) { + lite_cjson_delete(lite_array); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + lite_cjson_add_string_to_object(lite_array_item, "attrKey", extinfos[index].attrKey); + lite_cjson_add_string_to_object(lite_array_item, "attrValue", extinfos[index].attrValue); + lite_cjson_add_item_to_array(lite_array, lite_array_item); + } + + payload = lite_cjson_print_unformatted(lite_array); + if (payload == NULL) { + lite_cjson_delete(lite_array); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + lite_cjson_delete(lite_array); + + if (timeout_ms == 0) { + res = iotx_dm_deviceinfo_delete(devid, payload, strlen(payload)); + IMPL_GATEWAY_FREE(payload); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } else { + _linkkit_gateway_mutex_unlock(); + return SUCCESS_RETURN; + } + } + + res = iotx_dm_deviceinfo_delete(devid, payload, strlen(payload)); + if (res < SUCCESS_RETURN) { + IMPL_GATEWAY_FREE(payload); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + msgid = res; + IMPL_GATEWAY_FREE(payload); + + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + res = _linkkit_gateway_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, timeout_ms); + if (res < SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_lock(); + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_gateway_upstream_mutex_lock(); + code = node->code; + _linkkit_gateway_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + return FAIL_RETURN; + } + _linkkit_gateway_upstream_mutex_unlock(); + _linkkit_gateway_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int linkkit_gateway_get_num_devices(void) +{ + int dev_nums = 0; + linkkit_gateway_legacy_ctx_t *linkkit_gateway_ctx = _linkkit_gateway_legacy_get_ctx(); + + if (linkkit_gateway_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_gateway_mutex_lock(); + dev_nums = iotx_dm_subdev_number(); + _linkkit_gateway_mutex_unlock(); + + return dev_nums; +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_gateway.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_gateway.h new file mode 100644 index 00000000..c742223f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_gateway.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _LINKKIT_GATEWAY_LEGACY_H_ +#define _LINKKIT_GATEWAY_LEGACY_H_ + +#include "infra_list.h" +#include "linkkit_gateway_export.h" + +#define LINKKIT_GATEWAY_LEGACY_KEY_ID "id" +#define LINKKIT_GATEWAY_LEGACY_KEY_CODE "code" +#define LINKKIT_GATEWAY_LEGACY_KEY_DEVID "devid" +#define LINKKIT_GATEWAY_LEGACY_KEY_SERVICEID "serviceid" +#define LINKKIT_GATEWAY_LEGACY_KEY_PROPERTYID "propertyid" +#define LINKKIT_GATEWAY_LEGACY_KEY_EVENTID "eventid" +#define LINKKIT_GATEWAY_LEGACY_KEY_PAYLOAD "payload" +#define LINKKIT_GATEWAY_LEGACY_KEY_PRODUCT_KEY "productKey" +#define LINKKIT_GATEWAY_LEGACY_KEY_TIME "time" +#define LINKKIT_GATEWAY_LEGACY_KEY_VERSION "version" + +#define LINKKIT_GATEWAY_LEGACY_SYNC_DEFAULT_TIMEOUT_MS (10000) + +typedef struct { + int devid; + linkkit_cbs_t *callback; + void *callback_ctx; + struct list_head linked_list; +} linkkit_gateway_dev_callback_node_t; + +typedef void (*linkkit_gateway_upstream_async_callback)(int retval, void *ctx); +typedef struct { + int msgid; + void *semaphore; + int code; + struct list_head linked_list; +} linkkit_gateway_upstream_sync_callback_node_t; + +typedef struct { + int msgid; + int timeout_ms; + uint64_t timestamp_ms; + linkkit_gateway_upstream_async_callback callback; + void *callback_ctx; + struct list_head linked_list; +} linkkit_gateway_upstream_async_callback_node_t; + +typedef struct { + void *mutex; + void *upstream_mutex; + int is_inited; + int is_started; + linkkit_params_t init_params; + void *dispatch_thread; + handle_service_fota_callback_fp_t fota_callback; + struct list_head dev_callback_list; + struct list_head upstream_sync_callback_list; + struct list_head upstream_async_callback_list; +} linkkit_gateway_legacy_ctx_t; + + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_linkkit.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_linkkit.c new file mode 100644 index 00000000..834b7114 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_linkkit.c @@ -0,0 +1,1671 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "iotx_dm_internal.h" + +#if defined(DEVICE_MODEL_ENABLED) && !defined(DEPRECATED_LINKKIT) +#include "dev_model_api.h" + +#ifdef LOG_REPORT_TO_CLOUD + #include "iotx_log_report.h" +#endif + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define IMPL_LINKKIT_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "impl.linkkit") + #define IMPL_LINKKIT_FREE(ptr) LITE_free(ptr) +#else + #define IMPL_LINKKIT_MALLOC(size) HAL_Malloc(size) + #define IMPL_LINKKIT_FREE(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#ifdef DEV_BIND_ENABLED + #include "dev_bind_api.h" +#endif + +void HAL_Reboot(); + +#define IOTX_LINKKIT_KEY_ID "id" +#define IOTX_LINKKIT_KEY_CODE "code" +#define IOTX_LINKKIT_KEY_DEVID "devid" +#define IOTX_LINKKIT_KEY_SERVICEID "serviceid" +#define IOTX_LINKKIT_KEY_PROPERTYID "propertyid" +#define IOTX_LINKKIT_KEY_EVENTID "eventid" +#define IOTX_LINKKIT_KEY_PAYLOAD "payload" +#define IOTX_LINKKIT_KEY_CONFIG_ID "configId" +#define IOTX_LINKKIT_KEY_CONFIG_SIZE "configSize" +#define IOTX_LINKKIT_KEY_GET_TYPE "getType" +#define IOTX_LINKKIT_KEY_SIGN "sign" +#define IOTX_LINKKIT_KEY_SIGN_METHOD "signMethod" +#define IOTX_LINKKIT_KEY_URL "url" +#define IOTX_LINKKIT_KEY_VERSION "version" +#define IOTX_LINKKIT_KEY_UTC "utc" +#define IOTX_LINKKIT_KEY_RRPCID "rrpcid" +#define IOTX_LINKKIT_KEY_CTX "ctx" +#define IOTX_LINKKIT_KEY_TOPO "topo" +#define IOTX_LINKKIT_KEY_PRODUCT_KEY "productKey" +#define IOTX_LINKKIT_KEY_TIME "time" +#define IOTX_LINKKIT_KEY_DATA "data" + +#define IOTX_LINKKIT_SYNC_DEFAULT_TIMEOUT_MS 10000 + +typedef struct { + int msgid; + void *semaphore; + int code; + struct list_head linked_list; +} iotx_linkkit_upstream_sync_callback_node_t; + +typedef struct { + void *mutex; + void *upstream_mutex; + int is_opened; + int is_connected; + int cloud_redirect; + struct list_head upstream_sync_callback_list; +} iotx_linkkit_ctx_t; + +static iotx_linkkit_ctx_t g_iotx_linkkit_ctx = {0}; + +static iotx_linkkit_ctx_t *_iotx_linkkit_get_ctx(void) +{ + return &g_iotx_linkkit_ctx; +} + +static void _iotx_linkkit_mutex_lock(void) +{ + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + if (ctx->mutex) { + HAL_MutexLock(ctx->mutex); + } +} + +static void _iotx_linkkit_mutex_unlock(void) +{ + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + if (ctx->mutex) { + HAL_MutexUnlock(ctx->mutex); + } +} + +static int _impl_copy(_IN_ void *input, _IN_ int input_len, _OU_ void **output, _IN_ int output_len) +{ + if (input == NULL || output == NULL || *output != NULL) { + return DM_INVALID_PARAMETER; + } + + *output = IMPL_LINKKIT_MALLOC(output_len); + if (*output == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*output, 0, output_len); + memcpy(*output, input, input_len); + + return SUCCESS_RETURN; +} + +#ifdef DEVICE_MODEL_GATEWAY +static void _iotx_linkkit_upstream_mutex_lock(void) +{ + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + if (ctx->upstream_mutex) { + HAL_MutexLock(ctx->upstream_mutex); + } +} + +static void _iotx_linkkit_upstream_mutex_unlock(void) +{ + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + if (ctx->upstream_mutex) { + HAL_MutexUnlock(ctx->upstream_mutex); + } +} + + +static int _iotx_linkkit_upstream_sync_callback_list_insert(int msgid, void *semaphore, + iotx_linkkit_upstream_sync_callback_node_t **node) +{ + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + iotx_linkkit_upstream_sync_callback_node_t *search_node = NULL; + + list_for_each_entry(search_node, &ctx->upstream_sync_callback_list, linked_list, + iotx_linkkit_upstream_sync_callback_node_t) { + if (search_node->msgid == msgid) { + dm_log_debug("Message Already Exist: %d", msgid); + return FAIL_RETURN; + } + } + + search_node = IMPL_LINKKIT_MALLOC(sizeof(iotx_linkkit_upstream_sync_callback_node_t)); + if (search_node == NULL) { + dm_log_debug("malloc error"); + return FAIL_RETURN; + } + memset(search_node, 0, sizeof(iotx_linkkit_upstream_sync_callback_node_t)); + search_node->msgid = msgid; + search_node->semaphore = semaphore; + INIT_LIST_HEAD(&search_node->linked_list); + + list_add(&search_node->linked_list, &ctx->upstream_sync_callback_list); + dm_log_debug("New Message, msgid: %d", msgid); + + *node = search_node; + return SUCCESS_RETURN; +} + +static int _iotx_linkkit_upstream_sync_callback_list_remove(int msgid) +{ + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + iotx_linkkit_upstream_sync_callback_node_t *search_node = NULL; + + list_for_each_entry(search_node, &ctx->upstream_sync_callback_list, linked_list, + iotx_linkkit_upstream_sync_callback_node_t) { + if (search_node->msgid == msgid) { + dm_log_debug("Message Found: %d, Delete It", msgid); + HAL_SemaphoreDestroy(search_node->semaphore); + list_del(&search_node->linked_list); + IMPL_LINKKIT_FREE(search_node); + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +static int _iotx_linkkit_upstream_sync_callback_list_search(int msgid, + iotx_linkkit_upstream_sync_callback_node_t **node) +{ + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + iotx_linkkit_upstream_sync_callback_node_t *search_node = NULL; + + if (node == NULL || *node != NULL) { + dm_log_debug("invalid param"); + return FAIL_RETURN; + } + + list_for_each_entry(search_node, &ctx->upstream_sync_callback_list, linked_list, + iotx_linkkit_upstream_sync_callback_node_t) { + if (search_node->msgid == msgid) { + dm_log_debug("Sync Message Found: %d", msgid); + *node = search_node; + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +static void _iotx_linkkit_upstream_sync_callback_list_destroy(void) +{ + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + iotx_linkkit_upstream_sync_callback_node_t *search_node = NULL, *next_node = NULL; + + list_for_each_entry_safe(search_node, next_node, &ctx->upstream_sync_callback_list, linked_list, + iotx_linkkit_upstream_sync_callback_node_t) { + list_del(&search_node->linked_list); + HAL_SemaphoreDestroy(search_node->semaphore); + IMPL_LINKKIT_FREE(search_node); + } +} + + +static void _iotx_linkkit_upstream_callback_remove(int msgid, int code) +{ + int res = 0; + iotx_linkkit_upstream_sync_callback_node_t *sync_node = NULL; + res = _iotx_linkkit_upstream_sync_callback_list_search(msgid, &sync_node); + if (res == SUCCESS_RETURN) { + sync_node->code = (code == IOTX_DM_ERR_CODE_SUCCESS) ? (SUCCESS_RETURN) : (FAIL_RETURN); + dm_log_debug("Sync Message %d Result: %d", msgid, sync_node->code); + HAL_SemaphorePost(sync_node->semaphore); + } +} +#endif + +#ifdef LOG_REPORT_TO_CLOUD + int report_sample = 0; +#endif +#ifdef ALCS_ENABLED + extern void dm_server_free_context(_IN_ void *ctx); +#endif + +static void _iotx_linkkit_event_callback(iotx_dm_event_types_t type, char *payload) +{ + int res = 0; + void *callback; +#ifdef LOG_REPORT_TO_CLOUD + lite_cjson_t msg_id; +#endif + lite_cjson_t lite, lite_item_id, lite_item_devid, lite_item_serviceid, lite_item_payload, lite_item_ctx; + lite_cjson_t lite_item_code, lite_item_eventid, lite_item_utc, lite_item_rrpcid, lite_item_topo; + lite_cjson_t lite_item_pk, lite_item_time; + lite_cjson_t lite_item_version, lite_item_configid, lite_item_configsize, lite_item_gettype, lite_item_sign, + lite_item_signmethod, lite_item_url; + + dm_log_info("Receive Message Type: %d", type); + if (payload) { + dm_log_info("Receive Message: %s", payload); + res = dm_utils_json_parse(payload, strlen(payload), cJSON_Invalid, &lite); + if (res != SUCCESS_RETURN) { + return; + } +#ifdef LOG_REPORT_TO_CLOUD + dm_utils_json_object_item(&lite, "msgid", 5, cJSON_Invalid, &msg_id); +#endif + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_ID, strlen(IOTX_LINKKIT_KEY_ID), cJSON_Invalid, &lite_item_id); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_DEVID, strlen(IOTX_LINKKIT_KEY_DEVID), cJSON_Invalid, + &lite_item_devid); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_SERVICEID, strlen(IOTX_LINKKIT_KEY_SERVICEID), cJSON_Invalid, + &lite_item_serviceid); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_PAYLOAD, strlen(IOTX_LINKKIT_KEY_PAYLOAD), cJSON_Invalid, + &lite_item_payload); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_CTX, strlen(IOTX_LINKKIT_KEY_CTX), cJSON_Invalid, &lite_item_ctx); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_CODE, strlen(IOTX_LINKKIT_KEY_CODE), cJSON_Invalid, &lite_item_code); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_EVENTID, strlen(IOTX_LINKKIT_KEY_EVENTID), cJSON_Invalid, + &lite_item_eventid); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_UTC, strlen(IOTX_LINKKIT_KEY_UTC), cJSON_Invalid, &lite_item_utc); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_RRPCID, strlen(IOTX_LINKKIT_KEY_RRPCID), cJSON_Invalid, + &lite_item_rrpcid); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_TOPO, strlen(IOTX_LINKKIT_KEY_TOPO), cJSON_Invalid, + &lite_item_topo); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_PRODUCT_KEY, strlen(IOTX_LINKKIT_KEY_PRODUCT_KEY), cJSON_Invalid, + &lite_item_pk); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_TIME, strlen(IOTX_LINKKIT_KEY_TIME), cJSON_Invalid, + &lite_item_time); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_VERSION, strlen(IOTX_LINKKIT_KEY_VERSION), cJSON_Invalid, + &lite_item_version); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_CONFIG_ID, strlen(IOTX_LINKKIT_KEY_CONFIG_ID), cJSON_Invalid, + &lite_item_configid); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_CONFIG_SIZE, strlen(IOTX_LINKKIT_KEY_CONFIG_SIZE), cJSON_Invalid, + &lite_item_configsize); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_GET_TYPE, strlen(IOTX_LINKKIT_KEY_GET_TYPE), cJSON_Invalid, + &lite_item_gettype); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_SIGN, strlen(IOTX_LINKKIT_KEY_SIGN), cJSON_Invalid, + &lite_item_sign); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_SIGN_METHOD, strlen(IOTX_LINKKIT_KEY_SIGN_METHOD), cJSON_Invalid, + &lite_item_signmethod); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_URL, strlen(IOTX_LINKKIT_KEY_URL), cJSON_Invalid, + &lite_item_url); + + } + + switch (type) { + case IOTX_DM_EVENT_CLOUD_CONNECTED: { + callback = iotx_event_callback(ITE_CONNECT_SUCC); + if (callback) { + ((int (*)(void))callback)(); + } + } + break; + case IOTX_DM_EVENT_CLOUD_DISCONNECT: { + callback = iotx_event_callback(ITE_DISCONNECTED); + if (callback) { + ((int (*)(void))callback)(); + } + } + break; + case IOTX_DM_EVENT_INITIALIZED: { + if (payload == NULL || lite_item_devid.type != cJSON_Number) { + return; + } + + dm_log_debug("Current Devid: %d", lite_item_devid.value_int); + + callback = iotx_event_callback(ITE_INITIALIZE_COMPLETED); + if (callback) { + ((int (*)(const int))callback)(lite_item_devid.value_int); + } + } + break; + case IOTX_DM_EVENT_MODEL_DOWN_RAW: { + int raw_data_len = 0; + unsigned char *raw_data = NULL; + + if (payload == NULL || lite_item_devid.type != cJSON_Number || lite_item_payload.type != cJSON_String) { + return; + } + + dm_log_debug("Current Devid: %d", lite_item_devid.value_int); + dm_log_debug("Current Raw Data: %.*s", lite_item_payload.value_length, lite_item_payload.value); + + raw_data_len = lite_item_payload.value_length / 2; + raw_data = IMPL_LINKKIT_MALLOC(raw_data_len); + if (raw_data == NULL) { + dm_log_err("No Enough Memory"); + return; + } + LITE_hexstr_convert(lite_item_payload.value, lite_item_payload.value_length, raw_data, raw_data_len); + + HEXDUMP_DEBUG(raw_data, raw_data_len); + callback = iotx_event_callback(ITE_RAWDATA_ARRIVED); + if (callback) { + ((int (*)(const int, const unsigned char *, const int))callback)(lite_item_devid.value_int, raw_data, raw_data_len); + } + + IMPL_LINKKIT_FREE(raw_data); + } + break; + case IOTX_DM_EVENT_MODEL_UP_RAW_REPLY: { + int raw_data_len = 0; + unsigned char *raw_data = NULL; + + if (payload == NULL || lite_item_devid.type != cJSON_Number || lite_item_payload.type != cJSON_String) { + return; + } + + dm_log_debug("Current Devid: %d", lite_item_devid.value_int); + dm_log_debug("Current Raw Data: %.*s", lite_item_payload.value_length, lite_item_payload.value); + + raw_data_len = lite_item_payload.value_length / 2; + raw_data = IMPL_LINKKIT_MALLOC(raw_data_len); + if (raw_data == NULL) { + dm_log_err("No Enough Memory"); + return; + } + memset(raw_data, 0, raw_data_len); + LITE_hexstr_convert(lite_item_payload.value, lite_item_payload.value_length, raw_data, raw_data_len); + + HEXDUMP_DEBUG(raw_data, raw_data_len); + + callback = iotx_event_callback(ITE_RAWDATA_ARRIVED); + if (callback) { + ((int (*)(const int, const unsigned char *, const int))callback)(lite_item_devid.value_int, raw_data, raw_data_len); + } + + IMPL_LINKKIT_FREE(raw_data); + } + break; +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + case IOTX_DM_EVENT_THING_SERVICE_REQUEST: { + int response_len = 0; + char *request = NULL, *response = NULL; + + uintptr_t property_get_ctx_num = 0; + void *property_get_ctx = NULL; + + if (payload == NULL || lite_item_id.type != cJSON_String || lite_item_devid.type != cJSON_Number || + lite_item_serviceid.type != cJSON_String || lite_item_payload.type != cJSON_Object) { + return; + } + + dm_log_debug("Current Id: %.*s", lite_item_id.value_length, lite_item_id.value); + dm_log_debug("Current Devid: %d", lite_item_devid.value_int); + dm_log_debug("Current ServiceID: %.*s", lite_item_serviceid.value_length, lite_item_serviceid.value); + dm_log_debug("Current Payload: %.*s", lite_item_payload.value_length, lite_item_payload.value); + dm_log_debug("Current Ctx: %.*s", lite_item_ctx.value_length, lite_item_ctx.value); + + LITE_hexstr_convert(lite_item_ctx.value, lite_item_ctx.value_length, (unsigned char *)&property_get_ctx_num, + sizeof(uintptr_t)); + property_get_ctx = (void *)property_get_ctx_num; + + request = IMPL_LINKKIT_MALLOC(lite_item_payload.value_length + 1); + if (request == NULL) { + dm_log_err("Not Enough Memory"); + return; + } + memset(request, 0, lite_item_payload.value_length + 1); + memcpy(request, lite_item_payload.value, lite_item_payload.value_length); + + callback = iotx_event_callback(ITE_SERVICE_REQUEST); + if (callback) { + res = ((int (*)(const int, const char *, const int, const char *, const int, char **, + int *))callback)(lite_item_devid.value_int, lite_item_serviceid.value, + lite_item_serviceid.value_length, request, lite_item_payload.value_length, &response, &response_len); + if (response != NULL && response_len > 0) { + /* service response exist */ + iotx_dm_error_code_t code = (res == 0) ? (IOTX_DM_ERR_CODE_SUCCESS) : (IOTX_DM_ERR_CODE_REQUEST_ERROR); + iotx_dm_send_service_response(lite_item_devid.value_int, lite_item_id.value, lite_item_id.value_length, code, + lite_item_serviceid.value, + lite_item_serviceid.value_length, + response, response_len, property_get_ctx); + HAL_Free(response); + } + } +#ifdef ALCS_ENABLED + if (property_get_ctx) { + dm_server_free_context(property_get_ctx); + } +#endif + IMPL_LINKKIT_FREE(request); + } + break; + case IOTX_DM_EVENT_PROPERTY_SET: { + char *property_payload = NULL; + + if (payload == NULL || lite_item_devid.type != cJSON_Number || lite_item_payload.type != cJSON_Object) { + return; + } + + dm_log_debug("Current Devid: %d", lite_item_devid.value_int); + dm_log_debug("Current Payload: %.*s", lite_item_payload.value_length, lite_item_payload.value); + + property_payload = IMPL_LINKKIT_MALLOC(lite_item_payload.value_length + 1); + if (property_payload == NULL) { + dm_log_err("No Enough Memory"); + return; + } + memset(property_payload, 0, lite_item_payload.value_length + 1); + memcpy(property_payload, lite_item_payload.value, lite_item_payload.value_length); +#ifdef LOG_REPORT_TO_CLOUD + if (SUCCESS_RETURN == check_target_msg(msg_id.value, msg_id.value_length)) { + report_sample = 1; + send_permance_info(msg_id.value, msg_id.value_length, "3", 1); + } +#endif + callback = iotx_event_callback(ITE_PROPERTY_SET); + if (callback) { + ((int (*)(const int, const char *, const int))callback)(lite_item_devid.value_int, property_payload, + lite_item_payload.value_length); + } +#ifdef LOG_REPORT_TO_CLOUD + if (1 == report_sample) { + send_permance_info(NULL, 0, "5", 2); + report_sample = 0; + } +#endif + + IMPL_LINKKIT_FREE(property_payload); + } + break; +#ifdef DEVICE_MODEL_SHADOW + case IOTX_DM_EVENT_PROPERTY_DESIRED_GET_REPLY: { + char *property_data = NULL; + lite_cjson_t lite_item_data; + + memset(&lite_item_data, 0, sizeof(lite_cjson_t)); + dm_utils_json_object_item(&lite, IOTX_LINKKIT_KEY_DATA, strlen(IOTX_LINKKIT_KEY_DATA), cJSON_Invalid, + &lite_item_data); + if (payload == NULL || lite_item_data.type != cJSON_Object) { + return; + } + dm_log_debug("Current Data: %.*s", lite_item_data.value_length, lite_item_data.value); + + property_data = IMPL_LINKKIT_MALLOC(lite_item_data.value_length + 1); + if (property_data == NULL) { + dm_log_err("No Enough Memory"); + return; + } + memset(property_data, 0, lite_item_data.value_length + 1); + memcpy(property_data, lite_item_data.value, lite_item_data.value_length); + + callback = iotx_event_callback(ITE_PROPERTY_DESIRED_GET_REPLY); + if (callback) { + ((int (*)(const char *, const int))callback)(property_data, + lite_item_data.value_length); + } + + IMPL_LINKKIT_FREE(property_data); + } + break; +#endif + case IOTX_DM_EVENT_PROPERTY_GET: { + int response_len = 0; + char *request = NULL, *response = NULL; + uintptr_t property_get_ctx_num = 0; + void *property_get_ctx = NULL; + + if (payload == NULL || lite_item_id.type != cJSON_String || lite_item_devid.type != cJSON_Number || + lite_item_payload.type != cJSON_Array) { + return; + } + + dm_log_debug("Current Id: %.*s", lite_item_id.value_length, lite_item_id.value); + dm_log_debug("Current Devid: %d", lite_item_devid.value_int); + dm_log_debug("Current Payload: %.*s", lite_item_payload.value_length, lite_item_payload.value); + dm_log_debug("Current Ctx: %.*s", lite_item_ctx.value_length, lite_item_ctx.value); + + LITE_hexstr_convert(lite_item_ctx.value, lite_item_ctx.value_length, (unsigned char *)&property_get_ctx_num, + sizeof(uintptr_t)); + property_get_ctx = (void *)property_get_ctx_num; + dm_log_debug("property_get_ctx_num: %0x016llX", (unsigned int)property_get_ctx_num); + dm_log_debug("property_get_ctx: %p", property_get_ctx); + + request = IMPL_LINKKIT_MALLOC(lite_item_payload.value_length + 1); + if (request == NULL) { + dm_log_err("No Enough Memory"); + return; + } + memset(request, 0, lite_item_payload.value_length + 1); + memcpy(request, lite_item_payload.value, lite_item_payload.value_length); + + callback = iotx_event_callback(ITE_PROPERTY_GET); + if (callback) { + res = ((int (*)(const int, const char *, const int, char **, int *))callback)(lite_item_devid.value_int, request, + lite_item_payload.value_length, &response, &response_len); + + if (response != NULL && response_len > 0) { + /* property get response exist */ + iotx_dm_error_code_t code = (res == 0) ? (IOTX_DM_ERR_CODE_SUCCESS) : (IOTX_DM_ERR_CODE_REQUEST_ERROR); + iotx_dm_send_property_get_response(lite_item_devid.value_int, lite_item_id.value, lite_item_id.value_length, code, + response, response_len, property_get_ctx); + HAL_Free(response); + } + } + + IMPL_LINKKIT_FREE(request); + } + break; + case IOTX_DM_EVENT_EVENT_PROPERTY_POST_REPLY: + case IOTX_DM_EVENT_DEVICEINFO_UPDATE_REPLY: +#ifdef DEVICE_MODEL_SHADOW + case IOTX_DM_EVENT_PROPERTY_DESIRED_DELETE_REPLY: +#endif + case IOTX_DM_EVENT_DEVICEINFO_DELETE_REPLY: { + char *user_payload = NULL; + int user_payload_length = 0; + + if (payload == NULL || lite_item_id.type != cJSON_Number || lite_item_code.type != cJSON_Number + || lite_item_devid.type != cJSON_Number) { + return; + } + dm_log_debug("Current Id: %d", lite_item_id.value_int); + dm_log_debug("Current Code: %d", lite_item_code.value_int); + dm_log_debug("Current Devid: %d", lite_item_devid.value_int); + + if (lite_item_payload.type == cJSON_Object && lite_item_payload.value_length > 0) { + user_payload = IMPL_LINKKIT_MALLOC(lite_item_payload.value_length + 1); + if (user_payload == NULL) { + dm_log_err("No Enough Memory"); + return; + } + memset(user_payload, 0, lite_item_payload.value_length + 1); + memcpy(user_payload, lite_item_payload.value, lite_item_payload.value_length); + user_payload_length = lite_item_payload.value_length; + } + + callback = iotx_event_callback(ITE_REPORT_REPLY); + if (callback) { + ((int (*)(const int, const int, const int, const char *, const int))callback)(lite_item_devid.value_int, + lite_item_id.value_int, lite_item_code.value_int, user_payload, + user_payload_length); + } + + if (user_payload) { + IMPL_LINKKIT_FREE(user_payload); + } + } + break; + case IOTX_DM_EVENT_EVENT_SPECIFIC_POST_REPLY: { + char *user_eventid = NULL; + char *user_payload = NULL; + + if (payload == NULL || lite_item_id.type != cJSON_Number || lite_item_code.type != cJSON_Number || + lite_item_devid.type != cJSON_Number || lite_item_eventid.type != cJSON_String + || lite_item_payload.type != cJSON_String) { + return; + } + + dm_log_debug("Current Id: %d", lite_item_id.value_int); + dm_log_debug("Current Code: %d", lite_item_code.value_int); + dm_log_debug("Current Devid: %d", lite_item_devid.value_int); + dm_log_debug("Current EventID: %.*s", lite_item_eventid.value_length, lite_item_eventid.value); + dm_log_debug("Current Message: %.*s", lite_item_payload.value_length, lite_item_payload.value); + + user_eventid = IMPL_LINKKIT_MALLOC(lite_item_eventid.value_length + 1); + if (user_eventid == NULL) { + dm_log_err("Not Enough Memory"); + return; + } + memset(user_eventid, 0, lite_item_eventid.value_length + 1); + memcpy(user_eventid, lite_item_eventid.value, lite_item_eventid.value_length); + + user_payload = IMPL_LINKKIT_MALLOC(lite_item_payload.value_length + 1); + if (user_payload == NULL) { + dm_log_err("Not Enough Memory"); + IMPL_LINKKIT_FREE(user_eventid); + return; + } + memset(user_payload, 0, lite_item_payload.value_length + 1); + memcpy(user_payload, lite_item_payload.value, lite_item_payload.value_length); + + + callback = iotx_event_callback(ITE_TRIGGER_EVENT_REPLY); + if (callback) { + ((int (*)(const int, const int, const int, const char *, const int, const char *, + const int))callback)(lite_item_devid.value_int, + lite_item_id.value_int, lite_item_code.value_int, + user_eventid, lite_item_eventid.value_length, user_payload, lite_item_payload.value_length); + } + + IMPL_LINKKIT_FREE(user_eventid); + IMPL_LINKKIT_FREE(user_payload); + } + break; + case IOTX_DM_EVENT_NTP_RESPONSE: { + char *utc_payload = NULL; + + if (payload == NULL || lite_item_utc.type != cJSON_String) { + return; + } + + dm_log_debug("Current UTC: %.*s", lite_item_utc.value_length, lite_item_utc.value); + + utc_payload = IMPL_LINKKIT_MALLOC(lite_item_utc.value_length + 1); + if (utc_payload == NULL) { + dm_log_err("Not Enough Memory"); + return; + } + memset(utc_payload, 0, lite_item_utc.value_length + 1); + memcpy(utc_payload, lite_item_utc.value, lite_item_utc.value_length); + + callback = iotx_event_callback(ITE_TIMESTAMP_REPLY); + if (callback) { + ((int (*)(const char *))callback)(utc_payload); + } + + IMPL_LINKKIT_FREE(utc_payload); + } + break; + case IOTX_DM_EVENT_RRPC_REQUEST: { + int rrpc_response_len = 0; + char *rrpc_request = NULL, *rrpc_response = NULL; + + if (payload == NULL || lite_item_id.type != cJSON_String || lite_item_devid.type != cJSON_Number || + lite_item_serviceid.type != cJSON_String || lite_item_rrpcid.type != cJSON_String + || lite_item_payload.type != cJSON_Object) { + return; + } + + dm_log_debug("Current Id: %.*s", lite_item_id.value_length, lite_item_id.value); + dm_log_debug("Current Devid: %d", lite_item_devid.value_int); + dm_log_debug("Current ServiceID: %.*s", lite_item_serviceid.value_length, lite_item_serviceid.value); + dm_log_debug("Current RRPC ID: %.*s", lite_item_rrpcid.value_length, lite_item_rrpcid.value); + dm_log_debug("Current Payload: %.*s", lite_item_payload.value_length, lite_item_payload.value); + + rrpc_request = IMPL_LINKKIT_MALLOC(lite_item_payload.value_length + 1); + if (rrpc_request == NULL) { + dm_log_err("Not Enough Memory"); + return; + } + memset(rrpc_request, 0, lite_item_payload.value_length + 1); + memcpy(rrpc_request, lite_item_payload.value, lite_item_payload.value_length); + + callback = iotx_event_callback(ITE_SERVICE_REQUEST); + if (callback) { + res = ((int (*)(const int, const char *, const int, const char *, const int, char **, + int *))callback)(lite_item_devid.value_int, lite_item_serviceid.value, + lite_item_serviceid.value_length, + rrpc_request, lite_item_payload.value_length, &rrpc_response, &rrpc_response_len); + if (rrpc_response != NULL && rrpc_response_len > 0) { + iotx_dm_error_code_t code = (res == 0) ? (IOTX_DM_ERR_CODE_SUCCESS) : (IOTX_DM_ERR_CODE_REQUEST_ERROR); + iotx_dm_send_rrpc_response(lite_item_devid.value_int, lite_item_id.value, lite_item_id.value_length, code, + lite_item_rrpcid.value, + lite_item_rrpcid.value_length, + rrpc_response, rrpc_response_len); + HAL_Free(rrpc_response); + } + } + + IMPL_LINKKIT_FREE(rrpc_request); + } + break; +#endif + case IOTX_DM_EVENT_FOTA_NEW_FIRMWARE: { + char *version = NULL; + + if (payload == NULL || lite_item_version.type != cJSON_String) { + return; + } + + dm_log_debug("Current Firmware Version: %.*s", lite_item_version.value_length, lite_item_version.value); + + version = IMPL_LINKKIT_MALLOC(lite_item_version.value_length + 1); + if (version == NULL) { + return; + } + memset(version, 0, lite_item_version.value_length + 1); + memcpy(version, lite_item_version.value, lite_item_version.value_length); + + callback = iotx_event_callback(ITE_FOTA); + if (callback) { + ((int (*)(const int, const char *))callback)(0, version); + } + + if (version) { + IMPL_LINKKIT_FREE(version); + } + } + break; + case IOTX_DM_EVENT_COTA_NEW_CONFIG: { + char *config_id = NULL, *get_type = NULL, *sign = NULL, *sign_method = NULL, *url = NULL; + + if (payload == NULL || lite_item_configid.type != cJSON_String || lite_item_configsize.type != cJSON_Number || + lite_item_gettype.type != cJSON_String || lite_item_sign.type != cJSON_String + || lite_item_signmethod.type != cJSON_String || + lite_item_url.type != cJSON_String) { + return; + } + + dm_log_debug("Current Config ID: %.*s", lite_item_configid.value_length, lite_item_configid.value); + dm_log_debug("Current Config Size: %d", lite_item_configsize.value_int); + dm_log_debug("Current Get Type: %.*s", lite_item_gettype.value_length, lite_item_gettype.value); + dm_log_debug("Current Sign: %.*s", lite_item_sign.value_length, lite_item_sign.value); + dm_log_debug("Current Sign Method: %.*s", lite_item_signmethod.value_length, lite_item_signmethod.value); + dm_log_debug("Current URL: %.*s", lite_item_url.value_length, lite_item_url.value); + + _impl_copy(lite_item_configid.value, lite_item_configid.value_length, (void **)&config_id, + lite_item_configid.value_length + 1); + _impl_copy(lite_item_gettype.value, lite_item_gettype.value_length, (void **)&get_type, + lite_item_gettype.value_length + 1); + _impl_copy(lite_item_sign.value, lite_item_sign.value_length, (void **)&sign, lite_item_sign.value_length + 1); + _impl_copy(lite_item_signmethod.value, lite_item_signmethod.value_length, (void **)&sign_method, + lite_item_signmethod.value_length + 1); + _impl_copy(lite_item_url.value, lite_item_url.value_length, (void **)&url, lite_item_url.value_length + 1); + + if (config_id == NULL || get_type == NULL || sign == NULL || sign_method == NULL || url == NULL) { + if (config_id) { + IMPL_LINKKIT_FREE(config_id); + } + if (get_type) { + IMPL_LINKKIT_FREE(get_type); + } + if (sign) { + IMPL_LINKKIT_FREE(sign); + } + if (sign_method) { + IMPL_LINKKIT_FREE(sign_method); + } + if (url) { + IMPL_LINKKIT_FREE(url); + } + return; + } + + callback = iotx_event_callback(ITE_COTA); + if (callback) { + ((int (*)(const int, const char *, int, const char *, const char *, const char *, const char *))callback)(0, config_id, + lite_item_configsize.value_int, get_type, sign, sign_method, url); + } + + if (config_id) { + IMPL_LINKKIT_FREE(config_id); + } + if (get_type) { + IMPL_LINKKIT_FREE(get_type); + } + if (sign) { + IMPL_LINKKIT_FREE(sign); + } + if (sign_method) { + IMPL_LINKKIT_FREE(sign_method); + } + if (url) { + IMPL_LINKKIT_FREE(url); + } + } + break; +#ifdef DEVICE_MODEL_GATEWAY + case IOTX_DM_EVENT_TOPO_GET_REPLY: { + char *topo_list = NULL; + + if (payload == NULL || lite_item_id.type != cJSON_Number || lite_item_devid.type != cJSON_Number || + lite_item_code.type != cJSON_Number || lite_item_topo.type != cJSON_Array) { + return; + } + dm_log_debug("Current Id: %d", lite_item_id.value_int); + dm_log_debug("Current Devid: %d", lite_item_devid.value_int); + dm_log_debug("Current Code: %d", lite_item_code.value_int); + dm_log_debug("Current Topo List: %.*s", lite_item_topo.value_length, lite_item_topo.value); + + topo_list = IMPL_LINKKIT_MALLOC(lite_item_topo.value_length + 1); + if (topo_list == NULL) { + dm_log_err("Not Enough Memory"); + return; + } + memset(topo_list, 0, lite_item_topo.value_length + 1); + memcpy(topo_list, lite_item_topo.value, lite_item_topo.value_length); + + callback = iotx_event_callback(ITE_TOPOLIST_REPLY); + if (callback) { + ((int (*)(const int, const int, const int, const char *, const int))callback)(lite_item_devid.value_int, + lite_item_id.value_int, + lite_item_code.value_int, topo_list, lite_item_topo.value_length); + } + + IMPL_LINKKIT_FREE(topo_list); + } + break; + case IOTX_DM_EVENT_TOPO_DELETE_REPLY: + case IOTX_DM_EVENT_TOPO_ADD_REPLY: + case IOTX_DM_EVENT_SUBDEV_REGISTER_REPLY: + case IOTX_DM_EVENT_COMBINE_LOGIN_REPLY: + case IOTX_DM_EVENT_COMBINE_LOGOUT_REPLY: { + if (payload == NULL || lite_item_id.type != cJSON_Number || lite_item_devid.type != cJSON_Number || + lite_item_code.type != cJSON_Number) { + return; + } + dm_log_debug("Current Id: %d", lite_item_id.value_int); + dm_log_debug("Current Code: %d", lite_item_code.value_int); + dm_log_debug("Current Devid: %d", lite_item_devid.value_int); + + _iotx_linkkit_upstream_mutex_lock(); + _iotx_linkkit_upstream_callback_remove(lite_item_id.value_int, lite_item_code.value_int); + _iotx_linkkit_upstream_mutex_unlock(); + } + break; + case IOTX_DM_EVENT_GATEWAY_PERMIT: { + char *product_key = ""; + + if (payload == NULL || lite_item_time.type != cJSON_Number) { + return; + } + dm_log_debug("Current Time: %d", lite_item_time.value_int); + + if (lite_item_pk.type == cJSON_String) { + dm_log_debug("Current Product Key: %.*s", lite_item_pk.value_length, lite_item_pk.value); + product_key = IMPL_LINKKIT_MALLOC(lite_item_pk.value_length + 1); + if (product_key == NULL) { + dm_log_err("Not Enough Memory"); + return; + } + memset(product_key, 0, lite_item_pk.value_length + 1); + memcpy(product_key, lite_item_pk.value, lite_item_pk.value_length); + } + + callback = iotx_event_callback(ITE_PERMIT_JOIN); + if (callback) { + ((int (*)(const char *, int))callback)((const char *)product_key, (const int)lite_item_time.value_int); + } + + if (lite_item_pk.type == cJSON_String) { + IMPL_LINKKIT_FREE(product_key); + } + } + break; +#endif + default: { + } + break; + } +} + +static int _iotx_linkkit_master_open(iotx_linkkit_dev_meta_info_t *meta_info) +{ + int res = 0; + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + + if (ctx->is_opened) { + return FAIL_RETURN; + } + ctx->is_opened = 1; + + /* Create Mutex */ + ctx->mutex = HAL_MutexCreate(); + if (ctx->mutex == NULL) { + dm_log_err("Not Enough Memory"); + ctx->is_opened = 0; + return FAIL_RETURN; + } + +#ifdef DEVICE_MODEL_GATEWAY + ctx->upstream_mutex = HAL_MutexCreate(); + if (ctx->upstream_mutex == NULL) { + HAL_MutexDestroy(ctx->mutex); + dm_log_err("Not Enough Memory"); + ctx->is_opened = 0; + return FAIL_RETURN; + } +#endif + + res = iotx_dm_open(); + if (res != SUCCESS_RETURN) { +#ifdef DEVICE_MODEL_GATEWAY + HAL_MutexDestroy(ctx->upstream_mutex); +#endif + HAL_MutexDestroy(ctx->mutex); + ctx->is_opened = 0; + return FAIL_RETURN; + } + + INIT_LIST_HEAD(&ctx->upstream_sync_callback_list); + + return SUCCESS_RETURN; +} + +#ifdef DEVICE_MODEL_GATEWAY +static int _iotx_linkkit_slave_open(iotx_linkkit_dev_meta_info_t *meta_info) +{ + int res = 0, devid; + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + + if (!ctx->is_opened) { + return FAIL_RETURN; + } + + res = iotx_dm_subdev_create(meta_info->product_key, meta_info->device_name, meta_info->device_secret, &devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + return devid; +} +#endif + +static int _iotx_linkkit_master_connect(void) +{ + int res = 0; + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + iotx_dm_init_params_t dm_init_params; + iotx_dm_event_types_t type; + + if (ctx->is_connected) { + return FAIL_RETURN; + } + ctx->is_connected = 1; + + memset(&dm_init_params, 0, sizeof(iotx_dm_init_params_t)); + dm_init_params.event_callback = _iotx_linkkit_event_callback; + + res = iotx_dm_connect(&dm_init_params); + if (res != SUCCESS_RETURN) { + dm_log_err("DM Start Failed"); + ctx->is_connected = 0; + return FAIL_RETURN; + } + + res = iotx_dm_subscribe(IOTX_DM_LOCAL_NODE_DEVID); + if (res != SUCCESS_RETURN) { + dm_log_err("DM Subscribe Failed"); + ctx->is_connected = 0; + return FAIL_RETURN; + } + + type = IOTX_DM_EVENT_INITIALIZED; + _iotx_linkkit_event_callback(type, "{\"devid\":0}"); + + return SUCCESS_RETURN; +} + +#ifdef DEVICE_MODEL_GATEWAY +static int _iotx_linkkit_slave_connect(int devid) +{ + int res = 0, msgid = 0, code = 0; + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + iotx_linkkit_upstream_sync_callback_node_t *node = NULL; + void *semaphore = NULL; + + if (ctx->is_connected == 0) { + dm_log_err("master isn't start"); + return FAIL_RETURN; + } + + if (devid <= 0) { + dm_log_err("devid invalid"); + return FAIL_RETURN; + } + + /* Subdev Register */ + res = iotx_dm_subdev_register(devid); + if (res < SUCCESS_RETURN) { + return FAIL_RETURN; + } + + if (res > SUCCESS_RETURN) { + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + return FAIL_RETURN; + } + + msgid = res; + + _iotx_linkkit_upstream_mutex_lock(); + res = _iotx_linkkit_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + _iotx_linkkit_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, IOTX_LINKKIT_SYNC_DEFAULT_TIMEOUT_MS); + if (res < SUCCESS_RETURN) { + _iotx_linkkit_upstream_mutex_lock(); + _iotx_linkkit_upstream_sync_callback_list_remove(msgid); + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + + _iotx_linkkit_upstream_mutex_lock(); + code = node->code; + _iotx_linkkit_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + _iotx_linkkit_upstream_mutex_unlock(); + } + + /* Subdev Add Topo */ + res = iotx_dm_subdev_topo_add(devid); + if (res < SUCCESS_RETURN) { + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } + + msgid = res; + _iotx_linkkit_upstream_mutex_lock(); + res = _iotx_linkkit_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + _iotx_linkkit_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, IOTX_LINKKIT_SYNC_DEFAULT_TIMEOUT_MS); + if (res < SUCCESS_RETURN) { + _iotx_linkkit_upstream_mutex_lock(); + _iotx_linkkit_upstream_sync_callback_list_remove(msgid); + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + + _iotx_linkkit_upstream_mutex_lock(); + code = node->code; + _iotx_linkkit_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + _iotx_linkkit_upstream_mutex_unlock(); + + return SUCCESS_RETURN; +} + +static int _iotx_linkkit_subdev_delete_topo(int devid) +{ + int res = 0, msgid = 0, code = 0; + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + iotx_linkkit_upstream_sync_callback_node_t *node = NULL; + void *semaphore = NULL; + + if (ctx->is_connected == 0) { + dm_log_err("master isn't start"); + return FAIL_RETURN; + } + + if (devid <= 0) { + dm_log_err("devid invalid"); + return FAIL_RETURN; + } + + /* Subdev Delete Topo */ + res = iotx_dm_subdev_topo_del(devid); + if (res < SUCCESS_RETURN) { + return FAIL_RETURN; + } + msgid = res; + + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + return FAIL_RETURN; + } + + _iotx_linkkit_upstream_mutex_lock(); + res = _iotx_linkkit_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + _iotx_linkkit_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, IOTX_LINKKIT_SYNC_DEFAULT_TIMEOUT_MS); + if (res < SUCCESS_RETURN) { + _iotx_linkkit_upstream_mutex_lock(); + _iotx_linkkit_upstream_sync_callback_list_remove(msgid); + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + + _iotx_linkkit_upstream_mutex_lock(); + code = node->code; + _iotx_linkkit_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + _iotx_linkkit_upstream_mutex_unlock(); + + return SUCCESS_RETURN; +} +#endif + +static int _iotx_linkkit_master_close(void) +{ + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + + _iotx_linkkit_mutex_lock(); + if (ctx->is_opened == 0) { + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } + ctx->is_opened = 0; + + iotx_dm_close(); +#ifdef DEVICE_MODEL_GATEWAY + _iotx_linkkit_upstream_sync_callback_list_destroy(); + HAL_MutexDestroy(ctx->upstream_mutex); +#endif + _iotx_linkkit_mutex_unlock(); + HAL_MutexDestroy(ctx->mutex); + memset(ctx, 0, sizeof(iotx_linkkit_ctx_t)); + + return SUCCESS_RETURN; +} + +#ifdef DEVICE_MODEL_GATEWAY +static int _iotx_linkkit_slave_close(int devid) +{ + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + + _iotx_linkkit_mutex_lock(); + if (ctx->is_opened == 0) { + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } + + /* Release Subdev Resources */ + iotx_dm_subdev_destroy(devid); + + _iotx_linkkit_mutex_unlock(); + + return SUCCESS_RETURN; +} +#endif + +//data moved from global data center to the region user used, MUST reinitialized sdk and all devices. +int user_handle_redirect() +{ + iotx_linkkit_dev_meta_info_t meta_info; + int id = 0; + int res = 0; + + //close master + + memset(&meta_info, 0, sizeof(iotx_linkkit_dev_meta_info_t)); + HAL_GetProductKey(meta_info.product_key); + HAL_GetProductSecret(meta_info.product_secret); + HAL_GetDeviceName(meta_info.device_name); + HAL_GetDeviceSecret(meta_info.device_secret); + + IOT_Linkkit_Close(IOTX_DM_LOCAL_NODE_DEVID); + /* Create Master Device Resources */ + do { + id = IOT_Linkkit_Open(IOTX_LINKKIT_DEV_TYPE_MASTER, &meta_info); + if (id < 0) { + dm_log_err("IOT_Linkkit_Open Failed, retry after 5s...\n"); + HAL_SleepMs(5000); + } + } while (id < 0); + /* Start Connect Aliyun Server */ + do { + res = IOT_Linkkit_Connect(id); + if (res < 0) { + dm_log_err("IOT_Linkkit_Connect Failed, retry after 5s...\n"); + HAL_SleepMs(5000); + } + } while (res < 0); + + return 0; +} + +static int user_redirect_event_handler(void) +{ + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + + dm_log_debug("Cloud Redirect"); + + ctx->cloud_redirect = 1; + + return 0; +} + +int IOT_Linkkit_Open(iotx_linkkit_dev_type_t dev_type, iotx_linkkit_dev_meta_info_t *meta_info) +{ + int res = 0; + + if (dev_type < 0 || dev_type >= IOTX_LINKKIT_DEV_TYPE_MAX || meta_info == NULL) { + dm_log_err("Invalid Parameter"); + return FAIL_RETURN; + } + + switch (dev_type) { + case IOTX_LINKKIT_DEV_TYPE_MASTER: { + res = _iotx_linkkit_master_open(meta_info); + if (res == SUCCESS_RETURN) { + res = IOTX_DM_LOCAL_NODE_DEVID; + IOT_RegisterCallback(ITE_REDIRECT, user_redirect_event_handler); + } + } + break; + case IOTX_LINKKIT_DEV_TYPE_SLAVE: { +#ifdef DEVICE_MODEL_GATEWAY + res = _iotx_linkkit_slave_open(meta_info); +#else + res = FAIL_RETURN; +#endif + } + break; + default: { + dm_log_err("Unknown Device Type"); + res = FAIL_RETURN; + } + break; + } + + return res; +} + +int IOT_Linkkit_Connect(int devid) +{ + int res = 0; + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + + if (devid < 0) { + dm_log_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (ctx->is_opened == 0) { + + return FAIL_RETURN; + } + + _iotx_linkkit_mutex_lock(); + + if (devid == IOTX_DM_LOCAL_NODE_DEVID) { + res = _iotx_linkkit_master_connect(); + } else { +#ifdef DEVICE_MODEL_GATEWAY + res = _iotx_linkkit_slave_connect(devid); +#else + res = FAIL_RETURN; +#endif + } + _iotx_linkkit_mutex_unlock(); + + return res; +} + +void IOT_Linkkit_Yield(int timeout_ms) +{ + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + + if (timeout_ms <= 0) { + dm_log_err("Invalid Parameter"); + return; + } + + if (ctx->is_opened == 0 || ctx->is_connected == 0) { + return; + } + + // NOTICE: Do Not remove the following codes! + if (ctx->cloud_redirect == 1){ + // user_handle_redirect(); + dm_log_info("Reboot to redirect"); + HAL_Reboot(); + ctx->cloud_redirect = 0; + } + + iotx_dm_yield(timeout_ms); + iotx_dm_dispatch(); + +#ifdef DEVICE_MODEL_GATEWAY + HAL_SleepMs(timeout_ms); +#endif +} + +int IOT_Linkkit_Close(int devid) +{ + int res = 0; + + if (devid < 0) { + dm_log_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (devid == IOTX_DM_LOCAL_NODE_DEVID) { + res = _iotx_linkkit_master_close(); +#ifdef DEV_BIND_ENABLED + awss_bind_deinit(); +#endif + } else { +#ifdef DEVICE_MODEL_GATEWAY + res = _iotx_linkkit_slave_close(devid); +#else + res = FAIL_RETURN; +#endif + } + + return res; +} + +#ifdef DEVICE_MODEL_GATEWAY +static int _iotx_linkkit_subdev_login(int devid) +{ + int res = 0, msgid = 0, code = 0; + iotx_linkkit_upstream_sync_callback_node_t *node = NULL; + void *semaphore = NULL; + void *callback = NULL; + + res = iotx_dm_subdev_login(devid); + if (res < SUCCESS_RETURN) { + return FAIL_RETURN; + } + + msgid = res; + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + return FAIL_RETURN; + } + + _iotx_linkkit_upstream_mutex_lock(); + res = _iotx_linkkit_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + _iotx_linkkit_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, IOTX_LINKKIT_SYNC_DEFAULT_TIMEOUT_MS); + if (res < SUCCESS_RETURN) { + _iotx_linkkit_upstream_mutex_lock(); + _iotx_linkkit_upstream_sync_callback_list_remove(msgid); + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + + _iotx_linkkit_upstream_mutex_lock(); + code = node->code; + _iotx_linkkit_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + _iotx_linkkit_upstream_mutex_unlock(); + + res = iotx_dm_subscribe(devid); + if (res != SUCCESS_RETURN) { + return FAIL_RETURN; + } + + iotx_dm_send_aos_active(devid); + callback = iotx_event_callback(ITE_INITIALIZE_COMPLETED); + if (callback) { + ((int (*)(const int))callback)(devid); + } + + return res; +} + +static int _iotx_linkkit_subdev_logout(int devid) +{ + int res = 0, msgid = 0, code = 0; + iotx_linkkit_upstream_sync_callback_node_t *node = NULL; + void *semaphore = NULL; + + res = iotx_dm_subdev_logout(devid); + if (res < SUCCESS_RETURN) { + return FAIL_RETURN; + } + + msgid = res; + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + return FAIL_RETURN; + } + + _iotx_linkkit_upstream_mutex_lock(); + res = _iotx_linkkit_upstream_sync_callback_list_insert(msgid, semaphore, &node); + if (res != SUCCESS_RETURN) { + HAL_SemaphoreDestroy(semaphore); + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + _iotx_linkkit_upstream_mutex_unlock(); + + res = HAL_SemaphoreWait(semaphore, IOTX_LINKKIT_SYNC_DEFAULT_TIMEOUT_MS); + if (res < SUCCESS_RETURN) { + _iotx_linkkit_upstream_mutex_lock(); + _iotx_linkkit_upstream_sync_callback_list_remove(msgid); + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + + _iotx_linkkit_upstream_mutex_lock(); + code = node->code; + _iotx_linkkit_upstream_sync_callback_list_remove(msgid); + if (code != SUCCESS_RETURN) { + _iotx_linkkit_upstream_mutex_unlock(); + return FAIL_RETURN; + } + _iotx_linkkit_upstream_mutex_unlock(); + + return res; +} +#endif + +int IOT_Linkkit_Report(int devid, iotx_linkkit_msg_type_t msg_type, unsigned char *payload, int payload_len) +{ + int res = 0; + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + + if (devid < 0 || msg_type < 0 || msg_type >= IOTX_LINKKIT_MSG_MAX) { + dm_log_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (ctx->is_opened == 0 || ctx->is_connected == 0) { + return FAIL_RETURN; + } + + _iotx_linkkit_mutex_lock(); + switch (msg_type) { +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + case ITM_MSG_POST_PROPERTY: { + if (payload == NULL || payload_len <= 0) { + dm_log_err("Invalid Parameter"); + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } + res = iotx_dm_post_property(devid, (char *)payload, payload_len); +#ifdef LOG_REPORT_TO_CLOUD + if (1 == report_sample) { + send_permance_info(NULL, 0, "4", 1); + } +#endif + } + break; +#ifdef DEVICE_MODEL_SHADOW + case ITM_MSG_PROPERTY_DESIRED_GET: { + if (payload == NULL || payload_len <= 0) { + dm_log_err("Invalid Parameter"); + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } + res = iotx_dm_property_desired_get(devid, (char *)payload, payload_len); + } + break; + case ITM_MSG_PROPERTY_DESIRED_DELETE: { + if (payload == NULL || payload_len <= 0) { + dm_log_err("Invalid Parameter"); + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } + res = iotx_dm_property_desired_delete(devid, (char *)payload, payload_len); + } + break; +#endif + case ITM_MSG_DEVICEINFO_UPDATE: { + if (payload == NULL || payload_len <= 0) { + dm_log_err("Invalid Parameter"); + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } + res = iotx_dm_deviceinfo_update(devid, (char *)payload, payload_len); + } + break; + case ITM_MSG_DEVICEINFO_DELETE: { + if (payload == NULL || payload_len <= 0) { + dm_log_err("Invalid Parameter"); + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } + res = iotx_dm_deviceinfo_delete(devid, (char *)payload, payload_len); + } + break; +#endif + case ITM_MSG_POST_RAW_DATA: { + if (payload == NULL || payload_len <= 0) { + dm_log_err("Invalid Parameter"); + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } + res = iotx_dm_post_rawdata(devid, (char *)payload, payload_len); + } + break; + case ITM_MSG_LOGIN: { +#ifdef DEVICE_MODEL_GATEWAY + res = _iotx_linkkit_subdev_login(devid); + if (res != SUCCESS_RETURN) { + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } +#else + res = FAIL_RETURN; +#endif + } + break; + case ITM_MSG_LOGOUT: { +#ifdef DEVICE_MODEL_GATEWAY + res = _iotx_linkkit_subdev_logout(devid); + if (res != SUCCESS_RETURN) { + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } +#else + res = FAIL_RETURN; +#endif + } + break; + case ITM_MSG_DELETE_TOPO: { +#ifdef DEVICE_MODEL_GATEWAY + res = _iotx_linkkit_subdev_delete_topo(devid); + if (res != SUCCESS_RETURN) { + _iotx_linkkit_mutex_unlock(); + return FAIL_RETURN; + } +#else + res = FAIL_RETURN; +#endif + } + break; +#ifdef DEVICE_MODEL_GATEWAY +#ifdef DEVICE_MODEL_SUBDEV_OTA + case ITM_MSG_REPORT_SUBDEV_FIRMWARE_VERSION: { + res = iotx_dm_send_firmware_version(devid, (const char *)payload); + } + break; +#endif +#endif + default: { + dm_log_err("Unknown Message Type"); + res = FAIL_RETURN; + } + break; + } + _iotx_linkkit_mutex_unlock(); + return res; +} + +int IOT_Linkkit_Query(int devid, iotx_linkkit_msg_type_t msg_type, unsigned char *payload, int payload_len) +{ + int res = 0; + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + + if (devid < 0 || msg_type < 0 || msg_type >= IOTX_LINKKIT_MSG_MAX) { + dm_log_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (ctx->is_opened == 0 || ctx->is_connected == 0) { + return FAIL_RETURN; + } + + _iotx_linkkit_mutex_lock(); + switch (msg_type) { +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + case ITM_MSG_QUERY_TIMESTAMP: { + res = iotx_dm_qurey_ntp(); + } + break; +#endif + case ITM_MSG_QUERY_TOPOLIST: { +#ifdef DEVICE_MODEL_GATEWAY + res = iotx_dm_query_topo_list(); +#else + res = FAIL_RETURN; +#endif + } + break; + case ITM_MSG_QUERY_FOTA_DATA: { + res = iotx_dm_fota_perform_sync((char *)payload, payload_len); + } + break; + case ITM_MSG_QUERY_COTA_DATA: { + res = iotx_dm_cota_perform_sync((char *)payload, payload_len); + } + break; + case ITM_MSG_REQUEST_COTA: { + res = iotx_dm_cota_get_config("product", "file", ""); + } + break; + case ITM_MSG_REQUEST_FOTA_IMAGE: { + res = iotx_dm_fota_request_image((const char *)payload, payload_len); + } + break; + default: { + dm_log_err("Unknown Message Type"); + res = FAIL_RETURN; + } + break; + } + _iotx_linkkit_mutex_unlock(); + return res; +} + +int IOT_Linkkit_TriggerEvent(int devid, char *eventid, int eventid_len, char *payload, int payload_len) +{ +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + int res = 0; + iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx(); + + if (devid < 0 || eventid == NULL || eventid_len <= 0 || payload == NULL || payload_len <= 0) { + dm_log_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (ctx->is_opened == 0 || ctx->is_connected == 0) { + return FAIL_RETURN; + } + + _iotx_linkkit_mutex_lock(); + res = iotx_dm_post_event(devid, eventid, eventid_len, payload, payload_len); + _iotx_linkkit_mutex_unlock(); + + return res; +#else + return -1; +#endif +} + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_ntp.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_ntp.c new file mode 100644 index 00000000..ffb9f941 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_ntp.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "iotx_dm_internal.h" + +#ifdef DEPRECATED_LINKKIT + +#include "infra_json_parser.h" +#include "mqtt_api.h" +#include "impl_ntp.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#ifdef INFRA_MEM_STATS +#include "infra_mem_stats.h" +#define IMPL_NTP_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "impl.ntp") +#define IMPL_NTP_FREE(ptr) LITE_free(ptr) +#else +#define IMPL_NTP_MALLOC(size) HAL_Malloc(size) +#define IMPL_NTP_FREE(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +typedef void (*ntp_reply_cb_t)(const char *); +static ntp_reply_cb_t g_ntp_reply_cb = NULL; +static char g_ntp_time[NTP_TIME_STR_MAX_LEN + 1] = {0}; + +static void linkkit_ntp_time_reply(void *pcontext, void *pclient, void *mesg) +{ +#define DEV_TX_TIME "deviceSendTime" +#define SERVER_RX_TIME "serverRecvTime" +#define SERVER_TX_TIME "serverSendTime" + + int len = 0; + char *elem = NULL; + char server_rx_time[NTP_TIME_STR_MAX_LEN + 1] = {0}; + char server_tx_time[NTP_TIME_STR_MAX_LEN + 1] = {0}; + uint32_t payload_len; + char *payload; + uint32_t tx = 0; + uint32_t rx = 0; + uint32_t diff = 0; + + iotx_mqtt_event_msg_pt msg = (iotx_mqtt_event_msg_pt)mesg; + iotx_mqtt_topic_info_pt ptopic_info = (iotx_mqtt_topic_info_pt) msg->msg; + + switch (msg->event_type) { + case IOTX_MQTT_EVENT_PUBLISH_RECEIVED: + payload_len = ptopic_info->payload_len; + payload = (char *)ptopic_info->payload; + break; + default: + goto NTP_FAIL; + } + + if (payload == NULL || payload_len == 0) { + goto NTP_FAIL; + } + + memset(g_ntp_time, 0, sizeof(g_ntp_time)); + log_debug("[ntp]", "ntp reply len:%u, payload:%s\r\n", payload_len, payload); + + /* + * get deviceSendTime, serverRecvTime, serverSendTime + */ + elem = json_get_value_by_name(payload, payload_len, SERVER_TX_TIME, &len, NULL); + if (elem == NULL || len <= 0 || len > NTP_TIME_STR_MAX_LEN) { + goto NTP_FAIL; + } + + memcpy(server_tx_time, elem, len); + + elem = json_get_value_by_name(payload, payload_len, SERVER_RX_TIME, &len, NULL); + if (elem == NULL || len <= 0 || len > NTP_TIME_STR_MAX_LEN) { + goto NTP_FAIL; + } + + memcpy(server_rx_time, elem, len); + + elem = json_get_value_by_name(payload, payload_len, DEV_TX_TIME, &len, NULL); + if (elem == NULL || len <= 0 || len > NTP_TIME_STR_MAX_LEN) { + goto NTP_FAIL; + } + /* + * atoi fails to convert string to integer + * so we convert manully + */ + while (len -- > 0) { + tx *= 10; + tx += elem[0] - '0'; + elem ++; + } + rx = HAL_UptimeMs(); + diff = (rx - tx) >> 1; + if (diff >= 1000000) { + goto NTP_FAIL; + } + + len = strlen(server_tx_time); + elem = &server_tx_time[len > 9 ? len - 9 : 0]; + tx = atoi(elem); + tx += diff; + + if (tx > 999999999) { + tx = 999999999; + } + + if (len > 9) { + sprintf(elem, "%09u", (unsigned int)tx); + } else { + sprintf(elem, "%u", (unsigned int)tx); + } + + strncpy(g_ntp_time, (const char *)server_tx_time, sizeof(g_ntp_time) - 1); + +NTP_FAIL: + if (g_ntp_reply_cb != NULL) { + g_ntp_reply_cb(g_ntp_time); + } + return; +} + +int linkkit_ntp_time_request(void (*ntp_reply)(const char *ntp_offset_time_ms)) +{ + int ret = -1; + int final_len = 0; + int packet_len = 64; + int topic_len = 128; + char *packet = NULL; + char *topic = NULL; + + do { + char pk[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char dn[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + HAL_GetProductKey(pk); + HAL_GetDeviceName(dn); + + topic = (char *)IMPL_NTP_MALLOC(topic_len + 1); + if (topic == NULL) { + goto NTP_REQ_ERR; + } + memset(topic, 0, topic_len + 1); + + HAL_Snprintf(topic, topic_len, TOPIC_NTP_REPLY, pk, dn); + ret = IOT_MQTT_Subscribe_Sync(NULL, topic, IOTX_MQTT_QOS0, + (iotx_mqtt_event_handle_func_fpt)linkkit_ntp_time_reply, NULL, 1000); + if (ret < 0) { + goto NTP_REQ_ERR; + } + + memset(topic, 0, topic_len + 1); + HAL_Snprintf(topic, topic_len, TOPIC_NTP, pk, dn); + } while (0); + + packet = (char *)IMPL_NTP_MALLOC(packet_len + 1); + if (packet == NULL) { + ret = -1; + goto NTP_REQ_ERR; + } + memset(packet, 0, packet_len + 1); + + g_ntp_reply_cb = ntp_reply; + final_len = HAL_Snprintf(packet, packet_len, "{\"deviceSendTime\":\"%u\"}", (unsigned int)(HAL_UptimeMs())); + + log_debug("[ntp]", "report ntp:%s\r\n", packet); + + + ret = IOT_MQTT_Publish_Simple(NULL, topic, IOTX_MQTT_QOS0, packet, final_len); + +NTP_REQ_ERR: + if (topic) { + IMPL_NTP_FREE(topic); + } + if (packet) { + IMPL_NTP_FREE(packet); + } + return ret; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_ntp.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_ntp.h new file mode 100644 index 00000000..d5f20d06 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_ntp.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NTP_H +#define NTP_H + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + + +#define TOPIC_NTP "/ext/ntp/%s/%s/request" +#define TOPIC_NTP_REPLY "/ext/ntp/%s/%s/response" + +#define NTP_TIME_STR_MAX_LEN (20) + +int linkkit_ntp_time_request(void (*)(const char *ntp_offset_time_ms)); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_solo.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_solo.c new file mode 100644 index 00000000..7cb2a9a5 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_solo.c @@ -0,0 +1,1186 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "iotx_dm_internal.h" + +#ifdef DEPRECATED_LINKKIT + +#include "linkkit_export.h" +#include "impl_solo.h" + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define IMPL_SOLO_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "impl.solo") + #define IMPL_SOLO_FREE(ptr) LITE_free(ptr) +#else + #define IMPL_SOLO_MALLOC(size) HAL_Malloc(size) + #define IMPL_SOLO_FREE(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#ifdef INFRA_LOG + #include "infra_log.h" + #define impl_solo_err(...) log_err("impl.solo", __VA_ARGS__) + #define impl_solo_info(...) log_info("impl.solo", __VA_ARGS__) + #define impl_solo_debug(...) log_debug("impl.solo", __VA_ARGS__) +#else + #define impl_solo_err(...) + #define impl_solo_info(...) + #define impl_solo_debug(...) +#endif + +linkkit_solo_legacy_ctx_t g_linkkit_solo_legacy_ctx = {0}; + +static being_deprecated linkkit_solo_legacy_ctx_t *_linkkit_solo_legacy_get_ctx(void) +{ + return &g_linkkit_solo_legacy_ctx; +} + +static void _linkkit_solo_mutex_lock(void) +{ + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + if (linkkit_solo_ctx->mutex) { + HAL_MutexLock(linkkit_solo_ctx->mutex); + } +} + +static void _linkkit_solo_mutex_unlock(void) +{ + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + if (linkkit_solo_ctx->mutex) { + HAL_MutexUnlock(linkkit_solo_ctx->mutex); + } +} + +static void _linkkit_solo_upstream_mutex_lock(void) +{ + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + if (linkkit_solo_ctx->upstream_mutex) { + HAL_MutexLock(linkkit_solo_ctx->upstream_mutex); + } +} + +static void _linkkit_solo_upstream_mutex_unlock(void) +{ + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + if (linkkit_solo_ctx->upstream_mutex) { + HAL_MutexUnlock(linkkit_solo_ctx->upstream_mutex); + } +} + +static int _impl_copy(_IN_ void *input, _IN_ int input_len, _OU_ void **output, _IN_ int output_len) +{ + if (input == NULL || output == NULL || *output != NULL) { + return DM_INVALID_PARAMETER; + } + + *output = IMPL_SOLO_MALLOC(output_len); + if (*output == NULL) { + return DM_MEMORY_NOT_ENOUGH; + } + memset(*output, 0, output_len); + memcpy(*output, input, input_len); + + return SUCCESS_RETURN; +} + +static int _linkkit_solo_upstream_callback_list_insert(int msgid, handle_post_cb_fp_t callback) +{ + int count = 0; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + linkkit_solo_upstream_callback_node_t *search_node = NULL; + + list_for_each_entry(search_node, &linkkit_solo_ctx->callback_list, linked_list, linkkit_solo_upstream_callback_node_t) { + count++; + if (search_node->msgid == msgid) { + impl_solo_info("Message ID Already Exist: %d", msgid); + return FAIL_RETURN; + } + } + + impl_solo_info("linkkit_solo_upstream_callback_list node count: %d", count); + + search_node = IMPL_SOLO_MALLOC(sizeof(linkkit_solo_upstream_callback_node_t)); + if (search_node == NULL) { + return FAIL_RETURN; + } + memset(search_node, 0, sizeof(linkkit_solo_upstream_callback_node_t)); + + search_node->msgid = msgid; + search_node->callback = callback; + search_node->callback = callback; + INIT_LIST_HEAD(&search_node->linked_list); + + list_add(&search_node->linked_list, &linkkit_solo_ctx->callback_list); + + return SUCCESS_RETURN; +} + +static int _linkkit_solo_upstream_callback_list_remove(int msgid) +{ + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + linkkit_solo_upstream_callback_node_t *search_node = NULL; + + list_for_each_entry(search_node, &linkkit_solo_ctx->callback_list, linked_list, linkkit_solo_upstream_callback_node_t) { + if (search_node->msgid == msgid) { + list_del(&search_node->linked_list); + IMPL_SOLO_FREE(search_node); + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +static int _linkkit_solo_upstream_callback_list_search(int msgid, linkkit_solo_upstream_callback_node_t **node) +{ + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + linkkit_solo_upstream_callback_node_t *search_node = NULL; + + list_for_each_entry(search_node, &linkkit_solo_ctx->callback_list, linked_list, linkkit_solo_upstream_callback_node_t) { + if (search_node->msgid == msgid) { + *node = search_node; + return SUCCESS_RETURN; + } + } + + return FAIL_RETURN; +} + +static int _linkkit_solo_upstream_callback_list_destroy(void) +{ + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + linkkit_solo_upstream_callback_node_t *search_node = NULL, *next_node = NULL; + + list_for_each_entry_safe(search_node, next_node, &linkkit_solo_ctx->callback_list, linked_list, + linkkit_solo_upstream_callback_node_t) { + list_del(&search_node->linked_list); + IMPL_SOLO_FREE(search_node); + } + + return FAIL_RETURN; +} + +void *linkkit_dispatch(void) +{ + iotx_dm_dispatch(); + return NULL; +} + +int being_deprecated linkkit_is_try_leave(void) +{ + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + return linkkit_solo_ctx->is_leaved; +} + +int being_deprecated linkkit_set_opt(linkkit_opt_t opt, void *data) +{ + int res = 0; + + if (data == NULL) { + return FAIL_RETURN; + } + + _linkkit_solo_mutex_lock(); + res = iotx_dm_set_opt(opt, data); + _linkkit_solo_mutex_unlock(); + + return res; +} + +static void _linkkit_solo_event_callback(iotx_dm_event_types_t type, char *payload) +{ + int res = 0; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + lite_cjson_t lite, lite_item_id, lite_item_code, lite_item_devid, lite_item_payload, lite_item_serviceid; + lite_cjson_t lite_item_propertyid, lite_item_eventid, lite_item_configid, lite_item_configsize, lite_item_gettype; + lite_cjson_t lite_item_sign, lite_item_signmethod, lite_item_url, lite_item_version; + + impl_solo_info("Receive Message Type: %d", type); + if (payload) { + impl_solo_info("Receive Message: %s", payload); + res = dm_utils_json_parse(payload, strlen(payload), cJSON_Invalid, &lite); + if (res != SUCCESS_RETURN) { + return; + } + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_ID, strlen(LINKKIT_SOLO_LEGACY_KEY_ID), cJSON_Invalid, + &lite_item_id); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_CODE, strlen(LINKKIT_SOLO_LEGACY_KEY_CODE), cJSON_Invalid, + &lite_item_code); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_DEVID, strlen(LINKKIT_SOLO_LEGACY_KEY_DEVID), cJSON_Invalid, + &lite_item_devid); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_PAYLOAD, strlen(LINKKIT_SOLO_LEGACY_KEY_PAYLOAD), + cJSON_Invalid, &lite_item_payload); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_SERVICEID, strlen(LINKKIT_SOLO_LEGACY_KEY_SERVICEID), + cJSON_Invalid, &lite_item_serviceid); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_PROPERTYID, strlen(LINKKIT_SOLO_LEGACY_KEY_PROPERTYID), + cJSON_Invalid, &lite_item_propertyid); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_EVENTID, strlen(LINKKIT_SOLO_LEGACY_KEY_EVENTID), + cJSON_Invalid, &lite_item_eventid); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_CONFIG_ID, strlen(LINKKIT_SOLO_LEGACY_KEY_CONFIG_ID), + cJSON_Invalid, &lite_item_configid); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_CONFIG_SIZE, strlen(LINKKIT_SOLO_LEGACY_KEY_CONFIG_SIZE), + cJSON_Invalid, &lite_item_configsize); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_GET_TYPE, strlen(LINKKIT_SOLO_LEGACY_KEY_GET_TYPE), + cJSON_Invalid, &lite_item_gettype); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_SIGN, strlen(LINKKIT_SOLO_LEGACY_KEY_SIGN), cJSON_Invalid, + &lite_item_sign); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_SIGN_METHOD, strlen(LINKKIT_SOLO_LEGACY_KEY_SIGN_METHOD), + cJSON_Invalid, &lite_item_signmethod); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_URL, strlen(LINKKIT_SOLO_LEGACY_KEY_URL), cJSON_Invalid, + &lite_item_url); + dm_utils_json_object_item(&lite, LINKKIT_SOLO_LEGACY_KEY_VERSION, strlen(LINKKIT_SOLO_LEGACY_KEY_VERSION), + cJSON_Invalid, &lite_item_version); + } + + switch (type) { + case IOTX_DM_EVENT_CLOUD_CONNECTED: { + if (linkkit_solo_ctx->user_callback->on_connect) { + linkkit_solo_ctx->user_callback->on_connect(linkkit_solo_ctx->user_context); + } + } + break; + case IOTX_DM_EVENT_CLOUD_DISCONNECT: { + if (linkkit_solo_ctx->user_callback->on_disconnect) { + linkkit_solo_ctx->user_callback->on_disconnect(linkkit_solo_ctx->user_context); + } + } + break; + case IOTX_DM_EVENT_MODEL_DOWN_RAW: { + int res = 0, raw_data_len = 0; + void *thing_id = NULL; + unsigned char *raw_data = NULL; + + if (payload == NULL || lite_item_devid.type != cJSON_Number || lite_item_payload.type != cJSON_String) { + return; + } + + impl_solo_debug("Current Devid: %d", lite_item_devid.value_int); + impl_solo_debug("Current Raw Data: %.*s", lite_item_payload.value_length, lite_item_payload.value); + + res = iotx_dm_deprecated_legacy_get_thingid_by_devid(lite_item_devid.value_int, &thing_id); + if (res != SUCCESS_RETURN) { + return; + } + + res = dm_utils_str_to_hex(lite_item_payload.value, lite_item_payload.value_length, &raw_data, &raw_data_len); + if (res != SUCCESS_RETURN) { + return; + } + HEXDUMP_DEBUG(raw_data, raw_data_len); + + if (linkkit_solo_ctx->user_callback->raw_data_arrived) { + linkkit_solo_ctx->user_callback->raw_data_arrived(thing_id, raw_data, raw_data_len, linkkit_solo_ctx->user_context); + } + + IMPL_SOLO_FREE(raw_data); + } + break; + case IOTX_DM_EVENT_THING_SERVICE_REQUEST: { + int res = 0; + void *thing_id = NULL; + char *service = NULL; + + if (payload == NULL || lite_item_id.type != cJSON_Number || lite_item_devid.type != cJSON_Number || + lite_item_serviceid.type != cJSON_String) { + return; + } + + impl_solo_debug("Current Id: %d", lite_item_id.value_int); + impl_solo_debug("Current Devid: %d", lite_item_devid.value_int); + impl_solo_debug("Current ServiceID: %.*s", lite_item_serviceid.value_length, lite_item_serviceid.value); + + res = iotx_dm_deprecated_legacy_get_thingid_by_devid(lite_item_devid.value_int, &thing_id); + if (res != SUCCESS_RETURN) { + return; + } + + service = IMPL_SOLO_MALLOC(lite_item_serviceid.value_length + 1); + if (service == NULL) { + return; + } + memset(service, 0, lite_item_serviceid.value_length + 1); + memcpy(service, lite_item_serviceid.value, lite_item_serviceid.value_length); + + if (linkkit_solo_ctx->user_callback->thing_call_service) { + linkkit_solo_ctx->user_callback->thing_call_service(thing_id, (const char *)service, lite_item_id.value_int, + linkkit_solo_ctx->user_context); + } + + IMPL_SOLO_FREE(service); + } + break; + case IOTX_DM_EVENT_LEGACY_THING_CREATED: { + int res = 0; + void *thing_id = NULL; + + if (payload == NULL || lite_item_devid.type != cJSON_Number) { + return; + } + + impl_solo_debug("Current Devid: %d", lite_item_devid.value_int); + + res = iotx_dm_deprecated_legacy_get_thingid_by_devid(lite_item_devid.value_int, &thing_id); + if (res != SUCCESS_RETURN) { + return; + } + + if (linkkit_solo_ctx->user_callback->thing_create) { + linkkit_solo_ctx->user_callback->thing_create(thing_id, linkkit_solo_ctx->user_context); + } + } + break; + case IOTX_DM_EVENT_THING_DISABLE: { + int res = 0; + void *thing_id = NULL; + + if (payload == NULL || lite_item_devid.type != cJSON_Number) { + return; + } + + impl_solo_debug("Current Devid: %d", lite_item_devid.value_int); + + res = iotx_dm_deprecated_legacy_get_thingid_by_devid(lite_item_devid.value_int, &thing_id); + if (res != SUCCESS_RETURN) { + return; + } + + if (linkkit_solo_ctx->user_callback->thing_disable) { + linkkit_solo_ctx->user_callback->thing_disable(thing_id, linkkit_solo_ctx->user_context); + } + } + break; + case IOTX_DM_EVENT_THING_ENABLE: { + int res = 0; + void *thing_id = NULL; + + if (payload == NULL || lite_item_devid.type != cJSON_Number) { + return; + } + + impl_solo_debug("Current Devid: %d", lite_item_devid.value_int); + + res = iotx_dm_deprecated_legacy_get_thingid_by_devid(lite_item_devid.value_int, &thing_id); + if (res != SUCCESS_RETURN) { + return; + } + + if (linkkit_solo_ctx->user_callback->thing_enable) { + linkkit_solo_ctx->user_callback->thing_enable(thing_id, linkkit_solo_ctx->user_context); + } + } + break; + case IOTX_DM_EVENT_PROPERTY_SET: { + int res = 0; + void *thing_id = NULL; + char *propertyid = NULL; + + if (payload == NULL || lite_item_devid.type != cJSON_Number || lite_item_propertyid.type != cJSON_String) { + return; + } + + impl_solo_debug("Current Devid: %d", lite_item_devid.value_int); + impl_solo_debug("Current PropertyID: %.*s", lite_item_propertyid.value_length, lite_item_propertyid.value); + + res = iotx_dm_deprecated_legacy_get_thingid_by_devid(lite_item_devid.value_int, &thing_id); + if (res != SUCCESS_RETURN) { + return; + } + + propertyid = IMPL_SOLO_MALLOC(lite_item_propertyid.value_length + 1); + if (propertyid == NULL) { + return; + } + memset(propertyid, 0, lite_item_propertyid.value_length + 1); + memcpy(propertyid, lite_item_propertyid.value, lite_item_propertyid.value_length); + + if (linkkit_solo_ctx->user_callback->thing_prop_changed) { + linkkit_solo_ctx->user_callback->thing_prop_changed(thing_id, propertyid, linkkit_solo_ctx->user_context); + } + + IMPL_SOLO_FREE(propertyid); + } + break; + case IOTX_DM_EVENT_EVENT_PROPERTY_POST_REPLY: { + int res = 0; + void *thing_id = NULL; + linkkit_solo_upstream_callback_node_t *node = NULL; + handle_post_cb_fp_t callback = NULL; + + if (payload == NULL || lite_item_id.type != cJSON_Number || lite_item_code.type != cJSON_Number || + lite_item_devid.type != cJSON_Number) { + return; + } + + impl_solo_debug("Current Id: %d", lite_item_id.value_int); + impl_solo_debug("Current Code: %d", lite_item_code.value_int); + impl_solo_debug("Current Devid: %d", lite_item_devid.value_int); + + res = iotx_dm_deprecated_legacy_get_thingid_by_devid(lite_item_devid.value_int, &thing_id); + if (res != SUCCESS_RETURN) { + return; + } + + _linkkit_solo_upstream_mutex_lock(); + res = _linkkit_solo_upstream_callback_list_search(lite_item_id.value_int, &node); + if (res == SUCCESS_RETURN) { + callback = node->callback; + } + _linkkit_solo_upstream_mutex_unlock(); + if (res == SUCCESS_RETURN) { + if (callback) { + callback(thing_id, lite_item_id.value_int, lite_item_code.value_int, NULL, linkkit_solo_ctx->user_context); + } + _linkkit_solo_upstream_mutex_lock(); + _linkkit_solo_upstream_callback_list_remove(lite_item_id.value_int); + _linkkit_solo_upstream_mutex_unlock(); + } + } + break; + case IOTX_DM_EVENT_EVENT_SPECIFIC_POST_REPLY: { + int res = 0; + void *thing_id = NULL; + linkkit_solo_upstream_callback_node_t *node = NULL; + handle_post_cb_fp_t callback = NULL; + + if (payload == NULL || lite_item_id.type != cJSON_Number || lite_item_code.type != cJSON_Number || + lite_item_devid.type != cJSON_Number || lite_item_eventid.type != cJSON_String) { + return; + } + + impl_solo_debug("Current Id: %d", lite_item_id.value_int); + impl_solo_debug("Current Code: %d", lite_item_code.value_int); + impl_solo_debug("Current Devid: %d", lite_item_devid.value_int); + impl_solo_debug("Current EventID: %.*s", lite_item_eventid.value_length, lite_item_eventid.value); + + res = iotx_dm_deprecated_legacy_get_thingid_by_devid(lite_item_devid.value_int, &thing_id); + if (res != SUCCESS_RETURN) { + return; + } + + _linkkit_solo_upstream_mutex_lock(); + res = _linkkit_solo_upstream_callback_list_search(lite_item_id.value_int, &node); + if (res == SUCCESS_RETURN) { + callback = node->callback; + } + _linkkit_solo_upstream_mutex_unlock(); + if (res == SUCCESS_RETURN) { + if (callback) { + callback(thing_id, lite_item_id.value_int, lite_item_code.value_int, NULL, linkkit_solo_ctx->user_context); + } + _linkkit_solo_upstream_mutex_lock(); + _linkkit_solo_upstream_callback_list_remove(lite_item_id.value_int); + _linkkit_solo_upstream_mutex_unlock(); + } + } + break; + case IOTX_DM_EVENT_COTA_NEW_CONFIG: { + char *config_id = NULL, *get_type = NULL, *sign = NULL, *sign_method = NULL, *url = NULL; + + if (payload == NULL || lite_item_configid.type != cJSON_String || lite_item_configsize.type != cJSON_Number || + lite_item_gettype.type != cJSON_String || lite_item_sign.type != cJSON_String + || lite_item_signmethod.type != cJSON_String || + lite_item_url.type != cJSON_String) { + return; + } + + impl_solo_debug("Current Config ID: %.*s", lite_item_configid.value_length, lite_item_configid.value); + impl_solo_debug("Current Config Size: %d", lite_item_configsize.value_int); + impl_solo_debug("Current Get Type: %.*s", lite_item_gettype.value_length, lite_item_gettype.value); + impl_solo_debug("Current Sign: %.*s", lite_item_sign.value_length, lite_item_sign.value); + impl_solo_debug("Current Sign Method: %.*s", lite_item_signmethod.value_length, lite_item_signmethod.value); + impl_solo_debug("Current URL: %.*s", lite_item_url.value_length, lite_item_url.value); + + _impl_copy(lite_item_configid.value, lite_item_configid.value_length, (void **)&config_id, + lite_item_configid.value_length + 1); + _impl_copy(lite_item_gettype.value, lite_item_gettype.value_length, (void **)&get_type, + lite_item_gettype.value_length + 1); + _impl_copy(lite_item_sign.value, lite_item_sign.value_length, (void **)&sign, lite_item_sign.value_length + 1); + _impl_copy(lite_item_signmethod.value, lite_item_signmethod.value_length, (void **)&sign_method, + lite_item_signmethod.value_length + 1); + _impl_copy(lite_item_url.value, lite_item_url.value_length, (void **)&url, lite_item_url.value_length + 1); + + if (config_id == NULL || get_type == NULL || sign == NULL || sign_method == NULL || url == NULL) { + if (config_id) { + IMPL_SOLO_FREE(config_id); + } + if (get_type) { + IMPL_SOLO_FREE(get_type); + } + if (sign) { + IMPL_SOLO_FREE(sign); + } + if (sign_method) { + IMPL_SOLO_FREE(sign_method); + } + if (url) { + IMPL_SOLO_FREE(url); + } + return; + } + + if (linkkit_solo_ctx->cota_callback) { + linkkit_solo_ctx->cota_callback(service_cota_callback_type_new_version_detected, config_id, + lite_item_configsize.value_int, get_type, sign, sign_method, url); + } + + if (config_id) { + IMPL_SOLO_FREE(config_id); + } + if (get_type) { + IMPL_SOLO_FREE(get_type); + } + if (sign) { + IMPL_SOLO_FREE(sign); + } + if (sign_method) { + IMPL_SOLO_FREE(sign_method); + } + if (url) { + IMPL_SOLO_FREE(url); + } + } + break; + case IOTX_DM_EVENT_FOTA_NEW_FIRMWARE: { + char *version = NULL; + + if (payload == NULL || lite_item_version.type != cJSON_String) { + return; + } + + impl_solo_debug("Current Firmware Version: %.*s", lite_item_version.value_length, lite_item_version.value); + + _impl_copy(lite_item_version.value, lite_item_version.value_length, (void **)&version, + lite_item_version.value_length + 1); + if (version == NULL) { + return; + } + + if (linkkit_solo_ctx->fota_callback) { + linkkit_solo_ctx->fota_callback(service_fota_callback_type_new_version_detected, version); + } + + if (version) { + IMPL_SOLO_FREE(version); + } + } + break; +#ifdef LOCAL_CONN_ENABLE + case IOTX_DM_EVENT_LOCAL_CONNECTED: { + if (linkkit_solo_ctx->on_connect) { + linkkit_solo_ctx->on_connect(context, 0); + } + } + break; + case IOTX_DM_EVENT_LOCAL_DISCONNECT: { + if (linkkit_solo_ctx->on_connect) { + linkkit_solo_ctx->on_connect(context, 0); + } + } + break; +#endif + default: + break; + } +} + +int being_deprecated linkkit_start(int max_buffered_msg, int get_tsl_from_cloud, linkkit_loglevel_t log_level, + linkkit_ops_t *ops, + linkkit_cloud_domain_type_t domain_type, void *user_context) +{ + int res = 0; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + iotx_dm_init_params_t dm_init_params; + + if (linkkit_solo_ctx->is_started == 1) { + return FAIL_RETURN; + } + linkkit_solo_ctx->is_started = 1; + + if (max_buffered_msg <= 0 || ops == NULL || log_level > LOG_DEBUG_LEVEL || + domain_type >= linkkit_cloud_domain_max) { + impl_solo_err("Invalid Parameter"); + linkkit_solo_ctx->is_started = 0; + return FAIL_RETURN; + } + + /* Create Mutex */ + linkkit_solo_ctx->mutex = HAL_MutexCreate(); + if (linkkit_solo_ctx->mutex == NULL) { + linkkit_solo_ctx->is_started = 0; + return FAIL_RETURN; + } + + linkkit_solo_ctx->upstream_mutex = HAL_MutexCreate(); + if (linkkit_solo_ctx->upstream_mutex == NULL) { + HAL_MutexDestroy(linkkit_solo_ctx->mutex); + linkkit_solo_ctx->is_started = 0; + return FAIL_RETURN; + } + + /* Set Linkkit Log Level */ + IOT_SetLogLevel(log_level); + + /* Set Region */ + IOT_Ioctl(IOTX_IOCTL_SET_REGION, &domain_type); + + /* Initialize Device Manager */ + memset(&dm_init_params, 0, sizeof(iotx_dm_init_params_t)); + dm_init_params.secret_type = IOTX_DM_DEVICE_SECRET_DEVICE; + dm_init_params.domain_type = (iotx_dm_cloud_domain_types_t)domain_type; + dm_init_params.event_callback = _linkkit_solo_event_callback; + + res = iotx_dm_open(); + if (res != SUCCESS_RETURN) { + HAL_MutexDestroy(linkkit_solo_ctx->mutex); + HAL_MutexDestroy(linkkit_solo_ctx->upstream_mutex); + linkkit_solo_ctx->is_started = 0; + return FAIL_RETURN; + } + + res = iotx_dm_connect(&dm_init_params); + if (res != SUCCESS_RETURN) { + HAL_MutexDestroy(linkkit_solo_ctx->mutex); + HAL_MutexDestroy(linkkit_solo_ctx->upstream_mutex); + iotx_dm_close(); + linkkit_solo_ctx->is_started = 0; + return FAIL_RETURN; + } + + res = iotx_dm_subscribe(IOTX_DM_LOCAL_NODE_DEVID); + if (res != SUCCESS_RETURN) { + HAL_MutexDestroy(linkkit_solo_ctx->mutex); + HAL_MutexDestroy(linkkit_solo_ctx->upstream_mutex); + iotx_dm_close(); + linkkit_solo_ctx->is_started = 0; + return FAIL_RETURN; + } + + /* Get TSL From Cloud If Need */ + if (get_tsl_from_cloud != 0) { + res = iotx_dm_deprecated_set_tsl(IOTX_DM_LOCAL_NODE_DEVID, IOTX_DM_TSL_SOURCE_CLOUD, NULL, 0); + if (res < SUCCESS_RETURN) { + HAL_MutexDestroy(linkkit_solo_ctx->mutex); + HAL_MutexDestroy(linkkit_solo_ctx->upstream_mutex); + iotx_dm_close(); + linkkit_solo_ctx->is_started = 0; + return FAIL_RETURN; + } + } + + /* Init Message Callback List */ + INIT_LIST_HEAD(&linkkit_solo_ctx->callback_list); + + linkkit_solo_ctx->user_callback = ops; + linkkit_solo_ctx->user_context = user_context; + linkkit_solo_ctx->is_leaved = 0; + + return SUCCESS_RETURN; +} + +int being_deprecated linkkit_end(void) +{ + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_solo_mutex_lock(); + _linkkit_solo_upstream_mutex_lock(); + linkkit_solo_ctx->is_started = 0; + _linkkit_solo_upstream_callback_list_destroy(); + _linkkit_solo_upstream_mutex_unlock(); + + iotx_dm_close(); + _linkkit_solo_mutex_unlock(); + + HAL_MutexDestroy(linkkit_solo_ctx->upstream_mutex); + HAL_MutexDestroy(linkkit_solo_ctx->mutex); + + linkkit_solo_ctx->mutex = NULL; + linkkit_solo_ctx->upstream_mutex = NULL; + linkkit_solo_ctx->user_callback = NULL; + linkkit_solo_ctx->user_context = NULL; + linkkit_solo_ctx->cota_callback = NULL; + linkkit_solo_ctx->fota_callback = NULL; + INIT_LIST_HEAD(&linkkit_solo_ctx->callback_list); + + return SUCCESS_RETURN; +} + +void *linkkit_set_tsl(const char *tsl, int tsl_len) +{ + int res = 0; + void *thing_id = NULL; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (tsl == NULL || tsl_len <= 0) { + impl_solo_err("Invalid Parameter"); + return NULL; + } + + if (linkkit_solo_ctx->is_started == 0) { + return NULL; + } + + _linkkit_solo_mutex_lock(); + res = iotx_dm_deprecated_set_tsl(IOTX_DM_LOCAL_NODE_DEVID, IOTX_DM_TSL_SOURCE_LOCAL, tsl, tsl_len); + if (res != SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return NULL; + } + + res = iotx_dm_deprecated_legacy_get_thingid_by_devid(IOTX_DM_LOCAL_NODE_DEVID, &thing_id); + if (res != SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return NULL; + } + + _linkkit_solo_mutex_unlock(); + return thing_id; +} + +int being_deprecated linkkit_set_value(linkkit_method_set_t method_set, const void *thing_id, const char *identifier, + const void *value, + const char *value_str) +{ + int res = 0, devid = 0; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (thing_id == NULL || identifier == NULL || (value == NULL && value_str == NULL)) { + impl_solo_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_solo_mutex_lock(); + res = iotx_dm_deprecated_legacy_get_devid_by_thingid((void *)thing_id, &devid); + if (res != SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + switch (method_set) { + case linkkit_method_set_property_value: { + res = iotx_dm_deprecated_legacy_set_property_value(devid, (char *)identifier, strlen(identifier), (void *)value, + (char *)value_str); + } + break; + case linkkit_method_set_event_output_value: { + res = iotx_dm_deprecated_legacy_set_event_output_value(devid, (char *)identifier, strlen(identifier), (void *)value, + (char *)value_str); + } + break; + case linkkit_method_set_service_output_value: { + res = iotx_dm_deprecated_legacy_set_service_output_value(devid, (char *)identifier, strlen(identifier), (void *)value, + (char *)value_str); + } + break; + default: { + impl_solo_err("Invalid Parameter"); + res = FAIL_RETURN; + } + break; + } + + if (res < SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_solo_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int being_deprecated linkkit_get_value(linkkit_method_get_t method_get, const void *thing_id, const char *identifier, + void *value, + char **value_str) +{ + int res = 0, devid = 0; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (thing_id == NULL || identifier == NULL || (value == NULL && value_str == NULL)) { + impl_solo_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_solo_mutex_lock(); + res = iotx_dm_deprecated_legacy_get_devid_by_thingid((void *)thing_id, &devid); + if (res != SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + switch (method_get) { + case linkkit_method_get_property_value: { + res = iotx_dm_deprecated_legacy_get_property_value(devid, (char *)identifier, strlen(identifier), value, value_str); + } + break; + case linkkit_method_get_event_output_value: { + res = iotx_dm_deprecated_legacy_get_event_output_value(devid, (char *)identifier, strlen(identifier), value, value_str); + } + break; + case linkkit_method_get_service_input_value: { + res = iotx_dm_deprecated_legacy_get_service_input_value(devid, (char *)identifier, strlen(identifier), value, + value_str); + } + break; + case linkkit_method_get_service_output_value: { + res = iotx_dm_deprecated_legacy_get_service_output_value(devid, (char *)identifier, strlen(identifier), value, + value_str); + } + break; + default: { + impl_solo_err("Invalid Parameter"); + res = FAIL_RETURN; + } + break; + } + + if (res < SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_solo_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int being_deprecated linkkit_answer_service(const void *thing_id, const char *service_identifier, int response_id, + int code) +{ + int res = 0, devid = 0; + + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (thing_id == NULL || service_identifier == NULL) { + impl_solo_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_solo_mutex_lock(); + res = iotx_dm_deprecated_legacy_get_devid_by_thingid((void *)thing_id, &devid); + if (res != SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + res = iotx_dm_deprecated_send_service_response(devid, response_id, (iotx_dm_error_code_t)code, + (char *)service_identifier, strlen(service_identifier)); + if (res < SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_solo_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int being_deprecated linkkit_invoke_raw_service(const void *thing_id, int is_up_raw, void *raw_data, + int raw_data_length) +{ + int res = 0, devid = 0; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (thing_id == NULL || raw_data == NULL || raw_data_length <= 0) { + impl_solo_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_solo_mutex_lock(); + res = iotx_dm_deprecated_legacy_get_devid_by_thingid((void *)thing_id, &devid); + if (res != SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + res = iotx_dm_post_rawdata(devid, raw_data, raw_data_length); + if (res < SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_solo_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int being_deprecated linkkit_trigger_extended_info_operate(const void *thing_id, const char *params, + linkkit_extended_info_operate_t linkkit_extended_info_operation) +{ + int res = 0, devid = 0; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (thing_id == NULL || params == NULL) { + impl_solo_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_solo_mutex_lock(); + res = iotx_dm_deprecated_legacy_get_devid_by_thingid((void *)thing_id, &devid); + if (res != SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + switch (linkkit_extended_info_operation) { + case linkkit_extended_info_operate_update: { + res = iotx_dm_deviceinfo_update(devid, (char *)params, strlen(params)); + } + break; + case linkkit_extended_info_operate_delete: { + res = iotx_dm_deviceinfo_delete(devid, (char *)params, strlen(params)); + } + break; + default: { + impl_solo_err("Invalid Parameter"); + res = FAIL_RETURN; + } + break; + } + + if (res < SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + _linkkit_solo_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int being_deprecated linkkit_trigger_event(const void *thing_id, const char *event_identifier, handle_post_cb_fp_t cb) +{ + int res = 0, devid = 0, msgid = 0, post_event_reply = 0; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (thing_id == NULL || event_identifier == NULL) { + impl_solo_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_solo_mutex_lock(); + res = iotx_dm_deprecated_legacy_get_devid_by_thingid((void *)thing_id, &devid); + if (res != SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + res = iotx_dm_deprecated_post_event(devid, (char *)event_identifier, strlen((char *)event_identifier)); + if (res < SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + msgid = res; + + res = iotx_dm_get_opt(linkkit_opt_event_post_reply, &post_event_reply); + if (cb != NULL && post_event_reply) { + /* Insert Message ID Into Linked List */ + _linkkit_solo_upstream_mutex_lock(); + res = _linkkit_solo_upstream_callback_list_insert(msgid, cb); + _linkkit_solo_upstream_mutex_unlock(); + if (res != SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + } + + _linkkit_solo_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int being_deprecated linkkit_post_property(const void *thing_id, const char *property_identifier, + handle_post_cb_fp_t cb) +{ + int res = 0, devid = 0, msgid = 0, property_identifier_len = 0, post_property_reply = 0; + void *property_handle = NULL; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (thing_id == NULL) { + impl_solo_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_solo_mutex_lock(); + res = iotx_dm_deprecated_legacy_get_devid_by_thingid((void *)thing_id, &devid); + if (res != SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + res = iotx_dm_deprecated_post_property_start(devid, &property_handle); + if (res != SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + property_identifier_len = (property_identifier) ? (strlen((char *)property_identifier)) : (0); + res = iotx_dm_deprecated_post_property_add(property_handle, (char *)property_identifier, property_identifier_len); + if (res != SUCCESS_RETURN) { + iotx_dm_deprecated_post_property_end(&property_handle); + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + + res = iotx_dm_deprecated_post_property_end(&property_handle); + if (res < SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + msgid = res; + + res = iotx_dm_get_opt(linkkit_opt_property_post_reply, &post_property_reply); + if (cb != NULL && post_property_reply) { + /* Insert Message ID Into Linked List */ + _linkkit_solo_upstream_mutex_lock(); + res = _linkkit_solo_upstream_callback_list_insert(msgid, cb); + _linkkit_solo_upstream_mutex_unlock(); + if (res != SUCCESS_RETURN) { + _linkkit_solo_mutex_unlock(); + return FAIL_RETURN; + } + } + + _linkkit_solo_mutex_unlock(); + + return SUCCESS_RETURN; +} + +int being_deprecated linkkit_yield(int timeout_ms) +{ + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (timeout_ms <= 0) { + impl_solo_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + return iotx_dm_yield(timeout_ms); +} + +int being_deprecated linkkit_cota_init(handle_service_cota_callback_fp_t callback_fp) +{ + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + linkkit_solo_ctx->cota_callback = callback_fp; + + return SUCCESS_RETURN; +} + +int being_deprecated linkkit_invoke_cota_service(void *data_buf, int data_buf_length) +{ + int res = 0; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (data_buf == NULL || data_buf_length <= 0) { + impl_solo_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_solo_mutex_lock(); + res = iotx_dm_cota_perform_sync(data_buf, data_buf_length); + _linkkit_solo_mutex_unlock(); + + return res; +} + +int being_deprecated linkkit_invoke_cota_get_config(const char *config_scope, const char *get_type, + const char *attribute_Keys, + void *option) +{ + int res = 0; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (config_scope == NULL || get_type == NULL || attribute_Keys == NULL) { + impl_solo_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_solo_mutex_lock(); + res = iotx_dm_cota_get_config(config_scope, get_type, attribute_Keys); + _linkkit_solo_mutex_unlock(); + + return res; +} + +int being_deprecated linkkit_fota_init(handle_service_fota_callback_fp_t callback_fp) +{ + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + linkkit_solo_ctx->fota_callback = callback_fp; + + return SUCCESS_RETURN; +} + +int being_deprecated linkkit_invoke_fota_service(void *data_buf, int data_buf_length) +{ + int res = 0; + linkkit_solo_legacy_ctx_t *linkkit_solo_ctx = _linkkit_solo_legacy_get_ctx(); + + if (data_buf == NULL || data_buf_length <= 0) { + impl_solo_err("Invalid Parameter"); + return FAIL_RETURN; + } + + if (linkkit_solo_ctx->is_started == 0) { + return FAIL_RETURN; + } + + _linkkit_solo_mutex_lock(); + res = iotx_dm_fota_perform_sync(data_buf, data_buf_length); + _linkkit_solo_mutex_unlock(); + + return res; +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_solo.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_solo.h new file mode 100644 index 00000000..7bebcfd8 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/impl_solo.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _LINKKIT_SOLO_LEGACY_H_ +#define _LINKKIT_SOLO_LEGACY_H_ + +#include "linkkit_export.h" + +#define LINKKIT_SOLO_LEGACY_KEY_ID "id" +#define LINKKIT_SOLO_LEGACY_KEY_CODE "code" +#define LINKKIT_SOLO_LEGACY_KEY_DEVID "devid" +#define LINKKIT_SOLO_LEGACY_KEY_SERVICEID "serviceid" +#define LINKKIT_SOLO_LEGACY_KEY_PROPERTYID "propertyid" +#define LINKKIT_SOLO_LEGACY_KEY_EVENTID "eventid" +#define LINKKIT_SOLO_LEGACY_KEY_PAYLOAD "payload" +#define LINKKIT_SOLO_LEGACY_KEY_CONFIG_ID "configId" +#define LINKKIT_SOLO_LEGACY_KEY_CONFIG_SIZE "configSize" +#define LINKKIT_SOLO_LEGACY_KEY_GET_TYPE "getType" +#define LINKKIT_SOLO_LEGACY_KEY_SIGN "sign" +#define LINKKIT_SOLO_LEGACY_KEY_SIGN_METHOD "signMethod" +#define LINKKIT_SOLO_LEGACY_KEY_URL "url" +#define LINKKIT_SOLO_LEGACY_KEY_VERSION "version" + +typedef struct { + int msgid; + handle_post_cb_fp_t callback; + struct list_head linked_list; +} linkkit_solo_upstream_callback_node_t; + +typedef struct { + void *mutex; + void *upstream_mutex; + int is_started; + int is_leaved; + linkkit_ops_t *user_callback; + void *user_context; + handle_service_cota_callback_fp_t cota_callback; + handle_service_fota_callback_fp_t fota_callback; + struct list_head callback_list; +} linkkit_solo_legacy_ctx_t; + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iot_export_linkkit.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iot_export_linkkit.h new file mode 100644 index 00000000..93ad8026 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iot_export_linkkit.h @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _IOT_EXPORT_LINKKIT_H_ +#define _IOT_EXPORT_LINKKIT_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +#include "dm_wrapper.h" + +typedef enum { + IOTX_LINKKIT_DEV_TYPE_MASTER, + IOTX_LINKKIT_DEV_TYPE_SLAVE, + IOTX_LINKKIT_DEV_TYPE_MAX +} iotx_linkkit_dev_type_t; + +typedef struct { + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char product_secret[IOTX_PRODUCT_SECRET_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1]; +} iotx_linkkit_dev_meta_info_t; + +typedef enum { + /* post property value to cloud */ + ITM_MSG_POST_PROPERTY, + + /* post device info update message to cloud */ + ITM_MSG_DEVICEINFO_UPDATE, + + /* post device info delete message to cloud */ + ITM_MSG_DEVICEINFO_DELETE, + + /* post raw data to cloud */ + ITM_MSG_POST_RAW_DATA, + + /* only for slave device, send login request to cloud */ + ITM_MSG_LOGIN, + + /* only for slave device, send logout request to cloud */ + ITM_MSG_LOGOUT, + + /* only for slave device, send delete topo request to cloud */ + ITM_MSG_DELETE_TOPO, + + /* query ntp time from cloud */ + ITM_MSG_QUERY_TIMESTAMP, + + /* only for master device, query topo list */ + ITM_MSG_QUERY_TOPOLIST, + + /* only for master device, qurey firmware ota data */ + ITM_MSG_QUERY_FOTA_DATA, + + /* only for master device, qurey config ota data */ + ITM_MSG_QUERY_COTA_DATA, + + /* only for master device, request config ota data from cloud */ + ITM_MSG_REQUEST_COTA, + + /* only for master device, request fota image from cloud */ + ITM_MSG_REQUEST_FOTA_IMAGE, + + /* report subdev's firmware version */ + ITM_MSG_REPORT_SUBDEV_FIRMWARE_VERSION, + + /* get a device's desired property */ + ITM_MSG_PROPERTY_DESIRED_GET, + + /* delete a device's desired property */ + ITM_MSG_PROPERTY_DESIRED_DELETE, + + IOTX_LINKKIT_MSG_MAX +} iotx_linkkit_msg_type_t; + +/** + * @brief create a new device + * + * @param dev_type. type of device which will be created. see iotx_linkkit_dev_type_t + * @param meta_info. The product key, product secret, device name and device secret of new device. + * + * @return success: device id (>=0), fail: -1. + * + */ +DLL_IOT_API int IOT_Linkkit_Open(iotx_linkkit_dev_type_t dev_type, iotx_linkkit_dev_meta_info_t *meta_info); + +/** + * @brief start device network connection. + * for master device, start to connect aliyun server. + * for slave device, send message to cloud for register new device and add topo with master device + * + * @param devid. device identifier. + * + * @return success: device id (>=0), fail: -1. + * + */ +DLL_IOT_API int IOT_Linkkit_Connect(int devid); + +/** + * @brief try to receive message from cloud and dispatch these message to user event callback + * + * @param timeout_ms. timeout for waiting new message arrived + * + * @return void. + * + */ +DLL_IOT_API void IOT_Linkkit_Yield(int timeout_ms); + +/** + * @brief close device network connection and release resources. + * for master device, disconnect with aliyun server and release all local resources. + * for slave device, send message to cloud for delete topo with master device and unregister itself, then release device's resources. + * + * @param devid. device identifier. + * + * @return success: 0, fail: -1. + * + */ +DLL_IOT_API int IOT_Linkkit_Close(int devid); + +/** + * @brief Report message to cloud + * + * @param devid. device identifier. + * @param msg_type. message type. see iotx_linkkit_msg_type_t, as follows: + * ITM_MSG_POST_PROPERTY + * ITM_MSG_DEVICEINFO_UPDATE + * ITM_MSG_DEVICEINFO_DELETE + * ITM_MSG_POST_RAW_DATA + * ITM_MSG_LOGIN + * ITM_MSG_LOGOUT + * + * @param payload. message payload. + * @param payload_len. message payload length. + * + * @return success: 0 or message id (>=1), fail: -1. + * + */ +DLL_IOT_API int IOT_Linkkit_Report(int devid, iotx_linkkit_msg_type_t msg_type, unsigned char *payload, + int payload_len); + +/** + * @brief post message to cloud + * + * @param devid. device identifier. + * @param msg_type. message type. see iotx_linkkit_msg_type_t, as follows: + * ITM_MSG_QUERY_TIMESTAMP + * ITM_MSG_QUERY_TOPOLIST + * ITM_MSG_QUERY_FOTA_DATA + * ITM_MSG_QUERY_COTA_DATA + * ITM_MSG_REQUEST_COTA + * ITM_MSG_REQUEST_FOTA_IMAGE + * + * @param payload. message payload. + * @param payload_len. message payload length. + * + * @return success: 0 or message id (>=1), fail: -1. + * + */ +DLL_IOT_API int IOT_Linkkit_Query(int devid, iotx_linkkit_msg_type_t msg_type, unsigned char *payload, + int payload_len); + +/** + * @brief post event to cloud + * + * @param devid. device identifier. + * @param eventid. tsl event id. + * @param eventid_len. length of tsl event id. + * @param payload. event payload. + * @param payload_len. event payload length. + * + * @return success: message id (>=1), fail: -1. + * + */ +DLL_IOT_API int IOT_Linkkit_TriggerEvent(int devid, char *eventid, int eventid_len, char *payload, int payload_len); + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_alcs.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_alcs.h new file mode 100644 index 00000000..040a4aa3 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_alcs.h @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _IOT_EXPORT_ALCS_BACKUP_H_ +#define _IOT_EXPORT_ALCS_BACKUP_H_ + +#define IOTX_ALCS_ROLE_CLIENT (0x01) +#define IOTX_ALCS_ROLE_SERVER (0x02) + +#define ALCS_MSG_MAX_TOKEN_LEN (8) + +typedef enum { + + /*iotx_alcs_send Message Result And Receive Message*/ + IOTX_ALCS_EVENT_MSG_SEND_MESSAGE_SUCCESS, + IOTX_ALCS_EVENT_MSG_SEND_MESSAGE_RESP_TIMEOUT, + IOTX_ALCS_EVENT_MSG_RECV_MESSAGE, + /*Its data type is @iotx_alcs_transfer_msg_t and see detail at the declare of this type.*/ + +} iotx_alcs_event_type_t; + +typedef struct iotx_alcs_event_msg_st { + + /* Specify the event type */ + iotx_alcs_event_type_t event_type; + + void *msg; +} iotx_alcs_event_msg_t, *iotx_alcs_event_msg_pt; + +typedef struct iotx_alcs_transfer_msg_st { + char *ip; + uint16_t port; + char *uri; + uint8_t token_len; + uint8_t *token; + uint16_t payload_len; + uint8_t *payload; +} iotx_alcs_transfer_msg_t, *iotx_alcs_transfer_msg_pt; + +typedef void (*iotx_alcs_event_handle_func_fpt)(void *pcontext, void *phandle, iotx_alcs_event_msg_t *msg); + +typedef struct { + iotx_alcs_event_handle_func_fpt h_fp; + void *pcontext; +} iotx_alcs_event_handle_t; + +typedef struct iotx_alcs_param_st { + uint8_t role; /*can be client, server or both*/ + + uint8_t send_maxcount; /*list maximal count*/ + uint8_t obs_maxcount; /*observe maximal count*/ + uint16_t port; /* Local port */ + char *group; /* Multicast address */ + uint32_t waittime; + uint8_t res_maxcount; + + iotx_alcs_event_handle_t *handle_event; +} iotx_alcs_param_t, *iotx_alcs_param_pt; + +#define ITOX_ALCS_COAP_MSG_CODE_DEF(N) (((N)/100 << 5) | (N)%100) + +/*CoAP Message codes*/ +typedef enum { + /* CoAP Empty Message */ + ITOX_ALCS_COAP_MSG_CODE_EMPTY_MESSAGE = ITOX_ALCS_COAP_MSG_CODE_DEF(0), /* Mapping to CoAP code 0.00 */ + + /* CoAP Method Codes */ + ITOX_ALCS_COAP_MSG_CODE_GET = ITOX_ALCS_COAP_MSG_CODE_DEF(1), /* CoAP Get method */ + ITOX_ALCS_COAP_MSG_CODE_POST = ITOX_ALCS_COAP_MSG_CODE_DEF(2), /* CoAP Post method */ + ITOX_ALCS_COAP_MSG_CODE_PUT = ITOX_ALCS_COAP_MSG_CODE_DEF(3), /* CoAP Put method */ + ITOX_ALCS_COAP_MSG_CODE_DELETE = ITOX_ALCS_COAP_MSG_CODE_DEF(4), /* CoAP Delete method */ + + /* CoAP Success Response Codes */ + ITOX_ALCS_COAP_MSG_CODE_201_CREATED = ITOX_ALCS_COAP_MSG_CODE_DEF(201), /* Mapping to CoAP code 2.01, Hex:0x41, Created */ + ITOX_ALCS_COAP_MSG_CODE_202_DELETED = ITOX_ALCS_COAP_MSG_CODE_DEF(202), /* Mapping to CoAP code 2.02, Hex:0x42, Deleted*/ + ITOX_ALCS_COAP_MSG_CODE_203_VALID = ITOX_ALCS_COAP_MSG_CODE_DEF(203), /* Mapping to CoAP code 2.03, Hex:0x43, Valid*/ + ITOX_ALCS_COAP_MSG_CODE_204_CHANGED = ITOX_ALCS_COAP_MSG_CODE_DEF(204), /* Mapping to CoAP code 2.04, Hex:0x44, Changed*/ + ITOX_ALCS_COAP_MSG_CODE_205_CONTENT = ITOX_ALCS_COAP_MSG_CODE_DEF(205), /* Mapping to CoAP code 2.05, Hex:0x45, Content*/ + ITOX_ALCS_COAP_MSG_CODE_231_CONTINUE = ITOX_ALCS_COAP_MSG_CODE_DEF(231), /* Mapping to CoAP code 2.31, Hex:0x5F, Continue*/ + + /* CoAP Client Error Response Codes */ + ITOX_ALCS_COAP_MSG_CODE_400_BAD_REQUEST = ITOX_ALCS_COAP_MSG_CODE_DEF(400), /* Mapping to CoAP code 4.00, Hex:0x80, Bad Request */ + ITOX_ALCS_COAP_MSG_CODE_401_UNAUTHORIZED = ITOX_ALCS_COAP_MSG_CODE_DEF(401), /* Mapping to CoAP code 4.01, Hex:0x81, Unauthorized */ + ITOX_ALCS_COAP_MSG_CODE_402_BAD_OPTION = ITOX_ALCS_COAP_MSG_CODE_DEF(402), /* Mapping to CoAP code 4.02, Hex:0x82, Bad Option */ + ITOX_ALCS_COAP_MSG_CODE_403_FORBIDDEN = ITOX_ALCS_COAP_MSG_CODE_DEF(403), /* Mapping to CoAP code 4.03, Hex:0x83, Forbidden */ + ITOX_ALCS_COAP_MSG_CODE_404_NOT_FOUND = ITOX_ALCS_COAP_MSG_CODE_DEF(404), /* Mapping to CoAP code 4.04, Hex:0x84, Not Found */ + ITOX_ALCS_COAP_MSG_CODE_405_METHOD_NOT_ALLOWED = ITOX_ALCS_COAP_MSG_CODE_DEF(405), /* Mapping to CoAP code 4.05, Hex:0x85, Method Not Allowed */ + ITOX_ALCS_COAP_MSG_CODE_406_NOT_ACCEPTABLE = ITOX_ALCS_COAP_MSG_CODE_DEF(406), /* Mapping to CoAP code 4.06, Hex:0x86, Not Acceptable */ + ITOX_ALCS_COAP_MSG_CODE_408_REQUEST_ENTITY_INCOMPLETE = ITOX_ALCS_COAP_MSG_CODE_DEF(408), /* Mapping to CoAP code 4.08, Hex:0x88, Request Entity Incomplete */ + ITOX_ALCS_COAP_MSG_CODE_412_PRECONDITION_FAILED = ITOX_ALCS_COAP_MSG_CODE_DEF(412), /* Mapping to CoAP code 4.12, Hex:0x8C, Precondition Failed */ + ITOX_ALCS_COAP_MSG_CODE_413_REQUEST_ENTITY_TOO_LARGE = ITOX_ALCS_COAP_MSG_CODE_DEF(413), /* Mapping to CoAP code 4.13, Hex:0x8D, Request Entity Too Large */ + ITOX_ALCS_COAP_MSG_CODE_415_UNSUPPORTED_CONTENT_FORMAT = ITOX_ALCS_COAP_MSG_CODE_DEF(415), /* Mapping to CoAP code 4.15, Hex:0x8F, Unsupported Content-Format */ + + /* CoAP Server Error Response Codes */ + ITOX_ALCS_COAP_MSG_CODE_500_INTERNAL_SERVER_ERROR = ITOX_ALCS_COAP_MSG_CODE_DEF(500), /* Mapping to CoAP code 5.00, Hex:0xA0, Internal Server Error */ + ITOX_ALCS_COAP_MSG_CODE_501_NOT_IMPLEMENTED = ITOX_ALCS_COAP_MSG_CODE_DEF(501), /* Mapping to CoAP code 5.01, Hex:0xA1, Not Implemented */ + ITOX_ALCS_COAP_MSG_CODE_502_BAD_GATEWAY = ITOX_ALCS_COAP_MSG_CODE_DEF(502), /* Mapping to CoAP code 5.02, Hex:0xA2, Bad Gateway */ + ITOX_ALCS_COAP_MSG_CODE_503_SERVICE_UNAVAILABLE = ITOX_ALCS_COAP_MSG_CODE_DEF(503), /* Mapping to CoAP code 5.03, Hex:0xA3, Service Unavailable */ + ITOX_ALCS_COAP_MSG_CODE_504_GATEWAY_TIMEOUT = ITOX_ALCS_COAP_MSG_CODE_DEF(504), /* Mapping to CoAP code 5.04, Hex:0xA4, Gateway Timeout */ + ITOX_ALCS_COAP_MSG_CODE_505_PROXYING_NOT_SUPPORTED = ITOX_ALCS_COAP_MSG_CODE_DEF(505) /* Mapping to CoAP code 5.05, Hex:0xA5, Proxying Not Supported */ + +} iotx_alcs_message_code_t; + +typedef enum { + IOTX_ALCS_MESSAGE_TYPE_CON = 0, + IOTX_ALCS_MESSAGE_TYPE_NON = 1, + IOTX_ALCS_MESSAGE_TYPE_ACK = 2, + IOTX_ALCS_MESSAGE_TYPE_RST = 3 +} iotx_alcs_message_type_t; + +typedef enum { + IOTX_ALCS_MESSAGE_PERM_NONE = 0x0000, + IOTX_ALCS_MESSAGE_PERM_GET = 0x0001, + IOTX_ALCS_MESSAGE_PERM_POST = 0x0002, + IOTX_ALCS_MESSAGE_PERM_PUT = 0x0004, + IOTX_ALCS_MESSAGE_PERM_DEL = 0x0008, + IOTX_ALCS_MESSAGE_PERM_OBSERVE = 0x0100 +} iotx_alcs_message_perm_t; + +typedef enum { + IOTX_ALCS_MESSAGE_CT_TEXT_PLAIN = 0, /* text/plain (UTF-8) */ + IOTX_ALCS_MESSAGE_CT_APP_LINK_FORMAT = 40, /* application/link-format */ + IOTX_ALCS_MESSAGE_CT_APP_XML = 41, /* application/xml */ + IOTX_ALCS_MESSAGE_CT_APP_OCTET_STREAM = 42, /* application/octet-stream */ + IOTX_ALCS_MESSAGE_CT_APP_RDF_XML = 43, /* application/rdf+xml */ + IOTX_ALCS_MESSAGE_CT_APP_EXI = 47, /* application/exi */ + IOTX_ALCS_MESSAGE_CT_APP_JSON = 50, /* application/json */ + IOTX_ALCS_MESSAGE_CT_APP_CBOR = 60 /* application/cbor */ +} iotx_alcs_message_content_type_t; + +typedef struct iotx_alcs_msg_st { + uint16_t group_id; /*multicast group id, used as unicast when 0*/ + char *ip; /*dotted decimal notation, max len 16*/ + uint16_t port; + iotx_alcs_message_code_t msg_code; + iotx_alcs_message_type_t msg_type; + char *uri; + uint32_t payload_len; + uint8_t *payload; +} iotx_alcs_msg_t, *iotx_alcs_msg_pt; + +typedef struct iotx_alcs_res_st { + char *uri; + int32_t need_auth; + iotx_alcs_message_perm_t msg_perm; + iotx_alcs_message_content_type_t msg_ct; + uint32_t maxage; /*0~60*/ + CoAPRecvMsgHandler callback; +} iotx_alcs_res_t, *iotx_alcs_res_pt; + +/** + * @brief Construct the ALCS handle + * This function initialize the data structures, initialize ALCS information. + * + * @param [in] params: specify the ALCS initialize parameter. + * + * @retval NULL : Construct failed. + * @retval NOT_NULL : The handle of ALCS. + * @see None. + */ +void *iotx_alcs_construct(iotx_alcs_param_t *params); + +/** + * @brief Init Cloud Part + * This function initialize the cloud part. + * + * @param [in] params: specify the ALCS initialize parameter. + * + * @retval NULL : Construct failed. + * @retval NOT_NULL : The handle of ALCS. + * @see None. + */ +int iotx_alcs_cloud_init(void *handle); + +/** + * @brief Deconstruct the ALCS handle + * This function distroy ALCS handle and release the related resource. + * + * @param [in] phandle: pointer of handle, specify the MQTT client. + * + * @retval 0 : Deconstruct success. + * @retval -1 : Deconstruct failed. + * @see None. + */ +int iotx_alcs_destroy(void **phandle); + +/** + * @brief Handle ALCS message from specific udp port + * + * @param [in] handle: specify the ALCS handle. + * + * @return status. + * @see None. + */ +int iotx_alcs_yield(void *handle); + +/** + * @brief Send Message To Secific Deivce + * + * @param [in] handle: specify the ALCS handle. + * + * @return status. + * @see None. + */ +int iotx_alcs_send(void *handle, iotx_alcs_msg_t *msg); + +/** + * @brief Send Response Message To Secific Deivce + * + * @param [in] handle: specify the ALCS handle. + * + * @return status. + * @see None. + */ +int iotx_alcs_send_Response(void *handle, iotx_alcs_msg_t *msg, uint8_t token_len, uint8_t *token); + +/** + * @brief Register Resource + * + * @param [in] handle: specify the ALCS handle. + * @param [in] handle: the resource need to be registered. + * + * @return status. + * @see None. + */ +int iotx_alcs_register_resource(void *handle, iotx_alcs_res_t *resource); + +/** + * @brief ALCS Observe Notify + * + * @param [in] handle: specify the ALCS handle. + * @param [in] uri: the resource need to notify. + * + * @return status. + * @see None. + */ +int iotx_alcs_observe_notify(void *handle, const char *uri, uint32_t payload_len, uint8_t *payload); + +/** + * @brief Unregister Resource + * + * @param [in] handle: specify the ALCS handle. + * @param [in] handle: the resource need to be registered. + * + * @return status. + * @see None. + */ +int iotx_alcs_unregister_resource(void *handle, char *uri); + +/** + * @brief Add sub device + * + * @param [in] handle: specify the ALCS handle. + * @param [in] pk: the productkey of device. + * @param [in] dn: the deviceName of device. + * + * @return status. + * @see None. + */ +int iotx_alcs_add_sub_device(void *handle, const char *pk, const char *dn); + +/** + * @brief remove sub device + * + * @param [in] handle: specify the ALCS handle. + * @param [in] pk: the productkey of device. + * @param [in] dn: the deviceName of device. + * + * @return status. + * @see None. + */ +int iotx_alcs_remove_sub_device(void *handle, const char *pk, const char *dn); + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_alcs_config.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_alcs_config.h new file mode 100644 index 00000000..5294ac26 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_alcs_config.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __IOTX_ALCS_CONFIG_H__ +#define __IOTX_ALCS_CONFIG_H__ + +#if 0 +#ifndef ALCS_CLIENT_ENABLED + #define ALCS_CLIENT_ENABLED (1) +#endif +#endif + +#ifndef ALCS_SERVER_ENABLED + #define ALCS_SERVER_ENABLED (1) +#endif + +#ifndef USE_ALCS_SECURE + #define USE_ALCS_SECURE (1) +#endif + +#ifndef KEYPREFIX_LEN + #define KEYPREFIX_LEN (8) +#endif + +#ifndef GROUPID_LEN + #define GROUPID_LEN (8) +#endif + +#endif /* #ifndef __IOTX_ALCS_CONFIG_H__ */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm.c new file mode 100644 index 00000000..17e199be --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm.c @@ -0,0 +1,304 @@ +#include "iotx_cm_internal.h" + +#if defined(MQTT_COMM_ENABLED) || defined(MAL_ENABLED) +#include "iotx_cm_mqtt.h" +#endif +#ifdef COAP_COMM_ENABLED +#include "iotx_cm_coap.h" +#endif + + +static void *fd_lock = NULL; +static iotx_cm_connection_t *_cm_fd[CM_MAX_FD_NUM] = {NULL}; +static int _get_fd(iotx_cm_connection_t *handle); +static int _recycle_fd(int fd); +static int inline _fd_is_valid(int fd); +static int inited_conn_num = 0; + +#ifdef DEVICE_MODEL_GATEWAY + static void *_iotx_cm_yield_thread_func(void *params); + static void *yield_thread = NULL; + static int yield_task_leave = 1; +#endif + +const char ERR_INVALID_PARAMS[] = "invalid parameter"; +int iotx_cm_open(iotx_cm_init_param_t *params) +{ + int fd; + iotx_cm_connection_t *connection = NULL; + + switch (params->protocol_type) { + case IOTX_CM_PROTOCOL_TYPE_MQTT: +#if defined(MQTT_COMM_ENABLED) || defined(MAL_ENABLED) + connection = iotx_cm_open_mqtt(params); +#endif + break; + case IOTX_CM_PROTOCOL_TYPE_COAP: +#ifdef COAP_COMM_ENABLED + connection = iotx_cm_open_coap(params); +#endif + break; + default: + break; + } + + if (connection == NULL) { + cm_err("cm opon failed"); + return -1; + } + fd = _get_fd(connection); + if (fd < 0) { + cm_err("get fd failed"); + connection->close_func(); + return -1; + } + connection->fd = fd; + return fd; +} + +int iotx_cm_connect(int fd, uint32_t timeout) +{ + iotx_cm_connect_fp connect_func; + int ret; + + if (_fd_is_valid(fd) == -1) { + cm_err(ERR_INVALID_PARAMS); + return -1; + } + HAL_MutexLock(fd_lock); + connect_func = _cm_fd[fd]->connect_func; + HAL_MutexUnlock(fd_lock); + + iotx_event_post(IOTX_CONN_CLOUD); + + ret = connect_func(timeout); + + if (ret == 0) { + inited_conn_num++; + if (inited_conn_num == 1) { + +#ifdef DEVICE_MODEL_GATEWAY + int stack_used; + hal_os_thread_param_t task_parms = {0}; + task_parms.stack_size = 6144; + task_parms.name = "cm_yield"; + ret = HAL_ThreadCreate(&yield_thread, _iotx_cm_yield_thread_func, NULL, + &task_parms, &stack_used); + if (ret < 0) { + inited_conn_num--; + } +#endif + } + iotx_event_post(IOTX_CONN_CLOUD_SUC); + } else { + iotx_event_post(IOTX_CONN_CLOUD_FAIL); + } + + + return ret; +} + +static int _iotx_cm_yield(int fd, unsigned int timeout) +{ + iotx_cm_yield_fp yield_func; + + if (fd_lock == NULL) { + return NULL_VALUE_ERROR; + } + + if (fd == -1) { + int i; + for (i = 0; i < CM_MAX_FD_NUM; i++) { + yield_func = NULL; + HAL_MutexLock(fd_lock); + if (_cm_fd[i] != NULL) { + yield_func = _cm_fd[i]->yield_func; + } + HAL_MutexUnlock(fd_lock); + if (yield_func != NULL) { + yield_func(timeout); + } + } + return 0; + } + + if (_fd_is_valid(fd) == -1) { + cm_err(ERR_INVALID_PARAMS); + return -1; + } + + HAL_MutexLock(fd_lock); + yield_func = _cm_fd[fd]->yield_func; + HAL_MutexUnlock(fd_lock); + return yield_func(timeout); + +} +#ifdef DEVICE_MODEL_GATEWAY +static void *_iotx_cm_yield_thread_func(void *params) +{ + yield_task_leave = 0; + while (inited_conn_num > 0) { + _iotx_cm_yield(-1, CM_DEFAULT_YIELD_TIMEOUT); + } + yield_task_leave = 1; + return NULL; +} +#endif + +int iotx_cm_yield(int fd, unsigned int timeout) +{ +#ifdef DEVICE_MODEL_GATEWAY + return 0; +#else + return _iotx_cm_yield(fd, timeout); +#endif +} + + +int iotx_cm_sub(int fd, iotx_cm_ext_params_t *ext, const char *topic, + iotx_cm_data_handle_cb topic_handle_func, void *pcontext) +{ + iotx_cm_sub_fp sub_func; + + if (_fd_is_valid(fd) == -1) { + cm_err(ERR_INVALID_PARAMS); + return -1; + } + + HAL_MutexLock(fd_lock); + sub_func = _cm_fd[fd]->sub_func; + HAL_MutexUnlock(fd_lock); + return sub_func(ext, topic, topic_handle_func, pcontext); +} + +int iotx_cm_unsub(int fd, const char *topic) +{ + iotx_cm_unsub_fp unsub_func; + + if (_fd_is_valid(fd) == -1) { + cm_err(ERR_INVALID_PARAMS); + return -1; + } + + HAL_MutexLock(fd_lock); + unsub_func = _cm_fd[fd]->unsub_func; + HAL_MutexUnlock(fd_lock); + return unsub_func(topic); +} + + + +int iotx_cm_pub(int fd, iotx_cm_ext_params_t *ext, const char *topic, const char *payload, unsigned int payload_len) +{ + iotx_cm_pub_fp pub_func; + + if (_fd_is_valid(fd) == -1) { + cm_err(ERR_INVALID_PARAMS); + return -1; + } + + HAL_MutexLock(fd_lock); + pub_func = _cm_fd[fd]->pub_func; + HAL_MutexUnlock(fd_lock); + return pub_func(ext, topic, payload, payload_len); +} + +int iotx_cm_close(int fd) +{ + iotx_cm_close_fp close_func; + + if (_fd_is_valid(fd) != 0) { + cm_err(ERR_INVALID_PARAMS); + return -1; + } + + if (inited_conn_num > 0 && --inited_conn_num == 0) { +#ifdef DEVICE_MODEL_GATEWAY + while (!yield_task_leave) { + HAL_SleepMs(10); + } + HAL_ThreadDelete(yield_thread); +#endif + } + + HAL_MutexLock(fd_lock); + close_func = _cm_fd[fd]->close_func; + HAL_MutexUnlock(fd_lock); + if (close_func() != 0) { + return -1; + } + if (_recycle_fd(fd) != 0) { + return -1; + } + + if (inited_conn_num == 0) { + if (fd_lock != NULL) { + HAL_MutexDestroy(fd_lock); + fd_lock = NULL; + } + } + + return 0; +} + + +static int inline _fd_is_valid(int fd) +{ + int ret; + + if (fd_lock == NULL) { + return NULL_VALUE_ERROR; + } + + HAL_MutexLock(fd_lock); + ret = (fd >= 0 && fd < CM_MAX_FD_NUM && _cm_fd[fd] != NULL) ? 0 : -1; + HAL_MutexUnlock(fd_lock); + return ret; +} + +static int _recycle_fd(int fd) +{ + if (fd_lock == NULL) { + fd_lock = HAL_MutexCreate(); + if (fd_lock == NULL) { + return -1; + } + } + + if (fd < 0 || fd > CM_MAX_FD_NUM - 1) { + return -1; + } + + HAL_MutexLock(fd_lock); + _cm_fd[fd] = NULL; + HAL_MutexUnlock(fd_lock); + + return 0; +} + +static int _get_fd(iotx_cm_connection_t *handle) +{ + int i; + if (handle == NULL) { + return NULL_VALUE_ERROR; + } + + if (fd_lock == NULL) { + fd_lock = HAL_MutexCreate(); + if (fd_lock == NULL) { + return -1; + } + } + + HAL_MutexLock(fd_lock); + for (i = 0; i < CM_MAX_FD_NUM; i++) { + if (_cm_fd[i] == NULL) { + _cm_fd[i] = handle; + HAL_MutexUnlock(fd_lock); + return i; + } + } + HAL_MutexUnlock(fd_lock); + cm_err("cm fd reached the limit"); + return -1; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm.h new file mode 100644 index 00000000..877b1032 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef _IOTX_CM_H_ +#define _IOTX_CM_H_ + +#include "infra_types.h" + +#define CM_MAX_FD_NUM 3 +#define CM_DEFAULT_YIELD_TIMEOUT 200 +/* message confirmation type */ +typedef enum { + /* non ACK */ + /* MQTT: QoS is 0 */ + /* CoAP: NON */ + /* default */ + IOTX_CM_MESSAGE_NO_ACK, + /* need ACK */ + /* MQTT: QoS is 1 */ + /* CoAP: CON */ + IOTX_CM_MESSAGE_NEED_ACK, + /* non ACK */ + /* MQTT: QoS is 3 */ + /* CoAP: NONE*/ + IOTX_CM_MESSAGE_SUB_LOCAL, + /* Maximum number of ack type */ + IOTX_CM_MESSAGE_ACK_MAX +} iotx_cm_ack_types_t; + +/* message confirmation type */ +typedef enum { + /* non ACK */ + /* MQTT: QoS is 0 */ + /* CoAP: NON */ + /* default */ + IOTX_CM_ASYNC, + /* need ACK */ + /* MQTT: QoS is 1 */ + /* CoAP: CON */ + IOTX_CM_SYNC, + /* Maximum number of ack type */ + IOTX_CM_SYNC_MAX +} iotx_cm_sync_mode_types_t; + +/* protocol type */ +typedef enum IOTX_CM_PROTOCOL_TYPES { + /* MQTT */ + IOTX_CM_PROTOCOL_TYPE_MQTT = 1, + /* COAP */ + IOTX_CM_PROTOCOL_TYPE_COAP = 2, + /* HTTP */ + IOTX_CM_PROTOCOL_TYPE_HTTP = 3, + /* HTTP2 */ + IOTX_CM_PROTOCOL_TYPE_HTTP2 = 4, + /* Maximum number of protocol type */ + IOTX_CM_PROTOCOL_TYPE_MAX +} iotx_cm_protocol_types_t; + + +/* event type */ +typedef enum IOTX_CM_EVENT_TYPES { + /* cloud connected */ + IOTX_CM_EVENT_CLOUD_CONNECTED = 0, + /* cloud: disconnect */ + /* event_msg is null */ + IOTX_CM_EVENT_CLOUD_CONNECT_FAILED, + /* cloud: disconnect */ + /* event_msg is null */ + IOTX_CM_EVENT_CLOUD_DISCONNECT, + /* event_msg is iotx_cm_event_result_pt */ + IOTX_CM_EVENT_SUBCRIBE_SUCCESS, + IOTX_CM_EVENT_SUBCRIBE_FAILED, + IOTX_CM_EVENT_UNSUB_SUCCESS, + IOTX_CM_EVENT_UNSUB_FAILED, + IOTX_CM_EVENT_PUBLISH_SUCCESS, + IOTX_CM_EVENT_PUBLISH_FAILED, + /* Maximum number of event */ + IOTX_CM_EVENT_MAX +} iotx_cm_event_types_t; + +/* The structure of cloud Connection event struct */ +typedef struct { + iotx_cm_event_types_t type; + void *msg; +} iotx_cm_event_msg_t; + +typedef struct { + char *topic; + uint8_t *payload; + uint32_t payload_len; +} event_msg_data_t; + +#ifdef DEVICE_MODEL_ALINK2 +typedef void (*iotx_cm_data_handle_cb)(int fd, const char *topic, uint32_t topic_len, const char *payload, unsigned int payload_len, void *context); +#else +typedef void (*iotx_cm_data_handle_cb)(int fd, const char *topic, const char *payload, unsigned int payload_len, + void *context); +#endif + +typedef void (*iotx_cm_event_handle_cb)(int fd, iotx_cm_event_msg_t *event, void *context); + + +/* IoTx initializa parameters */ +typedef struct { + uint32_t request_timeout_ms; + uint32_t keepalive_interval_ms; + uint32_t write_buf_size; + uint32_t read_buf_size; + iotx_cm_protocol_types_t protocol_type; + iotx_cm_event_handle_cb handle_event; /* Specify MQTT event handle */ + void *context; +#ifdef DEVICE_MODEL_ALINK2 + iotx_dev_meta_info_t *dev_info; + iotx_mqtt_region_types_t region; +#endif +} iotx_cm_init_param_t; + +typedef struct { + iotx_cm_ack_types_t ack_type; + iotx_cm_sync_mode_types_t sync_mode; + uint32_t sync_timeout; + iotx_cm_data_handle_cb ack_cb; + void *cb_context; +} iotx_cm_ext_params_t; + +int iotx_cm_open(iotx_cm_init_param_t *params); +int iotx_cm_connect(int fd, uint32_t timeout); +int iotx_cm_yield(int fd, unsigned int timeout); +int iotx_cm_sub(int fd, iotx_cm_ext_params_t *ext, const char *topic, + iotx_cm_data_handle_cb topic_handle_func, void *pcontext); +int iotx_cm_unsub(int fd, const char *topic); +int iotx_cm_pub(int fd, iotx_cm_ext_params_t *ext, const char *topic, const char *payload, unsigned int payload_len); +int iotx_cm_close(int fd); +#endif /* _LINKKIT_CM_H_ */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_coap.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_coap.c new file mode 100644 index 00000000..10a24665 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_coap.c @@ -0,0 +1,408 @@ +#include "iotx_cm_internal.h" + +#ifdef COAP_COMM_ENABLED +#include "iotx_cm.h" +#include "iotx_cm_coap.h" +#include "infra_timer.h" + +#ifdef COAP_DTLS_SUPPORT /* DTLS */ + #ifdef ON_DAILY + #define IOTX_COAP_SERVER_URI "coaps://11.239.164.238:5684" + #else + #ifdef ON_PRE + #define IOTX_COAP_SERVER_URI "coaps://pre.coap.cn-shanghai.link.aliyuncs.com:5684" + + #else /* online */ + #define IOTX_COAP_SERVER_URI "coaps://%s.coap.cn-shanghai.link.aliyuncs.com:5684" + #endif + #endif + +#else + #ifdef COAP_PSK_SUPPORT /* PSK */ + #ifdef ON_DAILY + #define IOTX_COAP_SERVER_URI "coap-psk://10.101.83.159:5682" + #else + #ifdef ON_PRE + #define IOTX_COAP_SERVER_URI "coap-psk://pre.coap.cn-shanghai.link.aliyuncs.com:5682" + #else /* online */ + #define IOTX_COAP_SERVER_URI "coap-psk://%s.coap.cn-shanghai.link.aliyuncs.com:5682" + #endif + #endif + #else /* UDP */ + #ifdef ON_DAILY + #define IOTX_COAP_SERVER_URI "" + #else + #ifdef ON_PRE + #define IOTX_COAP_SERVER_URI "coap://pre.iot-as-coap.cn-shanghai.aliyuncs.com:5683" + #else /* online */ + #define IOTX_COAP_SERVER_URI "coap://%s.coap.cn-shanghai.link.aliyuncs.com:5683" + #endif + #endif + + #endif +#endif + +extern uint32_t IOT_CoAP_GetCurToken(iotx_coap_context_t *p_context); +int IOT_CoAP_GetMessageToken(void *p_message, unsigned int *token); +static struct list_head g_coap_response_list = LIST_HEAD_INIT(g_coap_response_list); + +static iotx_cm_connection_t *_coap_conncection = NULL; +static int iotx_set_devinfo(iotx_device_info_t *p_devinfo); + +static int _coap_connect(uint32_t timeout); +static int _coap_publish(iotx_cm_ext_params_t *params, const char *topic, const char *payload, + unsigned int payload_len); +static int _coap_sub(iotx_cm_ext_params_t *params, const char *topic, + iotx_cm_data_handle_cb topic_handle_func, void *pcontext); +static iotx_msg_type_t _get_coap_qos(iotx_cm_ack_types_t ack_type); +static int _coap_unsub(const char *topic); +static int _coap_close(); +static void _set_common_handlers(); + +iotx_cm_connection_t *iotx_cm_open_coap(iotx_cm_init_param_t *params) +{ + iotx_coap_config_t *coap_config = NULL; + iotx_device_info_t *deviceinfo = NULL; + + if (_coap_conncection != NULL) { + cm_warning("mqtt connection is opened already,return it"); + return _coap_conncection; + } + + _coap_conncection = (iotx_cm_connection_t *)cm_malloc(sizeof(iotx_cm_connection_t)); + if (_coap_conncection == NULL) { + cm_err("_coap_conncection malloc failed!"); + goto failed; + } + + _coap_conncection->list_lock = HAL_MutexCreate(); + if (_coap_conncection->list_lock == NULL) { + cm_err("list_lock create failed!"); + goto failed; + } + + coap_config = (iotx_coap_config_t *)cm_malloc(sizeof(iotx_coap_config_t)); + if (coap_config == NULL) { + cm_err("coap_config malloc failed!"); + goto failed; + } + memset(coap_config, 0, sizeof(iotx_coap_config_t)); + deviceinfo = (iotx_device_info_t *)cm_malloc(sizeof(iotx_device_info_t)); + if (deviceinfo == NULL) { + cm_err("deviceinfo malloc failed!"); + goto failed; + } + + _coap_conncection->open_params = coap_config; + + memset(deviceinfo, 0, sizeof(iotx_device_info_t)); + + iotx_set_devinfo(deviceinfo); + coap_config->wait_time_ms = params->request_timeout_ms; + coap_config->p_devinfo = deviceinfo; + /* coap_config->p_url = IOTX_COAP_SERVER_URI; */ + + _coap_conncection->event_handler = params->handle_event; + + _set_common_handlers(); + + return _coap_conncection; + +failed: + if (_coap_conncection != NULL) { + if (_coap_conncection->list_lock != NULL) { + HAL_MutexDestroy(_coap_conncection->list_lock); + } + cm_free(_coap_conncection); + _coap_conncection = NULL; + } + + if (coap_config != NULL) { + cm_free(coap_config); + } + if (deviceinfo != NULL) { + cm_free(deviceinfo); + } + + return NULL; +} + +static int iotx_set_devinfo(iotx_device_info_t *p_devinfo) +{ + if (NULL == p_devinfo) { + return IOTX_ERR_INVALID_PARAM; + } + + memset(p_devinfo, 0x00, sizeof(iotx_device_info_t)); + + /**< get device info*/ + HAL_GetProductKey(p_devinfo->product_key); + HAL_GetDeviceName(p_devinfo->device_name); + HAL_GetDeviceSecret(p_devinfo->device_secret); + HAL_Snprintf(p_devinfo->device_id, IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 2, "%s.%s", p_devinfo->product_key, p_devinfo->device_name); + p_devinfo->device_id[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 1] = '\0'; + /**< end*/ + cm_info("*****The Product Key : %s *****\r\n", p_devinfo->product_key); + cm_info("*****The Device Name : %s *****\r\n", p_devinfo->device_name); + cm_info("*****The Device Secret: %s *****\r\n", p_devinfo->device_secret); + cm_info("*****The Device ID : %s *****\r\n", p_devinfo->device_id); + return IOTX_SUCCESS; +} + +static int _coap_connect(uint32_t timeout) +{ + int ret; + char url[100] = {0}; + iotx_time_t timer; + iotx_coap_config_t *config = NULL; + iotx_coap_context_t *p_ctx = NULL; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + + if (_coap_conncection == NULL) { + return NULL_VALUE_ERROR; + } + + HAL_GetProductKey(product_key); + config = _coap_conncection->open_params; + if (config == NULL) { + return NULL_VALUE_ERROR; + } + + HAL_Snprintf(url, 100, IOTX_COAP_SERVER_URI, product_key); + config->p_url = url; + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, timeout); + do { + if (p_ctx == NULL) { + p_ctx = IOT_CoAP_Init(config); + if (NULL == p_ctx) { + continue; + } + } + ret = IOT_CoAP_DeviceNameAuth(p_ctx); + if (ret == 0) { + iotx_cm_event_msg_t event; + event.type = IOTX_CM_EVENT_CLOUD_CONNECTED; + event.msg = NULL; + _coap_conncection->context = p_ctx; + + if (_coap_conncection->event_handler) { + _coap_conncection->event_handler(_coap_conncection->fd, &event, (void *)_coap_conncection); + } + return 0; + } + } while (!utils_time_is_expired(&timer)); + + { + iotx_cm_event_msg_t event; + event.type = IOTX_CM_EVENT_CLOUD_CONNECT_FAILED; + event.msg = NULL; + + if (_coap_conncection->event_handler) { + _coap_conncection->event_handler(_coap_conncection->fd, &event, (void *)_coap_conncection); + } + } + cm_err("mqtt connect failed"); + return -1; +} + +static void _coap_response_default(void *p_arg, void *p_message) +{ + int ret; + int len = 0; + unsigned char *p_payload = NULL; + unsigned int token; + iotx_coap_resp_code_t resp_code; + coap_response_node_t *node = NULL; + coap_response_node_t *next = NULL; + + if (_coap_conncection == NULL || p_message == NULL) { + cm_err("paras err"); + return; + } + + ret = IOT_CoAP_GetMessageCode(p_message, &resp_code); + if (ret < 0) { + cm_err("get msg code err"); + return; + } + + cm_info("resp_code = %d", resp_code); + + ret = IOT_CoAP_GetMessagePayload(p_message, &p_payload, &len); + if (ret < 0) { + cm_err("get msg payload err"); + return; + } + + ret = IOT_CoAP_GetMessageToken(p_message, &token); + if (ret < 0) { + cm_err("get msg token err"); + return; + } + + HAL_MutexLock(_coap_conncection->list_lock); + list_for_each_entry_safe(node, next, &g_coap_response_list, linked_list, coap_response_node_t) { + if (node->token_num == token) { + iotx_cm_data_handle_cb recieve_cb = node->responce_cb; + void *context = node->context; + unsigned int topic_len = strlen(node->topic) + 1; + char *topic = cm_malloc(topic_len); + if (topic == NULL) { + cm_err("topic malloc failed"); + continue; + } + memset(topic, 0, topic_len); + strncpy(topic, node->topic, topic_len); + list_del(&node->linked_list); + cm_free(node->topic); + cm_free(node); + HAL_MutexUnlock(_coap_conncection->list_lock); /* do not lock while callback */ + + recieve_cb(_coap_conncection->fd, topic, (const char *)p_payload, len, context); + /* recieve_cb(_coap_conncection->fd, &msg, context); */ + cm_free(topic); + HAL_MutexLock(_coap_conncection->list_lock); + } + } + HAL_MutexUnlock(_coap_conncection->list_lock); +} + + +static int _coap_publish(iotx_cm_ext_params_t *ext, const char *topic, const char *payload, unsigned int payload_len) +{ + iotx_msg_type_t qos = 0; + iotx_message_t message; + uint32_t token; + int topic_len; + int ret; + + if (_coap_conncection == NULL) { + return NULL_VALUE_ERROR; + } + + if (ext != NULL) { + qos = _get_coap_qos(ext->ack_type); + } + memset(&message, 0, sizeof(iotx_message_t)); + + message.p_payload = (unsigned char *)payload; + message.payload_len = payload_len; + message.resp_callback = _coap_response_default; + message.msg_type = qos; + message.content_type = IOTX_CONTENT_TYPE_JSON; + + token = IOT_CoAP_GetCurToken((iotx_coap_context_t *)_coap_conncection->context); + ret = IOT_CoAP_SendMessage((iotx_coap_context_t *)_coap_conncection->context, (char *)topic, &message); + + if (ret < 0) { + return -1; + } + + if (ext != NULL && ext->ack_cb != NULL) { + coap_response_node_t *node; + node = (coap_response_node_t *)cm_malloc(sizeof(coap_response_node_t)); + if (node == NULL) { + return -1; + } + memset(node, 0, sizeof(coap_response_node_t)); + topic_len = strlen(topic) + 1; + node->topic = (char *)cm_malloc(topic_len); + if (node->topic == NULL) { + cm_free(node); + return -1; + } + + memset(node->topic, 0, topic_len); + strncpy(node->topic, topic, topic_len); + + node->user_data = _coap_conncection; + node->responce_cb = ext->ack_cb; + node->context = ext->cb_context; + node->token_num = token; + + HAL_MutexLock(_coap_conncection->list_lock); + list_add_tail(&node->linked_list, &g_coap_response_list); + HAL_MutexUnlock(_coap_conncection->list_lock); + } + return 0; +} + +static int _coap_yield(uint32_t timeout) +{ + if (_coap_conncection == NULL) { + return NULL_VALUE_ERROR; + } + return IOT_CoAP_Yield((iotx_coap_context_t *)_coap_conncection->context); +} + +static int _coap_sub(iotx_cm_ext_params_t *ext, const char *topic, + iotx_cm_data_handle_cb topic_handle_func, void *pcontext) +{ + return 0; +} + +static int _coap_unsub(const char *topic) +{ + return 0; +} + +static int _coap_close() +{ + coap_response_node_t *node = NULL; + coap_response_node_t *next = NULL; + iotx_coap_config_t *coap_config = NULL; + + if (_coap_conncection == NULL) { + return NULL_VALUE_ERROR; + } + + coap_config = (iotx_coap_config_t *)_coap_conncection->open_params; + + HAL_MutexLock(_coap_conncection->list_lock); + list_for_each_entry_safe(node, next, &g_coap_response_list, linked_list, coap_response_node_t) { + cm_free(node->topic); + list_del(&node->linked_list); + cm_free(node); + } + HAL_MutexUnlock(_coap_conncection->list_lock); + + if (_coap_conncection->list_lock != NULL) { + HAL_MutexDestroy(_coap_conncection->list_lock); + } + cm_free(coap_config->p_devinfo); + cm_free(coap_config); + IOT_CoAP_Deinit(&_coap_conncection->context); + + cm_free(_coap_conncection); + _coap_conncection = NULL; + return 0; +} + +static iotx_msg_type_t _get_coap_qos(iotx_cm_ack_types_t ack_type) +{ + switch (ack_type) { + case IOTX_CM_MESSAGE_NO_ACK: + return IOTX_MESSAGE_NON; + + case IOTX_CM_MESSAGE_NEED_ACK: + return IOTX_MESSAGE_CON; + + default: + return IOTX_MESSAGE_CON; + } +} + +static void _set_common_handlers() +{ + if (_coap_conncection != NULL) { + _coap_conncection->connect_func = _coap_connect; + _coap_conncection->sub_func = _coap_sub; + _coap_conncection->unsub_func = _coap_unsub; + _coap_conncection->pub_func = _coap_publish; + _coap_conncection->yield_func = _coap_yield; + _coap_conncection->close_func = _coap_close; + } +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_coap.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_coap.h new file mode 100644 index 00000000..9d664b3c --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_coap.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _IOTX_CM_COAP_H_ +#define _IOTX_CM_COAP_H_ +#include "iotx_cm.h" +#include "iotx_cm_internal.h" +#include "coap_api.h" + + +typedef struct { + uint32_t token_num; + void *user_data; + char *topic; + iotx_cm_data_handle_cb responce_cb; + void *context; + dlist_t linked_list; +} coap_response_node_t; + +iotx_cm_connection_t *iotx_cm_open_coap(iotx_cm_init_param_t *params); + +#endif /* _LINKKIT_CM_H_ */ + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_internal.h new file mode 100644 index 00000000..ca9fccd3 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_internal.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef _IOTX_CM_INTERNAL_H_ +#define _IOTX_CM_INTERNAL_H_ + +#include + +#include "infra_config.h" +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_list.h" +#include "infra_compat.h" +#include "infra_timer.h" + +#include "dm_wrapper.h" +#include "mqtt_api.h" + +#include "iotx_cm.h" + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define cm_malloc(size) LITE_malloc(size, MEM_MAGIC, "cm") + #define cm_free(ptr) LITE_free(ptr) +#else + #define cm_malloc(size) HAL_Malloc(size) + #define cm_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#ifdef INFRA_LOG + #include "infra_log.h" + #define cm_debug(...) log_debug("CM", __VA_ARGS__) + #define cm_info(...) log_info("CM", __VA_ARGS__) + #define cm_warning(...) log_warning("CM", __VA_ARGS__) + #define cm_err(...) log_err("CM", __VA_ARGS__) +#else + #define cm_debug(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define cm_info(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define cm_warning(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define cm_err(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#endif + +typedef int (*iotx_cm_connect_fp)(uint32_t timeout); +typedef int (*iotx_cm_yield_fp)(unsigned int timeout); +typedef int (*iotx_cm_sub_fp)(iotx_cm_ext_params_t *params, const char *topic, + iotx_cm_data_handle_cb topic_handle_func, void *pcontext); +typedef int (*iotx_cm_unsub_fp)(const char *topic); +typedef int (*iotx_cm_pub_fp)(iotx_cm_ext_params_t *params, const char *topic, const char *payload, + unsigned int payload_len); +typedef int (*iotx_cm_close_fp)(); + + +typedef struct iotx_connection_st { + int fd; + void *open_params; + void *context; + void *list_lock; + iotx_cm_protocol_types_t protocol_type; + iotx_cm_connect_fp connect_func; + iotx_cm_sub_fp sub_func; + iotx_cm_unsub_fp unsub_func; + iotx_cm_pub_fp pub_func; + iotx_cm_yield_fp yield_func; + iotx_cm_close_fp close_func; + iotx_cm_event_handle_cb event_handler; + void *cb_data; + +} iotx_cm_connection_t; + +#include "iotx_cm_mqtt.h" + +extern const char ERR_INVALID_PARAMS[]; +#endif /* _LINKKIT_CM_H_ */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_mqtt.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_mqtt.c new file mode 100644 index 00000000..6ae59f05 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_mqtt.c @@ -0,0 +1,404 @@ +#include "iotx_cm_internal.h" + +#if defined(MQTT_COMM_ENABLED) || defined(MAL_ENABLED) + +static iotx_cm_connection_t *_mqtt_conncection = NULL; +static void iotx_cloud_conn_mqtt_event_handle(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg); +static int _mqtt_connect(uint32_t timeout); +static int _mqtt_publish(iotx_cm_ext_params_t *params, const char *topic, const char *payload, + unsigned int payload_len); +static int _mqtt_sub(iotx_cm_ext_params_t *params, const char *topic, + iotx_cm_data_handle_cb topic_handle_func, void *pcontext); +static iotx_mqtt_qos_t _get_mqtt_qos(iotx_cm_ack_types_t ack_type); +static int _mqtt_unsub(const char *topic); +static int _mqtt_close(); +static void _set_common_handlers(); + +iotx_cm_connection_t *iotx_cm_open_mqtt(iotx_cm_init_param_t *params) +{ + iotx_mqtt_param_t *mqtt_param = NULL; + + if (_mqtt_conncection != NULL) { + cm_warning("mqtt connection is opened already,return it"); + return _mqtt_conncection; + } + + _mqtt_conncection = (iotx_cm_connection_t *)cm_malloc(sizeof(iotx_cm_connection_t)); + if (_mqtt_conncection == NULL) { + cm_err("_mqtt_conncection malloc failed!"); + goto failed; + } + + mqtt_param = (iotx_mqtt_param_t *)cm_malloc(sizeof(iotx_mqtt_param_t)); + if (mqtt_param == NULL) { + cm_err("mqtt_param malloc failed!"); + goto failed; + } + _mqtt_conncection->open_params = mqtt_param; + + mqtt_param->request_timeout_ms = params->request_timeout_ms; + mqtt_param->clean_session = 0; + mqtt_param->keepalive_interval_ms = params->keepalive_interval_ms; + mqtt_param->read_buf_size = params->read_buf_size; + mqtt_param->write_buf_size = params->write_buf_size; + + mqtt_param->handle_event.h_fp = iotx_cloud_conn_mqtt_event_handle; + mqtt_param->handle_event.pcontext = NULL; + + _mqtt_conncection->event_handler = params->handle_event; + _mqtt_conncection->cb_data = params->context; + _set_common_handlers(); + + return _mqtt_conncection; + +failed: + + if (_mqtt_conncection != NULL) { + cm_free(_mqtt_conncection); + _mqtt_conncection = NULL; + } + + if (mqtt_param != NULL) { + cm_free(mqtt_param); + } + + return NULL; +} + + +static void iotx_cloud_conn_mqtt_event_handle(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg) +{ + uintptr_t packet_id = (uintptr_t)msg->msg; + if (_mqtt_conncection == NULL) { + return; + } + + switch (msg->event_type) { + + case IOTX_MQTT_EVENT_DISCONNECT: { + iotx_cm_event_msg_t event; + cm_info("disconnected,fd = %d", _mqtt_conncection->fd); + event.type = IOTX_CM_EVENT_CLOUD_DISCONNECT; + event.msg = NULL; + if (_mqtt_conncection->event_handler) { + _mqtt_conncection->event_handler(_mqtt_conncection->fd, &event, _mqtt_conncection->cb_data); + } + } + break; + + case IOTX_MQTT_EVENT_RECONNECT: { + iotx_cm_event_msg_t event; + cm_info("connected,fd = %d", _mqtt_conncection->fd); + event.type = IOTX_CM_EVENT_CLOUD_CONNECTED; + event.msg = NULL; + /* cm_info(cm_log_info_MQTT_reconnect); */ + + if (_mqtt_conncection->event_handler) { + _mqtt_conncection->event_handler(_mqtt_conncection->fd, &event, _mqtt_conncection->cb_data); + } + } + break; + + case IOTX_MQTT_EVENT_SUBCRIBE_SUCCESS: { + iotx_cm_event_msg_t event; + event.type = IOTX_CM_EVENT_SUBCRIBE_SUCCESS; + event.msg = (void *)packet_id; + + if (_mqtt_conncection->event_handler) { + _mqtt_conncection->event_handler(_mqtt_conncection->fd, &event, _mqtt_conncection->cb_data); + } + } + break; + + case IOTX_MQTT_EVENT_SUBCRIBE_NACK: + case IOTX_MQTT_EVENT_SUBCRIBE_TIMEOUT: { + iotx_cm_event_msg_t event; + event.type = IOTX_CM_EVENT_SUBCRIBE_FAILED; + event.msg = (void *)packet_id; + + if (_mqtt_conncection->event_handler) { + _mqtt_conncection->event_handler(_mqtt_conncection->fd, &event, _mqtt_conncection->cb_data); + } + } + break; + + case IOTX_MQTT_EVENT_UNSUBCRIBE_SUCCESS: { + iotx_cm_event_msg_t event; + event.type = IOTX_CM_EVENT_UNSUB_SUCCESS; + event.msg = (void *)packet_id; + + if (_mqtt_conncection->event_handler) { + _mqtt_conncection->event_handler(_mqtt_conncection->fd, &event, _mqtt_conncection->cb_data); + } + } + break; + + case IOTX_MQTT_EVENT_UNSUBCRIBE_NACK: + case IOTX_MQTT_EVENT_UNSUBCRIBE_TIMEOUT: { + iotx_cm_event_msg_t event; + event.type = IOTX_CM_EVENT_UNSUB_FAILED; + event.msg = (void *)packet_id; + + if (_mqtt_conncection->event_handler) { + _mqtt_conncection->event_handler(_mqtt_conncection->fd, &event, _mqtt_conncection->cb_data); + } + } + break; + + case IOTX_MQTT_EVENT_PUBLISH_SUCCESS: { + iotx_cm_event_msg_t event; + event.type = IOTX_CM_EVENT_PUBLISH_SUCCESS; + event.msg = (void *)packet_id; + + if (_mqtt_conncection->event_handler) { + _mqtt_conncection->event_handler(_mqtt_conncection->fd, &event, _mqtt_conncection->cb_data); + } + } + break; + + case IOTX_MQTT_EVENT_PUBLISH_NACK: + case IOTX_MQTT_EVENT_PUBLISH_TIMEOUT: { + iotx_cm_event_msg_t event; + event.type = IOTX_CM_EVENT_PUBLISH_FAILED; + event.msg = (void *)packet_id; + + if (_mqtt_conncection->event_handler) { + _mqtt_conncection->event_handler(_mqtt_conncection->fd, &event, _mqtt_conncection->cb_data); + } + } + break; + + case IOTX_MQTT_EVENT_PUBLISH_RECEIVED: { + iotx_mqtt_topic_info_pt topic_info = (iotx_mqtt_topic_info_pt)msg->msg; + iotx_cm_data_handle_cb topic_handle_func = (iotx_cm_data_handle_cb)pcontext; +#ifndef DEVICE_MODEL_ALINK2 + char *topic = NULL; +#endif + if (topic_handle_func == NULL) { + cm_warning("bypass %d bytes on [%.*s]", topic_info->payload_len, topic_info->topic_len, topic_info->ptopic); + return; + } +#ifdef DEVICE_MODEL_ALINK2 + topic_handle_func(_mqtt_conncection->fd, topic_info->ptopic, topic_info->topic_len, topic_info->payload, + topic_info->payload_len, NULL); +#else + topic = cm_malloc(topic_info->topic_len + 1); + if (topic == NULL) { + cm_err("topic malloc failed"); + return; + } + memset(topic, 0, topic_info->topic_len + 1); + memcpy(topic, topic_info->ptopic, topic_info->topic_len); + + topic_handle_func(_mqtt_conncection->fd, topic, topic_info->payload, topic_info->payload_len, NULL); + + cm_free(topic); +#endif + } + break; + + case IOTX_MQTT_EVENT_BUFFER_OVERFLOW: + cm_warning("buffer overflow", msg->msg); + break; + + default: + cm_warning("msg type unkown, type = %d", msg->event_type); + break; + } +} + + +static int _mqtt_connect(uint32_t timeout) +{ + void *pclient; + iotx_time_t timer; + iotx_mqtt_param_t *mqtt_param = NULL; + iotx_conn_info_pt pconn_info = NULL; + iotx_cm_event_msg_t event; + + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1] = {0}; + + if (_mqtt_conncection == NULL) { + return NULL_VALUE_ERROR; + } + + mqtt_param = _mqtt_conncection->open_params; + + HAL_GetProductKey(product_key); + HAL_GetDeviceName(device_name); + HAL_GetDeviceSecret(device_secret); + + if (strlen(product_key) == 0 || strlen(device_name) == 0) { + return FAIL_RETURN; + } + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, timeout); + /* Device AUTH */ + do { + if (0 == IOT_SetupConnInfo(product_key, device_name, device_secret, (void **)&pconn_info)) { + mqtt_param->port = pconn_info->port; + mqtt_param->host = pconn_info->host_name; + mqtt_param->client_id = pconn_info->client_id; + mqtt_param->username = pconn_info->username; + mqtt_param->password = pconn_info->password; + mqtt_param->pub_key = pconn_info->pub_key; + break; + } + cm_err("IOT_SetupConnInfo failed"); + HAL_SleepMs(500); + } while (!utils_time_is_expired(&timer)); + + do { + pclient = IOT_MQTT_Construct((iotx_mqtt_param_t *)_mqtt_conncection->open_params); + if (pclient != NULL) { + iotx_cm_event_msg_t event; + _mqtt_conncection->context = pclient; + event.type = IOTX_CM_EVENT_CLOUD_CONNECTED; + event.msg = NULL; + + if (_mqtt_conncection->event_handler) { + _mqtt_conncection->event_handler(_mqtt_conncection->fd, &event, (void *)_mqtt_conncection); + } + return 0; + } + HAL_SleepMs(500); + } while (!utils_time_is_expired(&timer)); + + event.type = IOTX_CM_EVENT_CLOUD_CONNECT_FAILED; + event.msg = NULL; + + if (_mqtt_conncection->event_handler) { + _mqtt_conncection->event_handler(_mqtt_conncection->fd, &event, (void *)_mqtt_conncection); + } + cm_err("mqtt connect failed"); + return -1; +} + +static int _mqtt_publish(iotx_cm_ext_params_t *ext, const char *topic, const char *payload, unsigned int payload_len) +{ + int qos = 0; + + if (_mqtt_conncection == NULL) { + return NULL_VALUE_ERROR; + } + + if (ext != NULL) { + qos = (int)_get_mqtt_qos(ext->ack_type); + } + return IOT_MQTT_Publish_Simple(_mqtt_conncection->context, topic, qos, (void *)payload, payload_len); +} + +static int _mqtt_yield(uint32_t timeout) +{ + if (_mqtt_conncection == NULL) { + return NULL_VALUE_ERROR; + } + + return IOT_MQTT_Yield(_mqtt_conncection->context, timeout); +} + +static int _mqtt_sub(iotx_cm_ext_params_t *ext, const char *topic, + iotx_cm_data_handle_cb topic_handle_func, void *pcontext) +{ + + int sync = 0; + int qos = 0; + int timeout = 0; + int ret; + + if (_mqtt_conncection == NULL || topic == NULL || topic_handle_func == NULL) { + return NULL_VALUE_ERROR; + } + + if (ext != NULL) { + if (ext->sync_mode == IOTX_CM_ASYNC) { + sync = 0; + } else { + sync = 1; + timeout = ext->sync_timeout; + } + qos = (int)_get_mqtt_qos(ext->ack_type); + } + + if (sync != 0) { + ret = IOT_MQTT_Subscribe_Sync(_mqtt_conncection->context, + topic, + qos, + iotx_cloud_conn_mqtt_event_handle, + (void *)topic_handle_func, + timeout); + } else { + ret = IOT_MQTT_Subscribe(_mqtt_conncection->context, + topic, + qos, + iotx_cloud_conn_mqtt_event_handle, + (void *)topic_handle_func); + } + + return ret; +} + +static int _mqtt_unsub(const char *topic) +{ + int ret; + + if (_mqtt_conncection == NULL) { + return NULL_VALUE_ERROR; + } + + ret = IOT_MQTT_Unsubscribe(_mqtt_conncection->context, topic); + + if (ret < 0) { + return -1; + } + + return ret; +} + +static int _mqtt_close() +{ + if (_mqtt_conncection == NULL) { + return NULL_VALUE_ERROR; + } + + cm_free(_mqtt_conncection->open_params); + IOT_MQTT_Destroy(&_mqtt_conncection->context); + cm_free(_mqtt_conncection); + _mqtt_conncection = NULL; + return 0; +} + +static iotx_mqtt_qos_t _get_mqtt_qos(iotx_cm_ack_types_t ack_type) +{ + switch (ack_type) { + case IOTX_CM_MESSAGE_NO_ACK: + return IOTX_MQTT_QOS0; + + case IOTX_CM_MESSAGE_NEED_ACK: + return IOTX_MQTT_QOS1; + + case IOTX_CM_MESSAGE_SUB_LOCAL: + return IOTX_MQTT_QOS3_SUB_LOCAL; + + default: + return IOTX_MQTT_QOS0; + } +} + + +static void _set_common_handlers() +{ + if (_mqtt_conncection != NULL) { + _mqtt_conncection->connect_func = _mqtt_connect; + _mqtt_conncection->sub_func = _mqtt_sub; + _mqtt_conncection->unsub_func = _mqtt_unsub; + _mqtt_conncection->pub_func = _mqtt_publish; + _mqtt_conncection->yield_func = (iotx_cm_yield_fp)_mqtt_yield; + _mqtt_conncection->close_func = _mqtt_close; + } +} + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_mqtt.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_mqtt.h new file mode 100644 index 00000000..90b42890 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_cm_mqtt.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef _IOTX_CM_MQTT_H_ +#define _IOTX_CM_MQTT_H_ + +#include "iotx_cm.h" +#include "iotx_cm_internal.h" + + +typedef struct { + uintptr_t packet_id; + char * topic; + void * user_data; + iotx_mqtt_event_handle_func_fpt sub_state_cb; + iotx_cm_data_handle_cb sub_recieve_cb; + dlist_t linked_list; +} mqtt_sub_node_t; + +iotx_cm_connection_t *iotx_cm_open_mqtt(iotx_cm_init_param_t *params); + + +#endif /* _LINKKIT_CM_H_ */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_dm.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_dm.h new file mode 100644 index 00000000..b9b7929e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_dm.h @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _IOT_EXPORT_DM_H_ +#define _IOT_EXPORT_DM_H_ + +#ifndef _IN_ + #define _IN_ +#endif + +#ifndef _OU_ + #define _OU_ +#endif + +#ifdef DEVICE_MODEL_GATEWAY + #define IOTX_DM_DEVICE_TYPE IOTX_DM_DEVICE_GATEWAY +#else + #define IOTX_DM_DEVICE_TYPE IOTX_DM_DEVICE_SINGLE +#endif + +#define IOTX_DM_LOCAL_NODE_DEVID (0) + +#define IOTX_DM_DEVICE_SINGLE (0x01) +#define IOTX_DM_DEVICE_SUBDEV (0x02) +#define IOTX_DM_DEVICE_GATEWAY (0x04) +#define IOTX_DM_DEVICE_MAIN (IOTX_DM_DEVICE_SINGLE|IOTX_DM_DEVICE_GATEWAY) +#define IOTX_DM_DEVICE_ALL (IOTX_DM_DEVICE_SINGLE|IOTX_DM_DEVICE_SUBDEV|IOTX_DM_DEVICE_GATEWAY) + +/* Service Type 0~7bit: type, 8~15bit: extended*/ +#define IOTX_DM_SERVICE_CLOUD (0x0001) +#define IOTX_DM_SERVICE_LOCAL (0x0002) +#define IOTX_DM_SERVICE_LOCAL_NO_AUTH (0x0000) +#define IOTX_DM_SERVICE_LOCAL_AUTH (0x0100) + +#define IOTX_DM_LOCAL_AUTH (IOTX_DM_SERVICE_LOCAL|IOTX_DM_SERVICE_LOCAL_AUTH) +#define IOTX_DM_LOCAL_NO_AUTH (IOTX_DM_SERVICE_LOCAL|IOTX_DM_SERVICE_LOCAL_NO_AUTH) + +#define IOTX_DM_SERVICE_ALL (IOTX_DM_SERVICE_CLOUD|IOTX_DM_LOCAL_AUTH) + +typedef enum { + IOTX_DM_ERR_CODE_SUCCESS = 200, + IOTX_DM_ERR_CODE_REQUEST_ERROR = 400, + IOTX_DM_ERR_CODE_REQUEST_PARAMS_ERROR = 460, + IOTX_DM_ERR_CODE_REQUEST_TOO_MANY = 429, + IOTX_DM_ERR_CODE_NO_ACTIVE_SESSION = 520, + IOTX_DM_ERR_CODE_TIMEOUT = 100000 +} iotx_dm_error_code_t; + +typedef enum { + IOTX_DM_EVENT_CLOUD_CONNECTED = 0, + IOTX_DM_EVENT_CLOUD_DISCONNECT, + IOTX_DM_EVENT_CLOUD_RECONNECT, + IOTX_DM_EVENT_LOCAL_CONNECTED, + IOTX_DM_EVENT_LOCAL_DISCONNECT, + IOTX_DM_EVENT_LOCAL_RECONNECT, + IOTX_DM_EVENT_FOUND_DEVICE, + IOTX_DM_EVENT_REMOVE_DEVICE, + IOTX_DM_EVENT_REGISTER_RESULT, + IOTX_DM_EVENT_UNREGISTER_RESULT, + IOTX_DM_EVENT_INITIALIZED, + IOTX_DM_EVENT_SEND_RESULT, + IOTX_DM_EVENT_ADD_SERVICE_RESULT, + IOTX_DM_EVENT_REMOVE_SERVICE_RESULT, + IOTX_DM_EVENT_NEW_DATA_RECEIVED, + IOTX_DM_EVENT_PROPERTY_SET, + IOTX_DM_EVENT_PROPERTY_GET, + IOTX_DM_EVENT_PROPERTY_DESIRED_GET_REPLY, + IOTX_DM_EVENT_PROPERTY_DESIRED_DELETE_REPLY, + IOTX_DM_EVENT_TOPO_ADD_NOTIFY, + IOTX_DM_EVENT_THING_SERVICE_REQUEST, + IOTX_DM_EVENT_THING_DISABLE, + IOTX_DM_EVENT_THING_ENABLE, + IOTX_DM_EVENT_THING_DELETE, + IOTX_DM_EVENT_MODEL_DOWN_RAW, + IOTX_DM_EVENT_GATEWAY_PERMIT, + IOTX_DM_EVENT_SUBDEV_REGISTER_REPLY, + IOTX_DM_EVENT_SUBDEV_UNREGISTER_REPLY, + IOTX_DM_EVENT_TOPO_ADD_REPLY, + IOTX_DM_EVENT_TOPO_DELETE_REPLY, + IOTX_DM_EVENT_TOPO_GET_REPLY, + IOTX_DM_EVENT_TOPO_ADD_NOTIFY_REPLY, + IOTX_DM_EVENT_EVENT_PROPERTY_POST_REPLY, + IOTX_DM_EVENT_EVENT_SPECIFIC_POST_REPLY, + IOTX_DM_EVENT_DEVICEINFO_UPDATE_REPLY, + IOTX_DM_EVENT_DEVICEINFO_DELETE_REPLY, + IOTX_DM_EVENT_DSLTEMPLATE_GET_REPLY, + IOTX_DM_EVENT_COMBINE_LOGIN_REPLY, + IOTX_DM_EVENT_COMBINE_LOGOUT_REPLY, + IOTX_DM_EVENT_MODEL_UP_RAW_REPLY, + IOTX_DM_EVENT_LEGACY_THING_CREATED, + IOTX_DM_EVENT_COTA_NEW_CONFIG, + IOTX_DM_EVENT_FOTA_NEW_FIRMWARE, + IOTX_DM_EVENT_NTP_RESPONSE, + IOTX_DM_EVENT_RRPC_REQUEST, + IOTX_DM_EVENT_MAX +} iotx_dm_event_types_t; + +typedef void (*iotx_dm_event_callback)(iotx_dm_event_types_t type, char *payload); + +typedef enum { + IOTX_DM_DEVICE_SECRET_PRODUCT, + IOTX_DM_DEVICE_SECRET_DEVICE, + IOTX_DM_DEVICE_SECRET_TYPES_MAX +} iotx_dm_device_secret_types_t; + +typedef enum { + IOTX_DM_CLOUD_DOMAIN_SHANGHAI, + IOTX_DM_CLOUD_DOMAIN_SINGAPORE, + IOTX_DM_CLOUD_DOMAIN_JAPAN, + IOTX_DM_CLOUD_DOMAIN_AMERICA, + IOTX_DM_CLOUD_DOMAIN_GERMANY, + IOTX_DM_CLOUD_DOMAIN_MAX +} iotx_dm_cloud_domain_types_t; + +typedef enum { + IOTX_DM_MESSAGE_NO_AUTH, + IOTX_DM_MESSAGE_AUTH, + IOTX_DM_MESSAGE_AUTH_MAX +} iotx_dm_message_auth_types_t; + +typedef enum { + IOTX_DM_TSL_SOURCE_LOCAL, + IOTX_DM_TSL_SOURCE_CLOUD +} iotx_dm_tsl_source_t; + +typedef enum { + IOTX_DM_TSL_TYPE_ALINK, + IOTX_DM_TSL_TYPE_TLV +} iotx_dm_tsl_type_t; + +typedef struct { + iotx_dm_device_secret_types_t secret_type; + iotx_dm_cloud_domain_types_t domain_type; + iotx_dm_event_callback event_callback; +} iotx_dm_init_params_t; + +typedef enum { + IOTX_DM_DEV_AVAIL_ENABLE, + IOTX_DM_DEV_AVAIL_DISABLE +} iotx_dm_dev_avail_t; + +typedef enum { + IOTX_DM_DEV_STATUS_UNAUTHORIZED, /* Subdev Created */ + IOTX_DM_DEV_STATUS_AUTHORIZED, /* Receive Topo Add Notify */ + IOTX_DM_DEV_STATUS_REGISTERED, /* Receive Subdev Registered */ + IOTX_DM_DEV_STATUS_ATTACHED, /* Receive Subdev Topo Add Reply */ + IOTX_DM_DEV_STATUS_LOGINED, /* Receive Subdev Login Reply */ + IOTX_DM_DEV_STATUS_ONLINE /* After All Topic Subscribed */ +} iotx_dm_dev_status_t; + +typedef enum { + DM_TSL_SERVICE_GET_FAILED = -13, + DM_TSL_SERVICE_SET_FAILED = -12, + DM_TSL_EVENT_GET_FAILED = -11, + DM_TSL_EVENT_SET_FAILED = -10, + DM_TSL_PROPERTY_GET_FAILED = -9, + DM_TSL_PROPERTY_SET_FAILED = -8, + DM_TSL_EVENT_NOT_EXIST = -7, + DM_TSL_PROPERTY_NOT_EXIST = -6, + DM_TSL_SERVICE_NOT_EXIST = -5, + DM_JSON_PARSE_FAILED = -4, + DM_MEMORY_NOT_ENOUGH = -3, + DM_INVALID_PARAMETER = -2 +} dm_error_code_t; + +#define IOTX_DM_POST_PROPERTY_ALL (NULL) + +int iotx_dm_open(void); +int iotx_dm_connect(_IN_ iotx_dm_init_params_t *init_params); +int iotx_dm_subscribe(_IN_ int devid); +int iotx_dm_close(void); +int iotx_dm_yield(int timeout_ms); +void iotx_dm_dispatch(void); + +int iotx_dm_post_rawdata(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); + +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) +int iotx_dm_set_opt(int opt, void *data); +int iotx_dm_get_opt(int opt, void *data); +#ifdef LOG_REPORT_TO_CLOUD + int iotx_dm_log_post(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); +#endif +int iotx_dm_post_property(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); +int iotx_dm_property_desired_get(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); +int iotx_dm_property_desired_delete(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); +int iotx_dm_post_event(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len, _IN_ char *payload, + _IN_ int payload_len); + +int iotx_dm_send_service_response(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, _IN_ iotx_dm_error_code_t code, + _IN_ char *identifier, + _IN_ int identifier_len, _IN_ char *payload, _IN_ int payload_len, void *ctx); +int iotx_dm_send_property_get_response(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, + _IN_ iotx_dm_error_code_t code, + _IN_ char *payload, _IN_ int payload_len, _IN_ void *ctx); +int iotx_dm_send_rrpc_response(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len, _IN_ iotx_dm_error_code_t code, + _IN_ char *rrpcid, _IN_ int rrpcid_len, _IN_ char *payload, _IN_ int payload_len); +int iotx_dm_deviceinfo_update(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); +int iotx_dm_deviceinfo_delete(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len); +int iotx_dm_qurey_ntp(void); +int iotx_dm_send_aos_active(int devid); +#endif + +int iotx_dm_cota_perform_sync(_OU_ char *buffer, _IN_ int buffer_len); +int iotx_dm_cota_get_config(_IN_ const char *config_scope, const char *get_type, const char *attribute_keys); +int iotx_dm_fota_perform_sync(_OU_ char *buffer, _IN_ int buffer_len); +int iotx_dm_fota_request_image(_IN_ const char *version, _IN_ int buffer_len); + +#ifdef DEVICE_MODEL_GATEWAY +int iotx_dm_query_topo_list(void); +int iotx_dm_subdev_create(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], + _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1], _OU_ int *devid); +int iotx_dm_subdev_destroy(_IN_ int devid); +int iotx_dm_subdev_number(void); +int iotx_dm_subdev_register(_IN_ int devid); +int iotx_dm_subdev_unregister(_IN_ int devid); +int iotx_dm_subdev_topo_add(_IN_ int devid); +int iotx_dm_subdev_topo_del(_IN_ int devid); +int iotx_dm_subdev_login(_IN_ int devid); +int iotx_dm_subdev_logout(_IN_ int devid); +int iotx_dm_get_device_type(_IN_ int devid, _OU_ int *type); +int iotx_dm_get_device_avail_status(_IN_ int devid, _OU_ iotx_dm_dev_avail_t *status); +int iotx_dm_get_device_status(_IN_ int devid, _OU_ iotx_dm_dev_status_t *status); +#ifdef DEVICE_MODEL_SUBDEV_OTA + int iotx_dm_send_firmware_version(int devid, const char *firmware_version); + int iotx_dm_ota_switch_device(_IN_ int devid); +#endif +#endif + +#ifdef DEPRECATED_LINKKIT +int iotx_dm_deprecated_subdev_register(_IN_ int devid, _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1]); +int iotx_dm_deprecated_set_tsl(_IN_ int devid, _IN_ iotx_dm_tsl_source_t source, _IN_ const char *tsl, + _IN_ int tsl_len); +int iotx_dm_deprecated_set_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len); +int iotx_dm_deprecated_get_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value); +int iotx_dm_deprecated_set_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len); +int iotx_dm_deprecated_get_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value); +int iotx_dm_deprecated_get_service_input_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value); +int iotx_dm_deprecated_set_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ int value_len); +int iotx_dm_deprecated_get_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value); + +int iotx_dm_deprecated_post_property_start(_IN_ int devid, _OU_ void **handle); +int iotx_dm_deprecated_post_property_add(_IN_ void *handle, _IN_ char *identifier, _IN_ int identifier_len); +int iotx_dm_deprecated_post_property_end(_IN_ void **handle); +int iotx_dm_deprecated_post_event(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len); +int iotx_dm_deprecated_send_service_response(_IN_ int devid, _IN_ int msgid, _IN_ iotx_dm_error_code_t code, + _IN_ char *identifier, + _IN_ int identifier_len); + +int iotx_dm_deprecated_legacy_set_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ char *value_str); +int iotx_dm_deprecated_legacy_get_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ char **value_str); +int iotx_dm_deprecated_legacy_set_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ char *value_str); +int iotx_dm_deprecated_legacy_get_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value, + _IN_ char **value_str); +int iotx_dm_deprecated_legacy_get_service_input_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, + _IN_ void *value, + _IN_ char **value_str); +int iotx_dm_deprecated_legacy_set_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, + _IN_ void *value, + _IN_ char *value_str); +int iotx_dm_deprecated_legacy_get_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, + _IN_ void *value, + _IN_ char **value_str); + +int iotx_dm_deprecated_legacy_get_pkdn_by_devid(_IN_ int devid, _OU_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _OU_ char device_name[IOTX_DEVICE_NAME_LEN + 1]); +int iotx_dm_deprecated_legacy_get_devid_by_pkdn(_IN_ char product_key[IOTX_PRODUCT_KEY_LEN + 1], + _IN_ char device_name[IOTX_DEVICE_NAME_LEN + 1], _OU_ int *devid); +int iotx_dm_deprecated_legacy_get_thingid_by_devid(_IN_ int devid, _OU_ void **thing_id); +int iotx_dm_deprecated_legacy_get_devid_by_thingid(_IN_ void *thing_id, _OU_ int *devid); +int iotx_dm_deprecated_legacy_get_pkdn_ptr_by_devid(_IN_ int devid, _OU_ char **product_key, _OU_ char **device_name); +int iotx_dm_deprecated_legacy_send_service_response(_IN_ int devid, _IN_ int msgid, _IN_ iotx_dm_error_code_t code, + _IN_ char *identifier, _IN_ int identifier_len, _IN_ char *payload, _IN_ int payload_len); +#ifdef DEVICE_MODEL_GATEWAY + int iotx_dm_deprecated_subdev_register(_IN_ int devid, _IN_ char device_secret[IOTX_DEVICE_SECRET_LEN + 1]); +#endif +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_dm_config.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_dm_config.h new file mode 100644 index 00000000..7920fa5f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_dm_config.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef _IOTX_DM_CONFIG_H_ +#define _IOTX_DM_CONFIG_H_ + +#define IOTX_DM_CLIENT_CONNECT_TIMEOUT_MS (10000) +#define IOTX_DM_CLIENT_SUB_RETRY_MAX_COUNTS (3) +#define IOTX_DM_CLIENT_SUB_TIMEOUT_MS (5000) +#define IOTX_DM_CLIENT_REQUEST_TIMEOUT_MS (2000) +#define IOTX_DM_CLIENT_KEEPALIVE_INTERVAL_MS (30000) + +#ifndef CONFIG_MQTT_TX_MAXLEN + #define CONFIG_MQTT_TX_MAXLEN (1024) +#endif + +#ifndef CONFIG_MQTT_RX_MAXLEN + #define CONFIG_MQTT_RX_MAXLEN (1024) +#endif + +#ifndef CONFIG_DISPATCH_QUEUE_MAXLEN + #define CONFIG_DISPATCH_QUEUE_MAXLEN (50) +#endif + +#ifndef CONFIG_DISPATCH_PACKET_MAXCOUNT + #define CONFIG_DISPATCH_PACKET_MAXCOUNT (0) +#endif + +#ifndef CONFIG_MSGCACHE_QUEUE_MAXLEN + #define CONFIG_MSGCACHE_QUEUE_MAXLEN (50) +#endif + +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_dm_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_dm_internal.h new file mode 100644 index 00000000..310e0127 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_dm_internal.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _IOTX_DM_INTERNAL_H_ +#define _IOTX_DM_INTERNAL_H_ + +#include +#include +#include + +#include "infra_config.h" +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_list.h" +#include "infra_cjson.h" +#include "infra_report.h" +#include "infra_string.h" +#if defined(DEVICE_MODEL_GATEWAY) + #include "infra_sha1.h" +#endif + + +#ifndef _IN_ + #define _IN_ +#endif + +#ifndef _OU_ + #define _OU_ +#endif + +#ifndef DM_READ_ONLY + #define DM_READ_ONLY +#endif + +#define _BSD_SOURCE + +#include + +#if defined(OTA_ENABLED) && !defined(BUILD_AOS) + #include "iotx_ota.h" + #include "ota_api.h" +#endif + +/* CM Header File */ +#include "iotx_cm.h" + +/* ALCS Header File */ +#ifdef ALCS_ENABLED + #include "CoAPExport.h" + #include "iotx_alcs.h" +#endif + +/* DM Header File */ +#include "dm_wrapper.h" +#include "iotx_dm_config.h" +#include "iotx_dm.h" +#include "dm_utils.h" +#include "dm_shadow.h" +#include "dm_tsl_alink.h" +#include "dm_message_cache.h" +#include "dm_opt.h" +#include "dm_ota.h" +#include "dm_cota.h" +#include "dm_fota.h" +#include "dm_ipc.h" +#include "dm_message.h" +#include "dm_msg_process.h" +#include "dm_manager.h" +#include "dm_client_adapter.h" +#include "dm_client.h" +#include "dm_server_adapter.h" +#include "dm_server.h" +#include "dm_intf.h" + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define DM_malloc(size) LITE_malloc(size, MEM_MAGIC, "dm") + #define DM_free(ptr) LITE_free(ptr) +#else + #define DM_malloc(size) HAL_Malloc(size) + #define DM_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#if defined(COAP_COMM_ENABLED) && !defined(MQTT_COMM_ENABLED) + #define DM_URI_OFFSET 1 +#else + #define DM_URI_OFFSET 0 +#endif + +#ifdef INFRA_LOG + #include "infra_log.h" + #define dm_log_emerg(...) log_emerg("DM", __VA_ARGS__) + #define dm_log_crit(...) log_crit("DM", __VA_ARGS__) + #define dm_log_err(...) log_err("DM", __VA_ARGS__) + #define dm_log_warning(...) log_warning("DM", __VA_ARGS__) + #define dm_log_info(...) log_info("DM", __VA_ARGS__) + #define dm_log_debug(...) log_debug("DM", __VA_ARGS__) +#else + #define dm_log_emerg(...) + #define dm_log_crit(...) + #define dm_log_err(...) + #define dm_log_warning(...) + #define dm_log_info(...) + #define dm_log_debug(...) + #define HEXDUMP_INFO(...) + #define HEXDUMP_DEBUG(...) +#endif + +#ifdef LOG_REPORT_TO_CLOUD +#define LOG_POLL_SIZE (CONFIG_MQTT_TX_MAXLEN - 174) +#define REPORT_LEN (LOG_POLL_SIZE - 110) +#define OVERFLOW_LEN (LOG_POLL_SIZE - 10) + +typedef enum { + READY, + RUNNING, + DONE +} REPORT_STATE; +unsigned int add_tail(); +int reset_log_poll(); +int remove_log_poll(); +unsigned int push_log(const char *perform_data, int perform_data_size); +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_log_report.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_log_report.h new file mode 100644 index 00000000..dde32ee1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/iotx_log_report.h @@ -0,0 +1,3 @@ +void get_msgid(char *payload, int is_cloud); +int check_target_msg(const char *input, int len); +void send_permance_info(char *input, int input_len, char *comments, int report_format); diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/linkkit_export.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/linkkit_export.h new file mode 100644 index 00000000..0ce5b83a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/linkkit_export.h @@ -0,0 +1,370 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef LINKKIT_EXPORT_H +#define LINKKIT_EXPORT_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +typedef void (*handle_post_cb_fp_t)(const void *thing_id, int respons_id, int code, const char *response_message, + void *ctx); +typedef void (*handle_subdev_cb_fp_t)(const void *thing_id, int code, const char *response_message, int success, + void *ctx); + +typedef struct _linkkit_ops { +#ifdef LOCAL_CONN_ENABLE + int (*on_connect)(void *ctx, int cloud); /* true: cloud connection; false: local connection */ + int (*on_disconnect)(void *ctx, int cloud); /* true: cloud connection; false: local connection */ +#else + int (*on_connect)(void *ctx); /* true: cloud connection; false: local connection */ + int (*on_disconnect)(void *ctx); /* true: cloud connection; false: local connection */ +#endif + int (*raw_data_arrived)(const void *thing_id, const void *data, int len, void *ctx); + int (*thing_create)(const void *thing_id, void *ctx); + int (*thing_enable)(const void *thing_id, void *ctx); + int (*thing_disable)(const void *thing_id, void *ctx); + int (*thing_call_service)(const void *thing_id, const char *service, int request_id, void *ctx); + int (*thing_prop_changed)(const void *thing_id, const char *property, void *ctx); + int (*linkit_data_arrived)(const void *thing_id, const void *data, int len, void *ctx); +} linkkit_ops_t; + +typedef enum _linkkit_loglevel { + linkkit_loglevel_emerg = 0, + linkkit_loglevel_crit, + linkkit_loglevel_error, + linkkit_loglevel_warning, + linkkit_loglevel_info, + linkkit_loglevel_debug, +} linkkit_loglevel_t; + +/* domain type */ +/* please sync with dm_cloud_domain_type_t */ +typedef enum { + /* shanghai */ + linkkit_cloud_domain_shanghai, + /* singapore */ + linkkit_cloud_domain_singapore, + /* japan */ + linkkit_cloud_domain_japan, + /* america */ + linkkit_cloud_domain_america, + /* germany */ + linkkit_cloud_domain_germany, + + linkkit_cloud_domain_max, +} linkkit_cloud_domain_type_t; + +/* device info related operation */ +typedef enum { + linkkit_extended_info_operate_update, + linkkit_extended_info_operate_delete, + + linkkit_deviceinfo_operate_max, +} linkkit_extended_info_operate_t; + +/** + * @brief dispatch message of queue for further process. + * + * @return void* + */ +DLL_IOT_API void *linkkit_dispatch(void); + +typedef enum { + linkkit_opt_property_post_reply, /* data type: int */ + linkkit_opt_event_post_reply, /* data type: int */ + linkkit_opt_property_set_reply /* data type: int */ +} linkkit_opt_t; + +/** + * @brief get leave signal. + * + * + * @return int,0 no leave signal, 1 get a leave signal + */ +DLL_IOT_API int being_deprecated linkkit_is_try_leave(); + +/** + * @brief start linkkit routines, and install callback funstions(async type for cloud connecting). + * + * @param opt, specify the option need to be set. + * @param data, specify the option value. + * + * @return int, 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_set_opt(linkkit_opt_t opt, void *data); + +/** + * @brief start linkkit routines, and install callback funstions(async type for cloud connecting). + * + * @param max_buffered_msg, specify max buffered message size. + * @param ops, callback function struct to be installed. + * @param get_tsl_from_cloud, config if device need to get tsl from cloud(!0) or local(0), if local selected, must invoke linkkit_set_tsl to tell tsl to dm after start complete. + * @param log_level, config log level. + * @param user_context, user context pointer. + * @param domain_type, specify the could server domain. + * + * @return int, 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_start(int max_buffered_msg, int get_tsl_from_cloud, + linkkit_loglevel_t log_level, + linkkit_ops_t *ops, + linkkit_cloud_domain_type_t domain_type, void *user_context); + +/** + * @brief stop linkkit routines. + * + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_end(void); + +/** + * @brief install user tsl. + * + * @param tsl, tsl string that contains json description for thing object. + * @param tsl_len, tsl string length. + * + * @return pointer to thing object, NULL when fails. + */ +DLL_IOT_API void *linkkit_set_tsl(const char *tsl, int tsl_len); + +/* patterns: */ +/* method: + * set_property_/event_output_/service_output_value: + * method_set, thing_id, identifier, value */ + +typedef enum { + linkkit_method_set_property_value = 0, + linkkit_method_set_event_output_value, + linkkit_method_set_service_output_value, + + linkkit_method_set_number, +} linkkit_method_set_t; + +/** + * @brief set value to property, event output, service output items. + * if identifier is struct type or service output type or event output type, use '.' as delimeter like "identifier1.ientifier2" + * to point to specific item. + * value and value_str could not be NULL at the same time; + * if value and value_str both as not NULL, value shall be used and value_str will be ignored. + * if value is NULL, value_str not NULL, value_str will be used. + * in brief, value will be used if not NULL, value_str will be used only if value is NULL. + * + * @param method_set, specify set value type. + * @param thing_id, pointer to thing object, specify which thing to set. + * @param identifier, property, event output, service output identifier. + * @param value. The value to be set, data type decided by data type of property as follows: + * int: int*, float: float*, double: double*, + * text: char*, enum: int*, date: char*, bool: int* + * + * @param value_str, value to set in string format if value is null. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_set_value(linkkit_method_set_t method_set, const void *thing_id, + const char *identifier, + const void *value, const char *value_str); + +typedef enum { + linkkit_method_get_property_value = 0, + linkkit_method_get_event_output_value, + linkkit_method_get_service_input_value, + linkkit_method_get_service_output_value, + + linkkit_method_get_number, +} linkkit_method_get_t; + +/** + * @brief get value from property, event output, service input/output items. + * if identifier is struct type or service input/output type or event output type, use '.' as delimeter like "identifier1.ientifier2" + * to point to specific item. + * value and value_str could not be NULL at the same time; + * if value and value_str both as not NULL, value shall be used and value_str will be ignored. + * if value is NULL, value_str not NULL, value_str will be used. + * in brief, value will be used if not NULL, value_str will be used only if value is NULL. + * @param method_get, specify get value type. + * @param thing_id, pointer to thing object, specify which thing to get. + * @param identifier, property, event output, service input/output identifier. + * @param value. The variable to store value, data type decided by data type of property as follows: + * int: int*, float: float*, double: double*, + * text: char**, enum: int*, date: char**, bool: int* + * + * @param value_str, value to get in string format. If success, memory of *value_str will be allocated, + * user should free the memory. + * + * @warning if data type is text or date, *value well be end with '\0'. + * the memory allocated to *value must be free by user. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_get_value(linkkit_method_get_t method_get, const void *thing_id, + const char *identifier, + void *value, char **value_str); + + +/** + * @brief answer to a service when a service requested by cloud. + * + * @param thing_id, pointer to thing object. + * @param service_identifier, service identifier to answer, user should get this identifier from handle_dm_callback_fp_t type callback + * report that "dm_callback_type_service_requested" happened, use this function to generate response to the service sender. + * @param response_id, id value in response payload. its value is from "dm_callback_type_service_requested" type callback function. + * use the same id as the request to send response as the same communication session. + * @param code, code value in response payload. for example, 200 when service successfully executed, 400 when not successfully executed. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_answer_service(const void *thing_id, const char *service_identifier, + int response_id, int code); + +/** + * @brief answer a down raw service when a raw service requested by cloud, or invoke a up raw service to cloud. + * + * @param thing_id, pointer to thing object. + * @param is_up_raw, specify up raw(not 0) or down raw reply(0). + * @param raw_data, raw data that sent to cloud. + * @param raw_data_length, raw data length that sent to cloud. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_invoke_raw_service(const void *thing_id, int is_up_raw, void *raw_data, + int raw_data_length); + +/** + * @brief trigger extended info update procedure. + * + * @param thing_id, pointer to thing object. + * @param params, json type string that user to send to cloud. + * @param linkkit_extended_info_operation, specify update type or delete type. + * + * @return 0 when success, -1 when fail. + */ + +DLL_IOT_API int being_deprecated linkkit_trigger_extended_info_operate(const void *thing_id, const char *params, + linkkit_extended_info_operate_t linkkit_extended_info_operation); + +/** + * @brief trigger a event to post to cloud. + * + * @param thing_id, pointer to thing object. + * @param event_identifier, event identifier to trigger. + * @param cb, callback function of event post. + * + * @return >=0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_trigger_event(const void *thing_id, const char *event_identifier, + handle_post_cb_fp_t cb); + +/** + * @brief post property to cloud. + * + * @param thing_id, pointer to thing object. + * @param property_identifier, used when trigger event with method "event.property.post", if set, post specified property, if NULL, post all. + * @param cb, callback function of property post. + * + * @return >=0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_post_property(const void *thing_id, const char *property_identifier, + handle_post_cb_fp_t cb); + +/** + * @brief this function used to yield when want to receive or send data. + * if multi-thread enabled, user should NOT call this function. + * + * @param timeout_ms, timeout value in ms. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_yield(int timeout_ms); + +typedef enum { + service_cota_callback_type_new_version_detected = 10, + + service_cota_callback_type_number, +} service_cota_callback_type_t; + +typedef void (*handle_service_cota_callback_fp_t)(service_cota_callback_type_t callback_type, const char *configid, + uint32_t configsize, + const char *gettype, + const char *sign, + const char *signmethod, + const char *cota_url); + +/** + * @brief this function used to register callback for config ota. + * + * @param callback_fp, user callback which register to cota. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_cota_init(handle_service_cota_callback_fp_t callback_fp); + +/** + * @brief this function used to execute cota process. + * + * @param data_buf, data buf that used to do ota. ota service will use this buffer to download bin. + * @param data_buf_length, data buf length that used to do ota. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_invoke_cota_service(void *data_buf, int data_buf_length); + +/** + * @brief this function used to trigger cota process. + * + * @param config_scope, remote config scope, should be "product". + * @param get_type, remote config file type, should be "file". + * @param attribute_Keys, reserved. + * @param option, reserved. + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_invoke_cota_get_config(const char *config_scope, const char *get_type, + const char *attribute_Keys, void *option); + +typedef enum { + service_fota_callback_type_new_version_detected = 10, + + service_fota_callback_type_number, +} service_fota_callback_type_t; + +typedef void (*handle_service_fota_callback_fp_t)(service_fota_callback_type_t callback_type, const char *version); + +/** + * @brief this function used to register callback for firmware ota. + * + * @param callback_fp, user callback which register to fota. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_fota_init(handle_service_fota_callback_fp_t callback_fp); + +/** + * @brief this function used to execute fota process. + * + * @param data_buf, data buf that used to do ota. ota service will use this buffer to download bin. + * @param data_buf_length, data buf length that used to do ota. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_invoke_fota_service(void *data_buf, int data_buf_length); + +/** + * @brief this function used to get NTP time from cloud. + * + * @param ntp_reply_cb, user callback which register to ntp request. + * when cloud returns ntp reply, sdk would trigger the callback function + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int being_deprecated linkkit_ntp_time_request(void (*ntp_reply_cb)(const char *ntp_offset_time_ms)); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LINKKIT_EXPORT_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/linkkit_gateway_export.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/linkkit_gateway_export.h new file mode 100644 index 00000000..f60d9a9d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_model/linkkit_gateway_export.h @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef LINKKIT_GATEWAY_EXPORT_H +#define LINKKIT_GATEWAY_EXPORT_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef _WIN32 +#ifdef DLL_IOT_EXPORTS +#define DLL_IOT_API __declspec(dllexport) +#else +#define DLL_IOT_API __declspec(dllimport) +#endif +#else +#define DLL_IOT_API +#endif + +#if defined (__CC_ARM) +#define ssize_t int +#elif defined (__ICCARM__) +#define ssize_t int +#endif + +/***************************Gateway Interface***************************/ + +enum { + LINKKIT_EVENT_CLOUD_DISCONNECTED = 0, /* cloud disconnected */ + LINKKIT_EVENT_CLOUD_CONNECTED = 1, /* cloud connected */ + LINKKIT_EVENT_SUBDEV_DELETED = 2, /* subdev deleted */ + LINKKIT_EVENT_SUBDEV_PERMITED = 3, /* subdev permit join */ + LINKKIT_EVENT_SUBDEV_SETUP = 4, /* subdev install */ +}; + +/* + * option | default | minimum | maximum + *--------------------------------|---------|---------|--------- + * LINKKIT_OPT_MAX_MSG_SIZE | 20480 | 512 | 51200 + * LINKKIT_OPT_MAX_MSG_QUEUE_SIZE | 16 | 2 | 32 + * LINKKIT_OPT_THREAD_POOL_SIZE | 4 | 1 | 16 + * LINKKIT_OPT_THREAD_STACK_SIZE | 8192 | 1024 | 8388608 + * LINKKIT_OPT_LOG_LEVEL | 3 | 0 | 5 + */ + +enum { + LINKKIT_OPT_MAX_MSG_SIZE = 1, + LINKKIT_OPT_MAX_MSG_QUEUE_SIZE = 2, + LINKKIT_OPT_THREAD_POOL_SIZE = 3, + LINKKIT_OPT_THREAD_STACK_SIZE = 4, + LINKKIT_OPT_PROPERTY_POST_REPLY = 5, /* data type: int */ + LINKKIT_OPT_EVENT_POST_REPLY = 6, /* data type: int */ + LINKKIT_OPT_PROPERTY_SET_REPLY = 7 /* data type: int */ +}; + +typedef struct { + int event_type; /* see LINKKIT_EVENT_XXX for more details */ + + union { + struct { + char *productKey; + char *deviceName; + } subdev_deleted; + + struct { + char *productKey; + int timeoutSec; + } subdev_permited; + + struct { + char *subdevList; /* json format:[{"productKey":"","deviceName":""},...] */ + } subdev_install; + } event_data; +} linkkit_event_t; + +typedef struct linkkit_params_s { + int maxMsgSize; /* max message size */ + int maxMsgQueueSize; /* max message queue size */ + + int threadPoolSize; /* number threads in pool */ + int threadStackSize; /* default thread stack size */ + + int (*event_cb)(linkkit_event_t *ev, void *ctx); + + /* user private data */ + void *ctx; +} linkkit_params_t; + +/** + * @brief get default initialize parameters + * + * @return linkkit default parameters. + */ +linkkit_params_t *linkkit_gateway_get_default_params(void); + +/** + * @brief set option in paremeters + * + * @param params, linkkit initialize parameters, return from linkkit_gateway_get_default_params(). + * @param option, see LINKKIT_OPT_XXX for more detail. + * @param value, value of option. + * @param value_len, value length. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_setopt(linkkit_params_t *params, int option, void *value, int value_len); + +/** + * @brief set event callback + * + * @param params, linkkit initialize parameters, return from linkkit_gateway_get_default_params(). + * @param event_cb, event callback. + * @param ctx, user private data. + * + * @return 0 when success, < 0 when fail. + */ +DLL_IOT_API int linkkit_gateway_set_event_callback(linkkit_params_t *params, int (*event_cb)(linkkit_event_t *ev, + void *ctx), + void *ctx); + +/** + * @brief linkkit initialization. + * + * @param initParams, linkkit initialize parameters, see linkkit_params_t for more detail. + * + * @return 0 when success, < 0 when fail. + */ +DLL_IOT_API int linkkit_gateway_init(linkkit_params_t *initParams); + +/** + * @brief linkkit deinitialization. + * + * @return 0 when success, < 0 when fail. + */ +DLL_IOT_API int linkkit_gateway_exit(void); + +typedef struct { + + int (*register_complete)(void *ctx); + /** + * @brief get property callback. + * + * @param in, properties to be get, in JSON array format, terminated by NULL. + * @param out, output buffer fill by user, in json format, terminated by NULL. + * @param out_len, out buffer length. + * @param ctx, user private data passed by linkkit_gateway_start() or linkkit_gateway_subdev_create() + * + * @return 0 when success, -1 when fail. + */ + int (*get_property)(char *in, char *out, int out_len, void *ctx); + + /** + * @brief set property callback. + * + * @param in, properties to be set, in JSON object format, terminated by NULL. + * @param ctx, user private data passed by linkkit_gateway_start() or linkkit_gateway_subdev_create() + * + * @return 0 when success, -1 when fail. + */ + int (*set_property)(char *in, void *ctx); + + /** + * @brief call service callback. + * + * @param identifier, service identifier, available services define in TSL file. + * @param in, service input data, in JSON object format, terminated by NULL. + * @param out, service output, this buffer will be filled by user, in json format, terminated by NULL. + * @param out_len, out buffer length. + * @param ctx, user private data passed by linkkit_gateway_start() or linkkit_gateway_subdev_create(). + * + * @return 0 when success, -1 when fail. + */ + int (*call_service)(char *identifier, char *in, char *out, int out_len, void *ctx); + + /** + * @brief raw data from cloud. + * + * @param in, input data from cloud. + * @param in_len, input data length. + * @param out, output data to cloud, allocated by linkkit fill by user, no need to be free. + * @param out_len, out buffer length. + * @param ctx, user private data passed by linkkit_gateway_start() or linkkit_gateway_subdev_create(). + * + * @return output data size. < 0 when fail. + */ + int (*down_rawdata)(const void *in, int in_len, void *out, int out_len, void *ctx); + + /** + * @brief return data from cloud when calling linkkit_gateway_post_rawdata(). + * + * @param data, return raw data from cloud. + * @param len, data length. + * @param ctx, user private data passed by linkkit_gateway_start() or linkkit_gateway_subdev_create(). + * + * @return 0 when success, -1 when fail. + */ + int (*post_rawdata_reply)(const void *data, int len, void *ctx); +} linkkit_cbs_t; + +/** + * @brief start linkkit gateway routines and install callback funstions. + * + * @param cbs, callback function struct to be installed. + * @param ctx, user context pointer. + * + * @return device id, 0 > when success, < 0 when fail. + */ +DLL_IOT_API int linkkit_gateway_start(linkkit_cbs_t *cbs, void *ctx); + +/** + * @brief stop linkkit gateway. + + * @param devid, device id return from linkkit_gateway_start(). + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_stop(int devid); + +/** + * @brief register subdev to gateway. + + * @param productKey, subdev's product key. + * @param deviceName, subdev's device name. + * @param deviceSecret, subdev's device secret. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_subdev_register(char *productKey, char *deviceName, char *deviceSecret); + +/** + * @brief deregister subdev from gateway. + + * @param productKey, subdev's product key. + * @param deviceName, subdev's device name. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_subdev_unregister(char *productKey, char *deviceName); + +/** + * @brief create subdev and install callback funstions. + * + * @param productKey, subdev's product key. + * @param deviceName, subdev's device name. + * @param cbs, callback function struct to be installed. + * @param ctx, user context pointer. + * + * @return device id, 0 > when success, < 0 when fail. + */ +DLL_IOT_API int linkkit_gateway_subdev_create(char *productKey, char *deviceName, linkkit_cbs_t *cbs, void *ctx); + +/** + * @brief destroy subdev by device id. + + * @param devid, device id return from linkkit_gateway_subdev_create(). + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_subdev_destroy(int devid); + +/** + * @brief make subdev accessible from cloud. + + * @param devid, device id return from linkkit_gateway_subdev_create(). + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_subdev_login(int devid); + +/** + * @brief make subdev inaccessible on cloud. + + * @param devid, device id return from linkkit_gateway_subdev_create(). + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_subdev_logout(int devid); + +enum { + LINKKIT_STATE_ENABLED = 0, /* device is enabled by cloud */ + LINKKIT_STATE_DISABLED, /* device is disabled by cloud */ + LINKKIT_STATE_REMOVED, /* device is deleted by cloud */ +}; + +typedef struct { + char *productKey; /* device's product key */ + char *deviceName; /* device's device name */ + + int devtype; /* Device Type: 0 - gateway, 1 - subdev */ + int login; /* Login State: 0 - logout, 1 - login */ + int state; /* Device State: see LINKKIT_STATE_xxx */ + int online; /* 0 - offline, 1 - online */ +} linkkit_devinfo_t; + +/** + * @brief get device infomation specific by devid. + * + * @param devinfo, device information, see linkkit_devinfo_t for more detail. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_get_devinfo(int devid, linkkit_devinfo_t *devinfo); + +/** + * @brief post event to cloud. + * + * @param devid, device id return from linkkit_gateway_start() or linkkit_gateway_subdev_create(). + * @param identifier, event identifier, see tsl file for more detail. + * @param event, event data, in JSON format. + * @param timeout_ms, transmission timeout, in milliseconds. when timeout_ms is 0, wait no response. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_trigger_event_json_sync(int devid, char *identifier, char *event, int timeout_ms); + +/** + * @brief post event to cloud asynchronously. + * + * @param devid, device id return from linkkit_gateway_start() or linkkit_gateway_subdev_create(). + * @param identifier, event identifier, see tsl file for more detail. + * @param event, event data, in JSON format. + * @param timeout_ms, transmission timeout, in milliseconds. when timeout_ms is 0, wait no response. + * @param func, callback function when success(retval > 0), timeout(retval = 0) or failed(retval < 0). + * @param ctx, user data passed to 'func'. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_trigger_event_json(int devid, char *identifier, char *event, int timeout_ms, + void (*func)(int retval, void *ctx), void *ctx); + + +/** + * @brief post property to cloud. + * + * @param devid, device id return from linkkit_gateway_start() or linkkit_gateway_subdev_create(). + * @param property, property data, in JSON format. + * @param timeout_ms, transmission timeout, in milliseconds. when timeout_ms is 0, wait no response. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_post_property_json_sync(int devid, char *property, int timeout_ms); + +/** + * @brief post property to cloud asynchronously. + * + * @param devid, device id return from linkkit_gateway_start() or linkkit_gateway_subdev_create(). + * @param property, property data, in JSON format. + * @param timeout_ms, transmission timeout, in milliseconds. when timeout_ms is 0, wait no response. + * @param func, callback function when success(retval > 0), timeout(retval = 0) or failed(retval < 0). + * @param ctx, user data passed to 'func'. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_post_property_json(int devid, char *property, int timeout_ms, + void (*func)(int retval, void *ctx), + void *ctx); + +/** + * @brief post raw data to cloud. + * + * @param devid, device id return from linkkit_gateway_start() or linkkit_gateway_subdev_create(). + * @param data, raw data buffer pointer. + * @param len, raw data length. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_post_rawdata(int devid, void *data, int len); + +typedef enum { + LINKKIT_OTA_EVENT_NEW_VERSION_DETECTED = 1, +} linkkit_ota_event_t; + +typedef enum { + service_fota_callback_type_new_version_detected = 10, + + service_fota_callback_type_number, +} service_fota_callback_type_t; + +typedef void (*handle_service_fota_callback_fp_t)(service_fota_callback_type_t callback_type, const char *version); + +/** + * @brief this function used to register callback for firmware ota. + * + * @param callback_fp, user callback which register to fota. (NULL for unregister) + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_fota_init(handle_service_fota_callback_fp_t callback_fp); + +/** + * @brief this function used to execute fota process. + * + * @param data_buf, data buf that used to do ota. ota service will use this buffer to download bin. + * @param data_buf_length, data buf length that used to do ota. + * + * @return 0 when success, -1 when fail. + */ +DLL_IOT_API int linkkit_gateway_invoke_fota_service(void *data_buf, int data_buf_length); + +typedef struct { + char *attrKey; /* the key of extend info. */ + char *attrValue; /* the value of extend info. */ +} linkkit_extinfo_t; + +/** + * @brief post group of extend info to cloud + * + * @param devid, device id return from linkkit_gateway_start() or linkkit_gateway_subdev_create(). + * @param extinfos, group of extend info to be post. + * @param nb_extinfos, number of extend infos in extinfos. + * @param timeout_ms, transmission timeout, in milliseconds. when timeout_ms is 0, wait no response. + * + * @return 0 when success, < 0 when fail. + */ +DLL_IOT_API int linkkit_gateway_post_extinfos(int devid, linkkit_extinfo_t *extinfos, int nb_extinfos, + int timeout_ms); + +/** + * @brief delete extend info specific by key + * + * @param devid, device id return from linkkit_gateway_start() or linkkit_gateway_subdev_create(). + * @param extinfos, group of extend info to be deleted, attrValue in linkkit_extinfo_t will be ignore. + * @param nb_extinfos, number of extend infos in extinfos. + * @param timeout_ms, transmission timeout, in milliseconds. when timeout_ms is 0, wait no response. + * + * @return 0 when success, < 0 when fail. + */ +DLL_IOT_API int linkkit_gateway_delete_extinfos(int devid, linkkit_extinfo_t *extinfos, int nb_extinfos, + int timeout_ms); + +/** + * @brief get number devices currently in gateway + * + * @return number devinfos. + */ +DLL_IOT_API int linkkit_gateway_get_num_devices(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LINKKIT_GATEWAY_EXPORT_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_reset/dev_reset.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_reset/dev_reset.c new file mode 100644 index 00000000..59c89b83 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_reset/dev_reset.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "dev_reset_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +static int g_dev_reset_sub_flag = 0; +iotx_devrst_evt_handle_t g_devrst_event_handle = NULL; + + +#include "mqtt_api.h" +static void mqtt_sub_handle(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg) +{ + switch (msg->event_type) + { + case IOTX_MQTT_EVENT_PUBLISH_RECEIVED: { + iotx_mqtt_topic_info_t *packet_info = (iotx_mqtt_topic_info_t *)msg->msg; + if (g_devrst_event_handle) { + iotx_devrst_evt_recv_msg_t recv_msg; + memset(&recv_msg, 0, sizeof(iotx_devrst_evt_recv_msg_t)); + recv_msg.msgid = packet_info->packet_id; + recv_msg.payload = (char *)packet_info->payload; + recv_msg.payload_len = packet_info->payload_len; + g_devrst_event_handle(IOTX_DEVRST_EVT_RECEIVED, (void *)&recv_msg); + } + } + break; + + default: + break; + } +} + +int IOT_DevReset_Report(iotx_dev_meta_info_t *meta_info, iotx_devrst_evt_handle_t handle, void *extended) +{ + int res = 0; + const char *reset_fmt = "/sys/%s/%s/thing/reset"; + const char *reset_reply_fmt = "/sys/%s/%s/thing/reset_reply"; + const char *payload_fmt = "{\"id\":%d, \"version\":\"1.0\", \"method\":\"thing.reset\", \"params\":{}}"; + char topic[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 30] = {0}; + char payload[128] = {0}; + + if (meta_info == NULL || handle== NULL ) { + return FAIL_RETURN; + } + g_devrst_event_handle = handle; + + memset(topic, 0, IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 30); + HAL_Snprintf(topic,IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 30, reset_reply_fmt, meta_info->product_key, meta_info->device_name); + + if (g_dev_reset_sub_flag == 0) { + res = IOT_MQTT_Subscribe_Sync(NULL, topic, IOTX_MQTT_QOS0, mqtt_sub_handle, NULL, 5000); + if (res < 0 ) { + return FAIL_RETURN; + } + g_dev_reset_sub_flag = 1; + } + + memset(topic, 0, IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 30); + HAL_Snprintf(topic, IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 30, reset_fmt, meta_info->product_key, meta_info->device_name); + + memset(payload, 0, 128); + HAL_Snprintf(payload, 128, payload_fmt, iotx_report_id()); + + res = IOT_MQTT_Publish_Simple(NULL, topic, IOTX_MQTT_QOS0, payload, strlen(payload)); + + return res; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_reset/dev_reset_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_reset/dev_reset_api.h new file mode 100644 index 00000000..fed53791 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_reset/dev_reset_api.h @@ -0,0 +1,31 @@ +#ifndef __DEV_RESET_API_H__ +#define __DEV_RESET_API_H__ + +#include "infra_types.h" +#include "infra_defs.h" + +typedef enum { + IOTX_DEVRST_EVT_RECEIVED +} iotx_devrst_evt_type_t; + +typedef struct { + int msgid; + char *payload; + uint32_t payload_len; +} iotx_devrst_evt_recv_msg_t; + +typedef void (*iotx_devrst_evt_handle_t)(iotx_devrst_evt_type_t evt, void *msg); + +/** + * @brief report reset message to cloud. + * + * @param meta_info. device meta info, only product_key and device_name needed. + * @param extended. reserved. + * + * @retval -1 : failure + * @retval 0 : sucess + */ +int IOT_DevReset_Report(iotx_dev_meta_info_t *meta_info, iotx_devrst_evt_handle_t handle, void *extended); + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_reset/dev_reset_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_reset/dev_reset_internal.h new file mode 100644 index 00000000..8899e5da --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_reset/dev_reset_internal.h @@ -0,0 +1,36 @@ +#ifndef _DEV_RESET_INTERNAL_H_ +#define _DEV_RESET_INTERNAL_H_ + +#include +#include +#include "infra_config.h" +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_report.h" +#include "dev_reset_internal.h" +#include "dev_reset_wrapper.h" +#include "dev_reset_api.h" +#include "mqtt_api.h" + +#ifdef INFRA_LOG +#include "infra_log.h" +#define devrst_err(...) log_err("devrst", __VA_ARGS__) +#define devrst_info(...) log_info("devrst", __VA_ARGS__) +#define devrst_debug(...) log_debug("devrst", __VA_ARGS__) +#else +#define devrst_info(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define devrst_err(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define devrst_debug(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#endif + +#ifdef INFRA_MEM_STATS +#include "infra_mem_stats.h" +#define devrst_malloc(size) LITE_malloc(size, MEM_MAGIC, "devrst") +#define devrst_free(ptr) LITE_free(ptr) +#else +#define devrst_malloc(size) HAL_Malloc(size) +#define devrst_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_reset/dev_reset_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_reset/dev_reset_wrapper.h new file mode 100644 index 00000000..f1d09a51 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_reset/dev_reset_wrapper.h @@ -0,0 +1,7 @@ +#ifndef _DEV_RESET_WRAPPER_H_ +#define _DEV_RESET_WRAPPER_H_ + +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_api.h new file mode 100644 index 00000000..9b56c178 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_api.h @@ -0,0 +1,18 @@ +#ifndef _DEV_SIGN_H_ +#define _DEV_SIGN_H_ + +#include "dev_sign_internal.h" + +typedef struct { + char hostname[DEV_SIGN_HOSTNAME_MAXLEN]; + uint16_t port; + char clientid[DEV_SIGN_CLIENT_ID_MAXLEN]; + char username[DEV_SIGN_USERNAME_MAXLEN]; + char password[DEV_SIGN_PASSWORD_MAXLEN]; +} iotx_sign_mqtt_t; + +int32_t IOT_Sign_MQTT(iotx_mqtt_region_types_t region, iotx_dev_meta_info_t *meta, iotx_sign_mqtt_t *signout); + +#endif + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_config.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_config.h new file mode 100644 index 00000000..e99dd11c --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_config.h @@ -0,0 +1,11 @@ +#ifndef _DEV_SIGN_CONFIG_H_ +#define _DEV_SIGN_CONFIG_H_ + +#define DEV_SIGN_SOURCE_MAXLEN (200) +#define DEV_SIGN_HOSTNAME_MAXLEN (64) +#define DEV_SIGN_CLIENT_ID_MAXLEN (200) +#define DEV_SIGN_USERNAME_MAXLEN (64) +#define DEV_SIGN_PASSWORD_MAXLEN (65) + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_internal.h new file mode 100644 index 00000000..64875279 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_internal.h @@ -0,0 +1,13 @@ +#ifndef _DEV_SIGN_INTERNAL_H_ +#define _DEV_SIGN_INTERNAL_H_ + +#include +#include +#include "infra_config.h" +#include "infra_defs.h" +#include "dev_sign_config.h" +#include "dev_sign_api.h" +#include "dev_sign_wrapper.h" + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_mqtt.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_mqtt.c new file mode 100644 index 00000000..021b98a8 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_mqtt.c @@ -0,0 +1,201 @@ +#include +#include +#include "infra_defs.h" +#include "infra_config.h" +#include "infra_sha256.h" + +#include "dev_sign_api.h" +#include "dev_sign_wrapper.h" + + +#define SIGN_MQTT_PORT (1883) + +/* all secure mode define */ +#define MODE_TLS_GUIDER "-1" +#define MODE_TLS_DIRECT "2" +#define MODE_TCP_DIRECT_PLAIN "3" + +#ifdef MQTT_PRE_AUTH + #define SECURE_MODE MODE_TLS_GUIDER +#else + #ifdef SUPPORT_TLS + #define SECURE_MODE MODE_TLS_DIRECT + #else + #define SECURE_MODE MODE_TCP_DIRECT_PLAIN + #endif +#endif + +/* use fixed timestamp */ +#define TIMESTAMP_VALUE "2524608000000" + +/* clientid key value pair define */ +const char *clientid_kv[][2] = { + { + "timestamp", TIMESTAMP_VALUE + }, + { + "securemode", SECURE_MODE + }, + { + "signmethod", "hmacsha256" + }, +#if defined(DEVICE_MODEL_ENABLED) && !defined(DEVICE_MODEL_CLASSIC) + { + "v", IOTX_ALINK_VERSION + }, +#else + { + "gw", "0" + }, + { + "ext", "0" + }, +#endif + { + "_v", "sdk-c-"IOTX_SDK_VERSION + }, +}; + +static void _hex2str(uint8_t *input, uint16_t input_len, char *output) +{ + char *zEncode = "0123456789ABCDEF"; + int i = 0, j = 0; + + for (i = 0; i < input_len; i++) { + output[j++] = zEncode[(input[i] >> 4) & 0xf]; + output[j++] = zEncode[(input[i]) & 0xf]; + } +} + +int _sign_get_clientid(char *clientid_string, const char *device_id) +{ + uint8_t i; + + if (clientid_string == NULL || device_id == NULL) { + return FAIL_RETURN; + } + + memset(clientid_string, 0, DEV_SIGN_CLIENT_ID_MAXLEN); + memcpy(clientid_string, device_id, strlen(device_id)); + memcpy(clientid_string + strlen(clientid_string), "|", 1); + + for (i = 0; i < (sizeof(clientid_kv) / (sizeof(clientid_kv[0]))); i++) { + if ((strlen(clientid_string) + strlen(clientid_kv[i][0]) + strlen(clientid_kv[i][1]) + 2) >= + DEV_SIGN_CLIENT_ID_MAXLEN) { + return FAIL_RETURN; + } + + memcpy(clientid_string + strlen(clientid_string), clientid_kv[i][0], strlen(clientid_kv[i][0])); + memcpy(clientid_string + strlen(clientid_string), "=", 1); + memcpy(clientid_string + strlen(clientid_string), clientid_kv[i][1], strlen(clientid_kv[i][1])); + memcpy(clientid_string + strlen(clientid_string), ",", 1); + } + + memcpy(clientid_string + strlen(clientid_string) - 1, "|", 1); + + return SUCCESS_RETURN; +} + +int _iotx_generate_sign_string(const char *device_id, const char *device_name, const char *product_key, const char *device_secret, char *sign_string) +{ + char signsource[DEV_SIGN_SOURCE_MAXLEN] = {0}; + uint16_t signsource_len = 0; + const char sign_fmt[] = "clientId%sdeviceName%sproductKey%stimestamp%s"; + uint8_t sign_hex[32] = {0}; + + signsource_len = sizeof(sign_fmt) + strlen(device_id) + strlen(device_name) + strlen(product_key) + strlen(TIMESTAMP_VALUE); + if (signsource_len >= DEV_SIGN_SOURCE_MAXLEN) { + return ERROR_DEV_SIGN_SOURCE_TOO_SHORT; + } + + memset(signsource, 0, DEV_SIGN_SOURCE_MAXLEN); + memcpy(signsource, "clientId", strlen("clientId")); + memcpy(signsource + strlen(signsource), device_id, strlen(device_id)); + memcpy(signsource + strlen(signsource), "deviceName", strlen("deviceName")); + memcpy(signsource + strlen(signsource), device_name, strlen(device_name)); + memcpy(signsource + strlen(signsource), "productKey", strlen("productKey")); + memcpy(signsource + strlen(signsource), product_key, strlen(product_key)); + memcpy(signsource + strlen(signsource), "timestamp", strlen("timestamp")); + memcpy(signsource + strlen(signsource), TIMESTAMP_VALUE, strlen(TIMESTAMP_VALUE)); + + utils_hmac_sha256((uint8_t *)signsource, strlen(signsource), (uint8_t *)device_secret, + strlen(device_secret), sign_hex); + + _hex2str(sign_hex, 32, sign_string); + + return SUCCESS_RETURN; +} + +int32_t IOT_Sign_MQTT(iotx_mqtt_region_types_t region, iotx_dev_meta_info_t *meta, iotx_sign_mqtt_t *signout) +{ + uint16_t length = 0; + char device_id[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 1] = {0}; + int res; + + if (region >= IOTX_MQTT_DOMAIN_NUMBER || meta == NULL) { + return -1; + } + + memset(signout, 0, sizeof(iotx_sign_mqtt_t)); + + memcpy(device_id, meta->product_key, strlen(meta->product_key)); + memcpy(device_id + strlen(device_id), ".", strlen(".")); + memcpy(device_id + strlen(device_id), meta->device_name, strlen(meta->device_name)); + + /* setup clientid */ + if (_sign_get_clientid(signout->clientid, device_id) != SUCCESS_RETURN) { + return ERROR_DEV_SIGN_CLIENT_ID_TOO_SHORT; + } + + /* setup password */ + memset(signout->password, 0, DEV_SIGN_PASSWORD_MAXLEN); + res = _iotx_generate_sign_string(device_id, meta->device_name, meta->product_key, meta->device_secret, signout->password); + if (res < SUCCESS_RETURN) { + return res; + } + + /* setup hostname */ + if (IOTX_CLOUD_REGION_CUSTOM == region) { + if (g_infra_mqtt_domain[region] == NULL) { + return ERROR_DEV_SIGN_CUSTOM_DOMAIN_IS_NULL; + } + + length = strlen(g_infra_mqtt_domain[region]) + 1; + if (length >= DEV_SIGN_HOSTNAME_MAXLEN) { + return ERROR_DEV_SIGN_HOST_NAME_TOO_SHORT; + } + + memset(signout->hostname, 0, DEV_SIGN_HOSTNAME_MAXLEN); + memcpy(signout->hostname, g_infra_mqtt_domain[region], strlen(g_infra_mqtt_domain[region])); + } + else { + length = strlen(meta->product_key) + strlen(g_infra_mqtt_domain[region]) + 2; + if (length >= DEV_SIGN_HOSTNAME_MAXLEN) { + return ERROR_DEV_SIGN_HOST_NAME_TOO_SHORT; + } + memset(signout->hostname, 0, DEV_SIGN_HOSTNAME_MAXLEN); + memcpy(signout->hostname, meta->product_key, strlen(meta->product_key)); + memcpy(signout->hostname + strlen(signout->hostname), ".", strlen(".")); + memcpy(signout->hostname + strlen(signout->hostname), g_infra_mqtt_domain[region], + strlen(g_infra_mqtt_domain[region])); + } + + /* setup username */ + length = strlen(meta->device_name) + strlen(meta->product_key) + 2; + if (length >= DEV_SIGN_USERNAME_MAXLEN) { + return ERROR_DEV_SIGN_USERNAME_TOO_SHORT; + } + memset(signout->username, 0, DEV_SIGN_USERNAME_MAXLEN); + memcpy(signout->username, meta->device_name, strlen(meta->device_name)); + memcpy(signout->username + strlen(signout->username), "&", strlen("&")); + memcpy(signout->username + strlen(signout->username), meta->product_key, strlen(meta->product_key)); + + /* setup port */ +#ifdef SUPPORT_TLS + signout->port = 443; +#else + signout->port = 1883; +#endif /* #ifdef SUPPORT_TLS */ + return SUCCESS_RETURN; +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_wrapper.h new file mode 100644 index 00000000..c3520e6b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dev_sign/dev_sign_wrapper.h @@ -0,0 +1,4 @@ + + +#include "infra_types.h" +#include "infra_defs.h" diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dynamic_register/dynreg.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dynamic_register/dynreg.c new file mode 100644 index 00000000..29f6af78 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dynamic_register/dynreg.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include +#include "string.h" +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_string.h" +#include "infra_httpc.h" +#include "infra_sha256.h" +#include "dynreg_internal.h" +#include "dynreg_wrapper.h" + +#define HTTP_RESPONSE_PAYLOAD_LEN (256) + +#define DYNREG_RANDOM_KEY_LENGTH (15) +#define DYNREG_SIGN_LENGTH (65) +#define DYNREG_SIGN_METHOD_HMACSHA256 "hmacsha256" + +static int _parse_string_value(char *payload, int *pos, int *start, int *end) +{ + int idx = 0; + + for (idx = *pos + 1; idx < strlen(payload); idx++) { + if (payload[idx] == '\"') { + break; + } + } + *start = *pos + 1; + *end = idx - 1; + *pos = idx; + + return 0; +} + +static int _parse_dynreg_value(char *payload, char *key, int *pos, int *start, int *end) +{ + int idx = 0; + /* printf("=====%s\n",&payload[*pos]); */ + + if (memcmp(key, "code", strlen("code")) == 0) { + for (idx = *pos; idx < strlen(payload); idx++) { + if (payload[idx] < '0' || payload[idx] > '9') { + break; + } + } + *start = *pos; + *end = idx - 1; + *pos = *end; + return 0; + } else if (memcmp(key, "data", strlen("data")) == 0) { + int bracket_cnt = 0; + if (payload[*pos] != '{') { + return -1; + } + for (idx = *pos; idx < strlen(payload); idx++) { + if (payload[idx] == '{') { + bracket_cnt++; + } else if (payload[idx] == '}') { + bracket_cnt--; + } + if (bracket_cnt == 0) { + break; + } + } + *start = *pos; + *end = idx; + *pos = *end; + return 0; + } else { + if (payload[*pos] != '\"') { + return -1; + } + return _parse_string_value(payload, pos, start, end); + } + + return -1; +} + +static int _parse_dynreg_result(char *payload, char *key, int *start, int *end) +{ + int res = 0, idx = 0, pos = 0; + + for (idx = 0; idx < strlen(payload); idx++) { + /* printf("loop start: %s\n",&payload[idx]); */ + if (payload[idx] == '\"') { + for (pos = idx + 1; pos < strlen(payload); pos++) { + if (payload[pos] == '\"') { + /* printf("key: %.*s\n",pos - idx - 1, &payload[idx+1]); */ + break; + } + } + + if (pos == strlen(payload) || payload[pos + 1] != ':') { + return -1; + } + + pos += 2; + res = _parse_dynreg_value(payload, key, &pos, start, end); + if (res == 0 && memcmp(key, &payload[idx + 1], strlen(key)) == 0) { + /* printf("value: %.*s\n",*end - *start + 1,&payload[*start]); */ + return 0; + } + + idx = pos; + } + } + + printf("exit 4\n"); + return -1; +} + +static int _calc_dynreg_sign( + char product_key[IOTX_PRODUCT_KEY_LEN], + char product_secret[IOTX_PRODUCT_SECRET_LEN], + char device_name[IOTX_DEVICE_NAME_LEN], + char random[DYNREG_RANDOM_KEY_LENGTH + 1], + char sign[DYNREG_SIGN_LENGTH]) +{ + int sign_source_len = 0; + uint8_t signnum[32]; + uint8_t *sign_source = NULL; + const char *dynamic_register_sign_fmt = "deviceName%sproductKey%srandom%s"; + + /* Start Dynamic Register */ + memcpy(random, "8Ygb7ULYh53B6OA", strlen("8Ygb7ULYh53B6OA")); + dynreg_info("Random Key: %s", random); + + /* Calculate SHA256 Value */ + sign_source_len = strlen(dynamic_register_sign_fmt) + strlen(device_name) + strlen(product_key) + strlen(random) + 1; + sign_source = dynreg_malloc(sign_source_len); + if (sign_source == NULL) { + dynreg_err("Memory Not Enough"); + return FAIL_RETURN; + } + memset(sign_source, 0, sign_source_len); + HAL_Snprintf((char *)sign_source, sign_source_len, dynamic_register_sign_fmt, device_name, product_key, random); + + utils_hmac_sha256(sign_source, strlen((const char *)sign_source), (uint8_t *)product_secret, strlen(product_secret), + signnum); + infra_hex2str(signnum, 32, sign); + dynreg_free(sign_source); + dynreg_info("Sign: %s", sign); + + return SUCCESS_RETURN; +} + +static int _fetch_dynreg_http_resp(char *request_payload, char *response_payload, + iotx_http_region_types_t region, char device_secret[IOTX_DEVICE_SECRET_LEN]) +{ + int res = 0; + const char *domain = NULL; + const char *url_format = "http://%s/auth/register/device"; + char *url = NULL; + int url_len = 0; + const char *pub_key = NULL; + httpclient_t http_client; + httpclient_data_t http_client_data; + int start = 0, end = 0, data_start = 0, data_end = 0; + + memset(&http_client, 0, sizeof(httpclient_t)); + memset(&http_client_data, 0, sizeof(httpclient_data_t)); + + domain = g_infra_http_domain[region]; + if (NULL == domain) { + dynreg_err("Get domain failed"); + return FAIL_RETURN; + } + url_len = strlen(url_format) + strlen(domain) + 1; + url = (char *)dynreg_malloc(url_len); + if (NULL == url) { + dynreg_err("Not Enough Memory"); + return FAIL_RETURN; + } + memset(url, 0, url_len); + HAL_Snprintf(url, url_len, url_format, domain); + + http_client.header = "Accept: text/xml,text/javascript,text/html,application/json\r\n"; + + http_client_data.post_content_type = "application/x-www-form-urlencoded"; + http_client_data.post_buf = request_payload; + http_client_data.post_buf_len = strlen(request_payload); + http_client_data.response_buf = response_payload; + http_client_data.response_buf_len = HTTP_RESPONSE_PAYLOAD_LEN; + +#ifdef SUPPORT_TLS + { + extern const char *iotx_ca_crt; + pub_key = iotx_ca_crt; + } +#endif + + res = httpclient_common(&http_client, url, 443, pub_key, HTTPCLIENT_POST, 10000, &http_client_data); + if (res != SUCCESS_RETURN) { + dynreg_err("Http Download Failed"); + dynreg_free(url); + return FAIL_RETURN; + } + dynreg_free(url); + dynreg_info("Http Response Payload: %s", http_client_data.response_buf); + + _parse_dynreg_result(response_payload, "code", &start, &end); + dynreg_info("Dynamic Register Code: %.*s", end - start + 1, &response_payload[start]); + + if (memcmp(&response_payload[start], "200", strlen("200")) != 0) { + return FAIL_RETURN; + } + + _parse_dynreg_result(response_payload, "data", &data_start, &data_end); + /* dynreg_info("value: %.*s\n",data_end - data_start + 1,&response_payload[data_start]); */ + + _parse_dynreg_result(&response_payload[data_start + 1], "deviceSecret", &start, &end); + dynreg_info("Dynamic Register Device Secret: %.*s", end - start + 1, &response_payload[data_start + 1 + start]); + + if (end - start + 1 > IOTX_DEVICE_SECRET_LEN) { + return FAIL_RETURN; + } + + memcpy(device_secret, &response_payload[data_start + 1 + start], end - start + 1); + + return SUCCESS_RETURN; +} + +int32_t IOT_Dynamic_Register(iotx_http_region_types_t region, iotx_dev_meta_info_t *meta) +{ + int res = 0, dynamic_register_request_len = 0; + char sign[DYNREG_SIGN_LENGTH] = {0}; + char random[DYNREG_RANDOM_KEY_LENGTH + 1] = {0}; + const char *dynamic_register_format = "productKey=%s&deviceName=%s&random=%s&sign=%s&signMethod=%s"; + char *dynamic_register_request = NULL; + char *dynamic_register_response = NULL; + + if (strlen(meta->product_key) > IOTX_PRODUCT_KEY_LEN || + strlen(meta->product_secret) > IOTX_PRODUCT_SECRET_LEN || + strlen(meta->device_name) > IOTX_DEVICE_NAME_LEN) { + return FAIL_RETURN; + } + + /* Calcute Signature */ + res = _calc_dynreg_sign(meta->product_key, meta->product_secret, meta->device_name, random, sign); + if (res != SUCCESS_RETURN) { + dynreg_err("Calculate Sign Failed"); + return FAIL_RETURN; + } + + /* Assemble Http Dynamic Register Request Payload */ + dynamic_register_request_len = strlen(dynamic_register_format) + strlen(meta->product_key) + strlen(meta->device_name) + + strlen(random) + strlen(sign) + strlen(DYNREG_SIGN_METHOD_HMACSHA256) + 1; + dynamic_register_request = dynreg_malloc(dynamic_register_request_len); + if (dynamic_register_request == NULL) { + dynreg_err("Not Enough Memory"); + return FAIL_RETURN; + } + memset(dynamic_register_request, 0, dynamic_register_request_len); + HAL_Snprintf(dynamic_register_request, dynamic_register_request_len, dynamic_register_format, + meta->product_key, meta->device_name, random, sign, DYNREG_SIGN_METHOD_HMACSHA256); + + dynamic_register_response = dynreg_malloc(HTTP_RESPONSE_PAYLOAD_LEN); + if (dynamic_register_response == NULL) { + dynreg_err("Not Enough Memory"); + dynreg_free(dynamic_register_request); + return FAIL_RETURN; + } + + /* Send Http Request For Getting Device Secret */ + res = _fetch_dynreg_http_resp(dynamic_register_request, dynamic_register_response, region, meta->device_secret); + +#ifdef INFRA_LOG_NETWORK_PAYLOAD + dynreg_dbg("Downstream Payload:"); + iotx_facility_json_print(dynamic_register_response, LOG_DEBUG_LEVEL, '<'); +#endif + + dynreg_free(dynamic_register_request); + dynreg_free(dynamic_register_response); + if (res != SUCCESS_RETURN) { + dynreg_err("Get Device Secret Failed"); + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dynamic_register/dynreg_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dynamic_register/dynreg_api.h new file mode 100644 index 00000000..d1fcf8fe --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dynamic_register/dynreg_api.h @@ -0,0 +1,10 @@ +#ifndef _DYNREG_API_H_ +#define _DYNREG_API_H_ + +#include "infra_types.h" +#include "infra_defs.h" + +int32_t IOT_Dynamic_Register(iotx_http_region_types_t region, iotx_dev_meta_info_t *meta); + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dynamic_register/dynreg_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dynamic_register/dynreg_internal.h new file mode 100644 index 00000000..79d73306 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dynamic_register/dynreg_internal.h @@ -0,0 +1,27 @@ +#ifndef _DYNREG_INTERNAL_H_ +#define _DYNREG_INTERNAL_H_ + +#include "dynreg_wrapper.h" + +#ifdef INFRA_LOG + #include "infra_log.h" + #define dynreg_info(...) log_info("dynreg", __VA_ARGS__) + #define dynreg_err(...) log_err("dynreg", __VA_ARGS__) + #define dynreg_dbg(...) log_debug("dynreg", __VA_ARGS__) +#else + #define dynreg_info(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define dynreg_err(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define dynreg_dbg(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#endif + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define dynreg_malloc(size) LITE_malloc(size, MEM_MAGIC, "dynreg") + #define dynreg_free(ptr) LITE_free(ptr) +#else + #define dynreg_malloc(size) HAL_Malloc(size) + #define dynreg_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dynamic_register/dynreg_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dynamic_register/dynreg_wrapper.h new file mode 100644 index 00000000..b7e52f51 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/dynamic_register/dynreg_wrapper.h @@ -0,0 +1,12 @@ +#ifndef _DYNREG_WRAPPER_H_ +#define _DYNREG_WRAPPER_H_ + +#include "infra_types.h" + +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); +void HAL_Printf(const char *fmt, ...); +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http/http_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http/http_api.h new file mode 100644 index 00000000..69bd9338 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http/http_api.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _IOT_EXPORT_HTTP_H_ +#define _IOT_EXPORT_HTTP_H_ + +#include "infra_types.h" +#include "infra_defs.h" + +#if defined(__cplusplus) +extern "C" { +#endif + + +typedef struct { + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + char device_id[IOTX_DEVICE_ID_LEN + 1]; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1]; + char module_vendor_id[IOTX_MODULE_ID_LEN + 1]; +} iotx_device_info_t; + +/* IoTx http initial param */ +typedef struct { + iotx_device_info_t *device_info; + int keep_alive; + int timeout_ms; +} iotx_http_param_t; + +/* IoTx http context */ +typedef struct { + char *p_auth_token; + uint32_t auth_token_len; + char is_authed; + const char *version; + const char *signmethod; + const char *sign; + iotx_device_info_t *p_devinfo; + const char *timestamp; + void *httpc; + int keep_alive; + int timeout_ms; +} iotx_http_t, *iotx_http_pt; + +/* IoTx http message definition + * request_payload and response_payload need to be allocate in order to save memory. + * topic_path specify the topic url you want to publish message. + */ +typedef struct { + char *topic_path; + uint32_t request_payload_len; + char *request_payload; + uint32_t response_payload_len; + char *response_payload; + uint32_t timeout_ms; +} iotx_http_message_param_t; + +/* The response code from sever */ +typedef enum { + IOTX_HTTP_SUCCESS = 0, + IOTX_HTTP_COMMON_ERROR = 10000, + IOTX_HTTP_PARAM_ERROR = 10001, + IOTX_HTTP_AUTH_CHECK_ERROR = 20000, + IOTX_HTTP_TOKEN_EXPIRED_ERROR = 20001, + IOTX_HTTP_TOKEN_NULL_ERROR = 20002, + IOTX_HTTP_TOKEN_CHECK_ERROR = 20003, + IOTX_HTTP_UPDATE_SESSION_ERROR = 20004, + IOTX_HTTP_PUBLISH_MESSAGE_ERROR = 30001, + IOTX_HTTP_REQUEST_TOO_MANY_ERROR = 40000, +} iotx_http_upstream_response_t; + +/** @defgroup group_api api + * @{ + */ + +/** @defgroup group_api_http http + * @{ + */ + +/** + * @brief Initialize the HTTP client + * This function initialize the data. + * + * @param [in] pInitParams: Specify the init param infomation. + * + * @retval NULL : Initialize failed. + * @retval NOT_NULL : The contex of HTTP client. + * @see None. + */ +DLL_IOT_API void *IOT_HTTP_Init(iotx_http_param_t *pInitParams); + +/** + * @brief De-initialize the HTTP client + * This function release the related resource. + * + * @param [in] handle: pointer to http context pointer. + * @return None. + * @see None. + */ +DLL_IOT_API void IOT_HTTP_DeInit(void **handle); + +/** + * @brief Handle device name authentication with remote server. + * + * @param [in] handle: Pointer of context, specify the HTTP client. + * + * @retval 0 : Authenticate success. + * @retval -1 : Authenticate failed. + * @see iotx_err_t. + */ +DLL_IOT_API int IOT_HTTP_DeviceNameAuth(void *handle); + +/** + * @brief Send a message with specific path to server. + * Client must authentication with server before send message. + * + * @param [in] handle: Pointer of contex, specify the HTTP client. + * @param [in] msg_param: Specify the topic path and http payload configuration. + * + * @retval 0 : Success. + * @retval -1 : Failed. + * @see iotx_err_t. + */ +DLL_IOT_API int IOT_HTTP_SendMessage(void *handle, iotx_http_message_param_t *msg_param); + +/** + * @brief close tcp connection from client to server. + * + * @param [in] handle: Pointer of contex, specify the HTTP client. + * @return None. + * @see None. + */ +DLL_IOT_API void IOT_HTTP_Disconnect(void *handle); + +/** @} */ /* end of api_http */ +/** @} */ /* end of api */ + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http/http_debug.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http/http_debug.h new file mode 100644 index 00000000..98240001 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http/http_debug.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#ifndef __HTTP_DEBUG_H__ +#define __HTTP_DEBUG_H__ + +#ifdef INFRA_LOG + #include "infra_log.h" + #define http_emerg(...) log_emerg("HTTP", __VA_ARGS__) + #define http_crit(...) log_crit("HTTP", __VA_ARGS__) + #define http_err(...) log_err("HTTP", __VA_ARGS__) + #define http_warning(...) log_warning("HTTP", __VA_ARGS__) + #define http_info(...) log_info("HTTP", __VA_ARGS__) + #define http_debug(...) log_debug("HTTP", __VA_ARGS__) +#else + #define http_emerg(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define http_crit(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define http_err(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define http_warning(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define http_info(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define http_debug(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#endif + + +#endif /* __HTTP_DEBUG_H__ */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http/http_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http/http_wrapper.h new file mode 100644 index 00000000..2e712ee0 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http/http_wrapper.h @@ -0,0 +1,15 @@ +#ifndef _HTTP_WRAPPER_H +#define _HTTP_WRAPPER_H + +#include "infra_types.h" +#include "infra_defs.h" +#include "wrappers_defs.h" + +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); +void HAL_Printf(const char *fmt, ...); +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); +uint64_t HAL_UptimeMs(void); +void HAL_SleepMs(uint32_t ms); + +#endif /* #ifndef _HTTP_WRAPPER_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http/iotx_http_api.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http/iotx_http_api.c new file mode 100644 index 00000000..2d2489c1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http/iotx_http_api.c @@ -0,0 +1,763 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include +#include +#include +#include + +#include "infra_httpc.h" +#include "infra_json_parser.h" +#include "infra_timer.h" +#include "infra_sha1.h" +#include "infra_report.h" +#include "http_debug.h" +#include "http_api.h" +#include "http_wrapper.h" + + + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define HTTP_API_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "http.api") + #define HTTP_API_FREE(ptr) LITE_free(ptr) +#else + #define HTTP_API_MALLOC(size) HAL_Malloc(size) + #define HTTP_API_FREE(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#define HTTP_LITE_JSON_VALUE_OF(key, src) LITE_json_value_of(key, src, 0x1234, "http.api") + +#ifndef CONFIG_MID_HTTP_TIMEOUT + #define CONFIG_MID_HTTP_TIMEOUT (5 * 1000) +#endif + +#ifndef CONFIG_HTTP_AUTH_TIMEOUT + #define CONFIG_HTTP_AUTH_TIMEOUT (5 * 1000) +#endif + +/* +#define IOTX_HTTP_TIMESTAMP_OPTIONAL_ENABLE +*/ +#define IOTX_HTTP_SIGN_LENGTH (41) +#define IOTX_HTTP_SIGN_SOURCE_LEN (256) +#define IOTX_HTTP_AUTH_TOKEN_LEN (192+1) +#define IOTX_HTTP_URL_LEN_MAX (135) + +#ifdef IOTX_HTTP_TIMESTAMP_OPTIONAL_ENABLE +#define IOTX_HTTP_SIGN_SRC_STR "clientId%sdeviceName%sproductKey%stimestamp%s" +#define IOTX_HTTP_AUTH_DEVICENAME_STR \ + "{" \ + "\"version\":\"%s\", \"clientId\":\"%s\"," \ + "\"signmethod\":\"%s\",\"sign\":\"%s\"," \ + "\"productKey\":\"%s\",\"deviceName\":\"%s\"," \ + "\"timestamp\":\"%s\"" \ + "}" +#else +#define IOTX_HTTP_SIGN_SRC_STR "clientId%sdeviceName%sproductKey%s" +#define IOTX_HTTP_AUTH_DEVICENAME_STR \ + "{" \ + "\"version\":\"%s\", \"clientId\":\"%s\"," \ + "\"signmethod\":\"%s\",\"sign\":\"%s\"," \ + "\"productKey\":\"%s\",\"deviceName\":\"%s\"" \ + "}" +#endif + +#define IOTX_HTTP_AUTH_STR "auth" +#define IOTX_HTTP_ONLINE_SERVER_URL "https://iot-as-http.cn-shanghai.aliyuncs.com" +#define IOTX_HTTP_ONLINE_SERVER_PORT 443 + +#define IOTX_SHA_METHOD "hmacsha1" + +#define IOTX_HTTP_HEADER_KEEPALIVE_STR "Connection: Keep-Alive\r\n" +#define IOTX_HTTP_HEADER_PASSWORD_STR "password:" +#define IOTX_HTTP_UPSTREAM_HEADER_STR \ + IOTX_HTTP_HEADER_KEEPALIVE_STR \ + IOTX_HTTP_HEADER_PASSWORD_STR \ + "%s" \ + IOTX_HTTP_HEADER_END_STR +#define IOTX_HTTP_HEADER_END_STR "\r\n" + +#define HTTP_AUTH_RESP_MAX_LEN (256) + +static iotx_http_t *iotx_http_context_bak = NULL; + + +/* + Http server url: https://iot-as-http.cn-shanghai.aliyuncs.com + Only https protocal is supported at present. + The /auth interface is used to get access token before any data transform which need to be requested just one time. + The device must call /auth to get the token before transfer any data. + Every data transfer need to be with access token. + You need to request for a new token if the current token have been expired. + Token can be cached in local devices, which has 48 hours term of validity. + POST /auth HTTP/1.1 + Host: iot-as-http.cn-shanghai.aliyuncs.com + Content-Type: application/json + body: {"version":"default","clientId":"xxxxx","signmethod":"hmacsha1","sign":"xxxxxxxxxx","productKey":"xxxxxx","deviceName":"xxxxxxx","timestamp":"xxxxxxx"} +*/ + +static int iotx_calc_sign(const char *p_device_secret, const char *p_msg, char *sign) +{ + http_info("| method: %s", IOTX_SHA_METHOD); + utils_hmac_sha1(p_msg, strlen(p_msg), sign, p_device_secret, strlen(p_device_secret)); + return SUCCESS_RETURN; +} + +static int calc_snprintf_string_length(char *fmt, ...) +{ + va_list args; + int rc = 0; + char *p = NULL; + char *sval = NULL; + + if (NULL == fmt) { + return -1; + } + + va_start(args, fmt); + + for (p = fmt; *p; p++) { + if (*p != '%') { + rc++; + continue; + } + switch (*++p) { + case 's': + for (sval = va_arg(args, char *); *sval; sval++) { + rc++; + } + break; + default: + rc++; + break; + } + } + + va_end(args); + + return rc; +} + +static int construct_full_http_authenticate_url(char *buf) +{ + LITE_snprintf(buf, IOTX_HTTP_URL_LEN_MAX, + "%s/%s", IOTX_HTTP_ONLINE_SERVER_URL, IOTX_HTTP_AUTH_STR); + http_info("get_http_authenticate_url is %s", buf); + return 0; +} + +static int construct_full_http_upstream_url(char *buf, const char *topic_path) +{ + LITE_snprintf(buf, IOTX_HTTP_URL_LEN_MAX, + "%s%s", IOTX_HTTP_ONLINE_SERVER_URL, topic_path); + http_info("construct_full_http_upstream_url is %s", buf); + return 0; +} + +static int http_report_func(void *handle, const char *topic_name, int req_ack, void *data, int len) +{ + iotx_http_message_param_t msg_param; + char request_buf[1024]; + char topic_path[100]; + + if (handle == NULL || topic_name == NULL || data == NULL) { + http_err("params err"); + return -1; + } + + HAL_Snprintf(topic_path, sizeof(topic_path), "/topic%s", topic_name); + + memset(&msg_param, 0, sizeof(iotx_http_message_param_t)); + msg_param.request_payload = (char *)data; + msg_param.response_payload = request_buf; + msg_param.timeout_ms = CONFIG_MID_HTTP_TIMEOUT; + msg_param.request_payload_len = len; + msg_param.response_payload_len = 1024; + msg_param.topic_path = topic_path; + + return IOT_HTTP_SendMessage(handle, &msg_param); +} + +static void *verify_iotx_http_context(void *handle) +{ + iotx_http_t *iotx_http_context = (iotx_http_t *)handle; + + if (NULL == iotx_http_context || + NULL == iotx_http_context_bak || + iotx_http_context_bak != iotx_http_context) { + http_err("iotx_http_context not valid pointer!"); + + iotx_http_context = NULL; + } + + return iotx_http_context; +} + +void *IOT_HTTP_Init(iotx_http_param_t *pInitParams) +{ + iotx_device_info_t *p_devinfo; + iotx_http_t *iotx_http_context; + + /* currently http is singleton, init twice not allowed. */ + if (NULL != iotx_http_context_bak) { + http_err("Init twice not allowed, please deinit first"); + return NULL; + } + + if (NULL == pInitParams || NULL == pInitParams->device_info) { + http_err("Invalid argument: pInitParams or device_info = NULL"); + return NULL; + } + + p_devinfo = pInitParams->device_info; + +/* + HAL_SetProductKey(p_devinfo->product_key); + HAL_SetDeviceName(p_devinfo->device_name); + HAL_SetDeviceSecret(p_devinfo->device_secret); +*/ + + iotx_http_context = (iotx_http_t *)HTTP_API_MALLOC(sizeof(iotx_http_t)); + + if (NULL == iotx_http_context) { + http_err("Allocate memory for iotx_http_context failed"); + return NULL; + } + + memset(iotx_http_context, 0x00, sizeof(iotx_http_t)); + + iotx_http_context->keep_alive = pInitParams->keep_alive; + iotx_http_context->timeout_ms = pInitParams->timeout_ms; + iotx_http_context->p_auth_token = HTTP_API_MALLOC(IOTX_HTTP_AUTH_TOKEN_LEN); + if (NULL == iotx_http_context->p_auth_token) { + http_err("Allocate memory for auth token failed"); + goto err; + } + memset(iotx_http_context->p_auth_token, 0x00, IOTX_HTTP_AUTH_TOKEN_LEN); + iotx_http_context->is_authed = 0; + iotx_http_context->auth_token_len = IOTX_HTTP_AUTH_TOKEN_LEN; + + /*Get deivce information*/ + iotx_http_context->p_devinfo = (iotx_device_info_t *)HTTP_API_MALLOC(sizeof(iotx_device_info_t)); + if (NULL == iotx_http_context->p_devinfo) { + http_err("Allocate memory for iotx_http_context->p_devinfo failed"); + goto err; + } + memset(iotx_http_context->p_devinfo, 0x00, sizeof(iotx_device_info_t)); + + /*It should be implement by the user*/ + memset(iotx_http_context->p_devinfo, 0x00, sizeof(iotx_device_info_t)); + strncpy(iotx_http_context->p_devinfo->device_id, p_devinfo->device_id, strlen(p_devinfo->device_id)); + strncpy(iotx_http_context->p_devinfo->product_key, p_devinfo->product_key, strlen(p_devinfo->product_key)); + strncpy(iotx_http_context->p_devinfo->device_secret, p_devinfo->device_secret, strlen(p_devinfo->device_secret)); + strncpy(iotx_http_context->p_devinfo->device_name, p_devinfo->device_name, strlen(p_devinfo->device_name)); + + iotx_http_context->httpc = HTTP_API_MALLOC(sizeof(httpclient_t)); + if (NULL == iotx_http_context->httpc) { + http_err("Allocate memory for iotx_http_context->httpc failed"); + goto err; + } + memset(iotx_http_context->httpc, 0x00, sizeof(httpclient_t)); + + iotx_http_context_bak = iotx_http_context; + + return iotx_http_context; +err: + /* Error, release the memory */ + if (NULL != iotx_http_context) { + if (NULL != iotx_http_context->p_devinfo) { + HTTP_API_FREE(iotx_http_context->p_devinfo); + } + if (NULL != iotx_http_context->p_auth_token) { + HTTP_API_FREE(iotx_http_context->p_auth_token); + } + + iotx_http_context->auth_token_len = 0; + HTTP_API_FREE(iotx_http_context); + } + return NULL; +} + +void IOT_HTTP_DeInit(void **handle) +{ + iotx_http_t *iotx_http_context; + if (NULL == handle) { + http_err("handle is NULL pointer"); + return; + } + if (NULL == (iotx_http_context = verify_iotx_http_context(*handle))) { + return; + } + + if (NULL != iotx_http_context->p_devinfo) { + HTTP_API_FREE(iotx_http_context->p_devinfo); + } + if (NULL != iotx_http_context->p_auth_token) { + HTTP_API_FREE(iotx_http_context->p_auth_token); + } + if (NULL != iotx_http_context->httpc) { + HTTP_API_FREE(iotx_http_context->httpc); + } + + iotx_http_context->auth_token_len = 0; + HTTP_API_FREE(iotx_http_context); + iotx_http_context_bak = NULL; +} + +int IOT_HTTP_DeviceNameAuth(void *handle) +{ + int ret = -1; + int ret_code = 0; + char *pvalue = NULL; + char *response_message = NULL; + char sign[IOTX_HTTP_SIGN_LENGTH] = {0}; + char http_url[IOTX_HTTP_URL_LEN_MAX] = {0}; + char timestamp[14] = {0}; + httpclient_t *httpc; + httpclient_data_t httpc_data = {0}; + char *req_payload = NULL; + char *rsp_payload = NULL; + int len = 0; + char p_msg_unsign[IOTX_HTTP_SIGN_SOURCE_LEN] = {0}; + iotx_time_t timer; + iotx_http_t *iotx_http_context; + const char *pub_key = NULL; + /* */ + /* body: */ + /* { */ + /* "version": "default",//默认default */ + /* "clientId": "xxxxxx",//必填 */ + /* "signmethod": "hmacsha1",//只支持hmacmd5和hmacsha1,默认hmacmd5 */ + /* "sign": "xxxxxxxxxxxxx",//必填,signmethod(deviceSecret,content), content = 将所有提交给服务器的参数(version,sign,signmethod除外), 按照字母顺序排序, 然后将参数值依次拼接,无拼接符号 */ + /* "productKey": "xxxxxx",//必填 */ + /* "deviceName": "xxxxxx",//必填 */ + /* "timestamp": "xxxxxx"//选填 13byte */ + /* } */ + + if (NULL == (iotx_http_context = verify_iotx_http_context(handle))) { + goto do_exit; + } + iotx_http_context->is_authed = 0; + + /* FIXME:some compile error when calling this function. Get TimeStamp */ + /* + if(!utils_get_epoch_time_from_ntp(timestamp, sizeof(timestamp))) + { + http_info("http time response: \r\n\r\n%s", timestamp); + goto do_exit; + } + */ + + /* Calculate Sign */ + LITE_snprintf(p_msg_unsign, IOTX_HTTP_SIGN_SOURCE_LEN, + IOTX_HTTP_SIGN_SRC_STR, + iotx_http_context->p_devinfo->device_id, + iotx_http_context->p_devinfo->device_name, + iotx_http_context->p_devinfo->product_key +#ifdef IOTX_HTTP_TIMESTAMP_OPTIONAL_ENABLE + , timestamp +#endif + ); + + iotx_calc_sign(iotx_http_context->p_devinfo->device_secret, p_msg_unsign, sign); + + /* to save stack memory*/ + len = calc_snprintf_string_length(IOTX_HTTP_AUTH_DEVICENAME_STR, + "default", + iotx_http_context->p_devinfo->device_id, + IOTX_SHA_METHOD, + sign, + iotx_http_context->p_devinfo->product_key, + iotx_http_context->p_devinfo->device_name, + timestamp + ); + + if (len < 0) { + goto do_exit; + } + + req_payload = (char *)HTTP_API_MALLOC(len + 1); + memset(req_payload, 0, len + 1); + + http_debug("allocate req_payload: len = %d", len); + + len = HAL_Snprintf(req_payload, len + 1, + IOTX_HTTP_AUTH_DEVICENAME_STR, + "default", + iotx_http_context->p_devinfo->device_id, + IOTX_SHA_METHOD, + sign, + iotx_http_context->p_devinfo->product_key, + iotx_http_context->p_devinfo->device_name, + timestamp + ); + http_debug("len = %d, req_payload: \r\n%s", len, req_payload); + + /* Malloc Http Response Payload */ + rsp_payload = (char *)HTTP_API_MALLOC(HTTP_AUTH_RESP_MAX_LEN); + if (NULL == rsp_payload) { + http_err("Allocate HTTP rsp_payload buf failed!"); + goto do_exit; + } + memset(rsp_payload, 0, HTTP_AUTH_RESP_MAX_LEN); + + /* Construct Auth Url */ + construct_full_http_authenticate_url(http_url); + + /* Set httpclient and httpclient_data */ + httpc = (httpclient_t *)iotx_http_context->httpc; + + httpc_data.post_content_type = "application/json"; + httpc_data.post_buf = req_payload; + httpc_data.post_buf_len = len; + httpc_data.response_buf = rsp_payload; + httpc_data.response_buf_len = HTTP_AUTH_RESP_MAX_LEN; + + httpc->header = "Connection: Keep-Alive\r\n"; + + /* + Test Code + iotx_http_context->p_auth_token = "eyJ0eXBlIjoiSldUIiwiYWxnIjoiaG1hY3NoYTEifQ.eyJleHBpcmUiOjE1MDQ3ODE4MzQ5MDAsInRva2VuIjoiM2EyZTRmYzMyNjk5NDE0Y2E3MDFjNzIzNzI1YjIyNDgifQ.e87AFhkvNKiqF5xdgm1P47f9DwY"; + iotx_http_context->is_authed = 1; + ret = 0; + goto do_exit; + Test Code + */ + + { + extern const char *iotx_ca_crt; + pub_key = iotx_ca_crt; + } + + /* Send Request and Get Response */ + if (0 != iotx_post(httpc, + http_url, + IOTX_HTTP_ONLINE_SERVER_PORT, + pub_key, + &httpc_data)) { + goto do_exit; + } + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, CONFIG_HTTP_AUTH_TIMEOUT); + + + ret = httpclient_recv_response(httpc, iotx_time_left(&timer), &httpc_data); + if (ret < 0) { + http_err("httpclient_recv_response error, ret = %d", ret); + httpclient_close(httpc); + return ret; + } + if (0 == iotx_http_context->keep_alive) { + http_info("http not keepalive"); + httpclient_close(httpc); + } + /* + body: + { + "code": 0,//业务状态码 + "message": "success",//业务信息 + "info": { + "token": "eyJ0eXBlIjoiSldUIiwiYWxnIjoiaG1hY3NoYTEifQ.eyJleHBpcmUiOjE1MDI1MzE1MDc0NzcsInRva2VuIjoiODA0ZmFjYTBiZTE3NGUxNjliZjY0ODVlNWNiNDg3MTkifQ.OjMwu29F0CY2YR_6oOyiOLXz0c8" + } + } + */ + http_info("http response: \r\n\r\n%s\r\n", httpc_data.response_buf); + + pvalue = HTTP_LITE_JSON_VALUE_OF("code", httpc_data.response_buf); + if (!pvalue) { + goto do_exit; + } + ret_code = atoi(pvalue); + http_info("ret_code = %d", ret_code); + HTTP_API_FREE(pvalue); + pvalue = NULL; + + pvalue = HTTP_LITE_JSON_VALUE_OF("message", httpc_data.response_buf); + if (NULL == pvalue) { + goto do_exit; + } + response_message = pvalue; + http_info("response_message: %s", response_message); + (void)response_message; + HTTP_API_FREE(pvalue); + pvalue = NULL; + + switch (ret_code) { + case IOTX_HTTP_SUCCESS: + break; + case IOTX_HTTP_COMMON_ERROR: + case IOTX_HTTP_PARAM_ERROR: + case IOTX_HTTP_AUTH_CHECK_ERROR: + case IOTX_HTTP_UPDATE_SESSION_ERROR: + case IOTX_HTTP_REQUEST_TOO_MANY_ERROR: + default: + ret = FAIL_RETURN; + goto do_exit; + } + + pvalue = HTTP_LITE_JSON_VALUE_OF("info.token", httpc_data.response_buf); + if (NULL == pvalue) { + http_err("can't get token from json, Abort!"); + goto do_exit; + } + + strcpy(iotx_http_context->p_auth_token, pvalue); + iotx_http_context->is_authed = 1; + HTTP_API_FREE(pvalue); + pvalue = NULL; + + + iotx_set_report_func(http_report_func); + /* report module id */ + ret = iotx_report_mid(iotx_http_context); + if (SUCCESS_RETURN != ret) { + http_err("Send ModuleId message to server(Http) failed, ret = %d", ret); + goto do_exit; + } + /* report device information */ + ret = iotx_report_devinfo(iotx_http_context); + if (SUCCESS_RETURN != ret) { + http_err("Send devinfo message to server(Http) failed, ret = %d", ret); + goto do_exit; + } + /* report firmware */ + ret = iotx_report_firmware_version(iotx_http_context); + if (SUCCESS_RETURN != ret) { + http_err("Send firmware message to server(Http) failed, ret = %d", ret); + goto do_exit; + } + + ret = 0; + +do_exit: + if (pvalue) { + HTTP_API_FREE(pvalue); + pvalue = NULL; + } + if (req_payload) { + HTTP_API_FREE(req_payload); + req_payload = NULL; + } + if (rsp_payload) { + HTTP_API_FREE(rsp_payload); + rsp_payload = NULL; + } + + return ret; +} + +int IOT_HTTP_SendMessage(void *handle, iotx_http_message_param_t *msg_param) +{ + int ret = -1; + int response_code = 0; + char *pvalue = NULL; + char http_url[IOTX_HTTP_URL_LEN_MAX] = {0}; + httpclient_t *httpc = NULL; + httpclient_data_t httpc_data = {0}; + char *messageId = NULL; + char *user_data = NULL; + int len = 0; + uint32_t payload_len = 0; + iotx_time_t timer; + iotx_http_t *iotx_http_context; + const char *pub_key = NULL; + /* + POST /topic/${topic} HTTP/1.1 + Host: iot-as-http.cn-shanghai.aliyuncs.com + password:${token} + Content-Type: application/octet-stream + body: ${your_data} + */ + if (NULL == (iotx_http_context = verify_iotx_http_context(handle))) { + goto do_exit; + } + + if (NULL == msg_param) { + http_err("iotx_http_context or msg_param NULL pointer!"); + goto do_exit; + } + + httpc = (httpclient_t *)iotx_http_context->httpc; + + if (NULL == httpc) { + http_err("httpc null pointer"); + goto do_exit; + } + + if (0 == iotx_http_context->is_authed) { + http_err("Device is not authed"); + goto do_exit; + } + + if (NULL == msg_param->request_payload) { + http_err("IOT_HTTP_SendMessage request_payload NULL!"); + goto do_exit; + } + + if (NULL == msg_param->response_payload) { + http_err("IOT_HTTP_SendMessage response_payload NULL!"); + goto do_exit; + } + + if (NULL == msg_param->topic_path) { + http_err("IOT_HTTP_SendMessage topic_path NULL!"); + goto do_exit; + } + + payload_len = strlen(msg_param->request_payload) + 1; + msg_param->request_payload_len = msg_param->request_payload_len > payload_len \ + ? payload_len : msg_param->request_payload_len; + + /* Construct Auth Url */ + construct_full_http_upstream_url(http_url, msg_param->topic_path); + + len = strlen(IOTX_HTTP_HEADER_PASSWORD_STR) + strlen(iotx_http_context->p_auth_token) + strlen( + IOTX_HTTP_HEADER_KEEPALIVE_STR) + strlen(IOTX_HTTP_HEADER_END_STR); + httpc->header = HTTP_API_MALLOC(len + 1); + if (NULL == httpc->header) { + http_err("Allocate memory for httpc->header failed"); + goto do_exit; + } + LITE_snprintf(httpc->header, len + 1, + IOTX_HTTP_UPSTREAM_HEADER_STR, iotx_http_context->p_auth_token); + http_info("httpc->header = %s", httpc->header); + + httpc_data.post_content_type = "application/octet-stream"; + httpc_data.post_buf = msg_param->request_payload; + httpc_data.post_buf_len = msg_param->request_payload_len; + httpc_data.response_buf = msg_param->response_payload; + httpc_data.response_buf_len = msg_param->response_payload_len; + + http_info("request_payload: \r\n\r\n%s\r\n", httpc_data.post_buf); + + { + extern const char *iotx_ca_crt; + pub_key = iotx_ca_crt; + } + + /* Send Request and Get Response */ + if (iotx_post(httpc, + http_url, + IOTX_HTTP_ONLINE_SERVER_PORT, + pub_key, + &httpc_data)) { + goto do_exit_pre; + } + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, msg_param->timeout_ms); + + ret = httpclient_recv_response(httpc, iotx_time_left(&timer), &httpc_data); + if (ret < 0) { + http_err("httpclient_recv_response error, ret = %d", ret); + httpclient_close(httpc); + goto do_exit_pre; + } + + if (0 == iotx_http_context->keep_alive) { + httpclient_close(httpc); + } + + /* + body: + { + "code": 0, + "message": "success", + "info": { + "messageId": 892687627916247040, + "data": byte[]//may be NULL + } + } + */ + http_info("http response: \r\n\r\n%s\r\n", httpc_data.response_buf); + + pvalue = HTTP_LITE_JSON_VALUE_OF("code", httpc_data.response_buf); + if (!pvalue) { + goto do_exit_pre; + } + + response_code = atoi(pvalue); + HTTP_API_FREE(pvalue); + pvalue = NULL; + http_info("response code: %d", response_code); + + pvalue = HTTP_LITE_JSON_VALUE_OF("message", httpc_data.response_buf); + if (NULL == pvalue) { + goto do_exit_pre; + } + http_info("response_message: %s", pvalue); + HTTP_API_FREE(pvalue); + pvalue = NULL; + + switch (response_code) { + case IOTX_HTTP_SUCCESS: + break; + case IOTX_HTTP_TOKEN_EXPIRED_ERROR: + iotx_http_context->is_authed = IOT_FALSE; + IOT_HTTP_DeviceNameAuth((iotx_http_t *)iotx_http_context); + case IOTX_HTTP_COMMON_ERROR: + case IOTX_HTTP_PARAM_ERROR: + case IOTX_HTTP_AUTH_CHECK_ERROR: + case IOTX_HTTP_TOKEN_NULL_ERROR: + case IOTX_HTTP_TOKEN_CHECK_ERROR: + case IOTX_HTTP_UPDATE_SESSION_ERROR: + case IOTX_HTTP_PUBLISH_MESSAGE_ERROR: + case IOTX_HTTP_REQUEST_TOO_MANY_ERROR: + default: + goto do_exit_pre; + } + + /* info.messageId */ + pvalue = HTTP_LITE_JSON_VALUE_OF("info.messageId", httpc_data.response_buf); + if (NULL == pvalue) { + http_err("messageId: NULL"); + goto do_exit_pre; + } + messageId = pvalue; + http_info("messageId: %s", messageId); + (void)messageId; + HTTP_API_FREE(pvalue); + pvalue = NULL; + + /* info.data */ + pvalue = HTTP_LITE_JSON_VALUE_OF("info.data", httpc_data.response_buf); + user_data = pvalue; + + /* Maybe NULL */ + if (user_data) { + http_info("user_data: %s", user_data); + } else { + http_info("user_data: %p", user_data); + } + if (NULL != pvalue) { + HTTP_API_FREE(pvalue); + } + pvalue = NULL; + + ret = 0; + +do_exit_pre: + + if (pvalue) { + HTTP_API_FREE(pvalue); + } + + if (httpc != NULL && httpc->header) { + HTTP_API_FREE(httpc->header); + } + +do_exit: + + return ret; +} + +void IOT_HTTP_Disconnect(void *handle) +{ + iotx_http_t *iotx_http_context; + if (NULL != (iotx_http_context = verify_iotx_http_context(handle))) { + httpclient_close(iotx_http_context->httpc); + } +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_api.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_api.c new file mode 100644 index 00000000..b03b01d9 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_api.c @@ -0,0 +1,1159 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include +#include +#include +#include + +#include "infra_defs.h" +#include "infra_types.h" +#include "infra_httpc.h" +#include "infra_sha1.h" +#include "infra_timer.h" +#include "infra_list.h" +#include "infra_log.h" + +#include "http2_internal.h" +#include "http2_api.h" +#include "http2_config.h" +#include "http2_wrapper.h" + +#include "wrappers_defs.h" + +#define URL_MAX_LEN (100) + +typedef enum { + NUM_STRING_ENUM = 0, + PATH_CREATE_STR_ENUM = 1, + PATH_UPLOAD_STR_ENUM = 2, + CID_STRING_ENUM = 3, + ORI_SIGN_STR_ENUM = 4, + FS_STRING_ENUM = 5, + REAL_SIGN_STR_ENUM = 6, +} HEADER_TYPE_ENUM; + + +typedef struct _device_info_struct_ { + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1]; + char url[URL_MAX_LEN + 1]; + int port; +} device_info; + +typedef struct { + unsigned int stream_id; /* http2 protocol stream id */ + char *channel_id; /* string return by server to identify a specific stream channel, different from stream identifier which is a field in http2 frame */ + stream_type_t stream_type; /* check @stream_type_t */ + void *semaphore; /* semaphore for http2 response sync */ + char status_code[5]; /* http2 response status code */ + uint8_t rcv_hd_cnt; /* the number of concerned heads received*/ + void *user_data; /* data passed to the stream callback function */ + http2_list_t list; /* list_head */ +} http2_stream_node_t; + +static device_info g_device_info; + +static stream_handle_t *g_stream_handle = NULL; +static httpclient_t g_client; + +static int _set_device_info(device_conn_info_t *device_info) +{ + memset(g_device_info.product_key, 0, IOTX_PRODUCT_KEY_LEN + 1); + memset(g_device_info.device_name, 0, IOTX_DEVICE_NAME_LEN + 1); + memset(g_device_info.device_secret, 0, IOTX_DEVICE_SECRET_LEN + 1); + memset(g_device_info.url, 0, URL_MAX_LEN + 1); + + strncpy(g_device_info.product_key, device_info->product_key, IOTX_PRODUCT_KEY_LEN); + strncpy(g_device_info.device_name, device_info->device_name, IOTX_DEVICE_NAME_LEN); + strncpy(g_device_info.device_secret, device_info->device_secret, IOTX_DEVICE_SECRET_LEN); + if (device_info->url != NULL) { + strncpy(g_device_info.url, device_info->url, URL_MAX_LEN); + } + g_device_info.port = device_info->port; + + return 0; +} + +static int http2_nv_copy(http2_header *nva, int start, http2_header *nva_copy, int num) +{ + int i, j; + for (i = start, j = 0; j < num; i++, j++) { + nva[i].name = nva_copy[j].name; + nva[i].value = nva_copy[j].value; + nva[i].namelen = nva_copy[j].namelen; + nva[i].valuelen = nva_copy[j].valuelen; + } + return i; +} + +static int iotx_http2_get_url(char *buf, char *productkey) +{ + if (strlen(g_device_info.url) != 0) { + strncpy(buf, g_device_info.url, URL_MAX_LEN); + return g_device_info.port; + } +#if defined(ON_DAILY) + sprintf(buf, "%s", "10.101.12.205"); + return 9999; +#elif defined(ON_PRE) + sprintf(buf, "%s", "100.67.141.158"); + return 8443; +#else + sprintf(buf, "%s", productkey); + strcat(buf, ".iot-as-http2.cn-shanghai.aliyuncs.com"); + return 443; +#endif +} + +static void file_upload_gen_string(char *str, int type, char *para1, int para2) +{ + switch (type) { + case NUM_STRING_ENUM: { + sprintf(str, "%d", para2); + break; + } + case PATH_CREATE_STR_ENUM: + case PATH_UPLOAD_STR_ENUM: + case ORI_SIGN_STR_ENUM: + case CID_STRING_ENUM: { + if (type == PATH_CREATE_STR_ENUM) { + sprintf(str, "/message/pub_with_resp/sys/%s/%s/thing/%s/create", + g_device_info.product_key, + g_device_info.device_name, + para1); + } else if (type == PATH_UPLOAD_STR_ENUM) { + sprintf(str, "/message/pub_with_resp/sys/%s/%s/thing/%s/upload", + g_device_info.product_key, + g_device_info.device_name, + para1); + } else if (type == ORI_SIGN_STR_ENUM) { + sprintf(str, "clientId%sdeviceName%sproductKey%s", + para1, + g_device_info.device_name, + g_device_info.product_key); + } else { + sprintf(str, "%s.%s", g_device_info.product_key, g_device_info.device_name); + } + break; + } + case REAL_SIGN_STR_ENUM: { + utils_hmac_sha1(para1, strlen(para1), str, g_device_info.device_secret, strlen(g_device_info.device_secret)); + break; + } + default: { + h2_err("ASSERT\n"); + break; + } + } +} + +static int http2_stream_node_search(stream_handle_t *handle, unsigned int stream_id, http2_stream_node_t **p_node) +{ + http2_stream_node_t *search_node = NULL; + *p_node = NULL; + + POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(p_node, NULL_VALUE_ERROR); + + list_for_each_entry(search_node, &handle->stream_list, list, http2_stream_node_t) { + if (search_node->stream_id == stream_id) { + *p_node = search_node; + return SUCCESS_RETURN; + } + } + + h2_debug("stream node not exist, stream_id = %d", stream_id); + return FAIL_RETURN; +} + +static void on_stream_header(int32_t stream_id, int cat, const uint8_t *name, uint32_t namelen, + const uint8_t *value, uint32_t valuelen, uint8_t flags) +{ + http2_stream_node_t *node = NULL; + char *channel_id = NULL; + char *user_data = NULL; + + if (g_stream_handle == NULL) { + return; + } + http2_stream_node_search(g_stream_handle, stream_id, &node); + if (node != NULL) { + channel_id = node->channel_id; + user_data = node->user_data; + + switch (cat) { + case 0x01: + if (strncmp((char *)name, "x-data-stream-id", (int)namelen) == 0) { + node->channel_id = HTTP2_STREAM_MALLOC(valuelen + 1); + if (node->channel_id == NULL) { + return; + } + memset(node->channel_id, 0, (int)valuelen + 1); + memcpy(node->channel_id, (char *)value, (int)valuelen); + if (++node->rcv_hd_cnt == 2) { + HAL_SemaphorePost(node->semaphore); + } + } +#ifdef FS_ENABLED + else if (strncmp((char *)name, "x-file-upload-id", (int)namelen) == 0) { + fs_rsp_header_val_t *rsp_data = (fs_rsp_header_val_t *)user_data; + memcpy(rsp_data->fs_upload_id, value, valuelen); + } + else if (strncmp((char *)name, "x-next-append-position", (int)namelen) == 0) { + fs_rsp_header_val_t *rsp_data = (fs_rsp_header_val_t *)user_data; + rsp_data->fs_offset = atoi((char *)value); + } + else if (strncmp((char *)name, "x-response-status", (int)namelen) == 0) { + strncpy(node->status_code, (char *)value, sizeof(node->status_code) - 1); + if (++node->rcv_hd_cnt == 2) { + HAL_SemaphorePost(node->semaphore); + } + } +#else + else if (strncmp((char *)name, ":status", (int)namelen) == 0) { + strncpy(node->status_code, (char *)value, sizeof(node->status_code) - 1); + if (++node->rcv_hd_cnt == 2) { + HAL_SemaphorePost(node->semaphore); + } + } +#endif + } + } + + if (g_stream_handle->cbs && g_stream_handle->cbs->on_stream_header_cb) { + g_stream_handle->cbs->on_stream_header_cb(stream_id, channel_id, cat, name, namelen, value, valuelen, + flags, user_data); + } +} + +static void on_stream_chunk_recv(int32_t stream_id, const uint8_t *data, uint32_t len, uint8_t flags) +{ + http2_stream_node_t *node; + char *channel_id = NULL; + char *user_data = NULL; + + if (g_stream_handle == NULL) { + return; + } + http2_stream_node_search(g_stream_handle, stream_id, &node); + if (node != NULL) { + channel_id = node->channel_id; + user_data = node->user_data; + } + + if (g_stream_handle->cbs && g_stream_handle->cbs->on_stream_chunk_recv_cb) { + g_stream_handle->cbs->on_stream_chunk_recv_cb(stream_id, channel_id, data, len, flags, user_data); + } +} + +static void on_stream_close(int32_t stream_id, uint32_t error_code) +{ + http2_stream_node_t *node; + char *channel_id = NULL; + char *user_data = NULL; + + if (g_stream_handle == NULL) { + return; + } + http2_stream_node_search(g_stream_handle, stream_id, &node); + if (node != NULL) { + channel_id = node->channel_id; + user_data = node->user_data; + } + if (g_stream_handle->cbs && g_stream_handle->cbs->on_stream_close_cb) { + g_stream_handle->cbs->on_stream_close_cb(stream_id, channel_id, error_code, user_data); + } +} + +static void on_stream_frame_send(int32_t stream_id, int type, uint8_t flags) +{ + http2_stream_node_t *node; + char *channel_id = NULL; + char *user_data = NULL; + + if (g_stream_handle == NULL) { + return; + } + http2_stream_node_search(g_stream_handle, stream_id, &node); + if (node != NULL) { + channel_id = node->channel_id; + user_data = node->user_data; + } + if (g_stream_handle->cbs && g_stream_handle->cbs->on_stream_frame_send_cb) { + g_stream_handle->cbs->on_stream_frame_send_cb(stream_id, channel_id, type, flags, user_data); + } +} + +static void on_stream_frame_recv(int32_t stream_id, int type, uint8_t flags) +{ + http2_stream_node_t *node; + char *channel_id = NULL; + char *user_data = NULL; + if (g_stream_handle == NULL) { + return; + } + http2_stream_node_search(g_stream_handle, stream_id, &node); + if (node != NULL) { + channel_id = node->channel_id; + user_data = node->user_data; + } + + if (g_stream_handle->cbs && g_stream_handle->cbs->on_stream_frame_recv_cb) { + g_stream_handle->cbs->on_stream_frame_recv_cb(stream_id, channel_id, type, flags, user_data); + } +} + +static http2_user_cb_t my_cb = { + .on_user_header_cb = on_stream_header, + .on_user_chunk_recv_cb = on_stream_chunk_recv, + .on_user_stream_close_cb = on_stream_close, + .on_user_frame_send_cb = on_stream_frame_send, + .on_user_frame_recv_cb = on_stream_frame_recv, +}; + +static int reconnect(stream_handle_t *handle) +{ + char buf[100] = {0}; + http2_connection_t *conn = NULL; + int port = 0; + + iotx_http2_client_disconnect(handle->http2_connect); + handle->http2_connect = NULL; + port = iotx_http2_get_url(buf, g_device_info.product_key); + conn = iotx_http2_client_connect_with_cb((void *)&g_client, buf, port, &my_cb); + if (conn == NULL) { + return -1; + } + handle->http2_connect = conn; + return 0; +} + +static void *http2_io(void *user_data) +{ + stream_handle_t *handle = (stream_handle_t *)user_data; + int rv = 0; + iotx_time_t timer, timer_rsp; + static uint8_t timer_valid = 0; + POINTER_SANITY_CHECK(handle, NULL); + iotx_time_init(&timer); + iotx_time_init(&timer_rsp); + while (handle->init_state) { + if (handle->connect_state) { + HAL_MutexLock(handle->mutex); + rv = iotx_http2_exec_io(handle->http2_connect); + HAL_MutexUnlock(handle->mutex); + } + if (utils_time_is_expired(&timer)) { + HAL_MutexLock(handle->mutex); + rv = iotx_http2_client_send_ping(handle->http2_connect); + HAL_MutexUnlock(handle->mutex); + utils_time_countdown_ms(&timer, IOT_HTTP2_KEEP_ALIVE_TIME); + if (rv >= 0) { + utils_time_countdown_ms(&timer_rsp, 3000); + timer_valid = 1; + } + } + + if (timer_valid && utils_time_is_expired(&timer_rsp)) { + timer_valid = 0; + rv = iotx_http2_client_recv_ping(); + } + + if (rv < 0) { + if (handle->retry_cnt == IOT_HTTP2_KEEP_ALIVE_CNT - 1) { + h2_info("rv =%d, try reconnect\n", rv); + if (handle->connect_state != 0) { + handle->connect_state = 0; + if (handle->cbs && handle->cbs->on_disconnect_cb) { + handle->cbs->on_disconnect_cb(); + } + } + rv = reconnect(handle); + continue; + } else { + handle->retry_cnt++; + } + } else { + if (handle->connect_state == 0) { + handle->connect_state = 1; + handle->retry_cnt = 0; + if (handle->cbs && handle->cbs->on_reconnect_cb) { + handle->cbs->on_reconnect_cb(); + } + } + } + HAL_SleepMs(100); + } + HAL_SemaphorePost(handle->semaphore); + + return NULL; +} + +static int http2_stream_node_insert(stream_handle_t *handle, unsigned int id, void *user_data, + http2_stream_node_t **p_node) +{ + http2_stream_node_t *node = NULL; + void *semaphore = NULL; + + POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR); + + ARGUMENT_SANITY_CHECK(id != 0, FAIL_RETURN); + + if (p_node != NULL) { + *p_node = NULL; + } + + node = (http2_stream_node_t *)HTTP2_STREAM_MALLOC(sizeof(http2_stream_node_t)); + if (node == NULL) { + return FAIL_RETURN; + } + + memset(node, 0, sizeof(http2_stream_node_t)); + node->stream_id = id; + node->user_data = user_data; + semaphore = HAL_SemaphoreCreate(); + if (semaphore == NULL) { + HTTP2_STREAM_FREE(node); + return FAIL_RETURN; + } + node->semaphore = semaphore; + + INIT_LIST_HEAD((list_head_t *)&node->list); + list_add((list_head_t *)&node->list, (list_head_t *)&handle->stream_list); + + if (p_node != NULL) { + *p_node = node; + } + + return SUCCESS_RETURN; +} + +static int http2_stream_node_remove(stream_handle_t *handle, unsigned int id) +{ + http2_stream_node_t *search_node; + + POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR); + ARGUMENT_SANITY_CHECK(id != 0, FAIL_RETURN); + + list_for_each_entry(search_node, &handle->stream_list, list, http2_stream_node_t) { + if (id == search_node->stream_id) { + h2_info("stream_node found, delete\n"); + + list_del((list_head_t *)&search_node->list); + HTTP2_STREAM_FREE(search_node->channel_id); + HAL_SemaphoreDestroy(search_node->semaphore); + HTTP2_STREAM_FREE(search_node); + return SUCCESS_RETURN; + } + } + return FAIL_RETURN; +} + +static int get_version_int() +{ + const char *p_version = IOTX_SDK_VERSION; + int v_int = 0; + + while (*p_version != 0) { + if (*p_version <= '9' && *p_version >= '0') { + v_int = v_int * 10 + *p_version - '0'; + } + p_version ++; + } + return v_int; +} + +void *IOT_HTTP2_Connect(device_conn_info_t *conn_info, http2_stream_cb_t *user_cb) +{ + stream_handle_t *stream_handle = NULL; + http2_connection_t *conn = NULL; + hal_os_thread_param_t thread_parms = {0}; + char buf[URL_MAX_LEN + 1] = {0}; + int port = 0; + int ret = 0; + + POINTER_SANITY_CHECK(conn_info, NULL); + POINTER_SANITY_CHECK(conn_info->product_key, NULL); + POINTER_SANITY_CHECK(conn_info->device_name, NULL); + POINTER_SANITY_CHECK(conn_info->device_secret, NULL); + + memset(&g_client, 0, sizeof(httpclient_t)); + + stream_handle = HTTP2_STREAM_MALLOC(sizeof(stream_handle_t)); + if (stream_handle == NULL) { + return NULL; + } + + memset(stream_handle, 0, sizeof(stream_handle_t)); + stream_handle->mutex = HAL_MutexCreate(); + if (stream_handle->mutex == NULL) { + HTTP2_STREAM_FREE(stream_handle); + h2_err("mutex create error\n"); + return NULL; + } + stream_handle->semaphore = HAL_SemaphoreCreate(); + if (stream_handle->semaphore == NULL) { + h2_err("semaphore create error\n"); + HAL_MutexDestroy(stream_handle->mutex); + HTTP2_STREAM_FREE(stream_handle); + return NULL; + } + + INIT_LIST_HEAD((list_head_t *) & (stream_handle->stream_list)); + + _set_device_info(conn_info); + g_stream_handle = stream_handle; + g_stream_handle->cbs = user_cb; + + port = iotx_http2_get_url(buf, conn_info->product_key); + conn = iotx_http2_client_connect_with_cb((void *)&g_client, buf, port, &my_cb); + if (conn == NULL) { + HAL_MutexDestroy(stream_handle->mutex); + HAL_SemaphoreDestroy(stream_handle->semaphore); + HTTP2_STREAM_FREE(stream_handle); + return NULL; + } + stream_handle->http2_connect = conn; + stream_handle->init_state = 1; + + thread_parms.stack_size = 6144; + thread_parms.name = "http2_io"; + ret = HAL_ThreadCreate(&stream_handle->rw_thread, http2_io, stream_handle, &thread_parms, NULL); + if (ret != 0) { + h2_err("thread create error\n"); + IOT_HTTP2_Disconnect(stream_handle); + return NULL; + } + HAL_ThreadDetach(stream_handle->rw_thread); + + return stream_handle; +} + +int IOT_HTTP2_Stream_Open(void *hd, stream_data_info_t *info, header_ext_info_t *header) +{ + char client_id[64 + 1] = {0}; + char sign_str[256 + 1] = {0}; + char sign[41 + 1] = {0}; + char path[128] = {0}; + char version[33] = {0}; + int header_count = 0; + int header_num; + int rv = 0; + http2_data h2_data; + http2_stream_node_t *node = NULL; + stream_handle_t *handle = (stream_handle_t *)hd; + http2_header *nva = NULL; + + POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(info, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(info->identify, NULL_VALUE_ERROR); + + + memset(&h2_data, 0, sizeof(http2_data)); + + HAL_Snprintf(path, sizeof(path), "/stream/open/%s", info->identify); + + file_upload_gen_string(client_id, CID_STRING_ENUM, NULL, 0); + file_upload_gen_string(sign_str, ORI_SIGN_STR_ENUM, client_id, 0); + file_upload_gen_string(sign, REAL_SIGN_STR_ENUM, sign_str, 0); + + HAL_Snprintf(version, sizeof(version), "%d", get_version_int()); + + { + const http2_header static_header[] = { MAKE_HEADER(":method", "POST"), + MAKE_HEADER_CS(":path", path), + MAKE_HEADER(":scheme", "https"), + MAKE_HEADER("x-auth-name", "devicename"), + MAKE_HEADER_CS("x-auth-param-client-id", client_id), + MAKE_HEADER("x-auth-param-signmethod", "hmacsha1"), + MAKE_HEADER_CS("x-auth-param-product-key", g_device_info.product_key), + MAKE_HEADER_CS("x-auth-param-device-name", g_device_info.device_name), + MAKE_HEADER_CS("x-auth-param-sign", sign), + MAKE_HEADER_CS("x-sdk-version", version), + MAKE_HEADER_CS("x-sdk-version-name", IOTX_SDK_VERSION), + MAKE_HEADER("x-sdk-platform", "c"), + MAKE_HEADER("content-length", "0"), + }; + + header_num = sizeof(static_header) / sizeof(static_header[0]); + if (header != NULL) { + header_num += header->num; + } + nva = (http2_header *)HTTP2_STREAM_MALLOC(sizeof(http2_header) * header_num); + if (nva == NULL) { + h2_err("nva malloc failed\n"); + return FAIL_RETURN; + } + + /* add external header if it's not NULL */ + header_count = http2_nv_copy(nva, 0, (http2_header *)static_header, sizeof(static_header) / sizeof(static_header[0])); + if (header != NULL) { + header_count = http2_nv_copy(nva, header_count, (http2_header *)header->nva, header->num); + } + + h2_data.header = (http2_header *)nva; + h2_data.header_count = header_count; + h2_data.data = NULL; + h2_data.len = 0; + h2_data.flag = 1 ; + h2_data.stream_id = 0; + + HAL_MutexLock(handle->mutex); + rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data); + http2_stream_node_insert(handle, h2_data.stream_id, info->user_data, &node); + HTTP2_STREAM_FREE(nva); + } + + if (rv < 0) { + h2_err("client send error\n"); + HAL_MutexUnlock(handle->mutex); + return FAIL_RETURN; + } + + if (node == NULL) { + h2_err("node insert failed!"); + HAL_MutexUnlock(handle->mutex); + return FAIL_RETURN; + } + + node->stream_type = STREAM_TYPE_AUXILIARY; + HAL_MutexUnlock(handle->mutex); + + rv = HAL_SemaphoreWait(node->semaphore, IOT_HTTP2_RES_OVERTIME_MS); + if (rv < 0 || memcmp(node->status_code, "200", 3)) { + h2_err("semaphore wait overtime or status code error\n"); + HAL_MutexLock(handle->mutex); + http2_stream_node_remove(handle, node->stream_id); + HAL_MutexUnlock(handle->mutex); + return FAIL_RETURN; + } + info->channel_id = HTTP2_STREAM_MALLOC(strlen(node->channel_id) + 1); + if (info->channel_id == NULL) { + h2_err("channel_id malloc failed\n"); + HAL_MutexLock(handle->mutex); + http2_stream_node_remove(handle, node->stream_id); + HAL_MutexUnlock(handle->mutex); + return FAIL_RETURN; + } + memset(info->channel_id, 0, strlen(node->channel_id) + 1); + strcpy(info->channel_id, node->channel_id); + + return SUCCESS_RETURN; +} + +int IOT_HTTP2_Stream_Send_Message(void *hd, const char *identify,char *channel_id, char *data, uint32_t data_len, header_ext_info_t *header) +{ + int rv = 0; + http2_data h2_data; + char path[128] = {0}; + char data_len_str[33] = {0}; + int windows_size; + int count = 0; + stream_handle_t *handle = (stream_handle_t *)hd; + http2_header *nva = NULL; + int header_count, header_num; + char version[33] = {0}; + POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(identify, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(channel_id, NULL_VALUE_ERROR); + + windows_size = iotx_http2_get_available_window_size(handle->http2_connect); + while (windows_size < data_len) { + h2_warning("windows_size < info->packet_len ,wait ...\n"); + HAL_SleepMs(100); + if (++count > 50) { + return FAIL_RETURN; + } + windows_size = iotx_http2_get_available_window_size(handle->http2_connect); + } + + HAL_Snprintf(data_len_str, sizeof(data_len_str), "%d", data_len); + HAL_Snprintf(path, sizeof(path), "/stream/send/%s", identify); + HAL_Snprintf(version, sizeof(version), "%d", get_version_int()); + + { + const http2_header static_header[] = { MAKE_HEADER(":method", "POST"), + MAKE_HEADER_CS(":path", path), + MAKE_HEADER(":scheme", "https"), + MAKE_HEADER_CS("content-length", data_len_str), + MAKE_HEADER_CS("x-data-stream-id", channel_id), + MAKE_HEADER_CS("x-sdk-version", version), + MAKE_HEADER_CS("x-sdk-version-name", IOTX_SDK_VERSION), + MAKE_HEADER("x-sdk-platform", "c"), + }; + + header_num = sizeof(static_header) / sizeof(static_header[0]); + if (header != NULL) { + header_num += header->num; + } + nva = (http2_header *)HTTP2_STREAM_MALLOC(sizeof(http2_header) * header_num); + if (nva == NULL) { + h2_err("nva malloc failed\n"); + return FAIL_RETURN; + } + + /* add external header if it's not NULL */ + header_count = http2_nv_copy(nva, 0, (http2_header *)static_header, sizeof(static_header) / sizeof(static_header[0])); + if (header != NULL) { + header_count = http2_nv_copy(nva, header_count, (http2_header *)header->nva, header->num); + } + memset(&h2_data, 0, sizeof(h2_data)); + h2_data.header = (http2_header *)nva; + h2_data.header_count = header_count; + h2_data.data = data; + h2_data.len = data_len; + h2_data.flag = 1; + + HAL_MutexLock(handle->mutex); + rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data); + HAL_MutexUnlock(handle->mutex); + HTTP2_STREAM_FREE(nva); + } + + if (rv < 0) { + h2_err("send failed!"); + return rv; + } + + return h2_data.stream_id; +} + +int IOT_HTTP2_Stream_Send(void *hd, stream_data_info_t *info, header_ext_info_t *header) +{ + int rv = 0; + http2_data h2_data; + char path[128] = {0}; + char data_len_str[33] = {0}; + int windows_size; + int count = 0; + http2_stream_node_t *node = NULL; + stream_handle_t *handle = (stream_handle_t *)hd; + http2_header *nva = NULL; + + POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(info, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(info->stream, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(info->channel_id, NULL_VALUE_ERROR); + ARGUMENT_SANITY_CHECK(info->stream_len != 0, FAIL_RETURN); + ARGUMENT_SANITY_CHECK(info->packet_len != 0, FAIL_RETURN); + + windows_size = iotx_http2_get_available_window_size(handle->http2_connect); + while (windows_size < info->packet_len) { + h2_warning("windows_size < info->packet_len ,wait ...\n"); + HAL_SleepMs(100); + if (++count > 50) { + return FAIL_RETURN; + } + windows_size = iotx_http2_get_available_window_size(handle->http2_connect); + } + + HAL_Snprintf(data_len_str, sizeof(data_len_str), "%d", info->stream_len); + HAL_Snprintf(path, sizeof(path), "/stream/send/%s", info->identify); + if (info->send_len == 0) { /* first send,need header */ + int header_count, header_num; + char version[33] = {0}; + HAL_Snprintf(version, sizeof(version), "%d", get_version_int()); + { + const http2_header static_header[] = { MAKE_HEADER(":method", "POST"), + MAKE_HEADER_CS(":path", path), + MAKE_HEADER(":scheme", "https"), + MAKE_HEADER_CS("content-length", data_len_str), + MAKE_HEADER_CS("x-data-stream-id", info->channel_id), + MAKE_HEADER_CS("x-sdk-version", version), + MAKE_HEADER_CS("x-sdk-version-name", IOTX_SDK_VERSION), + MAKE_HEADER("x-sdk-platform", "c"), + }; + + header_num = sizeof(static_header) / sizeof(static_header[0]); + if (header != NULL) { + header_num += header->num; + } + nva = (http2_header *)HTTP2_STREAM_MALLOC(sizeof(http2_header) * header_num); + if (nva == NULL) { + h2_err("nva malloc failed\n"); + return FAIL_RETURN; + } + + /* add external header if it's not NULL */ + header_count = http2_nv_copy(nva, 0, (http2_header *)static_header, sizeof(static_header) / sizeof(static_header[0])); + if (header != NULL) { + header_count = http2_nv_copy(nva, header_count, (http2_header *)header->nva, header->num); + } + memset(&h2_data, 0, sizeof(h2_data)); + h2_data.header = (http2_header *)nva; + h2_data.header_count = header_count; + h2_data.data = info->stream; + h2_data.len = info->packet_len; /* TODO */ + + if (info->packet_len + info->send_len == info->stream_len) { /* last frame */ + h2_data.flag = 1; + } else { + h2_data.flag = 0; + } + + HAL_MutexLock(handle->mutex); + rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data); + http2_stream_node_insert(handle, h2_data.stream_id, info->user_data, &node); + HTTP2_STREAM_FREE(nva); + } + + if (rv < 0) { + h2_err("send failed!"); + HAL_MutexUnlock(handle->mutex); + return FAIL_RETURN; + } + + if (node == NULL) { + h2_err("node insert failed!"); + HAL_MutexUnlock(handle->mutex); + return FAIL_RETURN; + } + + node->stream_type = STREAM_TYPE_UPLOAD; + HAL_MutexUnlock(handle->mutex); + + info->h2_stream_id = h2_data.stream_id; + info->send_len += info->packet_len; + } else { + h2_data.header = NULL; + h2_data.header_count = 0; + h2_data.data = info->stream; + h2_data.len = info->packet_len; + + h2_data.stream_id = info->h2_stream_id; + if (info->packet_len + info->send_len == info->stream_len) { /* last frame */ + h2_data.flag = 1; + } else { + h2_data.flag = 0; + } + + HAL_MutexLock(handle->mutex); + rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data); + HAL_MutexUnlock(handle->mutex); + if (rv < 0) { + return FAIL_RETURN; + } + info->send_len += info->packet_len; + } + + if (h2_data.flag == 1) { + http2_stream_node_t *node = NULL; + HAL_MutexLock(handle->mutex); + http2_stream_node_search(handle, h2_data.stream_id, &node); + HAL_MutexUnlock(handle->mutex); + if (node == NULL) { + h2_err("node search failed!"); + return FAIL_RETURN; + } + rv = HAL_SemaphoreWait(node->semaphore, IOT_HTTP2_RES_OVERTIME_MS); + if (rv < 0 || memcmp(node->status_code, "200", 3)) { + h2_err("semaphore wait overtime or status code error,h2_data.stream_id %d\n", h2_data.stream_id); + HAL_MutexLock(handle->mutex); + http2_stream_node_remove(handle, node->stream_id); + HAL_MutexUnlock(handle->mutex); + return FAIL_RETURN; + } + } + + return rv; +} + +int IOT_HTTP2_Stream_Query(void *hd, stream_data_info_t *info, header_ext_info_t *header) +{ + int rv = 0; + http2_data h2_data; + http2_stream_node_t *node = NULL; + char path[128] = {0}; + int header_count, header_num; + stream_handle_t *handle = (stream_handle_t *)hd; + http2_header *nva = NULL; + char version[33] = {0}; + + POINTER_SANITY_CHECK(info, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(info->channel_id, NULL_VALUE_ERROR); + HAL_Snprintf(version, sizeof(version), "%d", get_version_int()); + HAL_Snprintf(path, sizeof(path), "/stream/send/%s", info->identify); + { + const http2_header static_header[] = { MAKE_HEADER(":method", "GET"), + MAKE_HEADER_CS(":path", path), + MAKE_HEADER(":scheme", "https"), + MAKE_HEADER_CS("x-data-stream-id", info->channel_id), + MAKE_HEADER("x-test-downstream", "1"), + MAKE_HEADER_CS("x-sdk-version", version), + MAKE_HEADER_CS("x-sdk-version-name", IOTX_SDK_VERSION), + MAKE_HEADER("x-sdk-platform", "c"), + }; + + header_num = sizeof(static_header) / sizeof(static_header[0]); + if (header != NULL) { + header_num += header->num; + } + nva = (http2_header *)HTTP2_STREAM_MALLOC(sizeof(http2_header) * header_num); + if (nva == NULL) { + h2_err("nva malloc failed\n"); + return FAIL_RETURN; + } + + /* add external header if it's not NULL */ + header_count = http2_nv_copy(nva, 0, (http2_header *)static_header, sizeof(static_header) / sizeof(static_header[0])); + if (header != NULL) { + header_count = http2_nv_copy(nva, header_count, (http2_header *)header->nva, header->num); + } + h2_data.header = (http2_header *)nva; + h2_data.header_count = header_count; + h2_data.data = NULL; + h2_data.len = 0; + h2_data.flag = 1; + h2_data.stream_id = 0; + + HAL_MutexLock(handle->mutex); + rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data); + http2_stream_node_insert(handle, h2_data.stream_id, info->user_data, &node); + HTTP2_STREAM_FREE(nva); + } + + if (rv < 0) { + h2_err("client send error\n"); + HAL_MutexUnlock(handle->mutex); + return rv; + } + + if (node == NULL) { + h2_err("node insert failed!"); + HAL_MutexUnlock(handle->mutex); + return FAIL_RETURN; + } + + node->stream_type = STREAM_TYPE_DOWNLOAD; + HAL_MutexUnlock(handle->mutex); + + rv = HAL_SemaphoreWait(node->semaphore, IOT_HTTP2_RES_OVERTIME_MS); + if (rv < 0 || memcmp(node->status_code, "200", 3)) { + h2_err("semaphore wait overtime or status code error\n"); + HAL_MutexLock(handle->mutex); + http2_stream_node_remove(handle, node->stream_id); + HAL_MutexUnlock(handle->mutex); + return FAIL_RETURN; + } + + return rv; +} + +#ifdef FS_ENABLED +int IOT_HTTP2_FS_Close(void *hd, stream_data_info_t *info, header_ext_info_t *header) +{ + int rv = 0; + http2_data h2_data; + char path[128] = {0}; + stream_handle_t *handle = (stream_handle_t *)hd; + char version[33] = {0}; + char *stream_id = info->channel_id; + int len = strlen(stream_id); + http2_stream_node_t *node, *next; + http2_header *nva = NULL; + int header_count, header_num; + + POINTER_SANITY_CHECK(info, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(info->channel_id, NULL_VALUE_ERROR); + HAL_Snprintf(version, sizeof(version), "%d", get_version_int()); + HAL_Snprintf(path, sizeof(path), "/stream/close/%s", info->identify); + { + const http2_header static_header[] = { MAKE_HEADER(":method", "POST"), + MAKE_HEADER_CS(":path", path), + MAKE_HEADER(":scheme", "https"), + MAKE_HEADER_CS("x-data-stream-id", info->channel_id), + MAKE_HEADER_CS("x-sdk-version", version), + MAKE_HEADER_CS("x-sdk-version-name", IOTX_SDK_VERSION), + MAKE_HEADER("x-sdk-platform", "c"), + }; + + header_num = sizeof(static_header) / sizeof(static_header[0]); + if (header != NULL) { + header_num += header->num; + } + nva = (http2_header *)HTTP2_STREAM_MALLOC(sizeof(http2_header) * header_num); + if (nva == NULL) { + h2_err("nva malloc failed\n"); + HTTP2_STREAM_FREE(info->channel_id); + return FAIL_RETURN; + } + + /* add external header if it's not NULL */ + header_count = http2_nv_copy(nva, 0, (http2_header *)static_header, sizeof(static_header) / sizeof(static_header[0])); + if (header != NULL) { + header_count = http2_nv_copy(nva, header_count, (http2_header *)header->nva, header->num); + } + + header_count = sizeof(static_header) / sizeof(static_header[0]); + h2_data.header = (http2_header *)static_header; + h2_data.header_count = header_count; + h2_data.data = NULL; + h2_data.len = 0; + h2_data.flag = 1; + h2_data.stream_id = 0; + + HAL_MutexLock(handle->mutex); + if(info->send_len < info->stream_len) { + iotx_http2_reset_stream(handle->http2_connect,info->h2_stream_id); + } + rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data); + http2_stream_node_insert(handle, h2_data.stream_id, info->user_data, &node); + HTTP2_STREAM_FREE(nva); + } + + if (rv < 0) { + h2_err("client send error\n"); + HAL_MutexUnlock(handle->mutex); + HTTP2_STREAM_FREE(info->channel_id); + return rv; + } + + if (node == NULL) { + h2_err("node insert failed!"); + HAL_MutexUnlock(handle->mutex); + HTTP2_STREAM_FREE(info->channel_id); + return FAIL_RETURN; + } + + node->stream_type = STREAM_TYPE_AUXILIARY; + HAL_MutexUnlock(handle->mutex); + + rv = HAL_SemaphoreWait(node->semaphore, IOT_HTTP2_RES_OVERTIME_MS); + if (rv < 0 || memcmp(node->status_code, "200", 3)) { + h2_err("semaphore wait overtime or status code error\n"); + } + + /* just delete stream node */ + HAL_MutexLock(handle->mutex); + list_for_each_entry_safe(node, next, &handle->stream_list, list, http2_stream_node_t) { + if (info->h2_stream_id == node->stream_id) { + h2_info("stream_node found:stream_id= %d, Delete It", node->stream_id); + list_del((list_head_t *)&node->list); + HTTP2_STREAM_FREE(node->channel_id); + HAL_SemaphoreDestroy(node->semaphore); + HTTP2_STREAM_FREE(node); + continue; + } + if ((node->channel_id != NULL) && (stream_id != NULL) && + (len == strlen(node->channel_id) && !strncmp(node->channel_id, stream_id, len))) { + list_del((list_head_t *)&node->list); + HTTP2_STREAM_FREE(node->channel_id); + HAL_SemaphoreDestroy(node->semaphore); + HTTP2_STREAM_FREE(node); + } + } + HTTP2_STREAM_FREE(info->channel_id); + info->channel_id = NULL; + HAL_MutexUnlock(handle->mutex); + + return rv; +} +#endif /* #ifdef FS_ENABLED */ + +int IOT_HTTP2_Stream_Close(void *hd, stream_data_info_t *info) +{ + int rv = 0; + http2_data h2_data; + char path[128] = {0}; + stream_handle_t *handle = (stream_handle_t *)hd; + char version[33] = {0}; + char *stream_id = info->channel_id; + int len = strlen(stream_id); + http2_stream_node_t *node, *next; + + POINTER_SANITY_CHECK(info, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR); + POINTER_SANITY_CHECK(info->channel_id, NULL_VALUE_ERROR); + HAL_Snprintf(version, sizeof(version), "%d", get_version_int()); + HAL_Snprintf(path, sizeof(path), "/stream/close/%s", info->identify); + { + const http2_header static_header[] = { MAKE_HEADER(":method", "POST"), + MAKE_HEADER_CS(":path", path), + MAKE_HEADER(":scheme", "https"), + MAKE_HEADER_CS("x-data-stream-id", info->channel_id), + MAKE_HEADER_CS("x-sdk-version", version), + MAKE_HEADER_CS("x-sdk-version-name", IOTX_SDK_VERSION), + MAKE_HEADER("x-sdk-platform", "c"), + }; + + int header_count = sizeof(static_header) / sizeof(static_header[0]); + h2_data.header = (http2_header *)static_header; + h2_data.header_count = header_count; + h2_data.data = NULL; + h2_data.len = 0; + h2_data.flag = 1; + h2_data.stream_id = 0; + + HAL_MutexLock(handle->mutex); + if(info->send_len < info->stream_len) + iotx_http2_reset_stream(handle->http2_connect,info->h2_stream_id); + rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data); + HAL_MutexUnlock(handle->mutex); + } + + if (rv < 0) { + h2_warning("client send error\n"); + } + + /* just delete stream node */ + HAL_MutexLock(handle->mutex); + list_for_each_entry_safe(node, next, &handle->stream_list, list, http2_stream_node_t) { + if (info->h2_stream_id == node->stream_id) { + h2_info("stream_node found:stream_id= %d, Delete It", node->stream_id); + list_del((list_head_t *)&node->list); + HTTP2_STREAM_FREE(node->channel_id); + HAL_SemaphoreDestroy(node->semaphore); + HTTP2_STREAM_FREE(node); + continue; + } + if ((node->channel_id != NULL) && (stream_id != NULL) && + (len == strlen(node->channel_id) && !strncmp(node->channel_id, stream_id, len))) { + list_del((list_head_t *)&node->list); + HTTP2_STREAM_FREE(node->channel_id); + HAL_SemaphoreDestroy(node->semaphore); + HTTP2_STREAM_FREE(node); + } + } + HTTP2_STREAM_FREE(info->channel_id); + info->channel_id = NULL; + HAL_MutexUnlock(handle->mutex); + return rv; +} + +int IOT_HTTP2_Disconnect(void *hd) +{ + int ret; + stream_handle_t *handle = (stream_handle_t *)hd; + http2_stream_node_t *node, *next; + + POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR); + handle->init_state = 0; + + ret = HAL_SemaphoreWait(handle->semaphore, PLATFORM_WAIT_INFINITE); + if (ret < 0) { + h2_err("semaphore wait err\n"); + return FAIL_RETURN; + } + + HAL_MutexLock(handle->mutex); + list_for_each_entry_safe(node, next, &handle->stream_list, list, http2_stream_node_t) { + list_del((list_head_t *)&node->list); + HTTP2_STREAM_FREE(node->channel_id); + HAL_SemaphoreDestroy(node->semaphore); + HTTP2_STREAM_FREE(node); + } + HAL_MutexUnlock(handle->mutex); + g_stream_handle = NULL; + + HAL_MutexDestroy(handle->mutex); + HAL_SemaphoreDestroy(handle->semaphore); + + ret = iotx_http2_client_disconnect(handle->http2_connect); + HTTP2_STREAM_FREE(handle); + return ret; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_api.h new file mode 100644 index 00000000..55fd4fee --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_api.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef IOT_EXPORT_HTTP2_STREAM_H +#define IOT_EXPORT_HTTP2_STREAM_H + +#include "infra_types.h" +#include "infra_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IOT_HTTP2_RES_OVERTIME_MS (10000) +#define IOT_HTTP2_KEEP_ALIVE_CNT (1) +#define IOT_HTTP2_KEEP_ALIVE_TIME (30*1000) /* in seconds */ + +#define MAKE_HEADER(NAME, VALUE) \ + { \ + (char *) NAME, (char *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1 \ + } + +#define MAKE_HEADER_CS(NAME, VALUE) \ + { \ + (char *) NAME, (char *)VALUE, strlen(NAME) , strlen(VALUE) \ + } + +typedef struct { + char *product_key; + char *device_name; + char *device_secret; + char *url; + int port; +} device_conn_info_t; + +typedef struct http2_header_struct { + char *name; /* header name */ + char *value; /* the value of name */ + int namelen; /* the length of header name */ + int valuelen; /* the length of value */ +} http2_header; + +typedef struct { + http2_header *nva; + int num; +} header_ext_info_t; + +typedef enum { + STREAM_TYPE_DOWNLOAD, + STREAM_TYPE_UPLOAD, + STREAM_TYPE_AUXILIARY, + STREAM_TYPE_NUM +} stream_type_t; + +typedef void (*on_stream_header_callback)(uint32_t stream_id, char *channel_id, int cat, const uint8_t *name, + uint32_t namelen, const uint8_t *value, uint32_t valuelen, uint8_t flags, void *user_data); + +typedef void (*on_stream_chunk_recv_callback)(uint32_t stream_id, char *channel_id, + const uint8_t *data, uint32_t len, uint8_t flags, void *user_data); + +typedef void (*on_stream_close_callback)(uint32_t stream_id, char *channel_id, uint32_t error_code, void *user_data); + +typedef void (*on_stream_frame_send_callback)(uint32_t stream_id, char *channel_id, int type, uint8_t flags, void *user_data); + +typedef void (*on_stream_frame_recv_callback)(uint32_t stream_id, char *channel_id, int type, uint8_t flags,void *user_data); + +typedef void (*on_reconnect_callback)(); +typedef void (*on_disconnect_callback)(); + +typedef struct { + on_stream_header_callback on_stream_header_cb; + on_stream_chunk_recv_callback on_stream_chunk_recv_cb; + on_stream_close_callback on_stream_close_cb; + on_stream_frame_send_callback on_stream_frame_send_cb; + on_stream_frame_recv_callback on_stream_frame_recv_cb; + on_reconnect_callback on_reconnect_cb; + on_disconnect_callback on_disconnect_cb; +} http2_stream_cb_t; + +typedef struct { + char *stream; /* point to stream data buffer */ + uint32_t stream_len; /* file content length */ + uint32_t send_len; /* data had sent length */ + uint32_t packet_len; /* one packet length */ + const char *identify; /* path string to identify a stream service */ + int h2_stream_id; /* stream identifier which is a field in HTTP2 frame */ + char *channel_id; /* string return by server to identify a specific stream channel, + different from stream identifier which is a field in HTTP2 frame */ + void *user_data; /* user data brought in at stream open */ +} stream_data_info_t; + +DLL_IOT_API void *IOT_HTTP2_Connect(device_conn_info_t *conn_info, http2_stream_cb_t *user_cb); +DLL_IOT_API int IOT_HTTP2_Stream_Open(void *handle, stream_data_info_t *info, header_ext_info_t *header); +DLL_IOT_API int IOT_HTTP2_Stream_Send(void *handle, stream_data_info_t *info, header_ext_info_t *header); +DLL_IOT_API int IOT_HTTP2_Stream_Query(void *handle, stream_data_info_t *info, header_ext_info_t *header); +DLL_IOT_API int IOT_HTTP2_Stream_Close(void *handle, stream_data_info_t *info); +DLL_IOT_API int IOT_HTTP2_Stream_Send_Message(void *handle, const char *identify,char *channel_id, char *data, + uint32_t data_len, header_ext_info_t *header); +DLL_IOT_API int IOT_HTTP2_Disconnect(void *handle); + +#ifdef __cplusplus +} +#endif + +#endif /* IOT_EXPORT_FILE_UPLOADER_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_config.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_config.h new file mode 100644 index 00000000..d1bc5d38 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_config.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _HTTP2_CONFIG_H +#define _HTTP2_CONFIG_H + +/* maximum packet len in one http2 frame */ +#ifndef FS_UPLOAD_PACKET_LEN +#define FS_UPLOAD_PACKET_LEN 10240 /* must < 16384 */ +#endif + +/* maximum content len of the http2 request */ +#ifndef FS_UPLOAD_PART_LEN +#define FS_UPLOAD_PART_LEN (1024 * 1024 * 4) /* 100KB ~ 100MB */ +#endif + + +#endif /* #ifdef _HTTP2_CONFIG_H */ + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_internal.h new file mode 100644 index 00000000..0b97aa38 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_internal.h @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef IOT_EXPORT_HTTP2_H +#define IOT_EXPORT_HTTP2_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "http2_api.h" +#include "http2_wrapper.h" + +#ifdef INFRA_LOG +#include "infra_log.h" +#define h2_emerg(...) log_emerg("h2", __VA_ARGS__) +#define h2_crit(...) log_crit("h2", __VA_ARGS__) +#define h2_err(...) log_err("h2", __VA_ARGS__) +#define h2_warning(...) log_warning("h2", __VA_ARGS__) +#define h2_info(...) log_info("h2", __VA_ARGS__) +#define h2_debug(...) log_debug("h2", __VA_ARGS__) +#else +#define h2_emerg(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define h2_crit(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define h2_err(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define h2_warning(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define h2_info(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define h2_debug(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#endif + +#ifdef INFRA_MEM_STATS +#include "infra_mem_stats.h" +#define HTTP2_STREAM_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "http2.stream") +#define HTTP2_STREAM_FREE(ptr) LITE_free(ptr) +#else +#define HTTP2_STREAM_MALLOC(size) HAL_Malloc(size) +#define HTTP2_STREAM_FREE(ptr) do{if(ptr != NULL) {HAL_Free(ptr);ptr = NULL;}}while(0) +#endif /* #ifdef INFRA_MEM_STATS */ + +#define POINTER_SANITY_CHECK(ptr, err) \ + do { \ + if (NULL == (ptr)) { \ + return (err); \ + } \ + } while(0) + +#define ARGUMENT_SANITY_CHECK(expr, err) \ + do { \ + if (!(expr)) { \ + return (err); \ + } \ + } while(0) + + +typedef enum { + + HTTP2_FLAG_NONE = 0, + + HTTP2_FLAG_END_STREAM = 0x01, + +} http2_flag; + +typedef struct http2_list_s { + struct http2_list_s *prev; + struct http2_list_s *next; +} http2_list_t; + +typedef void (*on_user_header_callback)(int32_t stream_id, int cat, const uint8_t *name, uint32_t namelen, + const uint8_t *value, uint32_t valuelen, uint8_t flags); + +typedef void (*on_user_chunk_recv_callback)(int32_t stream_id, + const uint8_t *data, uint32_t len, uint8_t flags); + +typedef void (*on_user_stream_close_callback)(int32_t stream_id, uint32_t error_code); + +typedef void (*on_user_frame_send_callback)(int32_t stream_id, int type, uint8_t flags); + +typedef void (*on_user_frame_recv_callback)(int32_t stream_id, int type, uint8_t flags); + +typedef struct { + on_user_header_callback on_user_header_cb; + on_user_chunk_recv_callback on_user_chunk_recv_cb; + on_user_stream_close_callback on_user_stream_close_cb; + on_user_frame_send_callback on_user_frame_send_cb; + on_user_frame_recv_callback on_user_frame_recv_cb; +} http2_user_cb_t; + +typedef struct http2_connection { + void *network; /* iot network ptr */ + void *session; /* http2 session */ + int flag; /* check the stream is end or not */ + int status; + http2_user_cb_t *cbs; +} http2_connection_t; + +typedef struct http2_data_struct { + http2_header *header; /* header data. */ + int header_count; /* the count of header data. */ + char *data; /* send data. */ + int len; /* send data length. */ + int stream_id; /* send data over specify stream */ + int flag; /* send data flag. */ +} http2_data; + +typedef struct { + http2_connection_t *http2_connect; + void *mutex; + void *semaphore; + void *rw_thread; + http2_list_t stream_list; + int init_state; + http2_stream_cb_t *cbs; + uint8_t connect_state; + uint8_t retry_cnt; +} stream_handle_t; + +#ifdef FS_ENABLED + +typedef struct { + char fs_upload_id[50]; + int fs_offset; +} fs_rsp_header_val_t; + +int IOT_HTTP2_FS_Close(void *hd, stream_data_info_t *info, header_ext_info_t *header); + +#endif /* #ifdef FS_ENABLED */ + +/** +* @brief the http2 client connect. +* @param[in] pclient: http client. +* @return http2 client connection handler. +*/ +extern http2_connection_t *iotx_http2_client_connect(void *pclient, char *url, int port); + +http2_connection_t *iotx_http2_client_connect_with_cb(void *pclient, char *url, int port, http2_user_cb_t *cb); +/** +* @brief the http2 client send data. +* @param[in] handler: http2 client connection handler. +* @param[in] data: send data. +* @return The result. 0 is ok. +*/ +extern int iotx_http2_client_send(http2_connection_t *conn, http2_data *h2_data); +/** +* @brief the http2 client receive data. +* @param[in] handler: http2 client connection handler. +* @param[in] data: receive data buffer. +* @param[in] data_len: buffer length. +* @param[in] len: receive data length. +* @param[in] timeout: receive data timeout. +* @return The result. 0 is ok. +*/ +extern int iotx_http2_client_recv(http2_connection_t *conn, char *data, int data_len, int *len, int timeout); +/** +* @brief the http2 client connect. +* @param[in] handler: http2 client connection handler. +* @return The result. 0 is ok. +*/ +extern int iotx_http2_client_disconnect(http2_connection_t *conn); +/** +* @brief the http2 client send ping to keep alive. +* @param[in] handler: http2 client connection handler. +* @return The result. 0 is ok. +*/ +extern int iotx_http2_client_send_ping(http2_connection_t *conn); +/** +* @brief the http2 client get available windows size. +* @param[in] handler: http2 client connection handler. +* @return The window size. +*/ +extern int iotx_http2_get_available_window_size(http2_connection_t *conn); +/** +* @brief the http2 client receive windows size packet to update window. +* @param[in] handler: http2 client connection handler. +* @return The result. 0 is ok. +*/ +extern int iotx_http2_update_window_size(http2_connection_t *conn); +/** +* @brief the http2 client performs the network I/O. +* @param[in] handler: http2 client connection handler. +* @return The result. 0 is ok. +*/ +extern int iotx_http2_exec_io(http2_connection_t *connection); + +extern int iotx_http2_client_recv_ping(void); + +int iotx_http2_reset_stream(http2_connection_t *connection, int32_t stream_id); +#ifdef __cplusplus +} +#endif + +#endif /* IOT_EXPORT_HTTP2_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_upload_api.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_upload_api.c new file mode 100644 index 00000000..0f9f2067 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_upload_api.c @@ -0,0 +1,595 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "infra_config.h" +#ifdef FS_ENABLED + +#include +#include +#include +#include + +#include "infra_defs.h" +#include "infra_types.h" +#include "infra_httpc.h" +#include "infra_sha1.h" +#include "infra_timer.h" +#include "infra_list.h" +#include "infra_log.h" + +#include "http2_internal.h" +#include "http2_api.h" +#include "http2_upload_api.h" +#include "http2_config.h" +#include "http2_wrapper.h" + +#include "wrappers_defs.h" + +#define PACKET_LEN 16384 +#define HTTP2_FS_SERVICE_ID "c/iot/sys/thing/file/upload" + + +typedef enum { + FS_STATUS_WAITING, + FS_STATUS_UPLOADING, + FS_STATUS_BREAK, + FS_STATUS_END, + FS_STATUS_NUM +} file_stream_status_t; + +typedef enum { + FS_TYPE_NORMAL, + FS_TYPE_CONTINUE, + FS_TYPE_OVERRIDE, +} file_stream_type_t; + +typedef struct { + int idx; + const char *file_path; + char upload_id[40]; + uint32_t spec_len; + uint32_t file_offset; + uint32_t part_len; + file_stream_type_t type; + http2_upload_id_received_cb_t opened_cb; + http2_upload_completed_cb_t end_cb; + void *user_data; + + uint8_t if_stop; + + http2_list_t list; +} http2_file_stream_t; + +typedef struct { + stream_handle_t *http2_handle; + const char *service_id; + http2_list_t file_list; + void *list_mutex; + void *file_thread; + int upload_idx; +} http2_file_stream_ctx_t; + + +typedef struct { + char *send_buffer; + const char *upload_id; + uint32_t file_offset; + uint32_t part_len; +} fs_send_ext_info_t; + + +static http2_file_stream_ctx_t g_http2_fs_ctx = { 0 }; +static http2_stream_cb_t callback_func = { 0 }; + + +/* utils, get file sizef */ +static int http2_stream_get_file_size(const char *file_name) +{ + void *fp = NULL; + int size = 0; + if ((fp = HAL_Fopen(file_name, "r")) == NULL) { + h2_err("The file %s can not be opened.\n", file_name); + return -1; + } + HAL_Fseek(fp, 0L, HAL_SEEK_END); + size = HAL_Ftell(fp); + HAL_Fclose(fp); + return size; +} + +/* utils, get file name */ +static const char *_http2_fs_get_filename(const char *file_path) +{ + const char *p_name = NULL; + + if (file_path == NULL) { + return NULL; + } + + p_name = file_path + strlen(file_path); + + while (--p_name != file_path) { + if (*p_name == '/') { + p_name++; + break; + } + } + + return p_name; +} + +/* utils, read file data */ +static int http2_stream_get_file_data(const char *file_name, char *data, int len, int offset) +{ + void *fp = NULL; + int ret = 0; + if ((fp = HAL_Fopen(file_name, "r")) == NULL) { + h2_err("The file %s can not be opened.\n", file_name); + return -1; + } + ret = HAL_Fseek(fp, offset, HAL_SEEK_SET); + if (ret != 0) { + HAL_Fclose(fp); + h2_err("The file %s can not move offset.\n", file_name); + return -1; + } + ret = HAL_Fread(data, len, 1, fp); + HAL_Fclose(fp); + return len; +} + +/* open http2 file upload channel */ +static int _http2_fs_open_channel(http2_file_stream_t *fs_node, stream_data_info_t *info) +{ + stream_handle_t *h2_handle = g_http2_fs_ctx.http2_handle; + header_ext_info_t ext_header; + fs_rsp_header_val_t *open_rsp = (fs_rsp_header_val_t *)info->user_data; + const char *filename = NULL; + int ret = UPLOAD_ERROR_COMMON; + + /* header for normal upload */ + http2_header header_filename[] = { + MAKE_HEADER_CS("x-file-name", ""), + }; + + /* header for override operation */ + http2_header header_overwrite[] = { + MAKE_HEADER_CS("x-file-name", ""), + MAKE_HEADER_CS("x-file-overwrite", "1"), + }; + + /* header for continue operation */ + http2_header header_uploadid[] = { + MAKE_HEADER("x-file-upload-id", ""), + }; + + filename = _http2_fs_get_filename(fs_node->file_path); + h2_info("filename = %s", filename); + + header_filename[0].value = (char *)filename; + header_filename[0].valuelen = strlen(filename); + header_overwrite[0].value = (char *)filename; + header_overwrite[0].valuelen = strlen(filename); + + /* setup http2 ext_header */ + switch (fs_node->type) { + case FS_TYPE_NORMAL: { + ext_header.num = 1; + ext_header.nva = header_filename; + + } break; + case FS_TYPE_OVERRIDE: { + ext_header.num = 2; + ext_header.nva = header_overwrite; + + } break; + case FS_TYPE_CONTINUE: { + /* upload id must be exist */ + header_uploadid[0].value = fs_node->upload_id; + header_uploadid[0].valuelen = strlen(fs_node->upload_id); + ext_header.num = 1; + ext_header.nva = header_uploadid; + } break; + default: break; + } + + ret = IOT_HTTP2_Stream_Open(h2_handle, info, &ext_header); + if (ret < 0 || open_rsp->fs_offset == -1 || open_rsp->fs_upload_id[0] == '\0') { + h2_err("IOT_HTTP2_Stream_Open failed %d\n", ret); + return UPLOAD_STREAM_OPEN_FAILED; + } + h2_info("fs channel open succeed"); + return SUCCESS_RETURN; +} + + +/* file part data send sync api */ +static int _http2_fs_part_send_sync(http2_file_stream_t *fs_node, stream_data_info_t *info, fs_send_ext_info_t *ext_info) +{ + stream_handle_t *h2_handle = g_http2_fs_ctx.http2_handle; + header_ext_info_t ext_header; + int res; + http2_header header_uploadid[] = { + MAKE_HEADER_CS("x-file-upload-id", ext_info->upload_id), + }; + + /* setup ext header */ + ext_header.num = 1; + ext_header.nva = header_uploadid; + + /* setup Stream_Send params */ + info->stream = ext_info->send_buffer; + info->stream_len = ext_info->part_len; + info->send_len = 0; + info->packet_len = FS_UPLOAD_PACKET_LEN; + + while (info->send_len < info->stream_len) { + if (!h2_handle->init_state) { + res = UPLOAD_ERROR_COMMON; + break; + } + + res = http2_stream_get_file_data(fs_node->file_path, ext_info->send_buffer, FS_UPLOAD_PACKET_LEN, (info->send_len + ext_info->file_offset)); /* offset used */ + if (res <= 0) { + res = UPLOAD_FILE_READ_FAILED; + break; + } + info->packet_len = res; + + /* adjust the packet len */ + if (info->stream_len - info->send_len < info->packet_len) { + info->packet_len = info->stream_len - info->send_len; + } + + res = IOT_HTTP2_Stream_Send(h2_handle, info, &ext_header); + if (res < 0) { + res = UPLOAD_STREAM_SEND_FAILED; + break; + } + h2_debug("send len = %d\n", info->send_len); + + if (fs_node->if_stop) { + res = UPLOAD_STOP_BY_IOCTL; + break; + } + + res = SUCCESS_RETURN; + } + + return res; +} + +void *_http2_fs_node_handle(http2_file_stream_t *fs_node) +{ + stream_handle_t *h2_handle = g_http2_fs_ctx.http2_handle; + int filesize = 0; + int upload_len = 0; + fs_rsp_header_val_t rsp_data; + fs_send_ext_info_t send_ext_info; + stream_data_info_t channel_info; + uint32_t part_len = 0; + int res = FAIL_RETURN; + + /* params check */ + if (h2_handle == NULL) { + /* TODO: handle */ + return NULL; + } + + /* get fileszie */ + filesize = http2_stream_get_file_size(fs_node->file_path); + if (filesize <= 0) { + if (fs_node->end_cb) { + fs_node->end_cb(fs_node->file_path, UPLOAD_FILE_NOT_EXIST, fs_node->user_data); + } + + return NULL; + } + h2_info("filesize = %d", filesize); + + /* open http2 file upload channel */ + memset(&rsp_data, 0, sizeof(fs_rsp_header_val_t)); + memset(&channel_info, 0, sizeof(stream_data_info_t)); + channel_info.identify = g_http2_fs_ctx.service_id; + channel_info.user_data = (void *)&rsp_data; + + res = _http2_fs_open_channel(fs_node, &channel_info); + if (res < SUCCESS_RETURN) { + if (fs_node->end_cb) { + fs_node->end_cb(fs_node->file_path, res, fs_node->user_data); + } + + return NULL; + } + + h2_info("upload_id = %s", rsp_data.fs_upload_id); + h2_info("upload_offset = %d", rsp_data.fs_offset); + if (fs_node->opened_cb) { + fs_node->opened_cb(fs_node->file_path, rsp_data.fs_upload_id, fs_node->user_data); + } + + if (fs_node->spec_len && (fs_node->spec_len + rsp_data.fs_offset < filesize)) { + upload_len = fs_node->spec_len + rsp_data.fs_offset; + } + else { + upload_len = filesize; + } + + /* setup send part len */ + if ((fs_node->part_len < (1024 * 100)) || (fs_node->part_len > (1024 * 1024 * 100))) { + part_len = FS_UPLOAD_PART_LEN; + } + else { + part_len = fs_node->part_len; + } + + /* send http2 file upload data */ + send_ext_info.upload_id = rsp_data.fs_upload_id; + send_ext_info.file_offset = rsp_data.fs_offset; + send_ext_info.send_buffer = HTTP2_STREAM_MALLOC(FS_UPLOAD_PACKET_LEN); + if (send_ext_info.send_buffer == NULL) { + if (fs_node->end_cb) { + fs_node->end_cb(fs_node->file_path, UPLOAD_MALLOC_FAILED, fs_node->user_data); + } + + return NULL; + } + + do { + /* setup the part len */ + send_ext_info.part_len = ((upload_len - send_ext_info.file_offset) < part_len)? + (upload_len - send_ext_info.file_offset): part_len; + + res = _http2_fs_part_send_sync(fs_node, &channel_info, &send_ext_info); + if (res < SUCCESS_RETURN) { + h2_err("fs send return %d", res); + break; + } + + send_ext_info.file_offset += send_ext_info.part_len; + h2_info("file offset = %d now", send_ext_info.file_offset); + } while (send_ext_info.file_offset < upload_len); + + if (res < 0) { + if (fs_node->end_cb) { + fs_node->end_cb(fs_node->file_path, res, fs_node->user_data); + } + + HTTP2_STREAM_FREE(channel_info.channel_id); + HTTP2_STREAM_FREE(send_ext_info.send_buffer); + return NULL; + } + + /* close http2 file upload channel */ + IOT_HTTP2_FS_Close(h2_handle, &channel_info, NULL); + + if (fs_node->end_cb) { + fs_node->end_cb(fs_node->file_path, UPLOAD_SUCCESS, fs_node->user_data); + } + + HTTP2_STREAM_FREE(send_ext_info.send_buffer); + return NULL; +} + +static void *http_upload_file_func(void *fs_data) +{ + http2_file_stream_ctx_t *fs_ctx = (http2_file_stream_ctx_t *)fs_data; + http2_file_stream_t *node = NULL; + if (fs_ctx == NULL) { + return NULL; + } + + while (fs_ctx->http2_handle->init_state) { + HAL_MutexLock(fs_ctx->list_mutex); + if (!list_empty((list_head_t *)&g_http2_fs_ctx.file_list)) { + node = list_first_entry(&fs_ctx->file_list, http2_file_stream_t, list); + HAL_MutexUnlock(fs_ctx->list_mutex); + + /* execute upload routine */ + _http2_fs_node_handle((void *)node); + + /* delete the completed node */ + HAL_MutexLock(fs_ctx->list_mutex); + list_del((list_head_t *)&node->list); + HTTP2_STREAM_FREE(node); + HAL_MutexUnlock(fs_ctx->list_mutex); + } + else { + HAL_MutexUnlock(fs_ctx->list_mutex); + h2_debug("file list is empty, file upload thread exit\n"); + g_http2_fs_ctx.file_thread = NULL; + break; + } + } + + return NULL; +} + +static void _http2_fs_list_insert(http2_file_stream_ctx_t *fs_ctx, http2_file_stream_t *node) +{ + INIT_LIST_HEAD((list_head_t *)&node->list); + HAL_MutexLock(fs_ctx->list_mutex); + list_add_tail((list_head_t *)&node->list, (list_head_t *)&fs_ctx->file_list); + HAL_MutexUnlock(fs_ctx->list_mutex); +} + +typedef enum { + HTTP2_IOCTL_STOP_UPLOAD, + HTTP2_IOCTL_COMMAND_NUM, +} http2_file_upload_ioctl_command_t; + +static int _http2_fs_list_search_by_idx(int idx, http2_file_stream_t **search_node) +{ + http2_file_stream_t *node = NULL; + + HAL_MutexLock(g_http2_fs_ctx.list_mutex); + + list_for_each_entry(node, &g_http2_fs_ctx.file_list, list, http2_file_stream_t) { + if (idx == node->idx) { + *search_node = node; + HAL_MutexUnlock(g_http2_fs_ctx.list_mutex); + return SUCCESS_RETURN; + } + } + + HAL_MutexUnlock(g_http2_fs_ctx.list_mutex); + *search_node = NULL; + return FAIL_RETURN; +} + +int IOT_HTTP2_Ioctl(int upload_idx, int command, void *data) +{ + http2_file_stream_t *node = NULL; + + if (g_http2_fs_ctx.http2_handle == NULL) { + return UPLOAD_ERROR_COMMON; + } + + _http2_fs_list_search_by_idx(upload_idx, &node); + if (node == NULL) { + return UPLOAD_ERROR_COMMON; + } + + switch (command) { + case HTTP2_IOCTL_STOP_UPLOAD: { + if (g_http2_fs_ctx.http2_handle) { + HAL_MutexLock(g_http2_fs_ctx.list_mutex); + node->if_stop = 1; + HAL_MutexUnlock(g_http2_fs_ctx.list_mutex); + return SUCCESS_RETURN; + } + else { + return UPLOAD_ERROR_COMMON; + } + } break; + default: { + return UPLOAD_ERROR_COMMON; + } + } + + return SUCCESS_RETURN; +} + +void *IOT_HTTP2_UploadFile_Connect(http2_upload_conn_info_t *conn_info, http2_status_cb_t *cb) +{ + void *handle; + + memset(&callback_func, 0, sizeof(http2_stream_cb_t)); + + if (cb != NULL) { + callback_func.on_reconnect_cb = cb->on_reconnect_cb; + callback_func.on_disconnect_cb = cb->on_disconnect_cb; + } + + handle = IOT_HTTP2_Connect((device_conn_info_t *)conn_info, &callback_func); + if (handle == NULL) { + return handle; + } + + /* TODO */ + g_http2_fs_ctx.list_mutex = HAL_MutexCreate(); + if (g_http2_fs_ctx.list_mutex == NULL) { + h2_err("fs mutex create error\n"); + IOT_HTTP2_UploadFile_Disconnect(handle); + return NULL; + } + + INIT_LIST_HEAD((list_head_t *)&(g_http2_fs_ctx.file_list)); + g_http2_fs_ctx.http2_handle = handle; + g_http2_fs_ctx.service_id = HTTP2_FS_SERVICE_ID; + + return handle; +} + +int IOT_HTTP2_UploadFile_Request(void *http2_handle, http2_upload_params_t *params, http2_upload_result_cb_t *cb, void *user_data) +{ + int ret; + http2_file_stream_t *file_node = NULL; + + if (http2_handle == NULL || params == NULL || cb == NULL) { + return NULL_VALUE_ERROR; + } + + if (params->file_path == NULL) { + return UPLOAD_FILE_PATH_IS_NULL; + } + + if ( (params->opt_bit_map & UPLOAD_FILE_OPT_BIT_RESUME) && params->upload_id == NULL) { + return UPLOAD_ID_IS_NULL; + } + + if ( (params->opt_bit_map & UPLOAD_FILE_OPT_BIT_SPECIFIC_LEN) && params->upload_len == 0) { + return UPLOAD_LEN_IS_ZERO; + } + + file_node = (http2_file_stream_t *)HTTP2_STREAM_MALLOC(sizeof(http2_file_stream_t)); + if (file_node == NULL) { + return UPLOAD_MALLOC_FAILED; + } + + memset(file_node, 0, sizeof(http2_file_stream_t)); + file_node->file_path = params->file_path; + file_node->part_len = params->part_len; + file_node->opened_cb = cb->upload_id_received_cb; + file_node->end_cb = cb->upload_completed_cb; + file_node->user_data = user_data; + file_node->type = FS_TYPE_NORMAL; + file_node->idx = g_http2_fs_ctx.upload_idx++; + + if (params->opt_bit_map & UPLOAD_FILE_OPT_BIT_SPECIFIC_LEN) { + file_node->spec_len = params->upload_len; + } + if (params->opt_bit_map & UPLOAD_FILE_OPT_BIT_OVERWRITE) { + file_node->type = FS_TYPE_OVERRIDE; + } + else if (params->opt_bit_map & UPLOAD_FILE_OPT_BIT_RESUME) { + file_node->type = FS_TYPE_CONTINUE; + memcpy(file_node->upload_id, params->upload_id, sizeof(file_node->upload_id)); + } + + /* inset http2_fs node */ + _http2_fs_list_insert(&g_http2_fs_ctx, file_node); + + if (g_http2_fs_ctx.file_thread == NULL) { + hal_os_thread_param_t thread_parms = {0}; + thread_parms.stack_size = 6144; + thread_parms.name = "file_upload"; + ret = HAL_ThreadCreate(&g_http2_fs_ctx.file_thread, http_upload_file_func, (void *)&g_http2_fs_ctx, &thread_parms, NULL); + if (ret != 0) { + h2_err("file upload thread create error\n"); + return -1; + } + HAL_ThreadDetach(g_http2_fs_ctx.file_thread); + } + + return SUCCESS_RETURN; +} + +int IOT_HTTP2_UploadFile_Disconnect(void *handle) +{ + int res = FAIL_RETURN; + + res = IOT_HTTP2_Disconnect(handle); + + if (g_http2_fs_ctx.list_mutex == NULL) { + memset(&g_http2_fs_ctx, 0, sizeof(g_http2_fs_ctx)); + } + else { + http2_file_stream_t *node, *next; + HAL_MutexLock(g_http2_fs_ctx.list_mutex); + list_for_each_entry_safe(node, next, &g_http2_fs_ctx.file_list, list, http2_file_stream_t) { + list_del((list_head_t *)&node->list); + HTTP2_STREAM_FREE(node); + break; + } + HAL_MutexUnlock(g_http2_fs_ctx.list_mutex); + + HAL_MutexDestroy(g_http2_fs_ctx.list_mutex); + memset(&g_http2_fs_ctx, 0, sizeof(g_http2_fs_ctx)); + } + + return res; +} + +#endif /* #ifdef FS_ENABLED */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_upload_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_upload_api.h new file mode 100644 index 00000000..af554448 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_upload_api.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _HTTP2_UPLOAD_API_H_ +#define _HTTP2_UPLOAD_API_H_ + +#include "infra_types.h" +#include "infra_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* bit define of file override option */ +#define UPLOAD_FILE_OPT_BIT_OVERWRITE (0x00000001) +#define UPLOAD_FILE_OPT_BIT_RESUME (0x00000002) +#define UPLOAD_FILE_OPT_BIT_SPECIFIC_LEN (0x00000004) + +/* http2 connect information */ +typedef struct { + char *product_key; + char *device_name; + char *device_secret; + char *url; + int port; +} http2_upload_conn_info_t; + +/* file upload option define */ +typedef struct { + const char *file_path; /* file path, filename must be ASCII string and strlen < 2014 */ + uint32_t part_len; /* maximum content len of one http2 request, must be in range of 100KB ~ 100MB */ + const char *upload_id; /* a specific id used to indicate one upload session, only required when UPLOAD_FILE_OPT_BIT_RESUME option set */ + uint32_t upload_len; /* used to indicate the upload length, only required when UPLOAD_FILE_OPT_BIT_SPECIFIC_LEN option set */ + uint32_t opt_bit_map; /* option bit map, support UPLOAD_FILE_OPT_BIT_OVERWRITE, UPLOAD_FILE_OPT_BIT_RESUME and UPLOAD_FILE_OPT_BIT_SPECIFIC_LEN */ +} http2_upload_params_t; + +/* error code for file upload */ +typedef enum { + UPLOAD_STOP_BY_IOCTL = -14, + UPLOAD_HTTP2_HANDLE_NULL = -13, + UPLOAD_LEN_IS_ZERO = -12, + UPLOAD_FILE_PATH_IS_NULL = -11, + UPLOAD_ID_IS_NULL = -10, + UPLOAD_FILE_NOT_EXIST = -9, + UPLOAD_FILE_READ_FAILED = -8, + UPLOAD_STREAM_OPEN_FAILED = -7, + UPLOAD_STREAM_SEND_FAILED = -6, + UPLOAD_MALLOC_FAILED = -5, + UPLOAD_NULL_POINT = -2, + UPLOAD_ERROR_COMMON = -1, + UPLOAD_SUCCESS = 0, +} http2_file_upload_result_t; + +/* gerneral callback function, this callback will be invoke when http2 disconnected */ +typedef void (*http2_disconnect_cb_t)(void); + +/* gerneral callback function, this callback will be invoke when http2 reconnected */ +typedef void (*http2_reconnect_cb_t)(void); + +/* callback function type define, this callback will be invoke when upload completed */ +typedef void (*http2_upload_completed_cb_t)(const char *file_path, int result, void *user_data); + +/* callback funciton type define, this callback will be invoke when upload_id received */ +typedef void (*http2_upload_id_received_cb_t)(const char *file_path, const char *upload_id, void *user_data); + +/* http2 connect status callback define */ +typedef struct { + http2_disconnect_cb_t on_disconnect_cb; + http2_reconnect_cb_t on_reconnect_cb; +} http2_status_cb_t; + +/* http2 upload result callback define */ +typedef struct { + http2_upload_id_received_cb_t upload_id_received_cb; + http2_upload_completed_cb_t upload_completed_cb; +} http2_upload_result_cb_t; + +/* http2 uploadfile connect api, http2 handle returned */ +DLL_IOT_API void *IOT_HTTP2_UploadFile_Connect(http2_upload_conn_info_t *conn_info, http2_status_cb_t *cb); + +/* http2 uploadfile start api */ +DLL_IOT_API int IOT_HTTP2_UploadFile_Request(void *http2_handle, http2_upload_params_t *params, http2_upload_result_cb_t *cb, void *user_data); + +/* http2 uploadfile disconnect api */ +DLL_IOT_API int IOT_HTTP2_UploadFile_Disconnect(void *handle); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef _HTTP2_UPLOAD_API_H_ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_wrapper.h new file mode 100644 index 00000000..454401b2 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/http2_wrapper.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __HTTP2_WRAPPER_H__ +#define __HTTP2_WRAPPER_H__ + +#include "infra_types.h" +#include "infra_defs.h" +#include "wrappers_defs.h" + +extern void HAL_Printf(const char *fmt, ...); +extern void HAL_SleepMs(uint32_t ms); + +extern void *HAL_Malloc(uint32_t size); +extern void *HAL_Realloc(void *ptr, uint32_t size); +extern void HAL_Free(void *ptr); + +extern void *HAL_MutexCreate(void); +extern void HAL_MutexDestroy(void *mutex); +extern void HAL_MutexLock(void *mutex); +extern void HAL_MutexUnlock(void *mutex); + +extern void *HAL_SemaphoreCreate(void); +extern void HAL_SemaphoreDestroy(void *sem); +extern void HAL_SemaphorePost(void *sem); +extern int HAL_SemaphoreWait(void *sem, uint32_t timeout_ms); + +extern int HAL_ThreadCreate( + void **thread_handle, + void *(*work_routine)(void *), + void *arg, + hal_os_thread_param_t *hal_os_thread_param, + int *stack_used); +extern void HAL_ThreadDetach(void *thread_handle); +extern void HAL_ThreadDelete(void *thread_handle); + +#ifdef FS_ENABLED +typedef enum { + HAL_SEEK_SET, + HAL_SEEK_CUR, + HAL_SEEK_END +} hal_fs_seek_type_t; + +extern void *HAL_Fopen(const char *path, const char *mode); +extern uint32_t HAL_Fread(void *buff, uint32_t size, uint32_t count, void *stream); +extern uint32_t HAL_Fwrite(const void *ptr, uint32_t size, uint32_t count, void *stream); +extern int HAL_Fseek(void *stream, long offset, int framewhere); +extern int HAL_Fclose(void *stream); +extern long HAL_Ftell(void *stream); +#endif /* #ifdef FS_ENABLED */ + +#endif /* #ifndef __HTTP2_WRAPPER_H__ */ + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/iotx_http2.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/iotx_http2.c new file mode 100644 index 00000000..e3fdef3b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/http2/iotx_http2.c @@ -0,0 +1,841 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include +#include +#include + +#include "nghttp2.h" +#include "nghttp2_session.h" +#include "infra_httpc.h" +#include "http2_internal.h" +#include "http2_wrapper.h" + + +#define MAX_HTTP2_HOST_LEN (128) +#define NGHTTP2_DBG h2_info + +typedef enum { + PING_IDLE, + PING_SENDING, + PING_SENT, + PING_RECVED, +} http2_ping_state_t; + + +enum { IO_NONE, WANT_READ, WANT_WRITE }; + +typedef struct _http2_request_struct_ { + /* Stream ID for this request. */ + int32_t stream_id; +} http2_request; + + +extern const char *iotx_ca_get(void); +extern int httpclient_connect(httpclient_t *client); +static int http2_nv_copy_nghttp2_nv(nghttp2_nv *nva, int start, http2_header *nva_copy, int end); +/*static int http2_parse_host(char *url, char *host, size_t maxHostLen);*/ + +static http2_ping_state_t ping_state = PING_IDLE; + +int g_recv_timeout = 10; + +int set_http2_recv_timeout(int timeout) +{ + g_recv_timeout = timeout; + return 1; +} + +static ssize_t send_callback(nghttp2_session *session, const uint8_t *data, + size_t length, int flags, void *user_data) +{ + http2_connection_t *connection; + httpclient_t *client; + int rv; + + connection = (http2_connection_t *)user_data; + if (connection == NULL) { + return 0; + } + + NGHTTP2_DBG("send_callback data len %d, session->remote_window_size=%d!\r\n", (int)length, + session->remote_window_size); + if (session->remote_window_size < length * 2) { + HAL_SleepMs(50); + NGHTTP2_DBG("wait a munite ...."); + } + /*if(length < 50) + LITE_hexdump("data:", data, length);*/ + client = (httpclient_t *)connection->network; + rv = client->net.write(&client->net, (char *)data, length, 5000); + NGHTTP2_DBG("send_callback data ends len = %d!\r\n", rv); + if (rv < 0) { + rv = NGHTTP2_ERR_CALLBACK_FAILURE; + } + return rv; +} + + +/** +* @brief The implementation of nghttp2_recv_callback type. Here we read |data| from the network +* and write them in |buf|. The capacity of |buf| is |length| bytes. Returns the number of +* bytes stored in |buf|. See the documentation of nghttp2_recv_callback for the details. +* To set this callback to :type:`nghttp2_session_callbacks`, use +* `nghttp2_session_callbacks_set_on_frame_send_callback()`. +* @param[in] session: nghttp2 session. +* @param[in] buf: receive data buffer. +* @param[in] length: data length. +* @param[in] flags: no using. +* @param[in] user_data: user data. +* @return Received data length. + */ +static ssize_t recv_callback(nghttp2_session *session, uint8_t *buf, + size_t length, int flags, void *user_data) +{ + http2_connection_t *connection; + int rv; + httpclient_t *client; + + connection = (http2_connection_t *)user_data; + if (connection == NULL) { + return 0; + } + + client = (httpclient_t *)connection->network; + + rv = client->net.read(&client->net, (char *)buf, length, g_recv_timeout); + /* NGHTTP2_DBG("recv_callback len= %d\r\n", rv); */ + if (rv < 0) { + rv = NGHTTP2_ERR_CALLBACK_FAILURE; + } else if (rv == 0) { + rv = 0; + } + return rv; +} +/** +* @brief Callback function invoked after the frame |frame| is sent. +* To set this callback to :type:`nghttp2_session_callbacks`, use +* `nghttp2_session_callbacks_set_on_frame_send_callback()`. +* @param[in] session: nghttp2 session. +* @param[in] frame: nghttp2 frame. +* @param[in] user_data: The |user_data| pointer is the third argument passed in to the call to +* `nghttp2_session_client_new()` or `nghttp2_session_server_new()` +* @return The implementation of this function must return 0 if it succeeds. +* If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()` +* and `nghttp2_session_mem_send()` functions immediately return :enum: +* `NGHTTP2_ERR_CALLBACK_FAILURE`. +*/ +static int on_frame_send_callback(nghttp2_session *session, + const nghttp2_frame *frame, + void *user_data) +{ + size_t i; + + http2_connection_t *connection = (http2_connection_t *)user_data; + if (connection == NULL) { + return 0; + } + + switch (frame->hd.type) { + case NGHTTP2_HEADERS: { + const nghttp2_nv *nva = frame->headers.nva; + NGHTTP2_DBG("[INFO] C ---------> S (HEADERS) stream_id [%d]\n", frame->hd.stream_id); + for (i = 0; i < frame->headers.nvlen; ++i) { + NGHTTP2_DBG("> %s: %s\n", nva[i].name, nva[i].value); + } + (void)nva; + } break; + case NGHTTP2_RST_STREAM: { + NGHTTP2_DBG("[INFO] C ---------> S (RST_STREAM)\n"); + } break; + case NGHTTP2_GOAWAY: { + NGHTTP2_DBG("[INFO] C ---------> S (GOAWAY) code = %d\n",frame->goaway.error_code); + } break; + case NGHTTP2_PING: { + NGHTTP2_DBG("[INFO] C ---------> S (PING)\n"); + ping_state = PING_SENDING; + } break; + default: break; + } + + if (connection->cbs && connection->cbs->on_user_frame_send_cb) { + connection->cbs->on_user_frame_send_cb(frame->hd.stream_id, frame->hd.type, frame->hd.flags); + } + return 0; +} + + +/** +* @brief Callback function invoked by `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` when a frame is received. +* If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen``member of their data structure are always +* ``NULL`` and 0 respectively. The header name/value pairs are emitted via:type:`nghttp2_on_header_callback` +* To set this callback to :type:`nghttp2_session_callbacks`, use`nghttp2_session_callbacks_set_on_frame_send_callback()`. +* For HEADERS, PUSH_PROMISE and DATA frames, this callback may be called after stream is closed (see:type: +* `nghttp2_on_stream_close_callback`). The application should check that stream is still alive using its own stream +* management or :func:`nghttp2_session_get_stream_user_data()`. +* Only HEADERS and DATA frame can signal the end of incoming data. If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` +* is nonzero, the|frame| is the last frame from the remote peer in this stream. +* This callback won't be called for CONTINUATION frames. +* HEADERS/PUSH_PROMISE + CONTINUATIONs are treated as single frame. +* @param[in] session: nghttp2 session. +* @param[in] frame: nghttp2 frame. +* @param[in] user_data: The |user_data| pointer is the third argument passed in to the call to +* `nghttp2_session_client_new()` or `nghttp2_session_server_new()` +* @return The implementation of this function must return 0 if it succeeds. +* If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()` +* and `nghttp2_session_mem_send()` functions immediately return :enum: +* `NGHTTP2_ERR_CALLBACK_FAILURE`. +*/ +static int on_frame_recv_callback(nghttp2_session *session, + const nghttp2_frame *frame, + void *user_data) +{ + http2_connection_t *connection = (http2_connection_t *)user_data; + http2_request *req; + NGHTTP2_DBG("on_frame_recv_callback, type = %d\n", frame->hd.type); + NGHTTP2_DBG("on_frame_recv_callback, stream_id = %d\n", frame->hd.stream_id); + + if (connection == NULL) { + return 0; + } + + req = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); + if (req == NULL) { + NGHTTP2_DBG("stream user data is not exist\n"); + } + + switch (frame->hd.type) { + case NGHTTP2_HEADERS: { + if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) { + + } + } break; + case NGHTTP2_RST_STREAM: { + connection->status = 0; + NGHTTP2_DBG("[INFO] C <--------- S (RST_STREAM)\n"); + } break; + case NGHTTP2_GOAWAY: { + connection->status = 0; + NGHTTP2_DBG("[INFO] C <--------- S (GOAWAY) code = %d\n",frame->goaway.error_code); + } break; + case NGHTTP2_DATA: { + if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { + NGHTTP2_DBG("end stream flag\r\n"); + } + } break; + case NGHTTP2_PING: { + NGHTTP2_DBG("[INFO] C <--------- S (PING)\n"); + ping_state = PING_RECVED; + } break; + } + + if (connection->cbs && connection->cbs->on_user_frame_recv_cb) { + connection->cbs->on_user_frame_recv_cb(frame->hd.stream_id, frame->hd.type, frame->hd.flags); + } + return 0; +} + +/** +* @brief Callback function invoked when the stream |stream_id| is closed. +* We use this function to know if the response is fully received. Since we just fetch 1 resource in this program, after +* the response is received, we submit GOAWAY and close the session. +* @param[in] session: nghttp2 session. +* @param[in] stream_id: stream id. +* @param[in] error_code: The reason of closure. +* Usually one of :enum:`nghttp2_error_code`, but that is not guaranteed. The stream_user_data, which was specified in +* `nghttp2_submit_request()` or `nghttp2_submit_headers()`, is still available in this function. +* @param[in] user_data: The |user_data| pointer is the third argument passed in to the call to +* `nghttp2_session_client_new()` or `nghttp2_session_server_new()` +* @return The implementation of this function must return 0 if it succeeds. +* If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()` +* and `nghttp2_session_mem_send()` functions immediately return :enum: +* `NGHTTP2_ERR_CALLBACK_FAILURE`. + */ +static int on_h2_stream_close_callback(nghttp2_session *session, int32_t stream_id, + uint32_t error_code, + void *user_data) +{ + http2_request *req; + http2_connection_t *connection = (http2_connection_t *)user_data; + + if (connection == NULL) { + return 0; + } + req = nghttp2_session_get_stream_user_data(session, stream_id); + if (req) { + int rv; + rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR); + + if (rv != 0) { + NGHTTP2_DBG("stream close nghttp2_session_terminate_session\r\n"); + } + } + if (connection->cbs && connection->cbs->on_user_stream_close_cb) { + connection->cbs->on_user_stream_close_cb(stream_id, error_code); + } + return 0; +} + + +/** +* @brief Callback function invoked when a chunk of data in DATA frame is received. +* The implementation of nghttp2_on_data_chunk_recv_callback type. We use this function to print the received response body. +* @param[in] session: nghttp2 session. +* @param[in] flags: no using. +* @param[in] stream_id: the stream ID this DATA frame belongs to. +* @param[in] data: receive data. +* @param[in] len: data length. +* @param[in] user_data: The |user_data| pointer is the third argument passed in to the call to +* `nghttp2_session_client_new()` or `nghttp2_session_server_new()` +* @return The implementation of this function must return 0 if it succeeds. +* If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()` +* and `nghttp2_session_mem_send()` functions immediately return :enum: +* `NGHTTP2_ERR_CALLBACK_FAILURE`. + */ +static int on_data_chunk_recv_callback(nghttp2_session *session, + uint8_t flags, int32_t stream_id, + const uint8_t *data, size_t len, + void *user_data) +{ + http2_request *req; + http2_connection_t *connection = (http2_connection_t *)user_data; + + if (connection == NULL) { + return 0; + } + + req = nghttp2_session_get_stream_user_data(session, stream_id); + if (req) { + NGHTTP2_DBG("stream user data is not exist\n"); + } + NGHTTP2_DBG("[INFO] C <----------- S (DATA chunk) stream_id [%d] :: %lu bytes\n", stream_id, (unsigned long int)len); + + if (connection->cbs && connection->cbs->on_user_chunk_recv_cb) { + connection->cbs->on_user_chunk_recv_cb(stream_id, data, len, flags); + } + + nghttp2_session_consume_connection(session, len); + nghttp2_session_consume(session, stream_id, len); + nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 0, len); + nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, stream_id, len); + nghttp2_session_send(session); + + return 0; +} + + +/** +* @brief Callback function invoked when a header name/value pair is received. +* The implementation of nghttp2_on_data_chunk_recv_callback type. We use this function to print the received response body. +* @param[in] session: nghttp2 session. +* @param[in] frame: nghttp2 frame. +* @param[in] name: header name. +* @param[in] namelen: length of header name. +* @param[in] value: header value. +* @param[in] valuelen: length of header value. +* @param[in] flags: no using. +* @param[in] user_data: The |user_data| pointer is the third argument passed in to the call to +* `nghttp2_session_client_new()` or `nghttp2_session_server_new()` +* @return The implementation of this function must return 0 if it succeeds. +* If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()` +* and `nghttp2_session_mem_send()` functions immediately return :enum: +* `NGHTTP2_ERR_CALLBACK_FAILURE`. +*/ + + +static int on_header_callback(nghttp2_session *session, + const nghttp2_frame *frame, const uint8_t *name, + size_t namelen, const uint8_t *value, + size_t valuelen, uint8_t flags, + void *user_data) +{ + http2_connection_t *connection = (http2_connection_t *)user_data; + if (connection == NULL) { + return 0; + } + switch (frame->hd.type) { + case NGHTTP2_HEADERS: + + if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) { + http2_connection_t *connection = (http2_connection_t *)user_data; + /* Print response headers for the initiated request. */ + NGHTTP2_DBG("< %s: %s\n", name, value); + + if (connection->cbs && connection->cbs->on_user_header_cb) { + connection->cbs->on_user_header_cb(frame->hd.stream_id, (int)frame->headers.cat, name, namelen, value, valuelen, flags); + } + break; + } + + } + return 0; +} + +/** +* @brief Called when nghttp2 library gets started to receive header block. +* @param[in] session: nghttp2 session. +* @param[in] frame: nghttp2 frame. +* @param[in] user_data: The |user_data| pointer is the third argument passed in to the call to +* `nghttp2_session_client_new()` or `nghttp2_session_server_new()` +* @return The implementation of this function must return 0 if it succeeds. +* If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()` +* and `nghttp2_session_mem_send()` functions immediately return :enum: +* `NGHTTP2_ERR_CALLBACK_FAILURE`. +*/ +static int on_begin_headers_callback(nghttp2_session *session, + const nghttp2_frame *frame, + void *user_data) +{ + switch (frame->hd.type) { + case NGHTTP2_HEADERS: + if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) { + NGHTTP2_DBG("[INFO] C <--------- S (HEADERS) stream_id [%d]\n", (int)frame->hd.stream_id); + } + break; + } + return 0; +} + + +/** +* @brief Setup callback functions. +* nghttp2 API offers many callback functions, but most of them are optional. The send_callback is always required. +* Since we use nghttp2_session_recv(), the recv_callback is also required. +* @param[in|out] callbacks: nghttp2 callbacks. +* @return None. + */ +static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks) +{ + nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); + + nghttp2_session_callbacks_set_recv_callback(callbacks, recv_callback); + + nghttp2_session_callbacks_set_on_frame_send_callback(callbacks, + on_frame_send_callback); + + nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, + on_frame_recv_callback); + + nghttp2_session_callbacks_set_on_stream_close_callback( + callbacks, on_h2_stream_close_callback); + + nghttp2_session_callbacks_set_on_data_chunk_recv_callback( + callbacks, on_data_chunk_recv_callback); + + nghttp2_session_callbacks_set_on_header_callback(callbacks, + on_header_callback); + + nghttp2_session_callbacks_set_on_begin_headers_callback( + callbacks, on_begin_headers_callback); + +} + + +static ssize_t data_read_callback(nghttp2_session *session, int32_t stream_id, + uint8_t *buf, size_t length, + uint32_t *data_flags, + nghttp2_data_source *source, + void *user_data) +{ + int len = 0; + http2_connection_t *connection = (http2_connection_t *)user_data; + if (connection == NULL) { + return 0; + } + + if (source->ptr == NULL) { + return 0; + } + if (connection != NULL && connection->flag != NGHTTP2_FLAG_END_STREAM) { + *data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM; + connection->flag = NGHTTP2_FLAG_NONE; + } + *data_flags |= NGHTTP2_DATA_FLAG_EOF; + + /*len = strlen((char *)source->ptr);*/ + len = source->len; + + if (length < len) { + len = length; + } + memcpy(buf, source->ptr, len); + return len; +} + + +static int http2_nv_copy_nghttp2_nv(nghttp2_nv *nva, int start, http2_header *nva_copy, int end) +{ + int i, j; + for (i = start, j = 0; j < end; i++, j++) { + nva[i].flags = NGHTTP2_NV_FLAG_NONE; + nva[i].name = (uint8_t *)nva_copy[j].name; + nva[i].value = (uint8_t *)nva_copy[j].value; + nva[i].namelen = nva_copy[j].namelen; + nva[i].valuelen = nva_copy[j].valuelen; + } + return i; +} + + +/** +* @brief Connect the SSL client. +* @param[in] pclient: http client. +* @param[in] url. destination url. +* @param[in] port. destination port. +* @param[in] ssl_config: custome config. +* @return The result. 0 is ok. +*/ +static int http2_client_conn(httpclient_t *pclient, char *url, int port) +{ + int ret = 0; + /*char host[MAX_HTTP2_HOST_LEN] = { 0 };*/ + + /*http2_parse_host(url, host, sizeof(host));*/ + if (0 == pclient->net.handle) { + /* Establish connection if no. */ + extern const char *iotx_ca_crt; + + ret = iotx_net_init(&pclient->net, url, port, iotx_ca_crt); + + if (0 != ret) { + return ret; + } + ret = httpclient_connect(pclient); + if (0 != ret) { + h2_err("http2client_connect is error, ret = %d", ret); + httpclient_close(pclient); + return ret; + } + } + return ret; +} + +int iotx_http2_client_send(http2_connection_t *conn, http2_data *h2_data) +{ + int send_flag = 0; + int rv = 0; + nghttp2_data_provider data_prd; + nghttp2_nv *nva = NULL; + int nva_size = 0; + http2_header *header = h2_data->header; + int header_count = h2_data->header_count; + char *data = h2_data->data; + int len = h2_data->len; + int stream_id = h2_data->stream_id; + int flags = h2_data->flag; + + if (conn == NULL) { + return -1; + } + + if (header != NULL && header_count != 0) { + nva = (nghttp2_nv *)HTTP2_STREAM_MALLOC(sizeof(nghttp2_nv) * header_count); + if (nva == NULL) { + return -1; + } + nva_size = http2_nv_copy_nghttp2_nv(nva, nva_size, header, header_count); + } + /*upload to server*/ + if (data != NULL && len != 0) { + data_prd.source.ptr = data; + data_prd.source.len = len; + data_prd.read_callback = data_read_callback; + if (nva_size != 0) { + rv = nghttp2_submit_request(conn->session, NULL, nva, nva_size, &data_prd, NULL); + h2_data->stream_id = rv; + } else { + rv = nghttp2_submit_data(conn->session, flags, stream_id, &data_prd); + } + } else { + rv = nghttp2_submit_request(conn->session, NULL, nva, nva_size, NULL, NULL); + h2_data->stream_id = rv; + } + HTTP2_STREAM_FREE(nva); + + if (rv < 0) { + return rv; + } + + send_flag = nghttp2_session_want_write(conn->session); + if (send_flag) { + rv = nghttp2_session_send(conn->session); + NGHTTP2_DBG("nghttp2_session_send %d\r\n", rv); + } + + return rv; +} + +int iotx_http2_client_recv(http2_connection_t *conn, char *data, int data_len, int *len, int timeout) +{ + int rv = 0; + int read_flag = 0; + + if (conn == NULL) { + return -1; + } + + set_http2_recv_timeout(timeout); + read_flag = nghttp2_session_want_read(conn->session); + if (read_flag) { + rv = nghttp2_session_recv(conn->session); + NGHTTP2_DBG("nghttp2_client_recv %d\r\n", rv); + if (rv < 0) { + read_flag = 0; + } + } + return rv; +} + +/** +* @brief the http2 client connect. +* @param[in] pclient: http client. +* @return http2 client connection handler. +*/ +http2_connection_t *iotx_http2_client_connect(void *pclient, char *url, int port) +{ + http2_connection_t *connection; + nghttp2_session_callbacks *callbacks; + int rv; + int ret = 0; + + connection = HTTP2_STREAM_MALLOC(sizeof(http2_connection_t)); + if (connection == NULL) { + return NULL; + } + memset(connection, 0, sizeof(http2_connection_t)); + + if (0 != (ret = http2_client_conn((httpclient_t *)pclient, url, port))) { + NGHTTP2_DBG("https_client_conn failed %d\r\n", ret); + HTTP2_STREAM_FREE(connection); + return NULL; + } + connection->network = pclient; + + rv = nghttp2_session_callbacks_new(&callbacks); + if (rv != 0) { + NGHTTP2_DBG("nghttp2_session_callbacks_new1 %d", rv); + HTTP2_STREAM_FREE(connection); + return NULL; + } + + setup_nghttp2_callbacks(callbacks); + rv = nghttp2_session_client_new((nghttp2_session **)&connection->session, callbacks, connection); + if (rv != 0) { + NGHTTP2_DBG("nghttp2_session_client_new3 %d", rv); + HTTP2_STREAM_FREE(connection); + return NULL; + } + nghttp2_session_callbacks_del(callbacks); + + nghttp2_submit_settings(connection->session, NGHTTP2_FLAG_NONE, NULL, 0); +#if 0 + + parse_uri(&uri, url); + request_init(&req, &uri); + /* Submit the HTTP request to the outbound queue. */ + submit_request(connection, &req); +#endif + + rv = nghttp2_session_send(connection->session); + /*request_free(&req);*/ + if (rv < 0) { + NGHTTP2_DBG("nghttp2_session_send fail %d", rv); + HTTP2_STREAM_FREE(connection); + return NULL; + } + connection->status = 1; + return connection; +} + +/** +* @brief the http2 client connect. +* @param[in] pclient: http client. +* @return http2 client connection handler. +*/ +http2_connection_t *iotx_http2_client_connect_with_cb(void *pclient, char *url, int port, http2_user_cb_t *cb) +{ + http2_connection_t *connection; + nghttp2_session_callbacks *callbacks; + int rv; + int ret = 0; + + connection = HTTP2_STREAM_MALLOC(sizeof(http2_connection_t)); + if (connection == NULL) { + return NULL; + } + memset(connection, 0, sizeof(http2_connection_t)); + + if (0 != (ret = http2_client_conn((httpclient_t *)pclient, url, port))) { + NGHTTP2_DBG("https_client_conn failed %d\r\n", ret); + HTTP2_STREAM_FREE(connection); + return NULL; + } + connection->network = pclient; + + rv = nghttp2_session_callbacks_new(&callbacks); + if (rv != 0) { + NGHTTP2_DBG("nghttp2_session_callbacks_new1 %d", rv); + HTTP2_STREAM_FREE(connection); + return NULL; + } + + connection->cbs = cb; + setup_nghttp2_callbacks(callbacks); + + rv = nghttp2_session_client_new((nghttp2_session **)&connection->session, callbacks, connection); + if (rv != 0) { + NGHTTP2_DBG("nghttp2_session_client_new3 %d", rv); + nghttp2_session_callbacks_del(callbacks); + HTTP2_STREAM_FREE(connection); + return NULL; + } + nghttp2_session_callbacks_del(callbacks); + + nghttp2_submit_settings(connection->session, NGHTTP2_FLAG_NONE, NULL, 0); +#if 0 + + parse_uri(&uri, url); + request_init(&req, &uri); + /* Submit the HTTP request to the outbound queue. */ + submit_request(connection, &req); +#endif + + rv = nghttp2_session_send(connection->session); + /*request_free(&req);*/ + if (rv < 0) { + nghttp2_session_del(connection->session); + NGHTTP2_DBG("nghttp2_session_send fail %d", rv); + HTTP2_STREAM_FREE(connection); + return NULL; + } + connection->status = 1; + return connection; +} + +int iotx_http2_client_disconnect(http2_connection_t *conn) +{ + /* Resource cleanup */ + if (conn == NULL) { + return -1; + } + httpclient_close((httpclient_t *)conn->network); + nghttp2_session_del(conn->session); + HTTP2_STREAM_FREE(conn); + return 0; +} + +int iotx_http2_client_send_ping(http2_connection_t *conn) +{ + int rv = 0; + int send_flag; + + ping_state = PING_IDLE; + + if (conn == NULL) { + return -1; + } + rv = nghttp2_submit_ping(conn->session, NGHTTP2_FLAG_NONE, NULL); + if (rv < 0) { + return rv; + } + send_flag = nghttp2_session_want_write(conn->session); + if (send_flag) { + rv = nghttp2_session_send(conn->session); + NGHTTP2_DBG("nghttp2_session_send %d\r\n", rv); + if (rv < 0) { + return rv; + } + } + + ping_state = PING_SENDING; + return 0; +} + +int iotx_http2_client_recv_ping(void) +{ + if (ping_state == PING_RECVED || ping_state == PING_IDLE) { + NGHTTP2_DBG("ping recv secceed\r\n"); + return 0; + } + else { + NGHTTP2_DBG("ping recv timeout"); + return -1; + } +} + +int iotx_http2_get_available_window_size(http2_connection_t *conn) +{ + int windows_size = 0; + + if (conn == NULL) { + return -1; + } + + windows_size = nghttp2_session_get_remote_window_size(conn->session); + return windows_size; +} + + +int iotx_http2_update_window_size(http2_connection_t *conn) +{ + int rv; + + if (conn == NULL) { + return -1; + } + + rv = nghttp2_session_recv(conn->session); + if (rv < 0) { + return -1; + } + return 0; +} + +/* + * Performs the network I/O. + */ +int iotx_http2_exec_io(http2_connection_t *connection) +{ + if (connection == NULL) { + return -1; + } + + if (nghttp2_session_want_read(connection->session) /*|| + nghttp2_session_want_write(connection->session)*/) { + + int rv; + rv = nghttp2_session_recv(connection->session); + if (rv < 0) { + NGHTTP2_DBG("nghttp2_session_recv error"); + return -1; + } + /* rv = nghttp2_session_send(connection->session); */ + /* if (rv < 0) { */ + /* NGHTTP2_DBG("nghttp2_session_send error"); */ + /* return -1; */ + /* } */ + } + return 0; +} + +int iotx_http2_reset_stream(http2_connection_t *connection, int32_t stream_id) +{ + int rv = 0; + if(connection == NULL){ + return -1; + } + if(!nghttp2_session_get_stream_local_close(connection->session,stream_id)) { + rv = nghttp2_submit_rst_stream(connection->session,0, stream_id, NGHTTP2_NO_ERROR); + } + if (rv < 0) { + return rv; + } + + rv = nghttp2_session_want_write(connection->session); + if (rv) { + rv = nghttp2_session_send(connection->session); + NGHTTP2_DBG("nghttp2_session_send %d\r\n", rv); + } + return rv; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_cjson.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_cjson.c new file mode 100644 index 00000000..b2260ca4 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_cjson.c @@ -0,0 +1,1897 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "infra_config.h" + +#ifdef INFRA_CJSON + +#include +#include +#include +#include + +#include +#include +#include + +#include "infra_cjson.h" +#include "infra_types.h" + +typedef struct { + const unsigned char *content; + int length; + int offset; + int depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Predeclare these prototypes. */ +static int parse_value(lite_cjson_t *const item, parse_buffer *const input_buffer); +static int parse_string(lite_cjson_t *const item, parse_buffer *const input_buffer); +static int parse_array(lite_cjson_t *const item, parse_buffer *const input_buffer); +static int parse_object(lite_cjson_t *const item, parse_buffer *const input_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) { + return NULL; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) { + buffer->offset++; + } + + if (buffer->offset == buffer->length) { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer *const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) { + buffer->offset += 3; + } + + return buffer; +} + +/* Parse the input text to generate a number, and populate the result into item. */ +static int parse_number(lite_cjson_t *const item, parse_buffer *const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = '.'; + int i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) { + return -1; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) { + switch (buffer_at_offset(input_buffer)[i]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + number = strtod((const char *)number_c_string, (char **)&after_end); + if (number_c_string == after_end) { + return -1; + } + + item->type = cJSON_Number; + item->value = (char *)buffer_at_offset(input_buffer); + item->value_length = (int)(after_end - number_c_string); + item->value_double = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) { + item->value_int = INT_MAX; + } else if (number <= INT_MIN) { + item->value_int = INT_MIN; + } else { + item->value_int = (int)number; + } + + input_buffer->offset += (int)(after_end - number_c_string); + return 0; +} + +/* Build an array from input text. */ +static int parse_array(lite_cjson_t *const item, parse_buffer *const input_buffer) +{ + lite_cjson_t current_item; + int start_pos = input_buffer->offset; + item->size = 0; + + if (input_buffer->depth >= LITE_CJSON_NESTING_LIMIT) { + return -1; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do { + memset(¤t_item, 0, sizeof(lite_cjson_t)); + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (parse_value(¤t_item, input_buffer) != 0) { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + + /* printf("current item index: %d, type: %d, length: %d, value: %.*s\n", */ + /* item->size+1, current_item.type, current_item.value_length, current_item.value_length, current_item.value); */ + + item->size++; + } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Array; + item->value = (char *)(input_buffer->content + start_pos); + item->value_length = input_buffer->offset - start_pos + 1; + + input_buffer->offset++; + + return 0; + +fail: + + return -1; +} + +/* Build an object from the text. */ +static int parse_object(lite_cjson_t *const item, parse_buffer *const input_buffer) +{ + lite_cjson_t current_item_key; + lite_cjson_t current_item_value; + int start_pos = input_buffer->offset; + item->size = 0; + + if (input_buffer->depth >= LITE_CJSON_NESTING_LIMIT) { + return -1; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do { + memset(¤t_item_key, 0, sizeof(lite_cjson_t)); + memset(¤t_item_value, 0, sizeof(lite_cjson_t)); + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (parse_string(¤t_item_key, input_buffer) != 0) { + goto fail; /* faile to parse name */ + } + buffer_skip_whitespace(input_buffer); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (parse_value(¤t_item_value, input_buffer) != 0) { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + + /* printf("Current Object [Index: %d], [Key Length: %d, Key Value: %.*s], [Value Length: %d, Value: %.*s]\n", */ + /* item->size+1,current_item_key.value_length,current_item_key.value_length,current_item_key.value, */ + /* current_item_value.value_length,current_item_value.value_length,current_item_value.value); */ + + item->size++; + } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Object; + item->value = (char *)(input_buffer->content + start_pos); + item->value_length = input_buffer->offset - start_pos + 1; + + input_buffer->offset++; + + return 0; + +fail: + + return -1; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static int parse_string(lite_cjson_t *const item, parse_buffer *const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + /* unsigned char *output_pointer = NULL; */ + /* unsigned char *output = NULL; */ + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') { + /* printf("not a string"); */ + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + /* int allocation_length = 0; */ + int skipped_bytes = 0; + while (((int)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) { + /* is escape sequence */ + if (input_end[0] == '\\') { + if ((int)(input_end + 1 - input_buffer->content) >= input_buffer->length) { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((int)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) { + /* printf("end error\n"); */ + goto fail; /* string ended unexpectedly */ + } +#if 0 + /* This is at most how much we need for the output */ + allocation_length = (int)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char *)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) { + goto fail; /* allocation failure */ + } +#endif + } + +#if 0 + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) { + if (*input_pointer != '\\') { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) { + goto fail; + } + + switch (input_pointer[1]) { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; +#endif + + item->type = cJSON_String; + item->value = (char *)input_pointer; + item->value_length = input_end - input_pointer; + + input_buffer->offset = (int)(input_end - input_buffer->content); + input_buffer->offset++; + + return 0; + +fail: +#if 0 + if (output != NULL) { + input_buffer->hooks.deallocate(output); + } +#endif + if (input_pointer != NULL) { + input_buffer->offset = (int)(input_pointer - input_buffer->content); + } + + return -1; +} + +/* Parser core - when encountering text, process appropriately. */ +static int parse_value(lite_cjson_t *const lite, parse_buffer *const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) { + return -1; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)) { + lite->type = cJSON_NULL; + lite->value = (char *)buffer_at_offset(input_buffer); + lite->value_length = 4; + + input_buffer->offset += 4; + return 0; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)) { + lite->type = cJSON_False; + lite->value = (char *)buffer_at_offset(input_buffer); + lite->value_length = 5; + + input_buffer->offset += 5; + return 0; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)) { + lite->type = cJSON_True; + lite->value = (char *)buffer_at_offset(input_buffer); + lite->value_length = 4; + + input_buffer->offset += 4; + return 0; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) { + /* printf("parse string\n"); */ + return parse_string(lite, input_buffer); + } + + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') + || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) { + /* printf("parse number\n"); */ + return parse_number(lite, input_buffer); + } + + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) { + /* printf("parse array\n"); */ + return parse_array(lite, input_buffer); + } + + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) { + return parse_object(lite, input_buffer); + } + + return -1; +} + +int lite_cjson_parse(const char *src, int src_len, lite_cjson_t *lite) +{ + parse_buffer buffer; + + if (!lite || !src || !lite || src_len <= 0) { + return -1; + } + + memset(&buffer, 0, sizeof(parse_buffer)); + buffer.content = (const unsigned char *)src; + buffer.length = src_len; + buffer.offset = 0; + + if (parse_value(lite, buffer_skip_whitespace(skip_utf8_bom(&buffer))) != 0) { + lite->type = cJSON_Invalid; + lite->value = NULL; + lite->value_length = 0; + return -1; + } + + return 0; +} + +#if 0 +int lite_cjson_is_false(lite_cjson_t *lite) +{ + if (!lite) { + return -1; + } + + return (lite->type & 0xFF) == cJSON_False; +} + +int lite_cjson_is_true(lite_cjson_t *lite) +{ + if (!lite) { + return -1; + } + + return (lite->type & 0xFF) == cJSON_True; +} + +int lite_cjson_is_null(lite_cjson_t *lite) +{ + if (!lite) { + return -1; + } + + return (lite->type & 0xFF) == cJSON_NULL; +} +#endif + +int lite_cjson_is_number(lite_cjson_t *lite) +{ + if (!lite) { + return -1; + } + + return (lite->type & 0xFF) == cJSON_Number; +} + +int lite_cjson_is_string(lite_cjson_t *lite) +{ + if (!lite) { + return -1; + } + + return (lite->type & 0xFF) == cJSON_String; +} + +int lite_cjson_is_array(lite_cjson_t *lite) +{ + if (!lite) { + return -1; + } + + return (lite->type & 0xFF) == cJSON_Array; +} + +int lite_cjson_is_object(lite_cjson_t *lite) +{ + if (!lite) { + return -1; + } + + return (lite->type & 0xFF) == cJSON_Object; +} + +int lite_cjson_array_item(lite_cjson_t *lite, int index, lite_cjson_t *lite_item) +{ + parse_buffer buffer; + parse_buffer *p_buffer = &buffer; + lite_cjson_t current_item; + int iter_index = 0; + + if (!lite || lite->type != cJSON_Array || !lite->value || + index < 0 || index >= lite->size || !lite_item) { + return -1; + } + + memset(&buffer, 0, sizeof(parse_buffer)); + buffer.content = (const unsigned char *)lite->value; + buffer.length = lite->value_length; + buffer.offset = 0; + + /* int start_pos = p_buffer->offset; */ + + if (buffer_at_offset(p_buffer)[0] != '[') { + /* not an array */ + return -1; + } + + p_buffer->offset++; + buffer_skip_whitespace(p_buffer); + if (can_access_at_index(p_buffer, 0) && (buffer_at_offset(p_buffer)[0] == ']')) { + /* empty array */ + return -1; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(p_buffer, 0)) { + p_buffer->offset--; + return -1; + } + + /* step back to character in front of the first element */ + p_buffer->offset--; + /* loop through the comma separated array elements */ + do { + memset(¤t_item, 0, sizeof(lite_cjson_t)); + + /* parse next value */ + p_buffer->offset++; + buffer_skip_whitespace(p_buffer); + if (parse_value(¤t_item, p_buffer) != 0) { + return -1; /* failed to parse value */ + } + buffer_skip_whitespace(p_buffer); + + /* printf("current item index: %d, type: %d, length: %d, value: %.*s\n", */ + /* iter_index+1, current_item.type, current_item.value_length, current_item.value_length, current_item.value); */ + + if (iter_index == index) { + memcpy(lite_item, ¤t_item, sizeof(lite_cjson_t)); + return 0; + } + + iter_index++; + } while (can_access_at_index(p_buffer, 0) && (buffer_at_offset(p_buffer)[0] == ',')); + + return -1; +} + +static int _lite_cjson_object_item(lite_cjson_t *lite, const char *key, int key_len, + lite_cjson_t *lite_item) +{ + parse_buffer buffer; + parse_buffer *p_buffer = &buffer; + lite_cjson_t current_item_key; + lite_cjson_t current_item_value; + int index = 0; + + if (!lite || lite->type != cJSON_Object || !lite->value || lite->size == 0 || !key || key_len <= 0 || !lite_item) { + return -1; + }; + + memset(&buffer, 0, sizeof(parse_buffer)); + buffer.content = (const unsigned char *)lite->value; + buffer.length = lite->value_length; + buffer.offset = 0; + + /* int start_pos = p_buffer->offset; */ + + if (cannot_access_at_index(p_buffer, 0) || (buffer_at_offset(p_buffer)[0] != '{')) { + return -1; /* not an object */ + } + + p_buffer->offset++; + buffer_skip_whitespace(p_buffer); + if (can_access_at_index(p_buffer, 0) && (buffer_at_offset(p_buffer)[0] == '}')) { + return -1; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(p_buffer, 0)) { + p_buffer->offset--; + return -1; + } + + /* step back to character in front of the first element */ + p_buffer->offset--; + /* loop through the comma separated array elements */ + do { + memset(¤t_item_key, 0, sizeof(lite_cjson_t)); + memset(¤t_item_value, 0, sizeof(lite_cjson_t)); + + /* parse the name of the child */ + p_buffer->offset++; + buffer_skip_whitespace(p_buffer); + if (parse_string(¤t_item_key, p_buffer) != 0) { + return -1; /* faile to parse name */ + } + buffer_skip_whitespace(p_buffer); + + if (cannot_access_at_index(p_buffer, 0) || (buffer_at_offset(p_buffer)[0] != ':')) { + return -1; /* invalid object */ + } + + /* parse the value */ + p_buffer->offset++; + buffer_skip_whitespace(p_buffer); + if (parse_value(¤t_item_value, p_buffer) != 0) { + return -1; /* failed to parse value */ + } + buffer_skip_whitespace(p_buffer); + + /* printf("Current Object [Index: %d], [Key Length: %d, Key Value: %.*s], [Value Length: %d, Value: %.*s]\n", */ + /* index + 1, current_item_key.value_length,current_item_key.value_length,current_item_key.value, */ + /* current_item_value.value_length,current_item_value.value_length,current_item_value.value); */ + index++; + + /* printf("key: %s, ken_len: %d\n",key,key_len); */ + if ((current_item_key.value_length == key_len) && + memcmp(current_item_key.value, key, key_len) == 0) { + memcpy(lite_item, ¤t_item_value, sizeof(lite_cjson_t)); + return 0; + } + } while (can_access_at_index(p_buffer, 0) && (buffer_at_offset(p_buffer)[0] == ',')); + + return -1; +} + +static int _lite_cjson_key_array_index(const char *key, int key_len, + int *partial_key_len, int *array_key_len, int *array_index) +{ + char *bracket_pre = NULL; + char *bracket_suf = NULL; + int index = 0; + int deep = 0; + char array_index_str[10] = {0}; + + if (!key || !partial_key_len || !array_key_len || !array_index) { + return -1; + } + + for (index = 0; index < key_len; index++) { + switch (key[index]) { + case '[': { + if (deep != 0) { + return -1; + } + deep++; + if (!bracket_pre) { + bracket_pre = (char *)&key[index]; + } + } + break; + case ']': { + if (deep != 1) { + return -1; + } + deep--; + if (key[index - 1] == '[') { + return -1; + } + if (!bracket_suf) { + bracket_suf = (char *)&key[index]; + } + } + break; + default: + break; + + } + } + + if (bracket_pre && bracket_suf && ((bracket_suf - key + 1) == key_len)) { + *partial_key_len = bracket_pre - key; + *array_key_len = bracket_suf - key + 1; + + /* Get Index */ + memcpy(array_index_str, bracket_pre + 1, bracket_suf - bracket_pre - 1); + *array_index = atoi(array_index_str); + return 0; + } + + return -1; +} + +int lite_cjson_object_item(lite_cjson_t *lite, const char *key, int key_len, + lite_cjson_t *lite_item) +{ + int res = 0; + char *delim = NULL; + lite_cjson_t lite_prev; + lite_cjson_t lite_next; + lite_cjson_t lite_iter; + char *key_iter = (char *)key; + int key_iter_len = 0; + int partial_key_len = 0; + int array_key_len = 0; + int array_index = 0; + + if (!lite || lite->type != cJSON_Object || !lite->value || lite->size == 0 || !key || key_len <= 0 || !lite_item) { + return -1; + }; + + memcpy(&lite_iter, lite, sizeof(lite_cjson_t)); + memset(&lite_prev, 0, sizeof(lite_cjson_t)); + + do { + if ((delim = strchr(key_iter, '.')) != NULL) { + /* printf("delim exist,delim : %s\n",delim); */ + memset(&lite_next, 0, sizeof(lite_cjson_t)); + partial_key_len = array_key_len = array_index = 0; + key_iter_len = (int)(delim - key_iter); + } else { + key_iter_len = key_len - (key_iter - key); + /* printf("key: %s, last key: %s, key len: %d, last key len: %d\n",key, key_iter, key_len, key_iter_len); */ + } + + if (_lite_cjson_key_array_index(key_iter, key_iter_len, + &partial_key_len, &array_key_len, &array_index) == 0) { + + /* printf("partial_key_len: %d, array_key_len: %d, array_index: %d\n", partial_key_len, array_key_len, array_index); */ + + res = _lite_cjson_object_item(&lite_iter, key_iter, partial_key_len, &lite_prev); + if (res || lite_prev.type != cJSON_Array) { + return -1; + } + /* printf("current array: %.*s\n",lite_prev.value_length,lite_prev.value); */ + + res = lite_cjson_array_item(&lite_prev, array_index, &lite_next); + if (res) { + return -1; + } + /* printf("current array item: %.*s\n",lite_next.value_length,lite_next.value); */ + + memcpy(&lite_iter, &lite_next, sizeof(lite_cjson_t)); + key_iter += array_key_len + 1; + /* printf("key_iter: %s\n",key_iter); */ + } else { + res = _lite_cjson_object_item(&lite_iter, key_iter, key_iter_len, &lite_prev); + if (res) { + return -1; + } + /* printf("current object: %.*s\n",lite_prev.value_length,lite_prev.value); */ + + memcpy(&lite_iter, &lite_prev, sizeof(lite_cjson_t)); + key_iter = delim + 1; + } + } while (delim); + + /* printf("final lite cjson value: %.*s\n",lite_iter.value_length,lite_iter.value); */ + memcpy(lite_item, &lite_iter, sizeof(lite_cjson_t)); + + return 0; +} + +int lite_cjson_object_item_by_index(lite_cjson_t *lite, int index, lite_cjson_t *lite_item_key, + lite_cjson_t *lite_item_value) +{ + parse_buffer buffer; + parse_buffer *p_buffer = &buffer; + lite_cjson_t current_item_key; + lite_cjson_t current_item_value; + /* int start_pos = p_buffer->offset; */ + int item_index = 0; + + if (!lite || lite->type != cJSON_Object || !lite->value || lite->size == 0 || index < 0 || index >= lite->size) { + return -1; + }; + + memset(&buffer, 0, sizeof(parse_buffer)); + buffer.content = (const unsigned char *)lite->value; + buffer.length = lite->value_length; + buffer.offset = 0; + + if (cannot_access_at_index(p_buffer, 0) || (buffer_at_offset(p_buffer)[0] != '{')) { + return -1; /* not an object */ + } + + p_buffer->offset++; + buffer_skip_whitespace(p_buffer); + if (can_access_at_index(p_buffer, 0) && (buffer_at_offset(p_buffer)[0] == '}')) { + return -1; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(p_buffer, 0)) { + p_buffer->offset--; + return -1; + } + + /* step back to character in front of the first element */ + p_buffer->offset--; + /* loop through the comma separated array elements */ + do { + memset(¤t_item_key, 0, sizeof(lite_cjson_t)); + memset(¤t_item_value, 0, sizeof(lite_cjson_t)); + + /* parse the name of the child */ + p_buffer->offset++; + buffer_skip_whitespace(p_buffer); + if (parse_string(¤t_item_key, p_buffer) != 0) { + return -1; /* faile to parse name */ + } + buffer_skip_whitespace(p_buffer); + + if (cannot_access_at_index(p_buffer, 0) || (buffer_at_offset(p_buffer)[0] != ':')) { + return -1; /* invalid object */ + } + + /* parse the value */ + p_buffer->offset++; + buffer_skip_whitespace(p_buffer); + if (parse_value(¤t_item_value, p_buffer) != 0) { + return -1; /* failed to parse value */ + } + buffer_skip_whitespace(p_buffer); + + /* printf("Current Object [Index: %d], [Key Length: %d, Key Value: %.*s], [Value Length: %d, Value: %.*s]\n", */ + /* index + 1, current_item_key.value_length,current_item_key.value_length,current_item_key.value, */ + /* current_item_value.value_length,current_item_value.value_length,current_item_value.value); */ + + /* printf("index:%d, key: %.*s, value: %.*s\n",index, */ + /* current_item_key.value_length,current_item_key.value, */ + /* current_item_value.value_length,current_item_value.value); */ + + if (item_index == index) { + if (lite_item_key) { + memcpy(lite_item_key, ¤t_item_key, sizeof(lite_cjson_t)); + } + if (lite_item_value) { + memcpy(lite_item_value, ¤t_item_value, sizeof(lite_cjson_t)); + } + return 0; + } + + item_index++; + } while (can_access_at_index(p_buffer, 0) && (buffer_at_offset(p_buffer)[0] == ',')); + + return -1; +} + +/*** cjson create, add and print ***/ +#if defined(DEVICE_MODEL_GATEWAY) || defined(ALCS_ENABLED) || defined(DEPRECATED_LINKKIT) +#define true ((cJSON_bool)1) +#define false ((cJSON_bool)0) +#define cjson_min(a, b) ((a < b) ? a : b) + +typedef struct internal_hooks { + void *(*allocate)(uint32_t size); + void (*deallocate)(void *pointer); + void *(*reallocate)(void *pointer, size_t size); +} internal_hooks; + +typedef struct { + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); + +static void *internal_malloc(uint32_t size) +{ + return HAL_Malloc(size); +} + +static void internal_free(void *ptr) +{ + HAL_Free(ptr); +} + +static internal_hooks global_hooks = { internal_malloc, internal_free, NULL }; +static cJSON_bool print_value(const lite_cjson_item_t *const item, printbuffer *const output_buffer); + +void lite_cjson_init_hooks(lite_cjson_hooks *hooks) +{ + if (hooks == NULL || hooks->malloc_fn == NULL || hooks->free_fn == NULL) { + return; + } + + global_hooks.allocate = hooks->malloc_fn; + global_hooks.deallocate = hooks->free_fn; +} + +static unsigned char *ensure(printbuffer *const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) { + newsize = INT_MAX; + } else { + return NULL; + } + } else { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) { + /* reallocate with realloc if available */ + newbuffer = (unsigned char *)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } else { + /* otherwise reallocate manually */ + newbuffer = (unsigned char *)p->hooks.allocate(newsize); + if (!newbuffer) { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) { + memcpy(newbuffer, p->buffer, p->offset + 1); + } + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +static int remove_zero(unsigned char buffer[26], int length) +{ + int idx = 0, found = 0; + + for (idx = 0; idx < 26; idx++) { + if (buffer[idx] == '.') { + found = 1; + continue; + } + if (buffer[idx] == '\0') { + break; + } + } + + if (found == 0) { + return length; + } + + for (; idx > 0; idx--) { + if (buffer[idx - 1] == '0') { + buffer[idx - 1] = '\0'; + length--; + } else { + if (buffer[idx - 1] == '.') { + buffer[idx - 1] = '\0'; + length--; + } + break; + } + } + + return length; +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const lite_cjson_item_t *const item, printbuffer *const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + float test_float; + double test; + + if (output_buffer == NULL) { + return false; + } + + /* This checks for NaN and Infinity */ + if ((d * 0) != 0) { + length = sprintf((char *)number_buffer, "null"); + } else { + /* Try float data type */ + length = sprintf((char *)number_buffer, "%f", d); + + if ((sscanf((char *)number_buffer, "%f", &test_float) != 1) || ((double)test_float != d)) { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char *)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char *)number_buffer, "%lg", &test) != 1) || ((double)test != d)) { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char *)number_buffer, "%1.17g", d); + } + } else { + length = remove_zero(number_buffer, length); + } + } + + /* sprintf failed or buffer overrun occured */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + if (output_pointer == NULL) { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) { + if (number_buffer[i] == decimal_point) { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) { + return false; + } + + /* empty string */ + if (input == NULL) { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) { + return false; + } + strcpy((char *)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) { + switch (*input_pointer) { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) { + /* normal character, copy */ + *output_pointer = *input_pointer; + } else { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char *)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const lite_cjson_item_t *const item, printbuffer *const p) +{ + return print_string_ptr((unsigned char *)item->valuestring, p); +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer *const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char *)buffer_pointer); +} + +/* Render an array to text */ +static cJSON_bool print_array(const lite_cjson_item_t *const item, printbuffer *const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + lite_cjson_item_t *current_element = item->child; + + if (output_buffer == NULL) { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) { + if (!print_value(current_element, output_buffer)) { + return false; + } + update_offset(output_buffer); + if (current_element->next) { + length = (size_t)(output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) { + return false; + } + *output_pointer++ = ','; + if (output_buffer->format) { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const lite_cjson_item_t *const item, printbuffer *const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + lite_cjson_item_t *current_item = item->child; + + if (output_buffer == NULL) { + return false; + } + + /* Compose the output: */ + length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) { + if (output_buffer->format) { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) { + return false; + } + for (i = 0; i < output_buffer->depth; i++) { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char *)current_item->string, output_buffer)) { + return false; + } + update_offset(output_buffer); + + length = (size_t)(output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = (size_t)((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) { + return false; + } + if (current_item->next) { + *output_pointer++ = ','; + } + + if (output_buffer->format) { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) { + return false; + } + if (output_buffer->format) { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const lite_cjson_item_t *const item, printbuffer *const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) { + return false; + } + + switch ((item->type) & 0xFF) { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) { + return false; + } + strcpy((char *)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) { + return false; + } + strcpy((char *)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) { + return false; + } + strcpy((char *)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: { + size_t raw_length = 0; + if (item->valuestring == NULL) { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +static unsigned char *print(const lite_cjson_item_t *const item, cJSON_bool format, const internal_hooks *const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char *) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) { + printed = (unsigned char *) hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } else { /* otherwise copy the JSON over to a new buffer */ + printed = (unsigned char *) hooks->allocate(buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) { + hooks->deallocate(buffer->buffer); + } + + return NULL; +} + +char *lite_cjson_print(lite_cjson_item_t *item) +{ + return (char *)print(item, true, &global_hooks); +} + +char *lite_cjson_print_unformatted(lite_cjson_item_t *item) +{ + return (char *)print(item, false, &global_hooks); +} + +/* Delete a cJSON structure. */ +void lite_cjson_delete(lite_cjson_item_t *item) +{ + lite_cjson_item_t *next = NULL; + while (item != NULL) { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) { + lite_cjson_delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +static void suffix_object(lite_cjson_item_t *prev, lite_cjson_item_t *item) +{ + prev->next = item; + item->prev = prev; +} + +static cJSON_bool add_item_to_array(lite_cjson_item_t *array, lite_cjson_item_t *item) +{ + lite_cjson_item_t *child = NULL; + + if ((item == NULL) || (array == NULL)) { + return false; + } + + child = array->child; + + if (child == NULL) { + /* list is empty, start new one */ + array->child = item; + } else { + /* append to the end */ + while (child->next) { + child = child->next; + } + suffix_object(child, item); + } + + return true; +} + +void lite_cjson_add_item_to_array(lite_cjson_item_t *array, lite_cjson_item_t *item) +{ + add_item_to_array(array, item); +} + +static void *cast_away_const(const void *string) +{ + return (void *)string; +} + +static unsigned char *cJSON_strdup(const unsigned char *string, const internal_hooks *const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) { + return NULL; + } + + length = strlen((const char *)string) + sizeof(""); + copy = (unsigned char *)hooks->allocate(length); + if (copy == NULL) { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +static cJSON_bool add_item_to_object(lite_cjson_item_t *const object, const char *const string, + lite_cjson_item_t *const item, const internal_hooks *const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL)) { + return false; + } + + if (constant_key) { + new_key = (char *)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } else { + new_key = (char *)cJSON_strdup((const unsigned char *)string, hooks); + if (new_key == NULL) { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +void lite_cjson_add_item_to_object(lite_cjson_item_t *object, const char *string, lite_cjson_item_t *item) +{ + add_item_to_object(object, string, item, &global_hooks, false); +} + +static lite_cjson_item_t *cJSON_New_Item(const internal_hooks *const hooks) +{ + lite_cjson_item_t *node = (lite_cjson_item_t *)hooks->allocate(sizeof(lite_cjson_item_t)); + if (node) { + memset(node, '\0', sizeof(lite_cjson_item_t)); + } + + return node; +} + +lite_cjson_item_t *lite_cjson_create_null(void) +{ + lite_cjson_item_t *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_NULL; + } + + return item; +} + +lite_cjson_item_t *lite_cjson_create_true(void) +{ + lite_cjson_item_t *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_True; + } + + return item; +} + +lite_cjson_item_t *lite_cjson_create_false(void) +{ + lite_cjson_item_t *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_False; + } + + return item; +} + +lite_cjson_item_t *lite_cjson_create_bool(cJSON_bool b) +{ + lite_cjson_item_t *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = b ? cJSON_True : cJSON_False; + } + + return item; +} + +lite_cjson_item_t *lite_cjson_create_number(double num) +{ + lite_cjson_item_t *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) { + item->valueint = INT_MAX; + } else if (num <= INT_MIN) { + item->valueint = INT_MIN; + } else { + item->valueint = (int)num; + } + } + + return item; +} +lite_cjson_item_t *lite_cjson_create_string(const char *string) +{ + lite_cjson_item_t *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_String; + item->valuestring = (char *)cJSON_strdup((const unsigned char *)string, &global_hooks); + if (!item->valuestring) { + lite_cjson_delete(item); + return NULL; + } + } + + return item; +} + +lite_cjson_item_t *lite_cjson_create_array(void) +{ + lite_cjson_item_t *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_Array; + } + + return item; +} + +lite_cjson_item_t *lite_cjson_create_object(void) +{ + lite_cjson_item_t *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_Object; + } + + return item; +} + +lite_cjson_item_t *lite_cjson_create_intArray(const int *numbers, int count) +{ + size_t i = 0; + lite_cjson_item_t *n = NULL; + lite_cjson_item_t *p = NULL; + lite_cjson_item_t *a = NULL; + + if ((count < 0) || (numbers == NULL)) { + return NULL; + } + + a = lite_cjson_create_array(); + for (i = 0; a && (i < (size_t)count); i++) { + n = lite_cjson_create_number(numbers[i]); + if (!n) { + lite_cjson_delete(a); + return NULL; + } + if (!i) { + a->child = n; + } else { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +lite_cjson_item_t *lite_cjson_create_floatArray(const float *numbers, int count) +{ + size_t i = 0; + lite_cjson_item_t *n = NULL; + lite_cjson_item_t *p = NULL; + lite_cjson_item_t *a = NULL; + + if ((count < 0) || (numbers == NULL)) { + return NULL; + } + + a = lite_cjson_create_array(); + + for (i = 0; a && (i < (size_t)count); i++) { + n = lite_cjson_create_number((double)numbers[i]); + if (!n) { + lite_cjson_delete(a); + return NULL; + } + if (!i) { + a->child = n; + } else { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +lite_cjson_item_t *lite_cjson_create_doubleArray(const double *numbers, int count) +{ + size_t i = 0; + lite_cjson_item_t *n = NULL; + lite_cjson_item_t *p = NULL; + lite_cjson_item_t *a = NULL; + + if ((count < 0) || (numbers == NULL)) { + return NULL; + } + + a = lite_cjson_create_array(); + + for (i = 0; a && (i < (size_t)count); i++) { + n = lite_cjson_create_number(numbers[i]); + if (!n) { + lite_cjson_delete(a); + return NULL; + } + if (!i) { + a->child = n; + } else { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +lite_cjson_item_t *lite_cjson_create_stringArray(const char **strings, int count) +{ + size_t i = 0; + lite_cjson_item_t *n = NULL; + lite_cjson_item_t *p = NULL; + lite_cjson_item_t *a = NULL; + + if ((count < 0) || (strings == NULL)) { + return NULL; + } + + a = lite_cjson_create_array(); + + for (i = 0; a && (i < (size_t)count); i++) { + n = lite_cjson_create_string(strings[i]); + if (!n) { + lite_cjson_delete(a); + return NULL; + } + if (!i) { + a->child = n; + } else { + suffix_object(p, n); + } + p = n; + } + + return a; +} +#endif +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_cjson.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_cjson.h new file mode 100644 index 00000000..77c14b55 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_cjson.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _INFRA_CJSON_H_ +#define _INFRA_CJSON_H_ + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#ifndef LITE_CJSON_NESTING_LIMIT + #define LITE_CJSON_NESTING_LIMIT 1000 +#endif + +/* The cJSON structure: */ +typedef struct lite_cjson_st { + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *value; + int value_length; + + /* The item's size, if type == cJSON_Array and type == cJSON_Object */ + int size; + + double value_double; + int value_int; +} lite_cjson_t; + +int lite_cjson_parse(const char *src, int src_len, lite_cjson_t *lite); + +int lite_cjson_is_false(lite_cjson_t *lite); +int lite_cjson_is_true(lite_cjson_t *lite); +int lite_cjson_is_null(lite_cjson_t *lite); +int lite_cjson_is_number(lite_cjson_t *lite); +int lite_cjson_is_string(lite_cjson_t *lite); +int lite_cjson_is_array(lite_cjson_t *lite); +int lite_cjson_is_object(lite_cjson_t *lite); + +int lite_cjson_array_item(lite_cjson_t *lite, int index, lite_cjson_t *lite_item); +int lite_cjson_object_item( + lite_cjson_t *lite, + const char *key, + int key_len, + lite_cjson_t *lite_item); +int lite_cjson_object_item_by_index( + lite_cjson_t *lite, + int index, + lite_cjson_t *lite_item_key, + lite_cjson_t *lite_item_value); + + +/*** lite_cjson create, add and print ***/ +typedef int cJSON_bool; + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct lite_cjson_item_t { + struct lite_cjson_item_t *next, + *prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct lite_cjson_item_t + *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + + int type; /* The type of the item, as above. */ + + char *valuestring; /* The item's string, if type==cJSON_String */ + int valueint; /* The item's number, if type==cJSON_Number */ + double valuedouble; /* The item's number, if type==cJSON_Number */ + + char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ +} lite_cjson_item_t; + +typedef struct { + void *(*malloc_fn)(unsigned int sz); + void(*free_fn)(void *ptr); +} lite_cjson_hooks; + +void lite_cjson_init_hooks(lite_cjson_hooks *hooks); + +/* Render a lite_cjson_item_t entity to text for transfer/storage. Free the char* when finished. */ +char *lite_cjson_print(lite_cjson_item_t *item); +char *lite_cjson_print_unformatted(lite_cjson_item_t *item); + +/* Delete a lite_cjson_item_t entity and all subentities. */ +void lite_cjson_delete(lite_cjson_item_t *item); + +/* Append item to specific object */ +void lite_cjson_add_item_to_array(lite_cjson_item_t *array, lite_cjson_item_t *item); +void lite_cjson_add_item_to_object(lite_cjson_item_t *object, const char *string, lite_cjson_item_t *item); + +/* These calls create a lite_cjson_item_t item of the appropriate type. */ +lite_cjson_item_t *lite_cjson_create_null(void); +lite_cjson_item_t *lite_cjson_create_true(void); +lite_cjson_item_t *lite_cjson_create_false(void); +lite_cjson_item_t *lite_cjson_create_bool(int b); +lite_cjson_item_t *lite_cjson_create_number(double num); +lite_cjson_item_t *lite_cjson_create_string(const char *string); +lite_cjson_item_t *lite_cjson_create_array(void); +lite_cjson_item_t *lite_cjson_create_object(void); + +/* These utilities create an Array of count items. */ +lite_cjson_item_t *lite_cjson_create_intArray(const int *numbers, int count); +lite_cjson_item_t *lite_cjson_create_floatArray(const float *numbers, int count); +lite_cjson_item_t *lite_cjson_create_doubleArray(const double *numbers, int count); +lite_cjson_item_t *lite_cjson_create_stringArray(const char **strings, int count); + +/* Macros for creating things quickly. */ +#define lite_cjson_add_null_to_object(object,name) lite_cjson_add_item_to_object(object, name, lite_cjson_create_null()) +#define lite_cjson_add_true_to_object(object,name) lite_cjson_add_item_to_object(object, name, lite_cjson_create_true()) +#define lite_cjson_add_false_to_object(object,name) lite_cjson_add_item_to_object(object, name, lite_cjson_create_false()) +#define lite_cjson_add_bool_to_object(object,name,b) lite_cjson_add_item_to_object(object, name, lite_cjson_create_bool(b)) +#define lite_cjson_add_number_to_object(object,name,n) lite_cjson_add_item_to_object(object, name, lite_cjson_create_number(n)) +#define lite_cjson_add_string_to_object(object,name,s) lite_cjson_add_item_to_object(object, name, lite_cjson_create_string(s)) +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_compat.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_compat.c new file mode 100644 index 00000000..a83ed728 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_compat.c @@ -0,0 +1,279 @@ +#include "infra_config.h" + +#ifdef INFRA_COMPAT +#include +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_compat.h" + +#if !defined(INFRA_LOG) +void IOT_SetLogLevel(IOT_LogLevel level) {} +#endif + +#ifdef MQTT_COMM_ENABLED +#include "dev_sign_api.h" +#include "mqtt_api.h" + +#ifdef INFRA_LOG + #include "infra_log.h" + #define sdk_err(...) log_err("infra_compat", __VA_ARGS__) + #define sdk_info(...) log_info("infra_compat", __VA_ARGS__) +#else + #define sdk_err(...) + #define sdk_info(...) +#endif + +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); + +static sdk_impl_ctx_t g_sdk_impl_ctx = {0}; +/* global variable for mqtt construction */ +static iotx_conn_info_t g_iotx_conn_info = {0}; +static char g_empty_string[1] = ""; + +int IOT_SetupConnInfo(const char *product_key, + const char *device_name, + const char *device_secret, + void **info_ptr) +{ + if (product_key == NULL || device_name == NULL || device_secret == NULL || + strlen(product_key) > IOTX_PRODUCT_KEY_LEN || + strlen(device_name) > IOTX_DEVICE_NAME_LEN || + strlen(device_secret) > IOTX_DEVICE_SECRET_LEN) { + return NULL_VALUE_ERROR; + } + + if (info_ptr) { + memset(&g_iotx_conn_info, 0, sizeof(iotx_conn_info_t)); + g_iotx_conn_info.host_name = g_empty_string; + g_iotx_conn_info.client_id = g_empty_string; + g_iotx_conn_info.username = g_empty_string; + g_iotx_conn_info.password = g_empty_string; + g_iotx_conn_info.pub_key = g_empty_string; + + *info_ptr = &g_iotx_conn_info; + } + return SUCCESS_RETURN; +} +#endif /* #ifdef MQTT_COMM_ENABLED */ + +#if defined(DEVICE_MODEL_CLASSIC) && defined(DEVICE_MODEL_ENABLED) + #include "iotx_dm.h" +#endif + +int IOT_Ioctl(int option, void *data) +{ + int res = SUCCESS_RETURN; + sdk_impl_ctx_t *ctx = NULL; + + ctx = &g_sdk_impl_ctx; + + if (option < 0 || data == NULL) { + return FAIL_RETURN; + } + + switch (option) { + case IOTX_IOCTL_SET_REGION: { + ctx->domain_type = *(int *)data; + /* iotx_guider_set_region(*(int *)data); */ + + res = SUCCESS_RETURN; + } + break; + case IOTX_IOCTL_GET_REGION: { + *(int *)data = ctx->domain_type; + + res = SUCCESS_RETURN; + } + break; + case IOTX_IOCTL_SET_MQTT_DOMAIN: { + ctx->domain_type = IOTX_CLOUD_REGION_CUSTOM; + + if (ctx->cloud_custom_domain) { + HAL_Free(ctx->cloud_custom_domain); + ctx->cloud_custom_domain = NULL; + g_infra_mqtt_domain[IOTX_CLOUD_REGION_CUSTOM] = NULL; + } + ctx->cloud_custom_domain = HAL_Malloc(strlen((char *)data) + 1); + if (ctx->cloud_custom_domain == NULL) { + return FAIL_RETURN; + } + memset(ctx->cloud_custom_domain, 0, strlen((char *)data) + 1); + memcpy(ctx->cloud_custom_domain, data, strlen((char *)data)); + g_infra_mqtt_domain[IOTX_CLOUD_REGION_CUSTOM] = (const char *)ctx->cloud_custom_domain; + res = SUCCESS_RETURN; + } + break; + case IOTX_IOCTL_SET_HTTP_DOMAIN: { + ctx->domain_type = IOTX_HTTP_REGION_CUSTOM; + + if (ctx->http_custom_domain) { + HAL_Free(ctx->http_custom_domain); + ctx->http_custom_domain = NULL; + g_infra_http_domain[IOTX_CLOUD_REGION_CUSTOM] = NULL; + } + ctx->http_custom_domain = HAL_Malloc(strlen((char *)data) + 1); + if (ctx->http_custom_domain == NULL) { + return FAIL_RETURN; + } + memset(ctx->http_custom_domain, 0, strlen((char *)data) + 1); + memcpy(ctx->http_custom_domain, data, strlen((char *)data)); + g_infra_http_domain[IOTX_CLOUD_REGION_CUSTOM] = (const char *)ctx->http_custom_domain; + res = SUCCESS_RETURN; + } + break; + case IOTX_IOCTL_SET_DYNAMIC_REGISTER: { + ctx->dynamic_register = *(int *)data; + + res = SUCCESS_RETURN; + } + break; + case IOTX_IOCTL_GET_DYNAMIC_REGISTER: { + *(int *)data = ctx->dynamic_register; + + res = SUCCESS_RETURN; + } + break; +#if defined(DEVICE_MODEL_CLASSIC) && defined(DEVICE_MODEL_ENABLED) && !defined(DEPRECATED_LINKKIT) +#if !defined(DEVICE_MODEL_RAWDATA_SOLO) + case IOTX_IOCTL_RECV_EVENT_REPLY: + case IOTX_IOCTL_RECV_PROP_REPLY: { + res = iotx_dm_set_opt(IMPL_LINKKIT_IOCTL_SWITCH_EVENT_POST_REPLY, data); + } + break; + case IOTX_IOCTL_SEND_PROP_SET_REPLY : { + res = iotx_dm_set_opt(IMPL_LINKKIT_IOCTL_SWITCH_PROPERTY_SET_REPLY, data); + } + break; +#endif + case IOTX_IOCTL_SET_SUBDEV_SIGN: { + /* todo */ + } + break; + case IOTX_IOCTL_GET_SUBDEV_LOGIN: { + /* todo */ + } + break; +#if defined(DEVICE_MODEL_CLASSIC) && defined(DEVICE_MODEL_GATEWAY) +#ifdef DEVICE_MODEL_SUBDEV_OTA + case IOTX_IOCTL_SET_OTA_DEV_ID: { + int devid = *(int *)(data); + res = iotx_dm_ota_switch_device(devid); + } + break; +#endif +#endif +#else + case IOTX_IOCTL_RECV_EVENT_REPLY: + case IOTX_IOCTL_RECV_PROP_REPLY: + case IOTX_IOCTL_SEND_PROP_SET_REPLY: + case IOTX_IOCTL_GET_SUBDEV_LOGIN: { + res = SUCCESS_RETURN; + } + break; +#endif + default: { + res = FAIL_RETURN; + } + break; + } + + return res; +} + +void IOT_DumpMemoryStats(IOT_LogLevel level) +{ +#ifdef INFRA_MEM_STATS + int lvl = (int)level; + + if (lvl > LOG_DEBUG_LEVEL) { + lvl = LOG_DEBUG_LEVEL; + HAL_Printf("Invalid input level, using default: %d => %d", level, lvl); + } + + LITE_dump_malloc_free_stats(lvl); +#endif +} + +static void *g_event_monitor = NULL; + +int iotx_event_regist_cb(void (*monitor_cb)(int event)) +{ + g_event_monitor = (void *)monitor_cb; + return 0; +} + +int iotx_event_post(int event) +{ + if (g_event_monitor == NULL) { + return -1; + } + ((void (*)(int))g_event_monitor)(event); + return 0; +} + +typedef struct { + int eventid; + void *callback; +} impl_event_map_t; + +static impl_event_map_t g_impl_event_map[] = { + {ITE_AWSS_STATUS, NULL}, + {ITE_CONNECT_SUCC, NULL}, + {ITE_CONNECT_FAIL, NULL}, + {ITE_DISCONNECTED, NULL}, + {ITE_REDIRECT, NULL}, + {ITE_RAWDATA_ARRIVED, NULL}, + {ITE_SERVICE_REQUEST, NULL}, + {ITE_PROPERTY_SET, NULL}, + {ITE_PROPERTY_GET, NULL}, +#ifdef DEVICE_MODEL_SHADOW + {ITE_PROPERTY_DESIRED_GET_REPLY, NULL}, +#endif + {ITE_REPORT_REPLY, NULL}, + {ITE_TRIGGER_EVENT_REPLY, NULL}, + {ITE_TIMESTAMP_REPLY, NULL}, + {ITE_TOPOLIST_REPLY, NULL}, + {ITE_PERMIT_JOIN, NULL}, + {ITE_INITIALIZE_COMPLETED, NULL}, + {ITE_FOTA, NULL}, + {ITE_COTA, NULL}, + {ITE_MQTT_CONNECT_SUCC, NULL} +}; + +void *iotx_event_callback(int evt) +{ + if (evt < 0 || evt >= sizeof(g_impl_event_map) / sizeof(impl_event_map_t)) { + return NULL; + } + return g_impl_event_map[evt].callback; +} + +DEFINE_EVENT_CALLBACK(ITE_AWSS_STATUS, int (*callback)(int)) +DEFINE_EVENT_CALLBACK(ITE_CONNECT_SUCC, int (*callback)(void)) +DEFINE_EVENT_CALLBACK(ITE_CONNECT_FAIL, int (*callback)(void)) +DEFINE_EVENT_CALLBACK(ITE_DISCONNECTED, int (*callback)(void)) +DEFINE_EVENT_CALLBACK(ITE_REDIRECT, int (*callback)(void)) +DEFINE_EVENT_CALLBACK(ITE_RAWDATA_ARRIVED, int (*callback)(const int, const unsigned char *, const int)) +DEFINE_EVENT_CALLBACK(ITE_SERVICE_REQUEST, int (*callback)(const int, const char *, const int, const char *, + const int, char **, int *)) +DEFINE_EVENT_CALLBACK(ITE_PROPERTY_SET, int (*callback)(const int, const char *, const int)) +#ifdef DEVICE_MODEL_SHADOW + DEFINE_EVENT_CALLBACK(ITE_PROPERTY_DESIRED_GET_REPLY, int (*callback)(const char *, const int)) +#endif +DEFINE_EVENT_CALLBACK(ITE_PROPERTY_GET, int (*callback)(const int, const char *, const int, char **, int *)) +DEFINE_EVENT_CALLBACK(ITE_REPORT_REPLY, int (*callback)(const int, const int, const int, const char *, + const int)) +DEFINE_EVENT_CALLBACK(ITE_TRIGGER_EVENT_REPLY, int (*callback)(const int, const int, const int, const char *, + const int, const char *, const int)) +DEFINE_EVENT_CALLBACK(ITE_TIMESTAMP_REPLY, int (*callback)(const char *)) +DEFINE_EVENT_CALLBACK(ITE_TOPOLIST_REPLY, int (*callback)(const int, const int, const int, const char *, + const int)) +DEFINE_EVENT_CALLBACK(ITE_PERMIT_JOIN, int (*callback)(const char *, int)) +DEFINE_EVENT_CALLBACK(ITE_INITIALIZE_COMPLETED, int (*callback)(const int)) +DEFINE_EVENT_CALLBACK(ITE_FOTA, int (*callback)(const int, const char *)) +DEFINE_EVENT_CALLBACK(ITE_COTA, int (*callback)(const int, const char *, int, const char *, + const char *, const char *, const char *)) +DEFINE_EVENT_CALLBACK(ITE_MQTT_CONNECT_SUCC, int (*callback)(void)) + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_compat.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_compat.h new file mode 100644 index 00000000..acba415f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_compat.h @@ -0,0 +1,290 @@ +#ifndef _INFRA_COMPAT_H_ +#define _INFRA_COMPAT_H_ + +#include "infra_defs.h" +#include "infra_list.h" + +#undef being_deprecated +#define being_deprecated + +typedef enum _IOT_LogLevel { + IOT_LOG_NONE = 0, + IOT_LOG_CRIT, + IOT_LOG_ERROR, + IOT_LOG_WARNING, + IOT_LOG_INFO, + IOT_LOG_DEBUG, +} IOT_LogLevel; + +DLL_IOT_API void IOT_SetLogLevel(IOT_LogLevel level); +DLL_IOT_API void IOT_DumpMemoryStats(IOT_LogLevel level); + +/** + * @brief event list used for iotx_regist_event_monitor_cb + */ +enum iotx_event_t { + IOTX_AWSS_START = 0x1000, /* AWSS start without enbale, just supports device discover */ + IOTX_AWSS_ENABLE, /* AWSS enable */ + IOTX_AWSS_LOCK_CHAN, /* AWSS lock channel(Got AWSS sync packet) */ + IOTX_AWSS_CS_ERR, /* AWSS AWSS checksum is error */ + IOTX_AWSS_PASSWD_ERR, /* AWSS decrypt passwd error */ + IOTX_AWSS_GOT_SSID_PASSWD, /* AWSS parse ssid and passwd successfully */ + IOTX_AWSS_CONNECT_ADHA, /* AWSS try to connnect adha (device discover, router solution) */ + IOTX_AWSS_CONNECT_ADHA_FAIL, /* AWSS fails to connect adha */ + IOTX_AWSS_CONNECT_AHA, /* AWSS try to connect aha (AP solution) */ + IOTX_AWSS_CONNECT_AHA_FAIL, /* AWSS fails to connect aha */ + IOTX_AWSS_SETUP_NOTIFY, /* AWSS sends out device setup information (AP and router solution) */ + IOTX_AWSS_CONNECT_ROUTER, /* AWSS try to connect destination router */ + IOTX_AWSS_CONNECT_ROUTER_FAIL, /* AWSS fails to connect destination router. */ + IOTX_AWSS_GOT_IP, /* AWSS connects destination successfully and got ip address */ + IOTX_AWSS_SUC_NOTIFY, /* AWSS sends out success notify (AWSS sucess) */ + IOTX_AWSS_BIND_NOTIFY, /* AWSS sends out bind notify information to support bind between user and device */ + IOTX_AWSS_ENABLE_TIMEOUT, /* AWSS enable timeout(user needs to call awss_config_press again to enable awss) */ + IOTX_CONN_CLOUD = 0x2000, /* Device try to connect cloud */ + IOTX_CONN_CLOUD_FAIL, /* Device fails to connect cloud, refer to net_sockets.h for error code */ + IOTX_CONN_CLOUD_SUC, /* Device connects cloud successfully */ + IOTX_RESET = 0x3000, /* Linkkit reset success (just got reset response from cloud without any other operation) */ +}; + +/** + * @brief register callback to monitor all event from system. + * + * @param callback, when some event occurs, the system will trigger callback to user. + * refer to enum iotx_event_t for event list supported. + * + * @return 0 when success, -1 when fail. + * @note: user should make sure that callback is not block and runs to complete fast. + */ +int iotx_event_regist_cb(void (*monitor_cb)(int event)); + +/** + * @brief post event to trigger callback resitered by iotx_event_regist_cb + * + * @param event, event id, refer to iotx_event_t + * + * @return 0 when success, -1 when fail. + */ +int iotx_event_post(int event); + +#ifndef BUILD_AOS + +#ifndef VERSION_NUM_SIZE + #define VERSION_NUM_SIZE 4 +#endif + +#ifndef RANDOM_NUM_SIZE + #define RANDOM_NUM_SIZE 4 +#endif + +#ifndef MAC_ADDRESS_SIZE + #define MAC_ADDRESS_SIZE 8 +#endif + +#ifndef CHIP_CODE_SIZE + #define CHIP_CODE_SIZE 4 +#endif + +#define AOS_ACTIVE_INFO_LEN (81) +unsigned int aos_get_version_info(unsigned char version_num[VERSION_NUM_SIZE], + unsigned char random_num[RANDOM_NUM_SIZE], + unsigned char mac_address[MAC_ADDRESS_SIZE], + unsigned char chip_code[CHIP_CODE_SIZE], + unsigned char *output_buffer, + unsigned int output_buffer_size); +#endif + +typedef enum { + ITE_AWSS_STATUS, + ITE_CONNECT_SUCC, + ITE_CONNECT_FAIL, + ITE_DISCONNECTED, + ITE_REDIRECT, + ITE_RAWDATA_ARRIVED, + ITE_SERVICE_REQUEST, + ITE_PROPERTY_SET, + ITE_PROPERTY_GET, +#ifdef DEVICE_MODEL_SHADOW + ITE_PROPERTY_DESIRED_GET_REPLY, +#endif + ITE_REPORT_REPLY, + ITE_TRIGGER_EVENT_REPLY, + ITE_TIMESTAMP_REPLY, + ITE_TOPOLIST_REPLY, + ITE_PERMIT_JOIN, + ITE_INITIALIZE_COMPLETED, + ITE_FOTA, + ITE_COTA, + ITE_MQTT_CONNECT_SUCC +} iotx_ioctl_event_t; + +#define IOT_RegisterCallback(evt, cb) iotx_register_for_##evt(cb); +#define DECLARE_EVENT_CALLBACK(evt, cb) DLL_IOT_API int iotx_register_for_##evt(cb); +#define DEFINE_EVENT_CALLBACK(evt, cb) DLL_IOT_API int iotx_register_for_##evt(cb) { \ + if (evt < 0 || evt >= sizeof(g_impl_event_map)/sizeof(impl_event_map_t)) {return -1;} \ + g_impl_event_map[evt].callback = (void *)callback;return 0;} + +DECLARE_EVENT_CALLBACK(ITE_AWSS_STATUS, int (*cb)(int)) +DECLARE_EVENT_CALLBACK(ITE_CONNECT_SUCC, int (*cb)(void)) +DECLARE_EVENT_CALLBACK(ITE_CONNECT_FAIL, int (*cb)(void)) +DECLARE_EVENT_CALLBACK(ITE_DISCONNECTED, int (*cb)(void)) +DECLARE_EVENT_CALLBACK(ITE_REDIRECT, int (*cb)(void)) +DECLARE_EVENT_CALLBACK(ITE_RAWDATA_ARRIVED, int (*cb)(const int, const unsigned char *, const int)) +DECLARE_EVENT_CALLBACK(ITE_SERVICE_REQUEST, int (*cb)(const int, const char *, const int, const char *, const int, + char **, int *)) +DECLARE_EVENT_CALLBACK(ITE_PROPERTY_SET, int (*cb)(const int, const char *, const int)) +DECLARE_EVENT_CALLBACK(ITE_PROPERTY_DESIRED_GET_REPLY, int (*cb)(const char *, const int)) +DECLARE_EVENT_CALLBACK(ITE_PROPERTY_GET, int (*cb)(const int, const char *, const int, char **, int *)) +DECLARE_EVENT_CALLBACK(ITE_REPORT_REPLY, int (*cb)(const int, const int, const int, const char *, const int)) +DECLARE_EVENT_CALLBACK(ITE_TRIGGER_EVENT_REPLY, int (*cb)(const int, const int, const int, const char *, const int, + const char *, const int)) +DECLARE_EVENT_CALLBACK(ITE_TIMESTAMP_REPLY, int (*cb)(const char *)) +DECLARE_EVENT_CALLBACK(ITE_TOPOLIST_REPLY, int (*cb)(const int, const int, const int, const char *, const int)) +DECLARE_EVENT_CALLBACK(ITE_PERMIT_JOIN, int (*cb)(const char *, const int)) +DECLARE_EVENT_CALLBACK(ITE_INITIALIZE_COMPLETED, int (*cb)(const int)) +DECLARE_EVENT_CALLBACK(ITE_FOTA, int (*cb)(const int, const char *)) +DECLARE_EVENT_CALLBACK(ITE_COTA, int (*cb)(const int, const char *, int, const char *, const char *, + const char *, const char *)) +DECLARE_EVENT_CALLBACK(ITE_MQTT_CONNECT_SUCC, int (*cb)(void)) + +void *iotx_event_callback(int evt); + +#ifndef offset_of + #define offset_of aos_offsetof +#endif +#ifndef container_of + #define container_of aos_container_of +#endif + +#define ALIYUN_LIST_HEAD AOS_DLIST_HEAD +#define LIST_HEAD_INIT AOS_DLIST_INIT +#define INIT_LIST_HEAD INIT_AOS_DLIST_HEAD +#define ALIYUN_LIST_INIT AOS_DLIST_INIT + +#define list_head dlist_s +#define list_head_t dlist_t + +#define list_add dlist_add +#define list_add_tail dlist_add_tail +#define list_del dlist_del +#define list_empty dlist_empty +#define list_entry_number dlist_entry_number +#define list_first_entry dlist_first_entry +#define list_for_each dlist_for_each +#define list_for_each_entry_reverse dlist_for_each_entry_reverse +#define list_for_each_safe dlist_for_each_safe +#define list_init dlist_init + +#define list_for_each_entry(pos, head, member, type) \ + dlist_for_each_entry(head, pos, type, member) + +#define list_for_each_entry_safe(pos, n, head, member, type) \ + for (pos = list_entry((head)->next, type, member), \ + n = list_entry(pos->member.next, type, member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, type, member)) + +#define list_next_entry(pos, member, type) \ + list_entry((pos)->member.next, type, member) + +static inline void list_del_init(struct list_head *entry) +{ + list_del(entry); + INIT_LIST_HEAD(entry); +} + +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +typedef struct { + uint16_t port; + uint8_t init; + char *host_name; + char *client_id; + char *username; + char *password; + const char *pub_key; +} iotx_conn_info_t, *iotx_conn_info_pt; + +int IOT_SetupConnInfo(const char *product_key, + const char *device_name, + const char *device_secret, + void **info_ptr); + +typedef struct { + int domain_type; + int dynamic_register; + char *cloud_custom_domain; + char *http_custom_domain; +} sdk_impl_ctx_t; + +typedef enum { + IOTX_IOCTL_SET_REGION, /* value(int*): iotx_cloud_region_types_t */ + IOTX_IOCTL_GET_REGION, /* value(int*) */ + IOTX_IOCTL_SET_MQTT_DOMAIN, /* value(const char*): point to mqtt domain string */ + IOTX_IOCTL_SET_HTTP_DOMAIN, /* value(const char*): point to http domain string */ + IOTX_IOCTL_SET_DYNAMIC_REGISTER, /* value(int*): 0 - Disable Dynamic Register, 1 - Enable Dynamic Register */ + IOTX_IOCTL_GET_DYNAMIC_REGISTER, /* value(int*) */ + IOTX_IOCTL_RECV_PROP_REPLY, /* value(int*): 0 - Disable property post reply by cloud; 1 - Enable property post reply by cloud */ + IOTX_IOCTL_RECV_EVENT_REPLY, /* value(int*): 0 - Disable event post reply by cloud; 1 - Enable event post reply by cloud */ + IOTX_IOCTL_SEND_PROP_SET_REPLY, /* value(int*): 0 - Disable send post set reply by devid; 1 - Enable property set reply by devid */ + IOTX_IOCTL_SET_SUBDEV_SIGN, /* value(const char*): only for slave device, set signature of subdevice */ + IOTX_IOCTL_GET_SUBDEV_LOGIN, /* value(int*): 0 - SubDev is logout; 1 - SubDev is login */ + IOTX_IOCTL_SET_OTA_DEV_ID /* value(int*): select the device to do OTA according to devid */ +} iotx_ioctl_option_t; + +typedef enum { + IMPL_LINKKIT_IOCTL_SWITCH_PROPERTY_POST_REPLY, /* only for master device, choose whether you need receive property post reply message */ + IMPL_LINKKIT_IOCTL_SWITCH_EVENT_POST_REPLY, /* only for master device, choose whether you need receive event post reply message */ + IMPL_LINKKIT_IOCTL_SWITCH_PROPERTY_SET_REPLY, /* only for master device, choose whether you need send property set reply message */ + IMPL_LINKKIT_IOCTL_MAX +} impl_linkkit_ioctl_cmd_t; + +/** + * @brief Setup Demain type, should be called before MQTT connection. + * + * @param [in] option: see iotx_ioctl_option_t. + * + * @return None. + * @see None. + */ +int IOT_Ioctl(int option, void *data); + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" +#endif + +/* compatible for V2.3.0 */ +#define IOTX_CLOUD_DOMAIN_SH IOTX_CLOUD_REGION_SHANGHAI +#define IOTX_CLOUD_DOMAIN_SG IOTX_CLOUD_REGION_SINGAPORE +#define IOTX_CLOUD_DOMAIN_JP IOTX_CLOUD_REGION_JAPAN +#define IOTX_CLOUD_DOMAIN_US IOTX_CLOUD_REGION_USA_WEST +#define IOTX_CLOUD_DOMAIN_GER IOTX_CLOUD_REGION_GERMANY +#define IOTX_IOCTL_SET_DOMAIN IOTX_IOCTL_SET_REGION +#define IOTX_IOCTL_GET_DOMAIN IOTX_IOCTL_GET_REGION + +#define IOT_OpenLog(arg) +#define IOT_CloseLog() IOT_SetLogLevel(IOT_LOG_NONE) +#define IOT_LOG_EMERG IOT_LOG_NONE + +#define IOT_Linkkit_Post IOT_Linkkit_Report +/* compatible for V2.3.0 end */ + +typedef enum { + HAL_AES_ENCRYPTION = 0, + HAL_AES_DECRYPTION = 1, +} AES_DIR_t; + +typedef void *p_HAL_Aes128_t; + +#define NETWORK_ADDR_LEN (16) + +typedef struct _network_addr_t { + unsigned char + addr[NETWORK_ADDR_LEN]; + unsigned short port; +} NetworkAddr; + +#endif /* _INFRA_COMPAT_H_ */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_config.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_config.h new file mode 100644 index 00000000..8e57a8eb --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_config.h @@ -0,0 +1,84 @@ +#ifndef _INFRA_CONFIG_H_ +#define _INFRA_CONFIG_H_ + +#include "sdkconfig.h" + +#define PLATFORM_HAS_STDINT +#define PLATFORM_HAS_DYNMEM +#define PLATFORM_HAS_OS +#define INFRA_STRING +#define INFRA_NET +#define INFRA_LIST +//#define INFRA_LOG_NETWORK_PAYLOAD +#define INFRA_LOG +//#define INFRA_LOG_ALL_MUTED +//#define INFRA_LOG_MUTE_FLW +//#define INFRA_LOG_MUTE_DBG +//#define INFRA_LOG_MUTE_INF +//#define INFRA_LOG_MUTE_WRN +//#define INFRA_LOG_MUTE_ERR +//#define INFRA_LOG_MUTE_CRT +#define INFRA_TIMER +#define INFRA_JSON_PARSER +#define INFRA_CJSON +#define INFRA_MD5 +#define INFRA_SHA1 +#define INFRA_SHA256 +#define INFRA_REPORT +#define INFRA_HTTPC +#define INFRA_COMPAT +#define INFRA_CLASSIC +#define DEV_SIGN +#define MQTT_COMM_ENABLED +#define MQTT_DEFAULT_IMPL +#if CONFIG_MQTT_DIRECT +#define MQTT_DIRECT +#else +#define MQTT_PRE_AUTH +#define INFRA_PREAUTH +#endif +#define DEVICE_MODEL_CLASSIC +//#define LOG_REPORT_TO_CLOUD +#define DEVICE_MODEL_ENABLED +#if CONFIG_DEVICE_MODEL_GATEWAY +#define DEVICE_MODEL_GATEWAY +#endif +#if CONFIG_DEVICE_ALCS_ENABLE +#define ALCS_ENABLED +#endif +#if CONFIG_DYNAMIC_REGISTER +#define DYNAMIC_REGISTER +#endif +#define DEVICE_MODEL_SUBDEV_OTA +#define DEVICE_MODEL_SHADOW +#define HAL_KV +#define SUPPORT_TLS +#if defined(SUPPORT_TLS) && CONFIG_SUPPORT_TCP +#define SUPPORT_TCP +#endif +#define HAL_CRYPTO +#define HAL_UDP +//#define COAP_DTLS_SUPPORT +#define OTA_ENABLED +//#define COAP_COMM_ENABLED +#define COAP_PACKET +#define COAP_CLIENT +#define COAP_SERVER +#define DEV_RESET +#define HTTP_COMM_ENABLED +#define HTTP2_COMM_ENABLED +#define FS_ENABLED +#define AWSS_SUPPORT_APLIST +#define AWSS_SUPPORT_ADHA +#define AWSS_FRAMEWORKS +#define WIFI_PROVISION_ENABLED +#define AWSS_SUPPORT_SMARTCONFIG_WPS +#define AWSS_SUPPORT_SMARTCONFIG +#define AWSS_SUPPORT_ZEROCONFIG +#define AWSS_SUPPORT_AHA +#define AWSS_SUPPORT_DEV_AP +#define DEV_BIND_ENABLED +#ifdef CONFIG_SUPPORT_SECURITY_OTA +#define SUPPORT_SECURITY_OTA +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_defs.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_defs.c new file mode 100644 index 00000000..45d97ca0 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_defs.c @@ -0,0 +1,23 @@ + +#include "infra_config.h" +#include "infra_types.h" +#include "infra_defs.h" + +const char * g_infra_mqtt_domain[IOTX_MQTT_DOMAIN_NUMBER] = { + "iot-as-mqtt.cn-shanghai.aliyuncs.com", /* Shanghai */ + "iot-as-mqtt.ap-southeast-1.aliyuncs.com", /* Singapore */ + "iot-as-mqtt.ap-northeast-1.aliyuncs.com", /* Japan */ + "iot-as-mqtt.us-west-1.aliyuncs.com", /* America */ + "iot-as-mqtt.eu-central-1.aliyuncs.com", /* Germany */ + NULL, /* Custom */ +}; + +const char *g_infra_http_domain[IOTX_HTTP_DOMAIN_NUMBER] = { + "iot-auth.cn-shanghai.aliyuncs.com", /* Shanghai */ + "iot-auth.ap-southeast-1.aliyuncs.com", /* Singapore */ + "iot-auth.ap-northeast-1.aliyuncs.com", /* Japan */ + "iot-auth.us-west-1.aliyuncs.com", /* America */ + "iot-auth.eu-central-1.aliyuncs.com", /* Germany */ + NULL, /* Custom */ +}; + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_defs.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_defs.h new file mode 100644 index 00000000..c5fa12f5 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_defs.h @@ -0,0 +1,356 @@ +#ifndef _INFRA_DEFS_H_ +#define _INFRA_DEFS_H_ + +#include "infra_types.h" + +#ifdef _WIN32 + #if !defined(CC_IS_MINGW32) + #ifdef DLL_HAL_EXPORTS + #define DLL_HAL_API __declspec(dllexport) + #else + #define DLL_HAL_API __declspec(dllimport) + #endif + #else + #define DLL_HAL_API + #endif +#else + #define DLL_HAL_API +#endif + +#ifdef _WIN32 + #if !defined(CC_IS_MINGW32) + #ifdef DLL_IOT_EXPORTS + #define DLL_IOT_API __declspec(dllexport) + #else + #define DLL_IOT_API __declspec(dllimport) + #endif + #else + #define DLL_IOT_API + #endif +#else + #define DLL_IOT_API +#endif + +#define IOTX_SDK_VERSION "3.0.1" +#define IOTX_ALINK_VERSION "20" +#define IOTX_FIRMWARE_VERSION_LEN (32) +#define IOTX_PRODUCT_KEY_LEN (20) +#define IOTX_DEVICE_NAME_LEN (32) +#define IOTX_DEVICE_SECRET_LEN (64) +#define IOTX_DEVICE_ID_LEN (64) +#define IOTX_PRODUCT_SECRET_LEN (64) +#define IOTX_PARTNER_ID_LEN (64) +#define IOTX_MODULE_ID_LEN (64) +#define IOTX_NETWORK_IF_LEN (160) +#define IOTX_FIRMWARE_VER_LEN (32) +#define IOTX_URI_MAX_LEN (135) + +#ifndef _IN_ + #define _IN_ +#endif + +#ifndef _OU_ + #define _OU_ +#endif + +#ifndef _IN_OPT_ + #define _IN_OPT_ +#endif + +#define NETWORK_ADDR_LEN (16) +#define HAL_MAC_LEN (17 + 1) /* MAC地址的长度 */ +#define STR_SHORT_LEN (32) +#ifndef ETH_ALEN +#define ETH_ALEN (6) +#endif +#define HAL_MAX_SSID_LEN (32 + 1) /* ssid: 32 octets at most, include the NULL-terminated */ +#define HAL_MAX_PASSWD_LEN (64 + 1) /* password: 8-63 ascii */ +#define WLAN_CONNECTION_TIMEOUT_MS (30 * 1000) + +typedef enum IOT_RETURN_CODES { + ERROR_DEVICE_NOT_EXIST = -311, + ERROR_NET_TIMEOUT = -310, + ERROR_CERT_VERIFY_FAIL = -309, + ERROR_NET_SETOPT_TIMEOUT = -308, + ERROR_NET_SOCKET = -307, + ERROR_NET_CONNECT = -306, + ERROR_NET_BIND = -305, + ERROR_NET_LISTEN = -304, + ERROR_NET_RECV = -303, + ERROR_NET_SEND = -302, + ERROR_NET_CONN = -301, + ERROR_NET_UNKNOWN_HOST = -300, + + MQTT_SUBHANDLE_LIST_LEN_TOO_SHORT = -47, + MQTT_OFFLINE_LIST_LEN_TOO_SHORT = -46, + MQTT_TOPIC_LEN_TOO_SHORT = -45, + MQTT_CONNECT_BLOCK = -44, + MQTT_SUB_INFO_NOT_FOUND_ERROR = -43, + MQTT_PUSH_TO_LIST_ERROR = -42, + MQTT_TOPIC_FORMAT_ERROR = -41, + NETWORK_RECONNECT_TIMED_OUT_ERROR = -40,/** Returned when the Network is disconnected and the reconnect attempt has timed out */ + MQTT_CONNACK_UNKNOWN_ERROR = -39,/** Connect request failed with the server returning an unknown error */ + MQTT_CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = -38,/** Connect request failed with the server returning an unacceptable protocol version error */ + MQTT_CONNACK_IDENTIFIER_REJECTED_ERROR = -37,/** Connect request failed with the server returning an identifier rejected error */ + MQTT_CONNACK_SERVER_UNAVAILABLE_ERROR = -36,/** Connect request failed with the server returning an unavailable error */ + MQTT_CONNACK_BAD_USERDATA_ERROR = -35,/** Connect request failed with the server returning a bad userdata error */ + MQTT_CONNACK_NOT_AUTHORIZED_ERROR = -34,/** Connect request failed with the server failing to authenticate the request */ + MQTT_CONNECT_ERROR = -33, + MQTT_CREATE_THREAD_ERROR = -32, + MQTT_PING_PACKET_ERROR = -31, + MQTT_CONNECT_PACKET_ERROR = -30, + MQTT_CONNECT_ACK_PACKET_ERROR = -29, + MQTT_NETWORK_CONNECT_ERROR = -28, + MQTT_STATE_ERROR = -27, + MQTT_SUBSCRIBE_PACKET_ERROR = -26, + MQTT_SUBSCRIBE_ACK_PACKET_ERROR = -25, + MQTT_SUBSCRIBE_ACK_FAILURE = -24, + MQTT_SUBSCRIBE_QOS_ERROR = -23, + MQTT_UNSUBSCRIBE_PACKET_ERROR = -22, + MQTT_PUBLISH_PACKET_ERROR = -21, + MQTT_PUBLISH_QOS_ERROR = -20, + MQTT_PUBLISH_ACK_PACKET_ERROR = -19, + MQTT_PUBLISH_COMP_PACKET_ERROR = -18, + MQTT_PUBLISH_REC_PACKET_ERROR = -17, + MQTT_PUBLISH_REL_PACKET_ERROR = -16, + MQTT_UNSUBSCRIBE_ACK_PACKET_ERROR = -15, + MQTT_NETWORK_ERROR = -14, + MQTT_PUBLISH_ACK_TYPE_ERROR = -13, + + ERROR_SHADOW_NO_METHOD = -2008, + ERROR_SHADOW_UNDEF_TYPE = -2007, + ERROR_SHADOW_UPDATE_TIMEOUT = -2006, + ERROR_SHADOW_UPDATE_NACK = -2005, /**< Negative ACK */ + ERROR_SHADOW_NO_ATTRIBUTE = -2004, + ERROR_SHADOW_ATTR_NO_EXIST = -2003, /**< NO such attribute */ + ERROR_SHADOW_ATTR_EXIST = -2002, /**< attribute already exists */ + ERROR_SHADOW_WAIT_LIST_OVERFLOW = -2001, + ERROR_SHADOW_INVALID_STATE = -2000, + + ERROR_SUBDEV_NULL_VALUE = -1501, /**< Indicating NULL value*/ + ERROR_SUBDEV_NOT_NULL_VALUE = -1500, /**< Indicating value not NULL*/ + ERROR_SUBDEV_STRING_NULL_VALUE = -1499, /**< Indicating NULL value or empty string */ + ERROR_SUBDEV_INVALID_GATEWAY_HANDLE = -1498, /**< Indicating gateway handle is null or invalid*/ + ERROR_SUBDEV_SESSION_NOT_FOUND = -1497, /**< Cannot find device session*/ + ERROR_SUBDEV_RRPC_CB_NOT_NULL = -1496, /**< RRPC callback function has been set,needn't to set again*/ + ERROR_SUBDEV_REPLY_TYPE_NOT_DEF = -1495, /**< Reply type not defined*/ + ERROR_SUBDEV_GET_JSON_VAL = -1494, /**< Get value from reply payload fail*/ + ERROR_SUBDEV_DATA_LEN_OVERFLOW = -1493, /**< Length of 'data' value from reply palyoad is large than limit(1024)*/ + ERROR_SUBDEV_MSG_LEN = -1492, /**< Indicating msg len is not correct*/ + ERROR_SUBDEV_REPLY_PROC = -1491, /**< Error occur when process publish reply */ + ERROR_SUBDEV_REPLY_TOPIC_NOT_MATCH = -1490, /**< Indicating that topic received is unknown*/ + ERROR_SUBDEV_REPLY_VAL_CHECK = -1489, /**< Indicating that value get from reply checked fail with local*/ + ERROR_SUBDEV_REGISTER_TYPE_NOT_DEF = -1488, /**< Register type not support*/ + ERROR_SUBDEV_PACKET_SPLICE_FAIL = -1487, /**< Splice packet error*/ + ERROR_SUBDEV_MQTT_PUBLISH_FAIL = -1486, /**< MQTT publish fail*/ + ERROR_SUBDEV_REPLY_PARSE_FAIL = -1485, /**< Parse reply fail*/ + ERROR_SUBDEV_CREATE_SESSION_FAIL = -1484, /**< Create session fail*/ + ERROR_SUBDEV_INVALID_CLEAN_SESSION_TYPE = -1483, /**< Clean session not support*/ + ERROR_SUBDEV_HAS_BEEN_LOGIN = -1482, /**< Device has been login*/ + ERROR_SUBDEV_SUB_UNSUB_FAIL = -1481, /**< subscribe or unsubscribe fail*/ + ERROR_SUBDEV_SESSION_STATE_FAIL = -1480, /**< Session state is error,may not login*/ + ERROR_SUBDEV_MEMORY_NOT_ENOUGH = -1479, /**< Set memory too small*/ + + ERROR_REPLY_TIMEOUT = -6099, /**< recieve reply timeout*/ + ERROR_DEVICE_NOT_FOUND = -6100, /**< device not found*/ + ERROR_TOO_LARGE_PAGE_SIZE = -6101, /**< page size must less than 200*/ + ERROR_DEVICE_COUNT_FAULT = -6102, /**< device count query service fault*/ + ERROR_DEVICE_DETAIL_FAULT = -6103, /**< device detail query service fault*/ + ERROR_TOO_LARGE_LIST_SIZE = -6104, /**< list size must less than 200*/ + ERROR_LIST_SIZE_CANNOT_BE_ZERO = -6105, /**< list size must greater than 0*/ + ERROR_TOO_LARGE_MAP_SIZE = -6106, /**< map size must less than 200*/ + ERROR_MAP_SIZE_CANNOT_BE_ZERO = -6107, /**< map size must greater than 0*/ + ERROR_DEVICE_STATUS_FAULT = -6108, /**< device status query service fault*/ + ERROR_DEVICE_INFO_FAULT = -6109, /**< device info query service fault*/ + ERROR_SET_THING_PROPERTIES_ERROR = -6150, /**< set thing properties error*/ + ERROR_INVOKE_THING_SERVICE_ERROR = -6151, /**< invoke thing service error*/ + ERROR_SCRIPT_REL_NOT_EXIST = -6200, /**< script relation not exist*/ + ERROR_SCRIPT_CONVERT_DATA_IS_NULL = -6201, /**< script convert data is null*/ + ERROR_DEVICE_PRODUCT_NOT_EXIST = -6202, /**< product not exist*/ + ERROR_TOPIC_NOT_EXIST = -6203, /**< topic not exist*/ + ERROR_DEVICE_IS_DISABLED = -6204, /**< device is disabled*/ + ERROR_IOT_MESSAGE_ERROR = -6205, /**< iot message service error*/ + ERROR_PRODUCT_PROPERTY_NOT_EXIST = -6206, /**< product property not exist*/ + ERROR_DATA_FORMAT_ERROR = -6207, /**< device data format is error*/ + ERROR_THING_STATUS_PROHIBITED = -6208, /**< thing status is prohibited*/ + ERROR_THING_STATUS_NOT_ACTIVE = -6209, /**< thing status not active*/ + /** + * + * -6250 ~ -6299 + */ + ERROR_PRODUCT_NOT_FOUND = -6250, /**< product not found*/ + ERROR_DEVICE_EXISTS = -6251, /**< device has existed*/ + ERROR_JUDGE_DEVICE_EXISTS_ERROR = -6252, /**< judge device exists error*/ + ERROR_ADD_DEVICE_FAILED = -6253, /**< add device failed*/ + ERROR_UPDATE_DEVICE_FAILED = -6254, /**< update device failed*/ + ERROR_INSERT_DGR_FAILED = -6255, /**< insert device group relation failed*/ + ERROR_SYN_DEVICE_FAILED = -6256, /**< device synchronization failed*/ + ERROR_PRODUCT_DOMAIN_ILLEGAL = -6257, /**< product domain illegal*/ + ERROR_TENANID_ILLEGAL = -6258, /**< tenantId illegal*/ + ERROR_PRODUCT_REGION_ILLEGAL = -6259, /**< product region illegal*/ + ERROR_PRODUCT_NETTYPE_ILLEGAL = -6260, /**< product nettype illegal*/ + ERROR_INSERT_DEVICE_APPLY_DETAIL_FAILED = -6261, /**< insert device apply detail failed*/ + ERROR_UPDATE_DEVICE_APPLY_STATUS_FAILED = -6262, /**< update device apply status failed*/ + ERROR_DELERE_DGR_FAILED = -6263, /**< delete device group relation status*/ + ERROR_DELETE_DEVICE_FAILED = -6264, /**< delete device failed*/ + ERROR_QUERY_DEVICE_DETAIL_FAILED = -6265, /**< query device detail failed*/ + ERROR_QUERY_DEVICE_COUNT_FAILED = -6266, /**< query device count failed*/ + ERROR_QUERY_ACTIVE_DEVICE_COUNT_FAILED = -6267, /**< query active device count failed*/ + ERROR_INSERT_AGR_FAILED = -6268, /**< insert apply group relation failed*/ + ERROR_QUERY_DEVICE_APPLY_FAILED = -6269, /**< query device apply failed*/ + ERROR_QUERY_PRODUCT_FAILED = -6270, /**< query product failed*/ + ERROR_DEVICE_APPLY_NOT_FOUND = -6271, /**< device apply not found*/ + ERROR_RELEASE_TRIAD_FAILED = -6272, /**< release triad failed*/ + ERROR_UPDATE_DAD_STATUS_FAILED = -6273, /**< update device apply detail status failed*/ + ERROR_REG_LORA_DEVICE_FAILED = -6274, /**< register lora device failed*/ + ERROR_SYN_APPLY_DEVICE_FAILED = -6275, /**< device apply synchronization failed*/ + ERROR_QUERY_DGR_FAILED = -6276, /**< query device group relation failed*/ + ERROR_JUDGE_DGR_FAILED = -6277, /**< judge device group relation failed*/ + ERROR_QUERY_AGR_FAILED = -6278, /**< query apply group relation failed*/ + ERROR_JUDGE_AGR_FAILED = -6279, /**< judge apply group relation failed*/ + ERROR_DEVICENAME_NOT_MEET_SPECS = -6280, /**< devicename not meet specs*/ + ERROR_DELETE_APPLY_DEVICE_FAILED = -6281, /**< delete apply device failed*/ + ERROR_GEN_DEVICEID_FAILED = -6282, /**< gennerate deviceId failed*/ + ERROR_APPLY_ILLEGAL = -6283, /**< apply illegal*/ + ERROR_LORA_DEVICE_METHOD_ERROR = -6284, /**< lora device cannot created by num*/ + ERROR_APPLY_NOT_READY = -6285, /**< apply not ready*/ + + + /** + * dsl + * -6300 ~ -6349 + */ + ERROR_DSL_PARSE_METHOD_NOT_EXIST = -6300, /**< dsl parse: method not exist*/ + ERROR_DSL_PARSE_PARAMS_FORMAT_ERROR = -6301, /**< dsl parse: params format must be JSONObject/JSONArray*/ + ERROR_DSL_PARSE_PARAMS_VALUE_EMPTY = -6302, /**< dsl parse: params value empty*/ + ERROR_DSL_PARSE_PARAMS_NUMBER_ERROR = -6303, /**< dsl parse: params number error*/ + ERROR_DSL_PARSE_PARAMS_NOT_EXIST = -6304, /**< dsl parse: params not exist*/ + ERROR_DSL_PARSE_PARAMS_TYPE_ERROR = -6305, /**< dsl parse: params type error*/ + ERROR_DSL_PARSE_INT_SPECS_ERROR = -6306, /**< dsl parse: int specs error*/ + ERROR_DSL_PARSE_FLOAT_SPECS_ERROR = -6307, /**< dsl parse: float specs error*/ + ERROR_DSL_PARSE_BOOL_SPECS_ERROR = -6308, /**< dsl parse: bool specs error*/ + ERROR_DSL_PARSE_ENUM_SPECS_ERROR = -6309, /**< dsl parse: enum specs error*/ + ERROR_DSL_PARSE_STRING_SPECS_ERROR = -6310, /**< dsl parse: string specs error*/ + ERROR_DSL_PARSE_DATE_SPECS_ERROR = -6311, /**< dsl parse: date specs error*/ + ERROR_DSL_PARSE_STRUCT_SPECS_ERROR = -6312, /**< dsl parse: struct specs error*/ + ERROR_DSL_SERVICE_NOT_AVAILABLE = -6313, /**< dsl service not available*/ + ERROR_DSL_PARSE_DATA_TYPE_PARSE_ERROR = -6314, /**< dsl parse: data type parse error*/ + ERROR_DATA_NOT_SATISFY_DSL = -6315, /**< dsl parse: data not satisfy dsl*/ + ERROR_DSL_PARSE_SPECS_NUMBER_FORMAT_ERROR = -6316, /**< dsl parse: specs number format error*/ + ERROR_DSL_PARSE_TEMPLATE_ERROR = -6317, /**< dsl parse: template error*/ + ERROR_DSL_EXCEPTION = -6318, /**< dsl exception*/ + ERROR_DSL_PARSE_EVENT_CALL_TYPE_ERROR = -6319, /**< dsl parse: event call type error*/ + ERROR_DSL_PARSE_NO_PROPERTY = -6320, /**< dsl parse: no property exist in product*/ + ERROR_DSL_PARSE_IDENTIFIER_IS_NULL = -6321, /**< dsl parse: template property/params idetifier is null*/ + ERROR_DSL_DEVICE_NOT_EXIST_IN_PRODUCT = -6321, /**< dsl: device not exist in product*/ + ERROR_DSL_PARSE_DOUBLE_SPECS_ERROR = -6322, /**< dsl parse: double specs error*/ + + /** + * + * -6350 ~ -6399 + */ + ERROR_EVENT_PUT_ERROR = -6350, /**< thing event put error*/ + ERROR_SERVICE_PUT_ERROR = -6351, /**< thing service put error*/ + ERROR_DEVICE_GET_EVENT_FAULT = -6352, /**< thing event get error*/ + ERROR_PRODUCT_KEY_ELEMENT_ALREADY_EXIST = -6353, /**< product key element already exist*/ + + /** + * + * -6400 ~ -6449 + */ + ERROR_TOPO_RELATION_COUNT_EXCEED = -6400, /**< topo relation count exceed*/ + ERROR_TOPO_RELATION_NOT_EXIST = -6401, /**< topo relation not exist*/ + ERROR_TOPO_RELATION_CANNOT_ADD_BYSELF = -6402, /**< topo relation cannot add by self*/ + + /** + * alink + * -6450 ~ -6469 + */ + ERROR_ALINK_METHOD_NOT_EXIST = -6450, /**< alink method not exist*/ + + /** + * + * -6550 ~ -6599 + */ + ERROR_DEVICE_GROUP_NOT_FOUND = -6550, /**< device group not found*/ + + /** + * @brief dev_sign + * + * -1100 ~ -1200 + * + */ + ERROR_DEV_SIGN_CUSTOM_DOMAIN_IS_NULL = -1105, + ERROR_DEV_SIGN_SOURCE_TOO_SHORT = -1104, + ERROR_DEV_SIGN_PASSWORD_TOO_SHORT = -1103, + ERROR_DEV_SIGN_USERNAME_TOO_SHORT = -1102, + ERROR_DEV_SIGN_CLIENT_ID_TOO_SHORT = -1101, + ERROR_DEV_SIGN_HOST_NAME_TOO_SHORT = -1100, + + ERROR_NO_MEM = -1016, + ERROR_CERTIFICATE_EXPIRED = -1015, + ERROR_MALLOC = -1014, + ERROR_NO_ENOUGH_MEM = -1013, /**< Writes more than size value. */ + + ERROR_NO_SUPPORT = -12, + ERROR_NO_PERSISTENCE = -11, + ERROR_HTTP_BREAK = -10, + ERROR_NULL_VALUE = -9, + ERROR_HTTP_CONN = -8, /**< Connection failed. */ + ERROR_HTTP_PARSE = -7, /**< A URL parse error occurred. */ + ERROR_HTTP_UNRESOLVED_DNS = -6, /**< Could not resolve the hostname. */ + ERROR_HTTP_PRTCL = -5, /**< A protocol error occurred. */ + ERROR_HTTP = -4, /**< An unknown error occurred. */ + ERROR_HTTP_CLOSED = -3, /**< Connection was closed by a remote host. */ + NULL_VALUE_ERROR = -2, + + FAIL_RETURN = -1, /**< generic error. */ + SUCCESS_RETURN = 0, + + + /* @value > 0, reserved for other usage */ + +} iotx_err_t; + +typedef struct _iotx_dev_meta_info { + char product_key[IOTX_PRODUCT_KEY_LEN + 1]; + char product_secret[IOTX_PRODUCT_SECRET_LEN + 1]; + char device_name[IOTX_DEVICE_NAME_LEN + 1]; + char device_secret[IOTX_DEVICE_SECRET_LEN + 1]; +} iotx_dev_meta_info_t; + +typedef struct { + const char *region; + uint16_t port; +} iotx_region_item_t; + +typedef enum { + IOTX_CLOUD_REGION_SHANGHAI, /* Shanghai */ + IOTX_CLOUD_REGION_SINGAPORE, /* Singapore */ + IOTX_CLOUD_REGION_JAPAN, /* Japan */ + IOTX_CLOUD_REGION_USA_WEST, /* America */ + IOTX_CLOUD_REGION_GERMANY, /* Germany */ + IOTX_CLOUD_REGION_CUSTOM, /* Custom setting */ + IOTX_CLOUD_DOMAIN_MAX /* Maximum number of domain */ +} iotx_mqtt_region_types_t; + +#define IOTX_MQTT_DOMAIN_NUMBER (6) +extern const char *g_infra_mqtt_domain[IOTX_MQTT_DOMAIN_NUMBER]; + +typedef enum { + IOTX_HTTP_REGION_SHANGHAI, /* Shanghai */ + IOTX_HTTP_REGION_SINGAPORE, /* Singapore */ + IOTX_HTTP_REGION_JAPAN, /* Japan */ + IOTX_HTTP_REGION_AMERICA, /* America */ + IOTX_HTTP_REGION_GERMANY, /* Germany */ + IOTX_HTTP_REGION_CUSTOM, /* Custom setting */ + IOTX_HTTP_REGION_MAX /* Maximum number of domain */ +} iotx_http_region_types_t; + +#define IOTX_HTTP_DOMAIN_NUMBER (6) +extern const char *g_infra_http_domain[IOTX_HTTP_DOMAIN_NUMBER]; + +#endif + +extern int iotx_facility_json_print(const char *str, int level, ...); + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_httpc.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_httpc.c new file mode 100644 index 00000000..19e893ca --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_httpc.c @@ -0,0 +1,587 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "infra_config.h" + +#ifdef INFRA_HTTPC + +#include +#include +#include + +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_httpc.h" +#include "infra_net.h" +#include "infra_timer.h" + +#ifdef INFRA_LOG + #include "infra_log.h" + #define httpc_err(...) log_err("httpc", __VA_ARGS__) + #define httpc_info(...) log_info("httpc", __VA_ARGS__) + #define httpc_debug(...) log_debug("httpc", __VA_ARGS__) +#else + #define httpc_err(...) + #define httpc_info(...) + #define httpc_debug(...) +#endif + +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); +void HAL_SleepMs(uint32_t ms); + +#define HTTPCLIENT_MIN(x,y) (((x)<(y))?(x):(y)) +#define HTTPCLIENT_MAX(x,y) (((x)>(y))?(x):(y)) + + +#define HTTPCLIENT_READ_BUF_SIZE (1024) /* read payload */ +#define HTTPCLIENT_RAED_HEAD_SIZE (32) /* read header */ +#define HTTPCLIENT_SEND_BUF_SIZE (1024) /* send */ + +#define HTTPCLIENT_MAX_URL_LEN (256) + +#define HTTP_RETRIEVE_MORE_DATA (1) /**< More data needs to be retrieved. */ + +#if defined(MBEDTLS_DEBUG_C) + #define DEBUG_LEVEL 2 +#endif +#define HTTPCLIENT_CHUNK_SIZE (1024) + +static int _utils_parse_url(const char *url, char *host, char *path); +static int _http_recv(httpclient_t *client, char *buf, int max_len, int *p_read_len, + uint32_t timeout); +static int _http_get_response_body(httpclient_t *client, char *data, int len, uint32_t timeout, + httpclient_data_t *client_data); +static int _http_parse_response_header(httpclient_t *client, char *data, int len, uint32_t timeout, + httpclient_data_t *client_data); + +static int _utils_parse_url(const char *url, char *host, + char *path) +{ + char *host_ptr = (char *) strstr(url, "://"); + uint32_t host_len = 0; + uint32_t path_len; + /* char *port_ptr; */ + char *path_ptr; + char *fragment_ptr; + + if (host_ptr == NULL) { + return -1; /* URL is invalid */ + } + host_ptr += 3; + + path_ptr = strchr(host_ptr, '/'); + if (NULL == path_ptr) { + return -2; + } + + if (host_len == 0) { + host_len = path_ptr - host_ptr; + } + + memcpy(host, host_ptr, host_len); + host[host_len] = '\0'; + fragment_ptr = strchr(host_ptr, '#'); + if (fragment_ptr != NULL) { + path_len = fragment_ptr - path_ptr; + } else { + path_len = strlen(path_ptr); + } + + memcpy(path, path_ptr, path_len); + path[path_len] = '\0'; + + return SUCCESS_RETURN; +} + +static int _utils_fill_tx_buffer(httpclient_t *client, char *send_buf, int *send_idx, char *buf, + uint32_t len) /* 0 on success, err code on failure */ +{ + int ret; + int cp_len; + int idx = *send_idx; + + if (len == 0) { + len = strlen(buf); + } + do { + if ((HTTPCLIENT_SEND_BUF_SIZE - idx) >= len) { + cp_len = len; + } else { + cp_len = HTTPCLIENT_SEND_BUF_SIZE - idx; + } + + memcpy(send_buf + idx, buf, cp_len); + idx += cp_len; + len -= cp_len; + + if (idx == HTTPCLIENT_SEND_BUF_SIZE) { + ret = client->net.write(&client->net, send_buf, HTTPCLIENT_SEND_BUF_SIZE, 5000); + if (ret) { + return (ret); + } + } + } while (len); + + *send_idx = idx; + return SUCCESS_RETURN; +} + +static int _http_send_header(httpclient_t *client, const char *host, const char *path, int method, + httpclient_data_t *client_data) +{ + int len; + char send_buf[HTTPCLIENT_SEND_BUF_SIZE] = { 0 }; + char buf[HTTPCLIENT_SEND_BUF_SIZE] = { 0 }; + char *meth = (method == HTTPCLIENT_GET) ? "GET" : (method == HTTPCLIENT_POST) ? "POST" : + (method == HTTPCLIENT_PUT) ? "PUT" : (method == HTTPCLIENT_DELETE) ? "DELETE" : + (method == HTTPCLIENT_HEAD) ? "HEAD" : ""; + int ret; + + /* Send request */ + memset(send_buf, 0, HTTPCLIENT_SEND_BUF_SIZE); + len = 0; /* Reset send buffer */ + + HAL_Snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); /* Write request */ + + ret = _utils_fill_tx_buffer(client, send_buf, &len, buf, strlen(buf)); + if (ret) { + /* httpc_err("Could not write request"); */ + return ERROR_HTTP_CONN; + } + + /* Add user header information */ + if (client->header) { + _utils_fill_tx_buffer(client, send_buf, &len, (char *) client->header, strlen(client->header)); + } + + if (client_data->post_buf != NULL) { + HAL_Snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", client_data->post_buf_len); + _utils_fill_tx_buffer(client, send_buf, &len, buf, strlen(buf)); + + if (client_data->post_content_type != NULL) { + HAL_Snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", client_data->post_content_type); + _utils_fill_tx_buffer(client, send_buf, &len, buf, strlen(buf)); + } + } + + /* Close headers */ + _utils_fill_tx_buffer(client, send_buf, &len, "\r\n", 0); + +#ifdef INFRA_LOG + log_multi_line(LOG_DEBUG_LEVEL, "REQUEST", "%s", send_buf, ">"); +#endif + + /* ret = httpclient_tcp_send_all(client->net.handle, send_buf, len); */ + ret = client->net.write(&client->net, send_buf, len, 5000); + if (ret <= 0) { + httpc_err("ret = client->net.write() = %d", ret); + return (ret == 0) ? ERROR_HTTP_CLOSED : ERROR_HTTP_CONN; + } + + return SUCCESS_RETURN; +} + +int _http_send_userdata(httpclient_t *client, httpclient_data_t *client_data) +{ + int ret = 0; + + if (client_data->post_buf && client_data->post_buf_len) { + /* ret = httpclient_tcp_send_all(client->handle, (char *)client_data->post_buf, client_data->post_buf_len); */ + ret = client->net.write(&client->net, (char *)client_data->post_buf, client_data->post_buf_len, 5000); + httpc_debug("client_data->post_buf: %s, ret is %d", client_data->post_buf, ret); + if (ret <= 0) { + return (ret == 0) ? ERROR_HTTP_CLOSED : ERROR_HTTP_CONN; /* Connection was closed by server */ + } + } + + return SUCCESS_RETURN; +} + +/* 0 on success, err code on failure */ +static int _http_recv(httpclient_t *client, char *buf, int max_len, int *p_read_len, + uint32_t timeout_ms) +{ + int ret = 0; + iotx_time_t timer; + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, timeout_ms); + + *p_read_len = 0; + + ret = client->net.read(&client->net, buf, max_len, iotx_time_left(&timer)); + /* httpc_debug("Recv: | %s", buf); */ + httpc_info("ret of _http_recv is %d", ret); + + if (ret > 0) { + *p_read_len = ret; + return 0; + } else if (ret == 0) { + /* timeout */ + return FAIL_RETURN; + } else { + return ERROR_HTTP_CONN; + } +} + +#define MIN_TIMEOUT (100) +#define MAX_RETRY_COUNT (600) + + +static int _utils_check_deadloop(int len, iotx_time_t *timer, int ret, unsigned int *dead_loop_count, + unsigned int *extend_count) +{ + /* if timeout reduce to zero, it will be translated into NULL for select function in TLS lib */ + /* it would lead to indenfinite behavior, so we avoid it */ + if (iotx_time_left(timer) < MIN_TIMEOUT) { + (*extend_count)++; + utils_time_countdown_ms(timer, MIN_TIMEOUT); + } + + /* if it falls into deadloop before reconnected to internet, we just quit*/ + if ((0 == len) && (0 == iotx_time_left(timer)) && (FAIL_RETURN == ret)) { + (*dead_loop_count)++; + if (*dead_loop_count > MAX_RETRY_COUNT) { + httpc_err("deadloop detected, exit"); + return ERROR_HTTP_CONN; + } + } else { + *dead_loop_count = 0; + } + + /*if the internet connection is fixed during the loop, the download stream might be disconnected. we have to quit */ + if ((0 == len) && (*extend_count > 2 * MAX_RETRY_COUNT) && (FAIL_RETURN == ret)) { + httpc_err("extend timer for too many times, exit"); + return ERROR_HTTP_CONN; + } + return SUCCESS_RETURN; +} + +static int _utils_fill_rx_buf(int *recv_count, int len_to_write_to_respons_buf, httpclient_data_t *client_data, + char *data) +{ + int count = *recv_count; + if (count + len_to_write_to_respons_buf < client_data->response_buf_len - 1) { + memcpy(client_data->response_buf + count, data, len_to_write_to_respons_buf); + count += len_to_write_to_respons_buf; + client_data->response_buf[count] = '\0'; + client_data->retrieve_len -= len_to_write_to_respons_buf; + *recv_count = count; + return SUCCESS_RETURN; + } else { + memcpy(client_data->response_buf + count, data, client_data->response_buf_len - 1 - count); + client_data->response_buf[client_data->response_buf_len - 1] = '\0'; + client_data->retrieve_len -= (client_data->response_buf_len - 1 - count); + return HTTP_RETRIEVE_MORE_DATA; + } +} + +static int _http_get_response_body(httpclient_t *client, char *data, int data_len_actually_received, + uint32_t timeout_ms, httpclient_data_t *client_data) +{ + int written_response_buf_len = 0; + int len_to_write_to_respons_buf = 0; + iotx_time_t timer; + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, timeout_ms); + + /* Receive data */ + /* httpc_debug("Current data: %s", data); */ + + client_data->is_more = IOT_TRUE; + + /* the header is not received finished */ + if (client_data->response_content_len == -1 && client_data->is_chunked == IOT_FALSE) { + /* can not enter this if */ + /* TODO check the way to go into this branch */ + httpc_err("header is not received yet"); + return ERROR_HTTP_CONN; + } + + while (1) { + unsigned int dead_loop_count = 0; + unsigned int extend_count = 0; + do { + int res; + /* move previous fetched data into response_buf */ + len_to_write_to_respons_buf = HTTPCLIENT_MIN(data_len_actually_received, client_data->retrieve_len); + res = _utils_fill_rx_buf(&written_response_buf_len, len_to_write_to_respons_buf, client_data, data); + if (HTTP_RETRIEVE_MORE_DATA == res) { + return HTTP_RETRIEVE_MORE_DATA; + } + + /* get data from internet and put into "data" buf temporary */ + if (client_data->retrieve_len) { + int ret; + int max_len_to_receive = HTTPCLIENT_MIN(HTTPCLIENT_CHUNK_SIZE - 1, client_data->response_buf_len - 1 - written_response_buf_len); + max_len_to_receive = HTTPCLIENT_MIN(max_len_to_receive, client_data->retrieve_len); + + ret = _http_recv(client, data, max_len_to_receive, &data_len_actually_received, iotx_time_left(&timer)); + if (ret == ERROR_HTTP_CONN) { + return ret; + } + httpc_debug("Total- remaind Payload: %d Bytes; currently Read: %d Bytes", client_data->retrieve_len, data_len_actually_received); + + /* TODO add deadloop processing*/ + ret = _utils_check_deadloop(data_len_actually_received, &timer, ret, &dead_loop_count, + &extend_count); + if (ERROR_HTTP_CONN == ret) { + return ret; + } + } + } while (client_data->retrieve_len); + client_data->is_more = IOT_FALSE; + break; + } + + return SUCCESS_RETURN; +} + +static int _http_parse_response_header(httpclient_t *client, char *data, int len, uint32_t timeout_ms, + httpclient_data_t *client_data) +{ + int crlf_pos; + iotx_time_t timer; + char *tmp_ptr, *ptr_body_end; + int new_trf_len, ret; + char *crlf_ptr; + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, timeout_ms); + + client_data->response_content_len = -1; + + /* http client response */ + /* HTTP/1.1 200 OK(CRLF) + + ...(CRLF) + + (CRLF) + + [] */ + crlf_ptr = strstr(data, "\r\n"); + if (crlf_ptr == NULL) { + httpc_err("\r\n not found"); + return ERROR_HTTP_UNRESOLVED_DNS; + } + + crlf_pos = crlf_ptr - data; + data[crlf_pos] = '\0'; + client->response_code = atoi(data + 9); + httpc_debug("Reading headers: %s", data); + memmove(data, &data[crlf_pos + 2], len - (crlf_pos + 2) + 1); /* Be sure to move NULL-terminating char as well */ + len -= (crlf_pos + 2); /* remove status_line length */ + client_data->is_chunked = IOT_FALSE; + + /*If not ending of response body*/ + /* try to read more header again until find response head ending "\r\n\r\n" */ + while (NULL == (ptr_body_end = strstr(data, "\r\n\r\n"))) { + /* try to read more header */ + ret = _http_recv(client, data + len, HTTPCLIENT_RAED_HEAD_SIZE, &new_trf_len, iotx_time_left(&timer)); + if (ret == ERROR_HTTP_CONN) { + return ret; + } + len += new_trf_len; + data[len] = '\0'; + } + + /* parse response_content_len */ + if (NULL != (tmp_ptr = strstr(data, "Content-Length"))) { + client_data->response_content_len = atoi(tmp_ptr + strlen("Content-Length: ")); + client_data->retrieve_len = client_data->response_content_len; + } else { + httpc_err("Could not parse header"); + return ERROR_HTTP; + } + + /* remove header length */ + /* len is Had read body's length */ + /* if client_data->response_content_len != 0, it is know response length */ + /* the remain length is client_data->response_content_len - len */ + len = len - (ptr_body_end + 4 - data); + memmove(data, ptr_body_end + 4, len + 1); + client_data->response_received_len += len; + return _http_get_response_body(client, data, len, iotx_time_left(&timer), client_data); +} + +int httpclient_connect(httpclient_t *client) +{ + int retry_max = 3; + int retry_cnt = 1; + int retry_interval = 1000; + int rc = -1; + + do { + client->net.handle = 0; + httpc_debug("calling TCP or TLS connect HAL for [%d/%d] iteration", retry_cnt, retry_max); + + rc = client->net.connect(&client->net); + if (0 != rc) { + client->net.disconnect(&client->net); + httpc_err("TCP or TLS connect failed, rc = %d", rc); + HAL_SleepMs(retry_interval); + continue; + } else { + httpc_debug("rc = client->net.connect() = %d, success @ [%d/%d] iteration", rc, retry_cnt, retry_max); + break; + } + } while (++retry_cnt <= retry_max); + + return SUCCESS_RETURN; +} + +int _http_send_request(httpclient_t *client, const char *host, const char *path, HTTPCLIENT_REQUEST_TYPE method, + httpclient_data_t *client_data) +{ + int ret = ERROR_HTTP_CONN; + + if (0 == client->net.handle) { + return -1; + } + + ret = _http_send_header(client, host, path, method, client_data); + if (ret != 0) { + return -2; + } + + if (method == HTTPCLIENT_POST || method == HTTPCLIENT_PUT) { + ret = _http_send_userdata(client, client_data); + if (ret < 0) { + ret = -3; + } + } + + return ret; +} + +int httpclient_recv_response(httpclient_t *client, uint32_t timeout_ms, httpclient_data_t *client_data) +{ + int reclen = 0, ret = ERROR_HTTP_CONN; + char buf[HTTPCLIENT_READ_BUF_SIZE] = { 0 }; + iotx_time_t timer; + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, timeout_ms); + + if (0 == client->net.handle) { + httpc_err("not connection have been established"); + return ret; + } + + if (client_data->is_more) { + client_data->response_buf[0] = '\0'; + ret = _http_get_response_body(client, buf, reclen, iotx_time_left(&timer), client_data); + } else { + client_data->is_more = 1; + /* try to read header */ + ret = _http_recv(client, buf, HTTPCLIENT_RAED_HEAD_SIZE, &reclen, iotx_time_left(&timer)); + if (ret != 0) { + return ret; + } + + buf[reclen] = '\0'; + + if (reclen) { +#ifdef INFRA_LOG + log_multi_line(LOG_DEBUG_LEVEL, "RESPONSE", "%s", buf, "<"); +#endif + ret = _http_parse_response_header(client, buf, reclen, iotx_time_left(&timer), client_data); + } + } + + return ret; +} + +void httpclient_close(httpclient_t *client) +{ + if (client->net.handle > 0) { + client->net.disconnect(&client->net); + } + client->net.handle = 0; + httpc_info("client disconnected"); +} + +static int _http_send(httpclient_t *client, const char *url, int port, const char *ca_crt, + HTTPCLIENT_REQUEST_TYPE method, httpclient_data_t *client_data) +{ + int ret; + char host[HTTPCLIENT_MAX_URL_LEN] = { 0 }; + char path[HTTPCLIENT_MAX_URL_LEN] = { 0 }; + + /* First we need to parse the url (http[s]://host[:port][/[path]]) */ + ret = _utils_parse_url(url, host, path); + if (ret != SUCCESS_RETURN) { + httpc_err("_utils_parse_url fail returned %d", ret); + return ret; + } + + if (0 == client->net.handle) { + /* Establish connection if no. */ + #ifdef SUPPORT_TCP + ret = iotx_net_tcp_init(&client->net, host, port, ca_crt); + #else + ret = iotx_net_init(&client->net, host, port, ca_crt); + #endif + if (0 != ret) { + return ret; + } + + ret = httpclient_connect(client); + if (0 != ret) { + httpclient_close(client); + return ret; + } + + ret = _http_send_request(client, host, path, method, client_data); + if (0 != ret) { + httpc_err("_http_send_request is error, ret = %d", ret); + httpclient_close(client); + return ret; + } + } + return SUCCESS_RETURN; +} + +int httpclient_common(httpclient_t *client, const char *url, int port, const char *ca_crt, + HTTPCLIENT_REQUEST_TYPE method, uint32_t timeout_ms, httpclient_data_t *client_data) +{ + iotx_time_t timer; + int ret = _http_send(client, url, port, ca_crt, method, client_data); + if (SUCCESS_RETURN != ret) { + return ret; + } + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, timeout_ms); + + if ((NULL != client_data->response_buf) + && (0 != client_data->response_buf_len)) { + ret = httpclient_recv_response(client, iotx_time_left(&timer), client_data); + if (ret < 0) { + httpc_err("httpclient_recv_response is error,ret = %d", ret); + httpclient_close(client); + return ret; + } + } + + if (! client_data->is_more) { + /* Close the HTTP if no more data. */ + httpc_info("close http channel"); + httpclient_close(client); + } + + ret = 0; + return ret; +} + +int iotx_post(httpclient_t *client, + const char *url, + int port, + const char *ca_crt, + httpclient_data_t *client_data) +{ + return _http_send(client, url, port, ca_crt, HTTPCLIENT_POST, client_data); +} +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_httpc.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_httpc.h new file mode 100644 index 00000000..0148ede8 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_httpc.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#ifndef _INFRA_HTTPC_H_ +#define _INFRA_HTTPC_H_ + +#include "infra_net.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup HttpClient + * @{ + * HttpClient API implements the client-side of HTTP/1.1. It provides base interfaces to execute an HTTP request on a given URL. It also supports HTTPS (HTTP over TLS) to provide secure communication.\n + * @section HttpClient_Usage_Chapter How to use this module + * In this release, MediaTek provides two types of APIs: high level APIs and low level APIs.\n + * - \b The \b high \b level \b APIs + * - Enables to execute a single HTTP request on a given URL. + * - Call #httpclient_get(), #httpclient_post(), #httpclient_put() or #httpclient_delete() to get, post, put or delete and HTTP request.\n + * - \b The \b low \b level \b APIs + * - Enables to execute more than one HTTP requests during a Keep-Alive connection. Keep-alive is the idea of using a single TCP connection to send and receive multiple HTTP requests/responses, as opposed to opening a new connection for every single request/response pair. + * - Step1: Call #httpclient_connect() to connect to a remote server. + * - Step2: Call #httpclient_send_request() to send an HTTP request to the server. + * - Step3: Call #httpclient_recv_response() to receive an HTTP response from the server. + * - Step4: Repeat Steps 2 and 3 to execute more requests. + * - Step5: Call #httpclient_close() to close the connection. + * - Sample code: Please refer to the example under /project/mt7687_hdk/apps/http_client/http_client_keepalive folder. + */ + +/** @defgroup httpclient_define Define + * @{ + */ +/** @brief This macro defines the HTTP port. */ +#define HTTP_PORT 80 + +/** @brief This macro defines the HTTPS port. */ +#define HTTPS_PORT 443 +/** + * @} + */ + +/** @defgroup httpclient_enum Enum + * @{ + */ +/** @brief This enumeration defines the HTTP request type. */ +typedef enum { + HTTPCLIENT_GET, + HTTPCLIENT_POST, + HTTPCLIENT_PUT, + HTTPCLIENT_DELETE, + HTTPCLIENT_HEAD +} HTTPCLIENT_REQUEST_TYPE; + + +/** @defgroup httpclient_struct Struct + * @{ + */ +/** @brief This structure defines the httpclient_t structure. */ +typedef struct { + int remote_port; /**< HTTP or HTTPS port. */ + utils_network_t net; + int response_code; /**< Response code. */ + char *header; /**< Custom header. */ + char *auth_user; /**< Username for basic authentication. */ + char *auth_password; /**< Password for basic authentication. */ +} httpclient_t; + +/** @brief This structure defines the HTTP data structure. */ +typedef struct { + int is_more; /**< Indicates if more data needs to be retrieved. */ + int is_chunked; /**< Response data is encoded in portions/chunks.*/ + int retrieve_len; /**< Content length to be retrieved. */ + int response_content_len; /**< Response content length. */ + int response_received_len; /**< Response have received length. */ + int post_buf_len; /**< Post data length. */ + int response_buf_len; /**< Response buffer length. */ + char *post_content_type; /**< Content type of the post data. */ + char *post_buf; /**< User data to be posted. */ + char *response_buf; /**< Buffer to store the response data. */ +} httpclient_data_t; + +int iotx_post(httpclient_t *client, + const char *url, + int port, + const char *ca_crt, + httpclient_data_t *client_data); + +int httpclient_recv_response(httpclient_t *client, uint32_t timeout_ms, httpclient_data_t *client_data); + +int httpclient_common(httpclient_t *client, const char *url, int port, const char *ca_crt, + HTTPCLIENT_REQUEST_TYPE method, uint32_t timeout_ms, httpclient_data_t *client_data); + +void httpclient_close(httpclient_t *client); + +#ifdef __cplusplus +} +#endif + +#endif /* __HTTPCLIENT_H__ */ + + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_json_parser.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_json_parser.c new file mode 100644 index 00000000..f3481925 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_json_parser.c @@ -0,0 +1,845 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "infra_config.h" + +#ifdef INFRA_JSON_PARSER + +#include +#include +#include +#include + +#include "infra_types.h" +#include "infra_json_parser.h" + +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); + +#ifdef INFRA_LOG +#include "infra_log.h" +#define jparser_debug(...) log_debug("jparser", __VA_ARGS__) +#else +#define jparser_debug(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#endif + +#ifdef INFRA_MEM_STATS +#include "infra_mem_stats.h" +#define jparser_malloc(size) LITE_malloc(size, MEM_MAGIC, "jparser") +#define jparser_free(ptr) LITE_free(ptr) +#else +#define jparser_malloc(size) HAL_Malloc(size) +#define jparser_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +char *json_get_object(int type, char *str, char *str_end) +{ + char *pos = NULL; + char ch = (type == JOBJECT) ? '{' : '['; + + if (!str || !str_end) { + return NULL; + } + + while (str != NULL && *str != 0 && str < str_end) { + if (*str == ' ') { + str++; + continue; + } + pos = (*str == ch) ? str : NULL; + break; + } + return pos; +} + +char *json_get_next_object(int type, char *str, char *str_end, char **key, int *key_len, + char **val, int *val_len, int *val_type) +{ + char JsonMark[JTYPEMAX][2] = { { '\"', '\"' }, { '{', '}' }, { '[', ']' }, { '0', ' ' } }; + int iMarkDepth = 0, iValueType = JNONE, iNameLen = 0, iValueLen = 0, iStringDepth = 0; + char *p_cName = 0, *p_cValue = 0, *p_cPos = str; + + if (type == JOBJECT) { + /* Get Key */ + p_cPos = strchr(p_cPos, '\"'); + if (!p_cPos) { + goto do_exit; + } + p_cName = ++p_cPos; + p_cPos = strchr(p_cPos, '\"'); + if (!p_cPos) { + goto do_exit; + } + iNameLen = p_cPos - p_cName; + + /* Get Value */ + p_cPos = strchr(p_cPos, ':'); + } + while (p_cPos && *p_cPos && p_cPos < str_end) { + if (*p_cPos == '\"') { + iValueType = JSTRING; + p_cValue = ++p_cPos; + break; + } else if (*p_cPos == '{') { + iValueType = JOBJECT; + p_cValue = p_cPos++; + break; + } else if (*p_cPos == '[') { + iValueType = JARRAY; + p_cValue = p_cPos++; + break; + } else if ((*p_cPos == '-') || (*p_cPos >= '0' && *p_cPos <= '9')) { + iValueType = JNUMBER; + p_cValue = p_cPos++; + break; + } else if (*p_cPos == 't' || *p_cPos == 'T' || *p_cPos == 'f' || *p_cPos == 'F') { + iValueType = JBOOLEAN; + p_cValue = p_cPos; + break; + } + p_cPos++; + } + + while (p_cPos && *p_cPos && p_cPos < str_end && iValueType > JNONE) { + if (iValueType == JBOOLEAN) { + int len = strlen(p_cValue); + + if ((*p_cValue == 't' || *p_cValue == 'T') && len >= 4 + && (!strncmp(p_cValue, "true", 4) + || !strncmp(p_cValue, "TRUE", 4))) { + iValueLen = 4; + p_cPos = p_cValue + iValueLen; + break; + } else if ((*p_cValue == 'f' || *p_cValue == 'F') && len >= 5 + && (!strncmp(p_cValue, "false", 5) + || !strncmp(p_cValue, "FALSE", 5))) { + iValueLen = 5; + p_cPos = p_cValue + iValueLen; + break; + } + } else if (iValueType == JNUMBER) { + if ((*p_cPos < '0' || *p_cPos > '9') && (*p_cPos != '.') && (*p_cPos != '+') \ + && (*p_cPos != '-') && ((*p_cPos != 'e')) && (*p_cPos != 'E')) { + iValueLen = p_cPos - p_cValue; + break; + } + } else if (iValueType == JSTRING) { + if (*p_cPos == '\"') { + iValueLen = p_cPos - p_cValue; + break; + } + } else if (*p_cPos == JsonMark[iValueType][1]) { + if (iStringDepth == 0) { + if (iMarkDepth == 0) { + iValueLen = p_cPos - p_cValue + 1; + p_cPos++; + break; + } else { + iMarkDepth--; + } + } + } else if (*p_cPos == JsonMark[iValueType][0]) { + if (iStringDepth == 0) { + iMarkDepth++; + } + } else if (*p_cPos == '\"') { + if (iStringDepth) { + iStringDepth = 0; + } else { + iStringDepth = 1; + } + } + p_cPos++; + } + + if (type == JOBJECT) { + if ((p_cName + iNameLen) > str_end) { + goto do_exit; + } + *key = p_cName; + *key_len = iNameLen; + } + if ((p_cValue + iValueLen) > str_end) { + goto do_exit; + } + + *val = p_cValue; + *val_len = iValueLen; + *val_type = iValueType; + if (iValueType == JSTRING) { + return p_cValue + iValueLen + 1; + } else { + return p_cValue + iValueLen; + } + +do_exit: + *val = NULL; + *val_len = 0; + *key = NULL; + *key_len = 0; + return NULL; +} + +int json_parse_name_value(char *p_cJsonStr, int iStrLen, json_parse_cb pfnCB, void *p_CBData) +{ + char *pos = 0, *key = 0, *val = 0; + int klen = 0, vlen = 0, vtype = 0; + int ret = JSON_RESULT_ERR; + + if (p_cJsonStr == NULL || iStrLen == 0 || pfnCB == NULL) { + return ret; + } + + json_object_for_each_kv(p_cJsonStr, iStrLen, pos, key, klen, val, vlen, vtype) { + if (key && klen && val && vlen) { + ret = JSON_RESULT_OK; + if (JSON_PARSE_FINISH == pfnCB(key, klen, val, vlen, vtype, p_CBData)) { + break; + } + } + } + + return ret; +} + +int json_get_value_by_name_cb(char *p_cName, int iNameLen, char *p_cValue, int iValueLen, int iValueType, + void *p_CBData) +{ + JSON_NV *p_stNameValue = (JSON_NV *)p_CBData; + +#ifdef JSON_DEBUG + int i; + + if (p_cName) { + jparser_debug("Name:"); + for (i = 0; i < iNameLen; i++) { + jparser_debug("%c", *(p_cName + i)); + } + } + + if (p_cValue) { + jparser_debug("Value:"); + for (i = 0; i < iValueLen; i++) { + jparser_debug("%c", *(p_cValue + i)); + } + } +#endif + + if ((iNameLen == p_stNameValue->nLen) && !strncmp(p_cName, p_stNameValue->pN, p_stNameValue->nLen)) { + p_stNameValue->pV = p_cValue; + p_stNameValue->vLen = iValueLen; + p_stNameValue->vType = iValueType; + return JSON_PARSE_FINISH; + } else { + return JSON_PARSE_OK; + } +} + +char *json_get_value_by_name(char *p_cJsonStr, int iStrLen, char *p_cName, int *p_iValueLen, int *p_iValueType) +{ + JSON_NV stNV; + + memset(&stNV, 0, sizeof(stNV)); + stNV.pN = p_cName; + stNV.nLen = strlen(p_cName); + if (JSON_RESULT_OK == json_parse_name_value(p_cJsonStr, iStrLen, json_get_value_by_name_cb, (void *)&stNV)) { + if (p_iValueLen) { + *p_iValueLen = stNV.vLen; + } + if (p_iValueType) { + *p_iValueType = stNV.vType; + } + } + return stNV.pV; +} + +char *json_get_value_by_name_len(char *p_cJsonStr, int iStrLen, char *p_cName, int p_cNameLen, int *p_iValueLen, + int *p_iValueType) +{ + JSON_NV stNV; + + memset(&stNV, 0, sizeof(stNV)); + stNV.pN = p_cName; + stNV.nLen = p_cNameLen; + if (JSON_RESULT_OK == json_parse_name_value(p_cJsonStr, iStrLen, json_get_value_by_name_cb, (void *)&stNV)) { + if (p_iValueLen) { + *p_iValueLen = stNV.vLen; + } + if (p_iValueType) { + *p_iValueType = stNV.vType; + } + } + return stNV.pV; +} + +char *LITE_json_value_of(char *key, char *src, ...) +{ + char *value = NULL; + char *ret = NULL; + char *delim = NULL; + char *key_iter; + char *key_next; + char *src_iter; + + int key_len; + int value_len = -1; + int src_iter_len; + + if (NULL == key || NULL == src) { + return NULL; + } + +#if WITH_MEM_STATS_PER_MODULE +{ + char *module_name = NULL; + int magic = 0; + va_list ap; + va_start(ap, src); + magic = va_arg(ap, int); + if (MEM_MAGIC == magic) { + module_name = va_arg(ap, char *); + } + va_end(ap); +} +#endif + + src_iter = src; + src_iter_len = strlen(src_iter); + key_iter = key; + + do { + if ((delim = strchr(key_iter, '.')) != NULL) { + key_len = delim - key_iter; + key_next = key_iter; + + value = json_get_value_by_name_len(src_iter, src_iter_len, key_next, key_len, &value_len, 0); + if (value == NULL) { + return NULL; + } + + src_iter = value; + src_iter_len = value_len; + key_iter = delim + 1; + } + } while (delim); + + key_len = strlen(key_iter); + key_next = key_iter; + value = json_get_value_by_name_len(src_iter, src_iter_len, key_next, key_len, &value_len, 0); + if (NULL == value) { + return NULL; + } + + ret = jparser_malloc((value_len + 1) * sizeof(char)); + + if (NULL == ret) { + return NULL; + } + + HAL_Snprintf(ret, value_len + 1, "%s", value); + return ret; +} + +#if WITH_JSON_KEYS_OF +static list_head_t *_LITE_json_keys_of(char *src, int src_len, char *prefix, ...) +{ + static ALIYUN_LIST_HEAD(keylist); + char *module_name = NULL; + char *iter_pre = NULL; + char *pos = 0, *key = 0, *val = 0; + int klen = 0, vlen = 0, vtype = 0; + int magic = 0; + unsigned int mlen = 0; + +#if WITH_MEM_STATS_PER_MODULE + va_list ap; + va_start(ap, prefix); + magic = va_arg(ap, int); + if (MEM_MAGIC == magic) { + module_name = va_arg(ap, char *); + } + va_end(ap); +#endif + + if (!strcmp("", prefix)) { + INIT_LIST_HEAD(&keylist); + } + + json_object_for_each_kv(src, src_len, pos, key, klen, val, vlen, vtype) { + if (key && klen && val && vlen) { + + json_key_t *entry = NULL; + + entry = jparser_malloc(sizeof(json_key_t), magic, module_name); + if (NULL == entry) { + utils_err("jparser_malloc failed!"); + return NULL; + } + memset(entry, 0, sizeof(json_key_t)); + + mlen = strlen(prefix) + klen + 1; + if (module_name) { + entry->key = LITE_format_nstring(mlen, "%s%.*s", magic, module_name, prefix, klen, key); + } else { + entry->key = LITE_format_nstring(mlen, "%s%.*s", prefix, klen, key); + } + if (NULL == entry->key) { + jparser_free(entry); + return NULL; + } + + list_add_tail(&entry->list, &keylist); + + if (JOBJECT == vtype) { + mlen = strlen(prefix) + klen + 2; + if (module_name) { + iter_pre = LITE_format_nstring(mlen, "%s%.*s.", magic, module_name, prefix, klen, key); + } else { + iter_pre = LITE_format_nstring(mlen, "%s%.*s.", prefix, klen, key); + } + if (NULL == iter_pre) { + return NULL; + } + + _LITE_json_keys_of(val, vlen, iter_pre, magic, module_name); + jparser_free(iter_pre); + } + } + } + + if (!strcmp("", prefix)) { + json_key_t *entry = NULL; + + entry = jparser_malloc(sizeof(json_key_t), magic, module_name); + if (NULL == entry) { + utils_err("jparser_malloc failed!"); + return NULL; + } + memset(entry, 0, sizeof(json_key_t)); + list_add_tail(&entry->list, &keylist); + + return &keylist; + } + + return NULL; +} + +list_head_t *LITE_json_keys_of(char *src, char *prefix, ...) +{ + char *module_name = NULL; + int magic = 0; + + if (!src || !prefix) { + return NULL; + } + +#if WITH_MEM_STATS_PER_MODULE + + va_list ap; + va_start(ap, prefix); + magic = va_arg(ap, int); + if (MEM_MAGIC == magic) { + module_name = va_arg(ap, char *); + } + va_end(ap); +#endif + + return _LITE_json_keys_of(src, strlen(src), prefix, magic, module_name); + +} + +#if WITH_JSON_TOKEN_EXT +static list_head_t *_LITE_json_keys_of_ext(int type, char *src, int src_len, char *prefix, ...) +{ + static ALIYUN_LIST_HEAD(keylist); + char *module_name = NULL; + char *iter_pre = NULL; + char *pos = 0, *key = 0, *val = 0; + int klen = 0, vlen = 0, vtype = 0; + int magic = 0; + unsigned int count = 1; + unsigned int mlen = 0; + + if (src == NULL || prefix == NULL) { + return NULL; + } + +#if WITH_MEM_STATS_PER_MODULE + va_list ap; + va_start(ap, prefix); + magic = va_arg(ap, int); + if (MEM_MAGIC == magic) { + module_name = va_arg(ap, char *); + } + va_end(ap); +#endif + + if (!strcmp("", prefix)) { + INIT_LIST_HEAD(&keylist); + } + + if (JOBJECT == type) { + json_object_for_each_kv(src, src_len, pos, key, klen, val, vlen, vtype) { + if (key && klen && val && vlen) { + + json_key_t *entry = NULL; + + entry = jparser_malloc(sizeof(json_key_t), magic, module_name); + + if (NULL == entry) { + utils_err("jparser_malloc failed!"); + return NULL; + } + memset(entry, 0, sizeof(json_key_t)); + + mlen = strlen(prefix) + klen + 1; + if (module_name) { + entry->key = LITE_format_nstring(mlen, "%s%.*s", magic, module_name, prefix, klen, key); + } else { + entry->key = LITE_format_nstring(mlen, "%s%.*s", prefix, klen, key); + } + + if (NULL == entry->key) { + jparser_free(entry); + return NULL; + } + + list_add_tail(&entry->list, &keylist); + + if (JOBJECT == vtype) { + mlen = strlen(prefix) + klen + 2; + if (module_name) { + iter_pre = LITE_format_nstring(mlen, "%s%.*s.", magic, module_name, prefix, klen, key); + } else { + iter_pre = LITE_format_nstring(mlen, "%s%.*s.", prefix, klen, key); + } + if (NULL == iter_pre) { + return NULL; + } + + _LITE_json_keys_of_ext(vtype, val, vlen, iter_pre, magic, module_name); + jparser_free(iter_pre); + } else if (JARRAY == vtype) { + mlen = strlen(prefix) + klen + 1; + if (module_name) { + iter_pre = LITE_format_nstring(mlen, "%s%.*s", magic, module_name, prefix, klen, key); + } else { + iter_pre = LITE_format_nstring(mlen, "%s%.*s", prefix, klen, key); + } + if (NULL == iter_pre) { + return NULL; + } + + _LITE_json_keys_of_ext(vtype, val, vlen, iter_pre, magic, module_name); + jparser_free(iter_pre); + } + } + } + } else if (JARRAY == type) { + json_array_for_each_entry(src, src_len, pos, val, vlen, vtype) { + if (val && vlen) { + + json_key_t *entry = NULL; + unsigned int tmp = 0; + unsigned int arridxlen = 0; + entry = jparser_malloc(sizeof(json_key_t), magic, module_name); + if (NULL == entry) { + utils_err("jparser_malloc failed!"); + return NULL; + } + memset(entry, 0, sizeof(json_key_t)); + + tmp = count; + do { + tmp /= 10; + ++arridxlen; + } while (tmp); + mlen = strlen("%s[%d]") + strlen(prefix) + arridxlen; + if (module_name) { + entry->key = LITE_format_nstring(mlen, "%s[%d]", magic, module_name, prefix, count); + } else { + entry->key = LITE_format_nstring(mlen, "%s[%d]", prefix, count); + } + if (NULL == entry->key) { + jparser_free(entry); + return NULL; + } + + list_add_tail(&entry->list, &keylist); + + if (JOBJECT == vtype) { + mlen = strlen("%s[%d].") + strlen(prefix) + arridxlen; + if (module_name) { + iter_pre = LITE_format_nstring(mlen, "%s[%d].", magic, module_name, prefix, count); + } else { + iter_pre = LITE_format_nstring(mlen, "%s[%d].", prefix, count); + } + if (NULL == iter_pre) { + return NULL; + } + + _LITE_json_keys_of_ext(vtype, val, vlen, iter_pre, magic, module_name); + jparser_free(iter_pre); + } else if (JARRAY == vtype) { + mlen = strlen("%s[%d]") + strlen(prefix) + arridxlen; + if (module_name) { + iter_pre = LITE_format_nstring(mlen, "%s[%d]", magic, module_name, prefix, count); + } else { + iter_pre = LITE_format_nstring(mlen, "%s[%d]", prefix, count); + } + if (NULL == iter_pre) { + return NULL; + } + + _LITE_json_keys_of_ext(vtype, val, vlen, iter_pre, magic, module_name); + jparser_free(iter_pre); + } + ++count; + } + } + } + + if (!strcmp("", prefix)) { + json_key_t *entry = NULL; + + entry = jparser_malloc(sizeof(json_key_t), magic, module_name); + if (NULL == entry) { + utils_err("jparser_malloc failed!"); + return NULL; + } + memset(entry, 0, sizeof(json_key_t)); + list_add_tail(&entry->list, &keylist); + + return &keylist; + } + + return NULL; + +} + +int contain_arr(const char *src, int src_len, const char **arr_pre) +{ + int i = 0; + int ret = -1; + int deep = 0; + const char *pre = NULL; + + if (NULL == src || NULL == arr_pre || src_len <= 0) { + return -1; + } + + *arr_pre = NULL; + for (i = 0; i < src_len; ++i) { + switch (src[i]) { + case '[': { + if (deep != 0) { + return ret; + } + ++deep; + if (!pre) { + pre = &src[i]; + } + } + break; + case ']': { + if (deep != 1) { + return ret; + } + --deep; + if ('[' == src[i - 1]) { + return ret; + } + } + break; + default: { + if ((pre != NULL) && (0 == deep)) { + return ret; + } + } + break; + } + } + if ((NULL != pre) && (pre < src + src_len) && (pre >= src)) { + *arr_pre = pre; + ret = 0; + } + return ret; +} + +static char *_json_value_by_arrname(char *src, int src_len, const char *key, int key_len, int *val_len) +{ + char *pos = src; + char *entry = NULL; + const char *p = NULL; + const char *arr_pre = key; + const char *arr_suf = NULL; + int vtype; + int loop; + int loop_tmp = 0; + do { + loop = 0; + + arr_pre = strchr(arr_pre, '['); + if (arr_pre && (arr_pre < key + key_len)) { + arr_suf = strchr(arr_pre, ']'); + } + if (arr_pre && arr_suf && (arr_suf < key + key_len)) { + loop_tmp = 0; + for (p = arr_pre + 1; p < arr_suf; ++p) { + if (*p > '9' || *p < '0') { + return NULL; + } + loop_tmp *= 10; + loop_tmp += *p - '0'; + + } + + pos = json_get_object(JARRAY, pos, src + src_len); + if (pos != 0 && *pos != 0) { + if (*pos == '[' && *(pos + 1) == ']') { + return NULL; + } + } + + json_array_for_each_entry(src, src_len, pos, entry, *val_len, vtype) { + if (entry && *val_len) { + if (++loop >= loop_tmp) { + break; + } + } + } + + if (loop != loop_tmp) { + return NULL; + } + src = entry; + arr_pre = arr_suf + 1; + } + } while (arr_pre && arr_suf && (arr_pre < key + key_len)); + return entry; +} + +void LITE_json_keys_release(list_head_t *keylist) +{ + json_key_t *pos, *tmp; + + if (NULL == keylist) { + return; + } + + list_for_each_entry_safe(pos, tmp, keylist, list, json_key_t) { + if (pos->key) { + jparser_free(pos->key); + } + list_del(&pos->list); + jparser_free(pos); + } +} + +list_head_t *LITE_json_keys_of_ext(char *src, char *prefix, ...) +{ + char *module_name = NULL; + int magic = 0; + +#if WITH_MEM_STATS_PER_MODULE + + va_list ap; + va_start(ap, prefix); + magic = va_arg(ap, int); + if (MEM_MAGIC == magic) { + module_name = va_arg(ap, char *); + } + va_end(ap); +#endif + + if (!src || !prefix) { + return NULL; + } + + return _LITE_json_keys_of_ext(JOBJECT, src, strlen(src), prefix, magic, module_name); +} + +static char *_LITE_json_value_of_ext(char *key, char *src, int src_len, int *val_len) +{ + char *value = NULL; + char *delim = NULL; + char *key_iter; + char *key_next; + char *src_iter; + const char *arr_pre = NULL; + + int value_len; + int key_len; + int obj_key_len = 0; + int key_type; + int src_iter_len; + + src_iter = src; + src_iter_len = src_len; + key_iter = key; + value_len = src_iter_len; + do { + if ((delim = strchr(key_iter, '.')) != NULL) { + key_len = delim - key_iter; + key_type = JOBJECT; + key_next = key_iter; + if (0 == contain_arr(key_next, key_len, &arr_pre)) { + key_type = JARRAY; + obj_key_len = arr_pre - key_iter; + if (obj_key_len) { + value = json_get_value_by_name_len(src_iter, src_iter_len, key_next, obj_key_len, &value_len, 0); + } else { + value = src_iter; + } + } else { + value = json_get_value_by_name_len(src_iter, src_iter_len, key_next, key_len, &value_len, 0); + } + + if (NULL == value) { + return NULL; + } + + if (key_type == JARRAY) { + if (NULL == (value = _json_value_by_arrname(value, value_len, arr_pre, key_len - obj_key_len, &value_len))) { + return NULL; + } + } + src_iter = value; + src_iter_len = value_len; + key_iter = delim + 1; + + } + } while (delim); + + key_len = strlen(key_iter); + key_next = key_iter; + key_type = JOBJECT; + if (0 == contain_arr(key_next, key_len, &arr_pre)) { + key_type = JARRAY; + obj_key_len = arr_pre - key_iter; + if (obj_key_len) { + value = json_get_value_by_name_len(src_iter, src_iter_len, key_next, obj_key_len, &value_len, 0); + } else { + value = src_iter; + } + } else { + value = json_get_value_by_name_len(src_iter, src_iter_len, key_next, key_len, &value_len, 0); + } + + if (NULL == value) { + return NULL; + } + if (key_type == JARRAY) { + if (NULL == (value = _json_value_by_arrname(value, value_len, arr_pre, key_len - obj_key_len, &value_len))) { + return NULL; + } + } + *val_len = value_len; + return value; +} + +#endif /* #if WITH_JSON_TOKEN_EXT */ +#endif /* #if WITH_JSON_KEYS_OF */ +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_json_parser.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_json_parser.h new file mode 100644 index 00000000..4224964b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_json_parser.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#ifndef _INFRA_JSON_PARSER_H_ +#define _INFRA_JSON_PARSER_H_ + +/* #include "iotx_utils_internal.h" */ + +typedef struct JSON_NV { + int nLen; + int vLen; + int vType; + char *pN; + char *pV; +} JSON_NV; + +/** +The descriptions of the json value node type +**/ +enum JSONTYPE { + JNONE = -1, + JSTRING = 0, + JOBJECT, + JARRAY, + JNUMBER, + JBOOLEAN, + JTYPEMAX +}; + +/** +The error codes produced by the JSON parsers +**/ +enum JSON_PARSE_CODE { + JSON_PARSE_ERR, + JSON_PARSE_OK, + JSON_PARSE_FINISH +}; + +/** +The return codes produced by the JSON parsers +**/ +enum JSON_PARSE_RESULT { + JSON_RESULT_ERR = -1, + JSON_RESULT_OK +}; + +typedef int (*json_parse_cb)(char *p_cName, int iNameLen, char *p_cValue, int iValueLen, int iValueType, + void *p_Result); + +/** +* @brief Parse the JSON string, and iterate through all keys and values, +* then handle the keys and values by callback function. +* +* @param[in] p_cJsonStr @n The JSON string +* @param[in] iStrLen @n The JSON string length +* @param[in] pfnCB @n Callback function +* @param[out] p_CBData @n User data +* @return JSON_RESULT_OK success, JSON_RESULT_ERR failed +* @see None. +* @note None. +**/ +int json_parse_name_value(char *p_cJsonStr, int iStrLen, json_parse_cb pfnCB, void *p_CBData); + +/** +* @brief Get the value by a specified key from a json string +* +* @param[in] p_cJsonStr @n the JSON string +* @param[in] iStrLen @n the JSON string length +* @param[in] p_cName @n the specified key string +* @param[out] p_iValueLen @n the value length +* @param[out] p_iValueType @n the value type +* @return A pointer to the value +* @see None. +* @note None. +**/ +char *json_get_value_by_name(char *p_cJsonStr, int iStrLen, char *p_cName, int *p_iValueLen, int *p_iValueType); + +/** +* @brief Get the value by a specified key from a json string +* +* @param[in] p_cJsonStr @n the JSON string +* @param[in] iStrLen @n the JSON string length +* @param[in] p_cName @n the specified key string +* @param[in] p_cNameLen @n the specified key string length +* @param[out] p_iValueLen @n the value length +* @param[out] p_iValueType @n the value type +* @return A pointer to the value +* @see None. +* @note None. +**/ +char *json_get_value_by_name_len(char *p_cJsonStr, int iStrLen, char *p_cName, int p_cNameLen, int *p_iValueLen, + int *p_iValueType); + +/** + * @brief Get the JSON object point associate with a given type. + * + * @param[in] type @n The object type + * @param[in] str @n The JSON string + * @param[in] str_end @n The end point of Json string + * @returns The json object point with the given field type. + * @see None. + * @note None. + */ +char *json_get_object(int type, char *str, char *str_end); +char *json_get_next_object(int type, char *str, char *str_end, char **key, int *key_len, char **val, int *val_len, + int *val_type); + +/** + * @brief retrieve each key&value pair from the json string + * + * @param[in] str @n Json string to revolve + * @param[in] slen @n The length of json string + * @param[in] pos @n cursor + * @param[out] key @n pointer to the next Key object + * @param[out] klen @n Key object length + * @param[out] val @n pointer to the next Value object + * @param[out] vlen @n Value object length + * @param[out] vtype @n Value object type(digital, string, object, array) + * @see None. + * @note None. + */ +#define json_object_for_each_kv(str, slen, pos, key, klen, val, vlen, vtype) \ + for (pos = json_get_object(JOBJECT, str, str + slen); \ + pos != NULL && *pos!= 0 && (pos=json_get_next_object(JOBJECT, pos, str + slen , &key, &klen, &val, &vlen, &vtype))!=0; ) + +/** + * @brief retrieve each entry from the json array + * + * @param[in] str @n Json array to revolve + * @param[in] slen @n the length of Json array + * @param[in] pos @n cursor + * @param[out] entry @n pointer to the next entry from the array + * @param[out] len @n entry length + * @param[out] type @n entry type(digital, string, object, array) + * @see None. + * @note None. + */ +#define json_array_for_each_entry(str, slen, pos, entry, len, type) \ + for (pos = json_get_object(JARRAY, str, str + slen); \ + pos != NULL && *pos!= 0 && (pos=json_get_next_object(JARRAY, ++pos, str + slen, 0, 0, &entry, &len, &type))!=0; ) + + +/** + * @brief backup the last character to register parameters, + * and set the end character with '\0' + * + * @param[in] json_str @n json string + * @param[in] str_len @n json string lenth + * @param[out] register @n used to backup the last character + * @see None. + * @note None. + */ +#define backup_json_str_last_char(json_str, str_len, register) { \ + register = *((char *)json_str + str_len); \ + *((char *)json_str + str_len) = '\0'; \ + } + +/** + * @brief restore the last character from register parameters + * + * @param[in] json_str @n json string + * @param[in] str_len @n json string lenth + * @param[in] register @n used to restore the last character + * @see None. + * @note None. + */ +#define restore_json_str_last_char(json_str, str_len, register) { \ + *((char *)json_str + str_len) = register; \ + } + +char *LITE_json_value_of(char *key, char *src, ...); + +#endif /* __JSON_PARSER_H__ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_list.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_list.h new file mode 100644 index 00000000..b2d6c35e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_list.h @@ -0,0 +1,346 @@ + +#ifndef _INFRA_LIST_H_ +#define _INFRA_LIST_H_ + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) || defined(__GNUC__)) && \ + !defined(inline) && !defined(__cplusplus) + #define inline __inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Get offset of a member variable. + * + * @param[in] type the type of the struct this is embedded in. + * @param[in] member the name of the variable within the struct. + */ +#define aos_offsetof(type, member) ((size_t)&(((type *)0)->member)) + +/* + * Get the struct for this entry. + * + * @param[in] ptr the list head to take the element from. + * @param[in] type the type of the struct this is embedded in. + * @param[in] member the name of the variable within the struct. + */ +#define aos_container_of(ptr, type, member) \ + ((type *) ((char *) (ptr) - aos_offsetof(type, member))) + +/* for double link list */ +typedef struct dlist_s { + struct dlist_s *prev; + struct dlist_s *next; +} dlist_t; + +static inline void __dlist_add(dlist_t *node, dlist_t *prev, dlist_t *next) +{ + node->next = next; + node->prev = prev; + + prev->next = node; + next->prev = node; +} + +/* + * Get the struct for this entry. + * + * @param[in] addr the list head to take the element from. + * @param[in] type the type of the struct this is embedded in. + * @param[in] member the name of the dlist_t within the struct. + */ +#define dlist_entry(addr, type, member) \ + ((type *)((long)addr - aos_offsetof(type, member))) + + +static inline void dlist_add(dlist_t *node, dlist_t *queue) +{ + __dlist_add(node, queue, queue->next); +} + +static inline void dlist_add_tail(dlist_t *node, dlist_t *queue) +{ + __dlist_add(node, queue->prev, queue); +} + +static inline void dlist_del(dlist_t *node) +{ + dlist_t *prev = node->prev; + dlist_t *next = node->next; + + prev->next = next; + next->prev = prev; +} + +static inline void dlist_init(dlist_t *node) +{ + node->next = node->prev = node; +} + +static inline void INIT_AOS_DLIST_HEAD(dlist_t *list) +{ + list->next = list; + list->prev = list; +} + +static inline int dlist_empty(const dlist_t *head) +{ + return head->next == head; +} + +/* + * Initialise the list. + * + * @param[in] list the list to be inited. + */ +#define AOS_DLIST_INIT(list) {&(list), &(list)} + +/* + * Get the first element from a list + * + * @param[in] ptr the list head to take the element from. + * @param[in] type the type of the struct this is embedded in. + * @param[in] member the name of the dlist_t within the struct. + */ +#define dlist_first_entry(ptr, type, member) \ + dlist_entry((ptr)->next, type, member) + +/* + * Iterate over a list. + * + * @param[in] pos the &struct dlist_t to use as a loop cursor. + * @param[in] head he head for your list. + */ +#define dlist_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/* + * Iterate over a list safe against removal of list entry. + * + * @param[in] pos the &struct dlist_t to use as a loop cursor. + * @param[in] n another &struct dlist_t to use as temporary storage. + * @param[in] head he head for your list. + */ +#define dlist_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/* + * Iterate over list of given type. + * + * @param[in] queue he head for your list. + * @param[in] node the &struct dlist_t to use as a loop cursor. + * @param[in] type the type of the struct this is embedded in. + * @param[in] member the name of the dlist_t within the struct. + */ +#define dlist_for_each_entry(queue, node, type, member) \ + for (node = aos_container_of((queue)->next, type, member); \ + &node->member != (queue); \ + node = aos_container_of(node->member.next, type, member)) + +/* + * Iterate over list of given type safe against removal of list entry. + * + * @param[in] queue the head for your list. + * @param[in] n the type * to use as a temp. + * @param[in] node the type * to use as a loop cursor. + * @param[in] type the type of the struct this is embedded in. + * @param[in] member the name of the dlist_t within the struct. + */ +#define dlist_for_each_entry_safe(queue, n, node, type, member) \ + for (node = aos_container_of((queue)->next, type, member), \ + n = (queue)->next ? (queue)->next->next : NULL; \ + &node->member != (queue); \ + node = aos_container_of(n, type, member), n = n ? n->next : NULL) + +/* + * Get the struct for this entry. + * @param[in] ptr the list head to take the element from. + * @param[in] type the type of the struct this is embedded in. + * @param[in] member the name of the variable within the struct. + */ +#define list_entry(ptr, type, member) \ + aos_container_of(ptr, type, member) + + +/* + * Iterate backwards over list of given type. + * + * @param[in] pos the type * to use as a loop cursor. + * @param[in] head he head for your list. + * @param[in] member the name of the dlist_t within the struct. + * @param[in] type the type of the struct this is embedded in. + */ +#define dlist_for_each_entry_reverse(pos, head, member, type) \ + for (pos = list_entry((head)->prev, type, member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, type, member)) + + +/* + * Get the list length. + * + * @param[in] queue the head for your list. + */ +static inline int __dlist_entry_number(dlist_t *queue) +{ + int num; + dlist_t *cur = queue; + for (num = 0; cur->next != queue; cur = cur->next, num++) + ; + + return num; +} + +/* + * Get the list length. + * + * @param[in] queue the head for your list. + */ +#define dlist_entry_number(head) \ + __dlist_entry_number(head) + +/* + * Initialise the list. + * + * @param[in] name the list to be initialized. + */ +#define AOS_DLIST_HEAD_INIT(name) { &(name), &(name) } + +/* + * Initialise the list. + * + * @param[in] name the list to be initialized. + */ +#define AOS_DLIST_HEAD(name) \ + dlist_t name = AOS_DLIST_HEAD_INIT(name) + +/* for single link list */ +typedef struct slist_s { + struct slist_s *next; +} slist_t; + +static inline void slist_add(slist_t *node, slist_t *head) +{ + node->next = head->next; + head->next = node; +} + +static inline void slist_add_tail(slist_t *node, slist_t *head) +{ + while (head->next) { + head = head->next; + } + + slist_add(node, head); +} + +static inline void slist_del(slist_t *node, slist_t *head) +{ + while (head->next) { + if (head->next == node) { + head->next = node->next; + break; + } + + head = head->next; + } +} + +static inline int slist_empty(const slist_t *head) +{ + return !head->next; +} + +static inline void slist_init(slist_t *head) +{ + head->next = 0; +} + +/* +* Iterate over list of given type. +* +* @param[in] queue he head for your list. +* @param[in] node the type * to use as a loop cursor. +* @param[in] type the type of the struct this is embedded in. +* @param[in] member the name of the slist_t within the struct. +*/ +#define slist_for_each_entry(queue, node, type, member) \ + for (node = aos_container_of((queue)->next, type, member); \ + &node->member; \ + node = aos_container_of(node->member.next, type, member)) + +/* + * Iterate over list of given type safe against removal of list entry. + * + * @param[in] queue the head for your list. + * @param[in] tmp the type * to use as a temp. + * @param[in] node the type * to use as a loop cursor. + * @param[in] type the type of the struct this is embedded in. + * @param[in] member the name of the slist_t within the struct. + */ +#define slist_for_each_entry_safe(queue, tmp, node, type, member) \ + for (node = aos_container_of((queue)->next, type, member), \ + tmp = (queue)->next ? (queue)->next->next : NULL; \ + &node->member; \ + node = aos_container_of(tmp, type, member), tmp = tmp ? tmp->next : tmp) + +/* + * Initialise the list. + * + * @param[in] name the list to be initialized. + */ +#define AOS_SLIST_HEAD_INIT(name) {0} + +/* + * Initialise the list. + * + * @param[in] name the list to be initialized. + */ +#define AOS_SLIST_HEAD(name) \ + slist_t name = AOS_SLIST_HEAD_INIT(name) + +/* + * Get the struct for this entry. + * @param[in] addr the list head to take the element from. + * @param[in] type the type of the struct this is embedded in. + * @param[in] member the name of the slist_t within the struct. + */ +#define slist_entry(addr, type, member) ( \ + addr ? (type *)((long)addr - aos_offsetof(type, member)) : (type *)addr \ + ) + +/* +* Get the first element from a list. +* +* @param[in] ptr the list head to take the element from. +* @param[in] type the type of the struct this is embedded in. +* @param[in] member the name of the slist_t within the struct. +*/ +#define slist_first_entry(ptr, type, member) \ + slist_entry((ptr)->next, type, member) + +/* + * Get the list length. + * + * @param[in] queue the head for your list. + */ +static inline int slist_entry_number(slist_t *queue) +{ + int num; + slist_t *cur = queue; + for (num = 0; cur->next; cur = cur->next, num++) + ; + + return num; +} + +#include "infra_compat.h" +#ifdef __cplusplus +} +#endif + +#endif /* AOS_LIST_H */ + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_log.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_log.c new file mode 100644 index 00000000..add4f6ee --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_log.c @@ -0,0 +1,266 @@ +#include "infra_config.h" + +extern void **LITE_get_mem_mutex(void); +extern void *HAL_MutexCreate(void); +extern void HAL_MutexDestroy(void *); + +#include +#include +#include "infra_compat.h" +#include "infra_log.h" +#if defined(INFRA_CJSON) + #include "infra_cjson.h" +#endif + +#if defined(INFRA_LOG) && !defined(INFRA_LOG_ALL_MUTED) +static log_client logcb = { + .name = "linkkit", + .priority = LOG_DEBUG_LEVEL, + .text_buf = {0} +}; + +static char *lvl_names[] = { + "non", "crt", "err", "wrn", "inf", "dbg", "flw" +}; + +/* 31, red. 32, green. 33, yellow. 34, blue. 35, magenta. 36, cyan. 37, white. */ +char *lvl_color[] = { + "[0m", "[1;31m", "[1;31m", "[1;35m", "[1;33m", "[1;36m", "[1;37m" +}; + +void LITE_syslog_routine(char *m, const char *f, const int l, const int level, const char *fmt, va_list *params) +{ + char *tmpbuf = logcb.text_buf; + char *o = tmpbuf; + int truncated = 0; + + if (LITE_get_loglevel() < level || level < LOG_NONE_LEVEL) { + return; + } + +#if !defined(_WIN32) + LITE_printf("%s%s", "\033", lvl_color[level]); + LITE_printf(LOG_PREFIX_FMT, lvl_names[level], f, l); +#endif /* #if !defined(_WIN32) */ + + memset(tmpbuf, 0, sizeof(logcb.text_buf)); + + o = tmpbuf; + o += LITE_vsnprintf(o, LOG_MSG_MAXLEN + 1, fmt, *params); + + if (o - tmpbuf > LOG_MSG_MAXLEN) { + o = tmpbuf + strlen(tmpbuf); + truncated = 1; + } + if (strlen(tmpbuf) == LOG_MSG_MAXLEN) { + truncated = 1; + } + + LITE_printf("%s", tmpbuf); + if (truncated) { + LITE_printf(" ..."); + } + + if (tmpbuf[strlen(tmpbuf) - 1] != '\n') { + LITE_printf("\r\n"); + } + +#if !defined(_WIN32) + LITE_printf("%s", "\033[0m"); +#endif /* #if !defined(_WIN32) */ + return; +} + +void LITE_syslog(char *m, const char *f, const int l, const int level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + LITE_syslog_routine(m, f, l, level, fmt, &ap); + va_end(ap); +} + +int LITE_get_loglevel(void) +{ + return logcb.priority; +} + +void LITE_set_loglevel(int pri) +{ + void **mutex = NULL; + logcb.priority = pri; + +#if WITH_MEM_STATS + mutex = LITE_get_mem_mutex(); + if (pri != LOG_NONE_LEVEL) { + if (*mutex == NULL) { + *mutex = HAL_MutexCreate(); + if (*mutex == NULL) { + LITE_printf("\nCreate memStats mutex error\n"); + } + } + } else if (*mutex != NULL) { + HAL_MutexDestroy(*mutex); + *mutex = NULL; + } +#endif +} + +void LITE_rich_hexdump(const char *f, const int l, + const int level, + const char *buf_str, + const void *buf_ptr, + const int buf_len) +{ + if (LITE_get_loglevel() < level) { + return; + } + + LITE_printf("%s%s", "\033", lvl_color[level]); + LITE_printf(LOG_PREFIX_FMT, lvl_names[level], f, l); + LITE_printf("HEXDUMP %s @ %p[%d]\r\n", buf_str, buf_ptr, buf_len); + LITE_hexdump(buf_str, buf_ptr, buf_len); + + LITE_printf("%s", "\033[0m"); + return; +} + +int log_multi_line_internal(const char *f, const int l, + const char *title, int level, char *payload, const char *mark) +{ + const char *pos; + const char *endl; + int i; + + if (LITE_get_loglevel() < level) { + return 1; + } + + LITE_printf("[%s] %s(%d): %s (Length: %d Bytes)\r\n", + lvl_names[LITE_get_loglevel()], f, l, title, (int)strlen(payload)); + + pos = payload; + while (pos && *pos) { + LITE_printf("%s ", mark); + + if (*pos == '\r') { + LITE_printf("\r\n"); + pos += 2; + continue; + } + + endl = strchr(pos + 1, '\r'); + if (endl == NULL) { + endl = pos; + do { + ++endl; + } while (*endl); + } + + for (i = 0; i < endl - pos; ++i) { + LITE_printf("%c", pos[i]); + } + LITE_printf("\r\n"); + + pos = *endl ? endl + 2 : 0; + } + + return 0; +} + +#define LITE_HEXDUMP_DRAWLINE(start_mark, len, end_mark) \ + do { \ + int i; \ + \ + LITE_printf("%s", start_mark); \ + for(i = 0; i < len; ++i) { LITE_printf("-"); } \ + LITE_printf("%s", end_mark); \ + LITE_printf("\r\n"); \ + \ + } while(0) + +int LITE_hexdump(const char *title, const void *buff, const int len) +{ + int i, j, written; + unsigned char ascii[20] = {0}; + char header[64] = {0}; + unsigned char *buf = (unsigned char *)buff; + + LITE_snprintf(header, sizeof(header), "| %s: (len=%d) |\r\n", title, (int)len); + + LITE_HEXDUMP_DRAWLINE("+", strlen(header) - 4, "+"); + LITE_printf("%s", header); + LITE_printf("%s\r\n", HEXDUMP_SEP_LINE); + + written = 0; + for (i = 0; i < len; ++ i) { + if (i % 16 == 0) { + LITE_printf("| %08X: ", (unsigned int)(i + (long)buff)); + written += 8; + } + + LITE_printf("%02X", buf[i]); + written += 2; + + if (i % 2 == 1) { + LITE_printf(" "); + written += 1; + } + LITE_snprintf((char *)ascii + i % 16, (1 + 1), "%c", ((buf[i] >= ' ' && buf[i] <= '~') ? buf[i] : '.')); + + if (((i + 1) % 16 == 0) || (i == len - 1)) { + for (j = 0; j < 48 - written; ++j) { + LITE_printf(" "); + } + + LITE_printf(" %s", ascii); + LITE_printf("\r\n"); + + written = 0; + memset(ascii, 0, sizeof(ascii)); + } + } + LITE_printf("%s\r\n", HEXDUMP_SEP_LINE); + + return 0; +} + +void IOT_SetLogLevel(IOT_LogLevel level) +{ + int lvl = (int)level; + + if (lvl > LOG_DEBUG_LEVEL) { + HAL_Printf("Invalid input level: %d out of [%d, %d]", level, + LOG_NONE_LEVEL, + LOG_DEBUG_LEVEL); + return; + } + + LITE_set_loglevel(lvl); + HAL_Printf("[prt] log level set as: [ %d ]\r\n", lvl); +} + +#else + +void IOT_SetLogLevel(IOT_LogLevel level) +{ + return; +} + +int log_multi_line_internal(const char *f, const int l, + const char *title, int level, char *payload, const char *mark) +{ + return 0; +} + +void LITE_rich_hexdump(const char *f, const int l, + const int level, + const char *buf_str, + const void *buf_ptr, + const int buf_len) +{ + return; +} + +#endif /* #if defined(INFRA_LOG) && !defined(INFRA_LOG_ALL_MUTED) */ + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_log.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_log.h new file mode 100644 index 00000000..1a8572ea --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_log.h @@ -0,0 +1,119 @@ +#ifndef _INFRA_LOG_H_ +#define _INFRA_LOG_H_ + +#include +#include "infra_defs.h" + +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); +void HAL_Printf(const char *fmt, ...); +int HAL_Vsnprintf(char *str, const int len, const char *format, va_list ap); + +#define LITE_printf HAL_Printf +#define LITE_snprintf HAL_Snprintf +#define LITE_vsnprintf HAL_Vsnprintf +#define LITE_LOG_ENABLED + +#define LOG_MSG_MAXLEN (255) +#define LOG_MOD_NAME_LEN (7) +#define LOG_PREFIX_FMT "[%s] %s(%d): " + +#define HEXDUMP_SEP_LINE "+" \ + "-----------------------" \ + "-----------------------" \ + "-----------------------" + +#if defined(_PLATFORM_IS_LINUX_) + #undef LOG_MSG_MAXLEN + #define LOG_MSG_MAXLEN (512) +#endif + +typedef struct { + char name[LOG_MOD_NAME_LEN + 1]; + int priority; + char text_buf[LOG_MSG_MAXLEN + 1]; +} log_client; + +int LITE_get_loglevel(void); +void LITE_set_loglevel(int level); +int LITE_hexdump(const char *title, const void *buf, const int len); + +void LITE_syslog_routine(char *m, const char *f, const int l, const int level, const char *fmt, va_list *params); +void LITE_syslog(char *m, const char *f, const int l, const int level, const char *fmt, ...); + +#define LOG_NONE_LEVEL (0) /* no log printed at all */ +#define LOG_CRIT_LEVEL (1) /* current application aborting */ +#define LOG_ERR_LEVEL (2) /* current app-module error */ +#define LOG_WARNING_LEVEL (3) /* using default parameters */ +#define LOG_INFO_LEVEL (4) /* running messages */ +#define LOG_DEBUG_LEVEL (5) /* debugging messages */ +#define LOG_FLOW_LEVEL (6) /* code/packet flow messages */ + +#if defined(INFRA_LOG) && !defined(INFRA_LOG_ALL_MUTED) + #if defined(INFRA_LOG_MUTE_FLW) + #define log_flow(mod, ...) + #else + #define log_flow(mod, ...) LITE_syslog(mod, __FUNCTION__, __LINE__, LOG_FLOW_LEVEL, __VA_ARGS__) + #endif + + #if defined(INFRA_LOG_MUTE_DBG) + #define log_debug(mod, ...) + #else + #define log_debug(mod, ...) LITE_syslog(mod, __FUNCTION__, __LINE__, LOG_DEBUG_LEVEL, __VA_ARGS__) + #endif + + #if defined(INFRA_LOG_MUTE_INF) + #define log_info(mod, ...) + #else + #define log_info(mod, ...) LITE_syslog(mod, __FUNCTION__, __LINE__, LOG_INFO_LEVEL, __VA_ARGS__) + #endif + + #if defined(INFRA_LOG_MUTE_WRN) + #define log_warning(mod, ...) + #else + #define log_warning(mod, ...) LITE_syslog(mod, __FUNCTION__, __LINE__, LOG_WARNING_LEVEL, __VA_ARGS__) + #endif + + #if defined(INFRA_LOG_MUTE_ERR) + #define log_err(mod, ...) + #else + #define log_err(mod, ...) LITE_syslog(mod, __FUNCTION__, __LINE__, LOG_ERR_LEVEL, __VA_ARGS__) + #endif + + #if defined(INFRA_LOG_MUTE_CRT) + #define log_crit(mod, ...) + #else + #define log_crit(mod, ...) LITE_syslog(mod, __FUNCTION__, __LINE__, LOG_CRIT_LEVEL, __VA_ARGS__) + #endif +#else /* #if defined(INFRA_LOG) */ + + #define log_flow(mod, ...) + #define log_debug(mod, ...) + #define log_info(mod, ...) + #define log_warning(mod, ...) + #define log_err(mod, ...) + #define log_crit(mod, ...) + +#endif + +int log_multi_line_internal(const char *f, const int l, + const char *title, int level, char *payload, const char *mark); +#define log_multi_line(level, title, fmt, payload, mark) \ + log_multi_line_internal(__func__, __LINE__, title, level, payload, mark) + +void LITE_rich_hexdump(const char *f, const int l, + const int level, + const char *buf_str, + const void *buf_ptr, + const int buf_len + ); + +#define HEXDUMP_DEBUG(buf, len) \ + LITE_rich_hexdump(__func__, __LINE__, LOG_DEBUG_LEVEL, #buf, (const void *)buf, (const int)len) + +#define HEXDUMP_INFO(buf, len) \ + LITE_rich_hexdump(__func__, __LINE__, LOG_INFO_LEVEL, #buf, (const void *)buf, (const int)len) + +int iotx_facility_json_print(const char *str, int level, ...); + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_md5.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_md5.c new file mode 100644 index 00000000..cd8dc648 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_md5.c @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "infra_config.h" + +#ifdef INFRA_MD5 + +#include +#include + +#include "infra_md5.h" + +#define MD5_KEY_IOPAD_SIZE (64) +#define MD5_DIGEST_SIZE (16) + +/* Implementation that should never be optimized out by the compiler */ +static void utils_md5_zeroize(void *v, size_t n) +{ + volatile unsigned char *p = v; + while (n--) { + *p++ = 0; + } +} + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef IOT_MD5_GET_UINT32_LE +#define IOT_MD5_GET_UINT32_LE(n,b,i) \ + { \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ + } +#endif + +#ifndef IOT_MD5_PUT_UINT32_LE +#define IOT_MD5_PUT_UINT32_LE(n,b,i) \ + { \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ + } +#endif + +void utils_md5_init(iot_md5_context *ctx) +{ + memset(ctx, 0, sizeof(iot_md5_context)); +} + +void utils_md5_free(iot_md5_context *ctx) +{ + if (ctx == NULL) { + return; + } + + utils_md5_zeroize(ctx, sizeof(iot_md5_context)); +} + +void utils_md5_clone(iot_md5_context *dst, + const iot_md5_context *src) +{ + *dst = *src; +} + +/* + * MD5 context setup + */ +void utils_md5_starts(iot_md5_context *ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64]) +{ + uint32_t X[16], A, B, C, D; + + IOT_MD5_GET_UINT32_LE(X[ 0], data, 0); + IOT_MD5_GET_UINT32_LE(X[ 1], data, 4); + IOT_MD5_GET_UINT32_LE(X[ 2], data, 8); + IOT_MD5_GET_UINT32_LE(X[ 3], data, 12); + IOT_MD5_GET_UINT32_LE(X[ 4], data, 16); + IOT_MD5_GET_UINT32_LE(X[ 5], data, 20); + IOT_MD5_GET_UINT32_LE(X[ 6], data, 24); + IOT_MD5_GET_UINT32_LE(X[ 7], data, 28); + IOT_MD5_GET_UINT32_LE(X[ 8], data, 32); + IOT_MD5_GET_UINT32_LE(X[ 9], data, 36); + IOT_MD5_GET_UINT32_LE(X[10], data, 40); + IOT_MD5_GET_UINT32_LE(X[11], data, 44); + IOT_MD5_GET_UINT32_LE(X[12], data, 48); + IOT_MD5_GET_UINT32_LE(X[13], data, 52); + IOT_MD5_GET_UINT32_LE(X[14], data, 56); + IOT_MD5_GET_UINT32_LE(X[15], data, 60); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define P(a,b,c,d,k,s,t) \ + { \ + a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) + + P(A, B, C, D, 0, 7, 0xD76AA478); + P(D, A, B, C, 1, 12, 0xE8C7B756); + P(C, D, A, B, 2, 17, 0x242070DB); + P(B, C, D, A, 3, 22, 0xC1BDCEEE); + P(A, B, C, D, 4, 7, 0xF57C0FAF); + P(D, A, B, C, 5, 12, 0x4787C62A); + P(C, D, A, B, 6, 17, 0xA8304613); + P(B, C, D, A, 7, 22, 0xFD469501); + P(A, B, C, D, 8, 7, 0x698098D8); + P(D, A, B, C, 9, 12, 0x8B44F7AF); + P(C, D, A, B, 10, 17, 0xFFFF5BB1); + P(B, C, D, A, 11, 22, 0x895CD7BE); + P(A, B, C, D, 12, 7, 0x6B901122); + P(D, A, B, C, 13, 12, 0xFD987193); + P(C, D, A, B, 14, 17, 0xA679438E); + P(B, C, D, A, 15, 22, 0x49B40821); + +#undef F + +#define F(x,y,z) (y ^ (z & (x ^ y))) + + P(A, B, C, D, 1, 5, 0xF61E2562); + P(D, A, B, C, 6, 9, 0xC040B340); + P(C, D, A, B, 11, 14, 0x265E5A51); + P(B, C, D, A, 0, 20, 0xE9B6C7AA); + P(A, B, C, D, 5, 5, 0xD62F105D); + P(D, A, B, C, 10, 9, 0x02441453); + P(C, D, A, B, 15, 14, 0xD8A1E681); + P(B, C, D, A, 4, 20, 0xE7D3FBC8); + P(A, B, C, D, 9, 5, 0x21E1CDE6); + P(D, A, B, C, 14, 9, 0xC33707D6); + P(C, D, A, B, 3, 14, 0xF4D50D87); + P(B, C, D, A, 8, 20, 0x455A14ED); + P(A, B, C, D, 13, 5, 0xA9E3E905); + P(D, A, B, C, 2, 9, 0xFCEFA3F8); + P(C, D, A, B, 7, 14, 0x676F02D9); + P(B, C, D, A, 12, 20, 0x8D2A4C8A); + +#undef F + +#define F(x,y,z) (x ^ y ^ z) + + P(A, B, C, D, 5, 4, 0xFFFA3942); + P(D, A, B, C, 8, 11, 0x8771F681); + P(C, D, A, B, 11, 16, 0x6D9D6122); + P(B, C, D, A, 14, 23, 0xFDE5380C); + P(A, B, C, D, 1, 4, 0xA4BEEA44); + P(D, A, B, C, 4, 11, 0x4BDECFA9); + P(C, D, A, B, 7, 16, 0xF6BB4B60); + P(B, C, D, A, 10, 23, 0xBEBFBC70); + P(A, B, C, D, 13, 4, 0x289B7EC6); + P(D, A, B, C, 0, 11, 0xEAA127FA); + P(C, D, A, B, 3, 16, 0xD4EF3085); + P(B, C, D, A, 6, 23, 0x04881D05); + P(A, B, C, D, 9, 4, 0xD9D4D039); + P(D, A, B, C, 12, 11, 0xE6DB99E5); + P(C, D, A, B, 15, 16, 0x1FA27CF8); + P(B, C, D, A, 2, 23, 0xC4AC5665); + +#undef F + +#define F(x,y,z) (y ^ (x | ~z)) + + P(A, B, C, D, 0, 6, 0xF4292244); + P(D, A, B, C, 7, 10, 0x432AFF97); + P(C, D, A, B, 14, 15, 0xAB9423A7); + P(B, C, D, A, 5, 21, 0xFC93A039); + P(A, B, C, D, 12, 6, 0x655B59C3); + P(D, A, B, C, 3, 10, 0x8F0CCC92); + P(C, D, A, B, 10, 15, 0xFFEFF47D); + P(B, C, D, A, 1, 21, 0x85845DD1); + P(A, B, C, D, 8, 6, 0x6FA87E4F); + P(D, A, B, C, 15, 10, 0xFE2CE6E0); + P(C, D, A, B, 6, 15, 0xA3014314); + P(B, C, D, A, 13, 21, 0x4E0811A1); + P(A, B, C, D, 4, 6, 0xF7537E82); + P(D, A, B, C, 11, 10, 0xBD3AF235); + P(C, D, A, B, 2, 15, 0x2AD7D2BB); + P(B, C, D, A, 9, 21, 0xEB86D391); + +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} + +/* + * MD5 process buffer + */ +void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, uint32_t ilen) +{ + uint32_t fill; + uint32_t left; + + if (ilen == 0) { + return; + } + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < (uint32_t) ilen) { + ctx->total[1]++; + } + + if (left && ilen >= fill) { + memcpy((void *)(ctx->buffer + left), input, fill); + utils_md5_process(ctx, ctx->buffer); + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= 64) { + utils_md5_process(ctx, input); + input += 64; + ilen -= 64; + } + + if (ilen > 0) { + memcpy((void *)(ctx->buffer + left), input, ilen); + } +} + +static const unsigned char iot_md5_padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD5 final digest + */ +void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16]) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = (ctx->total[0] >> 29) + | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + IOT_MD5_PUT_UINT32_LE(low, msglen, 0); + IOT_MD5_PUT_UINT32_LE(high, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + utils_md5_update(ctx, iot_md5_padding, padn); + utils_md5_update(ctx, msglen, 8); + + IOT_MD5_PUT_UINT32_LE(ctx->state[0], output, 0); + IOT_MD5_PUT_UINT32_LE(ctx->state[1], output, 4); + IOT_MD5_PUT_UINT32_LE(ctx->state[2], output, 8); + IOT_MD5_PUT_UINT32_LE(ctx->state[3], output, 12); +} + + +/* + * output = MD5( input buffer ) + */ +void utils_md5(const unsigned char *input, uint32_t ilen, unsigned char output[16]) +{ + iot_md5_context ctx; + + utils_md5_init(&ctx); + utils_md5_starts(&ctx); + utils_md5_update(&ctx, input, ilen); + utils_md5_finish(&ctx, output); + utils_md5_free(&ctx); +} + +static int8_t utils_hb2hex(uint8_t hb) +{ + hb = hb & 0xF; + return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a'); +} + +void utils_hmac_md5(const char *msg, int msg_len, char *digest, const char *key, int key_len) +{ + iot_md5_context context; + unsigned char k_ipad[MD5_KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[MD5_KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + unsigned char out[MD5_DIGEST_SIZE]; + int i; + + if ((NULL == msg) || (NULL == digest) || (NULL == key)) { + return; + } + + if (key_len > MD5_KEY_IOPAD_SIZE) { + return; + } + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < MD5_KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner MD5 */ + utils_md5_init(&context); /* init context for 1st pass */ + utils_md5_starts(&context); /* setup context for 1st pass */ + utils_md5_update(&context, k_ipad, MD5_KEY_IOPAD_SIZE); /* start with inner pad */ + utils_md5_update(&context, (unsigned char *) msg, msg_len); /* then text of datagram */ + utils_md5_finish(&context, out); /* finish up 1st pass */ + + /* perform outer MD5 */ + utils_md5_init(&context); /* init context for 2nd pass */ + utils_md5_starts(&context); /* setup context for 2nd pass */ + utils_md5_update(&context, k_opad, MD5_KEY_IOPAD_SIZE); /* start with outer pad */ + utils_md5_update(&context, out, MD5_DIGEST_SIZE); /* then results of 1st hash */ + utils_md5_finish(&context, out); /* finish up 2nd pass */ + + for (i = 0; i < MD5_DIGEST_SIZE; ++i) { + digest[i * 2] = utils_hb2hex(out[i] >> 4); + digest[i * 2 + 1] = utils_hb2hex(out[i]); + } +} + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_md5.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_md5.h new file mode 100644 index 00000000..f850163e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_md5.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#ifndef _INFRA_MD5_H_ +#define _INFRA_MD5_H_ + +#include "infra_types.h" + +typedef struct { + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} iot_md5_context; + +/** + * \brief Initialize MD5 context + * + * \param ctx MD5 context to be initialized + */ +void utils_md5_init(iot_md5_context *ctx); + +/** + * \brief Clear MD5 context + * + * \param ctx MD5 context to be cleared + */ +void utils_md5_free(iot_md5_context *ctx); + +/** + * \brief Clone (the state of) an MD5 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void utils_md5_clone(iot_md5_context *dst, + const iot_md5_context *src); + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + */ +void utils_md5_starts(iot_md5_context *ctx); + +/** + * \brief MD5 process buffer + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, uint32_t ilen); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + */ +void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16]); + +/* Internal use */ +void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64]); + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + */ +void utils_md5(const unsigned char *input, uint32_t ilen, unsigned char output[16]); + +void utils_hmac_md5(const char *msg, int msg_len, char *digest, const char *key, int key_len); + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_net.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_net.c new file mode 100644 index 00000000..6aaf049b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_net.c @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "infra_config.h" + +#ifdef INFRA_NET +#include +#include +#include "infra_defs.h" +#include "infra_net.h" +#include "wrappers_defs.h" + +#ifdef INFRA_LOG + #include "infra_log.h" + #define net_err(...) log_err("infra_net", __VA_ARGS__) +#else + #define net_err(...) +#endif + + + +/*** SSL connection ***/ +#ifdef SUPPORT_TLS +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define NET_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "infra_net") + #define NET_FREE(ptr) LITE_free(ptr) +#else + #define NET_MALLOC(size) HAL_Malloc(size) + #define NET_FREE(ptr) HAL_Free(ptr) +#endif + +static void *ssl_malloc(uint32_t size) +{ + return NET_MALLOC(size); +} +static void ssl_free(void *ptr) +{ + NET_FREE(ptr); +} +#endif + +#if defined(SUPPORT_TLS) || defined(SUPPORT_ITLS) +uintptr_t HAL_SSL_Establish(const char *host, uint16_t port, const char *ca_crt, size_t ca_crt_len); +int32_t HAL_SSL_Destroy(uintptr_t handle); +int HAL_SSL_Read(uintptr_t handle, char *buf, int len, int timeout_ms); +int HAL_SSL_Write(uintptr_t handle, const char *buf, int len, int timeout_ms); +int HAL_SSLHooks_set(ssl_hooks_t *hooks); +int HAL_GetProductKey(char *product_key); +int HAL_GetProductSecret(char *product_secret); + +static int read_ssl(utils_network_pt pNetwork, char *buffer, uint32_t len, uint32_t timeout_ms) +{ + if (NULL == pNetwork) { + net_err("network is null"); + return -1; + } + + return HAL_SSL_Read((uintptr_t)pNetwork->handle, buffer, len, timeout_ms); +} + +static int write_ssl(utils_network_pt pNetwork, const char *buffer, uint32_t len, uint32_t timeout_ms) +{ + if (NULL == pNetwork) { + net_err("network is null"); + return -1; + } + + return HAL_SSL_Write((uintptr_t)pNetwork->handle, buffer, len, timeout_ms); +} + +static int disconnect_ssl(utils_network_pt pNetwork) +{ + if (NULL == pNetwork) { + net_err("network is null"); + return -1; + } + + HAL_SSL_Destroy((uintptr_t)pNetwork->handle); + pNetwork->handle = 0; + + return 0; +} + +static int connect_ssl(utils_network_pt pNetwork) +{ + ssl_hooks_t ssl_hooks; + + if (NULL == pNetwork) { + net_err("network is null"); + return 1; + } + +#if defined(SUPPORT_ITLS) + char pkps[IOTX_PRODUCT_KEY_LEN + IOTX_PRODUCT_SECRET_LEN + 3] = {0}; + + HAL_GetProductKey(pkps); + int len = strlen(pkps); + HAL_GetProductSecret(pkps + len + 1); + len += strlen(pkps + len + 1) + 2; + + if (0 != (pNetwork->handle = (intptr_t)HAL_SSL_Establish( + pNetwork->pHostAddress, + pNetwork->port, + pkps, len))) { + return 0; + } +#else + memset(&ssl_hooks, 0, sizeof(ssl_hooks_t)); + ssl_hooks.malloc = ssl_malloc; + ssl_hooks.free = ssl_free; + + HAL_SSLHooks_set(&ssl_hooks); + + if (0 != (pNetwork->handle = (intptr_t)HAL_SSL_Establish( + pNetwork->pHostAddress, + pNetwork->port, + pNetwork->ca_crt, + pNetwork->ca_crt_len + 1))) { + return 0; + } +#endif + else { + /* TODO SHOLUD not remove this handle space */ + /* The space will be freed by calling disconnect_ssl() */ + /* utils_memory_free((void *)pNetwork->handle); */ +#ifdef INFRA_EVENT + iotx_event_post(IOTX_CONN_CLOUD_FAIL); +#endif + return -1; + } +} +#elif defined(AT_TCP_ENABLED) +uintptr_t AT_TCP_Establish(const char *host, uint16_t port); +int AT_TCP_Destroy(uintptr_t fd); +int32_t AT_TCP_Write(uintptr_t fd, const char *buf, uint32_t len, uint32_t timeout_ms); +int32_t AT_TCP_Read(uintptr_t fd, char *buf, uint32_t len, uint32_t timeout_ms); +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); + +/*** TCP connection ***/ +static int read_tcp(utils_network_pt pNetwork, char *buffer, uint32_t len, uint32_t timeout_ms) +{ + return AT_TCP_Read(pNetwork->handle, buffer, len, timeout_ms); +} + +static int write_tcp(utils_network_pt pNetwork, const char *buffer, uint32_t len, uint32_t timeout_ms) +{ + return AT_TCP_Write(pNetwork->handle, buffer, len, timeout_ms); +} + +static int disconnect_tcp(utils_network_pt pNetwork) +{ + if (pNetwork->handle == (uintptr_t)(-1)) { + net_err("Network->handle = -1"); + return -1; + } + + AT_TCP_Destroy(pNetwork->handle); + pNetwork->handle = (uintptr_t)(-1); + return 0; +} + +static int connect_tcp(utils_network_pt pNetwork) +{ + if (NULL == pNetwork) { + net_err("network is null"); + return 1; + } + + pNetwork->handle = AT_TCP_Establish(pNetwork->pHostAddress, pNetwork->port); + if (pNetwork->handle == (uintptr_t)(-1)) { + return -1; + } + + return 0; +} + +#else +uintptr_t HAL_TCP_Establish(const char *host, uint16_t port); +int HAL_TCP_Destroy(uintptr_t fd); +int32_t HAL_TCP_Write(uintptr_t fd, const char *buf, uint32_t len, uint32_t timeout_ms); +int32_t HAL_TCP_Read(uintptr_t fd, char *buf, uint32_t len, uint32_t timeout_ms); +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); + +/*** TCP connection ***/ +static int read_tcp(utils_network_pt pNetwork, char *buffer, uint32_t len, uint32_t timeout_ms) +{ + return HAL_TCP_Read(pNetwork->handle, buffer, len, timeout_ms); +} + + +static int write_tcp(utils_network_pt pNetwork, const char *buffer, uint32_t len, uint32_t timeout_ms) +{ + return HAL_TCP_Write(pNetwork->handle, buffer, len, timeout_ms); +} + +static int disconnect_tcp(utils_network_pt pNetwork) +{ + if (pNetwork->handle == (uintptr_t)(-1)) { + net_err("Network->handle = -1"); + return -1; + } + + HAL_TCP_Destroy(pNetwork->handle); + pNetwork->handle = (uintptr_t)(-1); + return 0; +} + +static int connect_tcp(utils_network_pt pNetwork) +{ + if (NULL == pNetwork) { + net_err("network is null"); + return 1; + } + + pNetwork->handle = HAL_TCP_Establish(pNetwork->pHostAddress, pNetwork->port); + if (pNetwork->handle == (uintptr_t)(-1)) { + return -1; + } + + return 0; +} +#endif /* #ifdef SUPPORT_TLS */ + +/****** network interface ******/ +int utils_net_read(utils_network_pt pNetwork, char *buffer, uint32_t len, uint32_t timeout_ms) +{ + int ret = 0; +#ifdef SUPPORT_TLS + if (NULL != pNetwork->ca_crt) { + ret = read_ssl(pNetwork, buffer, len, timeout_ms); + } +#else + if (NULL == pNetwork->ca_crt) { +#ifdef SUPPORT_ITLS + ret = read_ssl(pNetwork, buffer, len, timeout_ms); +#else + ret = read_tcp(pNetwork, buffer, len, timeout_ms); +#endif + } +#endif + else { + ret = -1; + net_err("no method match!"); + } + + return ret; +} + +int utils_net_write(utils_network_pt pNetwork, const char *buffer, uint32_t len, uint32_t timeout_ms) +{ + int ret = 0; +#ifdef SUPPORT_TLS + if (NULL != pNetwork->ca_crt) { + ret = write_ssl(pNetwork, buffer, len, timeout_ms); + } +#else + if (NULL == pNetwork->ca_crt) { +#ifdef SUPPORT_ITLS + ret = write_ssl(pNetwork, buffer, len, timeout_ms); +#else + ret = write_tcp(pNetwork, buffer, len, timeout_ms); +#endif + } +#endif + + else { + ret = -1; + net_err("no method match!"); + } + + return ret; +} + +int iotx_net_disconnect(utils_network_pt pNetwork) +{ + int ret = 0; +#ifdef SUPPORT_TLS + if (NULL != pNetwork->ca_crt) { + ret = disconnect_ssl(pNetwork); + } +#else + if (NULL == pNetwork->ca_crt) { +#ifdef SUPPORT_ITLS + ret = disconnect_ssl(pNetwork); +#else + ret = disconnect_tcp(pNetwork); +#endif + } +#endif + else { + ret = -1; + net_err("no method match!"); + } + + return ret; +} + +int iotx_net_connect(utils_network_pt pNetwork) +{ + int ret = 0; +#ifdef SUPPORT_TLS + if (NULL != pNetwork->ca_crt) { + ret = connect_ssl(pNetwork); + } +#else + if (NULL == pNetwork->ca_crt) { +#ifdef SUPPORT_ITLS + ret = connect_ssl(pNetwork); +#else + ret = connect_tcp(pNetwork); +#endif + } +#endif + else { + ret = -1; + net_err("no method match!"); + } + + return ret; +} + +int iotx_net_init(utils_network_pt pNetwork, const char *host, uint16_t port, const char *ca_crt) +{ + if (!pNetwork || !host) { + net_err("parameter error! pNetwork=%p, host = %p", pNetwork, host); + return -1; + } + pNetwork->pHostAddress = host; + pNetwork->port = port; + pNetwork->ca_crt = ca_crt; + + if (NULL == ca_crt) { + pNetwork->ca_crt_len = 0; + } else { + pNetwork->ca_crt_len = strlen(ca_crt); + } + + pNetwork->handle = 0; + pNetwork->read = utils_net_read; + pNetwork->write = utils_net_write; + pNetwork->disconnect = iotx_net_disconnect; + pNetwork->connect = iotx_net_connect; + + return 0; +} + +#ifdef SUPPORT_TCP +uintptr_t HAL_TCP_Establish(const char *host, uint16_t port); +int HAL_TCP_Destroy(uintptr_t fd); +int32_t HAL_TCP_Write(uintptr_t fd, const char *buf, uint32_t len, uint32_t timeout_ms); +int32_t HAL_TCP_Read(uintptr_t fd, char *buf, uint32_t len, uint32_t timeout_ms); +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); + +/*** TCP connection ***/ +static int read_tcp(utils_network_pt pNetwork, char *buffer, uint32_t len, uint32_t timeout_ms) +{ + return HAL_TCP_Read(pNetwork->handle, buffer, len, timeout_ms); +} + + +static int write_tcp(utils_network_pt pNetwork, const char *buffer, uint32_t len, uint32_t timeout_ms) +{ + return HAL_TCP_Write(pNetwork->handle, buffer, len, timeout_ms); +} + +static int disconnect_tcp(utils_network_pt pNetwork) +{ + if (pNetwork->handle == (uintptr_t)(-1)) { + net_err("Network->handle = -1"); + return -1; + } + + HAL_TCP_Destroy(pNetwork->handle); + pNetwork->handle = (uintptr_t)(-1); + return 0; +} + +static int connect_tcp(utils_network_pt pNetwork) +{ + if (NULL == pNetwork) { + net_err("network is null"); + return 1; + } + + pNetwork->handle = HAL_TCP_Establish(pNetwork->pHostAddress, pNetwork->port); + if (pNetwork->handle == (uintptr_t)(-1)) { + return -1; + } + + return 0; +} + +/****** network interface ******/ +int utils_net_tcp_read(utils_network_pt pNetwork, char *buffer, uint32_t len, uint32_t timeout_ms) +{ + int ret = 0; + + if (NULL == pNetwork->ca_crt) { + ret = read_tcp(pNetwork, buffer, len, timeout_ms); + } + else { + ret = read_ssl(pNetwork, buffer, len, timeout_ms); + } + + return ret; +} + +int utils_net_tcp_write(utils_network_pt pNetwork, const char *buffer, uint32_t len, uint32_t timeout_ms) +{ + int ret = 0; + + if (NULL == pNetwork->ca_crt) { + ret = write_tcp(pNetwork, buffer, len, timeout_ms); + } + else { + ret = write_ssl(pNetwork, buffer, len, timeout_ms); + } + + return ret; +} + +int iotx_net_tcp_disconnect(utils_network_pt pNetwork) +{ + int ret = 0; + + if (NULL == pNetwork->ca_crt) { + ret = disconnect_tcp(pNetwork); + } + else { + ret = disconnect_ssl(pNetwork); + } + + return ret; +} + +int iotx_net_tcp_connect(utils_network_pt pNetwork) +{ + int ret = 0; + if (NULL == pNetwork->ca_crt) { + ret = connect_tcp(pNetwork); + } + else { + ret = connect_ssl(pNetwork); + } + + return ret; +} + +int iotx_net_tcp_init(utils_network_pt pNetwork, const char *host, uint16_t port, const char *ca_crt) +{ + if (!pNetwork || !host) { + net_err("parameter error! pNetwork=%p, host = %p", pNetwork, host); + return -1; + } + pNetwork->pHostAddress = host; + pNetwork->port = port; + pNetwork->ca_crt = ca_crt; + + if (NULL == ca_crt) { + pNetwork->ca_crt_len = 0; + } else { + pNetwork->ca_crt_len = strlen(ca_crt); + } + + pNetwork->handle = 0; + pNetwork->read = utils_net_tcp_read; + pNetwork->write = utils_net_tcp_write; + pNetwork->disconnect = iotx_net_tcp_disconnect; + pNetwork->connect = iotx_net_tcp_connect; + + return 0; +} +#endif + +#endif + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_net.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_net.h new file mode 100644 index 00000000..1d716624 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_net.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _INFRA_NET_H_ +#define _INFRA_NET_H_ + +#include "infra_types.h" + +/** + * @brief The structure of network connection(TCP or SSL). + * The user has to allocate memory for this structure. + */ + +struct utils_network; +typedef struct utils_network utils_network_t, *utils_network_pt; + +struct utils_network { + const char *pHostAddress; + uint16_t port; + uint16_t ca_crt_len; + + /**< NULL, TCP connection; NOT NULL, SSL connection */ + const char *ca_crt; + /**< NOT NULL,iTLS connection*/ + char *product_key; + /**< connection handle: 0, NOT connection; NOT 0, handle of the connection */ + uintptr_t handle; + + /**< Read data from server function pointer. */ + int (*read)(utils_network_pt, char *, uint32_t, uint32_t); + + /**< Send data to server function pointer. */ + int (*write)(utils_network_pt, const char *, uint32_t, uint32_t); + + /**< Disconnect the network */ + int (*disconnect)(utils_network_pt); + + /**< Establish the network */ + int (*connect)(utils_network_pt); +}; + +int utils_net_read(utils_network_pt pNetwork, char *buffer, uint32_t len, uint32_t timeout_ms); +int utils_net_write(utils_network_pt pNetwork, const char *buffer, uint32_t len, uint32_t timeout_ms); +int iotx_net_disconnect(utils_network_pt pNetwork); +int iotx_net_connect(utils_network_pt pNetwork); +int iotx_net_init(utils_network_pt pNetwork, const char *host, uint16_t port, const char *ca_crt); +#ifdef SUPPORT_TCP +int iotx_net_tcp_init(utils_network_pt pNetwork, const char *host, uint16_t port, const char *ca_crt); +#endif +#endif /* IOTX_COMMON_NET_H */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_preauth.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_preauth.c new file mode 100644 index 00000000..044dc575 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_preauth.c @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "infra_config.h" + +#ifdef INFRA_PREAUTH + +#include +#include +#include + +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_httpc.h" +#include "infra_preauth.h" +#include "infra_string.h" +#include "dev_sign_api.h" + +#define PREAUTH_HTTP_REQ_LEN 300 +#define PREAUTH_HTTP_RSP_LEN 300 + +#define PREAUTH_IOT_ID_MAXLEN (64) +#define PREAUTH_IOT_TOKEN_MAXLEN (65) +#define PREAUTH_IOT_HOST_MAXLEN (64) + +#ifndef CONFIG_GUIDER_AUTH_TIMEOUT + #define CONFIG_GUIDER_AUTH_TIMEOUT (10 * 1000) +#endif + +#ifdef SUPPORT_TLS + extern const char *iotx_ca_crt; +#endif + +int _preauth_assemble_auth_req_string(const iotx_dev_meta_info_t *dev_meta, const char *sign, + const char *device_id, char *request_buff, uint32_t buff_len) +{ + uint8_t i = 0; + const char *kv[][2] = { + { "productKey", NULL }, + { "deviceName", NULL }, + { "signmethod", "hmacsha256"}, + { "sign", NULL }, + { "version", "default" }, + { "clientId", NULL }, + { "timestamp", "2524608000000" }, + { "resources", "mqtt" } + }; + + if (dev_meta == NULL || sign == NULL || device_id == NULL || request_buff == NULL) { + return FAIL_RETURN; + } + + kv[0][1] = dev_meta->product_key; + kv[1][1] = dev_meta->device_name; + kv[3][1] = sign; + kv[5][1] = device_id; + + for (i = 0; i < (sizeof(kv) / (sizeof(kv[0]))); i++) { + if ((strlen(request_buff) + strlen(kv[i][0]) + strlen(kv[i][1]) + 2) >= + buff_len) { + return FAIL_RETURN; + } + + memcpy(request_buff + strlen(request_buff), kv[i][0], strlen(kv[i][0])); + memcpy(request_buff + strlen(request_buff), "=", 1); + memcpy(request_buff + strlen(request_buff), kv[i][1], strlen(kv[i][1])); + memcpy(request_buff + strlen(request_buff), "&", 1); + } + + memset(request_buff + strlen(request_buff) - 1, '\0', 1); + return SUCCESS_RETURN; +} + +static int _preauth_get_string_value(char *p_string, char *value_buff, uint32_t buff_len) +{ + char *p = p_string; + char *p_start = NULL; + char *p_end = NULL; + uint32_t len = 0; + + while (*(++p) != ',' || *p != '}') { + if (*p == '\"') { + if (p_start) { + p_end = p; + break; + } else { + p_start = p + 1; + } + } + } + + if (p_start == NULL || p_end == NULL) { + return FAIL_RETURN; + } + + len = p_end - p_start; + if (len > buff_len) { + return FAIL_RETURN; + } + + memcpy(value_buff, p_start, len); + return SUCCESS_RETURN; +} + +static int _preauth_parse_auth_rsp_string(char *json_string, uint32_t string_len, iotx_sign_mqtt_t *output) +{ + int res = FAIL_RETURN; + char *p = json_string; + char *p_start, *p_end, *pt; + uint8_t len; + int code = 0; + + while (p < (json_string + string_len)) { + while (*(++p) != ':') { + if (p >= (json_string + string_len)) { + if (code != 200) { + return FAIL_RETURN; + } + else { + return SUCCESS_RETURN; + } + } + } + + pt = p; + p_start = p_end = NULL; + while (--pt > json_string) { + if (*pt == '\"') { + if (p_end != NULL) { + p_start = pt + 1; + break; + } else { + p_end = pt; + } + } + } + + if (p_start == NULL || p_end == NULL) { + return FAIL_RETURN; + } + len = p_end - p_start; + + if (strlen("code") == len && !memcmp(p_start, "code", len)) { + infra_str2int(++p, &code); + if (code != 200) { + return FAIL_RETURN; + } + } else if (strlen("iotId") == len && !memcmp(p_start, "iotId", len)) { + res = _preauth_get_string_value(p, output->username, PREAUTH_IOT_ID_MAXLEN); + if (res < SUCCESS_RETURN) { + return res; + } + } else if (strlen("iotToken") == len && !memcmp(p_start, "iotToken", len)) { + res = _preauth_get_string_value(p, output->password, PREAUTH_IOT_TOKEN_MAXLEN); + if (res < SUCCESS_RETURN) { + return res; + } + } else if (strlen("host") == len && !memcmp(p_start, "host", len)) { + res = _preauth_get_string_value(p, output->hostname, PREAUTH_IOT_HOST_MAXLEN); + if (res < SUCCESS_RETURN) { + return res; + } + } else if (strlen("port") == len && !memcmp(p_start, "port", len)) { + int port_temp; + infra_str2int(++p, &port_temp); + output->port = port_temp; + } + } + + return SUCCESS_RETURN; +} + +int preauth_get_connection_info(iotx_mqtt_region_types_t region, iotx_dev_meta_info_t *dev_meta, + const char *sign, const char *device_id, iotx_sign_mqtt_t *preauth_output) +{ + char http_url[128] = "http://"; + char http_url_frag[] = "/auth/devicename"; +#ifdef SUPPORT_TLS + int http_port = 443; +#else + int http_port = 80; +#endif + int res = FAIL_RETURN; + httpclient_t httpc; + httpclient_data_t httpc_data; + char request_buff[PREAUTH_HTTP_REQ_LEN] = {0}; + char response_buff[PREAUTH_HTTP_RSP_LEN] = {0}; + + if (g_infra_http_domain[region] == NULL) { + return FAIL_RETURN; + } + + memset(&httpc, 0, sizeof(httpclient_t)); + memset(&httpc_data, 0, sizeof(httpclient_data_t)); + memcpy(http_url + strlen(http_url), g_infra_http_domain[region], strlen(g_infra_http_domain[region])); + memcpy(http_url + strlen(http_url), http_url_frag, sizeof(http_url_frag)); + + httpc.header = "Accept: text/xml,text/javascript,text/html,application/json\r\n"; + + _preauth_assemble_auth_req_string(dev_meta, sign, device_id, request_buff, sizeof(request_buff)); + + httpc_data.post_content_type = "application/x-www-form-urlencoded;charset=utf-8"; + httpc_data.post_buf = request_buff; + httpc_data.post_buf_len = strlen(request_buff); + httpc_data.response_buf = response_buff; + httpc_data.response_buf_len = sizeof(response_buff); + + res = httpclient_common(&httpc, + http_url, + http_port, +#ifdef SUPPORT_TLS + iotx_ca_crt, +#else + NULL, +#endif + HTTPCLIENT_POST, + CONFIG_GUIDER_AUTH_TIMEOUT, + &httpc_data); + if (res < SUCCESS_RETURN) { + return res; + } + +#ifdef INFRA_LOG_NETWORK_PAYLOAD + preauth_info("Downstream Payload:"); + iotx_facility_json_print(response_buff, LOG_INFO_LEVEL, '<'); +#endif + res = _preauth_parse_auth_rsp_string(response_buff, strlen(response_buff), preauth_output); + + return res; +} + +#endif /* #ifdef MQTT_PRE_AUTH */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_preauth.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_preauth.h new file mode 100644 index 00000000..61723fc3 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_preauth.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __INFRA_PREAUTH__ +#define __INFRA_PREAUTH__ + +#include "infra_defs.h" +#include "infra_types.h" +#include "dev_sign_api.h" + +#ifdef INFRA_LOG + #include "infra_log.h" + #define preauth_err(...) log_err("preauth", __VA_ARGS__) + #define preauth_info(...) log_info("preauth", __VA_ARGS__) + #define preauth_debug(...) log_debug("preauth", __VA_ARGS__) +#else + #define preauth_err(...) + #define preauth_info(...) + #define preauth_debug(...) +#endif + +int preauth_get_connection_info(iotx_mqtt_region_types_t region, iotx_dev_meta_info_t *dev_meta, + const char *sign, const char *device_id, iotx_sign_mqtt_t *preauth_output); + +#endif /* #ifndef __INFRA_PREAUTH__ */ \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_prt_nwk_payload.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_prt_nwk_payload.c new file mode 100644 index 00000000..97c0bf9b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_prt_nwk_payload.c @@ -0,0 +1,159 @@ +#include "infra_config.h" + +#ifdef INFRA_LOG_NETWORK_PAYLOAD +#include +#include +#include "infra_log.h" +#if defined(INFRA_CJSON) + #include "infra_cjson.h" +#endif + +#define JSON_NEWLINE "\r\n" +#define JSON_INDENT " " + +#define JSON_PRINT_NEWSTR HAL_Printf("%s", newstr); +#define JSON_PRINT_NEWLINE \ + do { \ + HAL_Printf("%s", JSON_NEWLINE); \ + if (mark == '>' || mark == '<' || mark == ':') { \ + HAL_Printf("%c ", mark); \ + } \ + } while(0) + +/* 31, red. 32, green. 33, yellow. 34, blue. 35, magenta. 36, cyan. 37, white. */ +static char *_color[] = { + "[0m", "[1;31m", "[1;31m", "[1;35m", "[1;33m", "[1;36m", "[1;37m" +}; + +int iotx_facility_json_print(const char *str, int level, ...) +{ + int length = 0; + char newstr[2]; + int quoted = 0; + int escaped = 0; + int indent = 0; + int i = 0, j = 0; +#if defined(INFRA_CJSON) + int res = -1; + lite_cjson_t lite; +#endif + va_list ap; + int mark = ' '; + + newstr[0] = 0x00; + newstr[1] = 0x00; + + if (str == NULL || strlen(str) == 0) { + return -1; + } + +#if defined(INFRA_CJSON) + res = lite_cjson_parse(str, strlen(str), &lite); + if (res != SUCCESS_RETURN || !lite_cjson_is_object(&lite)) { + return -2; + } +#endif + + length = strlen(str); + HAL_Printf("%s%s", "\033", _color[level]); + va_start(ap, level); + mark = va_arg(ap, int); + JSON_PRINT_NEWLINE; + va_end(ap); + + for (i = 0 ; i < length ; i++) { + char ch = str[i]; + switch (ch) { + case '{': + case '[': + newstr[0] = ch; + JSON_PRINT_NEWSTR; + + if (!quoted) { + JSON_PRINT_NEWLINE; + + if (!(str[i + 1] == '}' || str[i + 1] == ']')) { + ++indent; + + for (j = 0 ; j < indent ; j++) { + HAL_Printf("%s", JSON_INDENT); + } + } + } + + break; + + case '}': + case ']': + if (!quoted) { + if ((i > 0) && (!(str[i - 1] == '{' || str[i - 1] == '['))) { + JSON_PRINT_NEWLINE; + --indent; + + for (j = 0 ; j < indent ; j++) { + HAL_Printf("%s", JSON_INDENT); + } + } else if ((i > 0) && ((str[i - 1] == '[' && ch == ']') || (str[i - 1] == '{' && ch == '}'))) { + for (j = 0 ; j < indent ; j++) { + HAL_Printf("%s", JSON_INDENT); + } + } + } + + newstr[0] = ch; + JSON_PRINT_NEWSTR; + + break; + + case '"': + newstr[0] = ch; + JSON_PRINT_NEWSTR; + escaped = 1; + + if (i > 0 && str[i - 1] == '\\') { + escaped = !escaped; + } + + if (!escaped) { + quoted = !quoted; + } + + break; + + case ',': + newstr[0] = ch; + JSON_PRINT_NEWSTR; + if (!quoted) { + JSON_PRINT_NEWLINE; + + for (j = 0 ; j < indent ; j++) { + HAL_Printf("%s", JSON_INDENT); + } + } + + break; + + case ':': + newstr[0] = ch; + JSON_PRINT_NEWSTR; + if (!quoted) { + HAL_Printf("%s", " "); + } + + break; + + default: + newstr[0] = ch; + JSON_PRINT_NEWSTR; + + break; + } + } + + HAL_Printf("%s", JSON_NEWLINE JSON_NEWLINE); + HAL_Printf("%s", "\033[0m"); + return 0; +} + +#endif /* #ifdef INFRA_LOG_NETWORK_PAYLOAD */ + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_redirect_region.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_redirect_region.c new file mode 100644 index 00000000..7b699007 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_redirect_region.c @@ -0,0 +1,384 @@ +#include "infra_config.h" + +#ifdef MQTT_COMM_ENABLED + +#include +#include +#include +#include +#include "infra_compat.h" + +#include "infra_json_parser.h" +#include "iotx_mqtt_config.h" +#include "mqtt_api.h" +#include "coap_api.h" +#include "infra_redirect_region.h" + +static iotx_conn_info_t iotx_redir_info = {0, 0, NULL, NULL, NULL, NULL, NULL}; +static int redirect_region_flag = 0; +static int redirect_region_retry_cnt = 0; + + +//#define REDIRECT_DEBUG +//#define REDIRECT_DEBUG_TOPIC + +#define TOPIC_LENGTH (128) +#define DATA_LENGTH (48) +#define REDIRECT_IOT_ID_LEN (128) +#define REDIRECT_IOT_TOKEN_LEN (64) +#define REDIRECT_MAX_RETRY_CNT (3) + +#ifdef REDIRECT_DEBUG_TOPIC +#define REDIRECT_SUB_TOPIC "/%s/%s/user/thing/bootstrap/config/push" +#define REDIRECT_PUB_TOPIC "/%s/%s/user/thing/bootstrap/config/push_reply" +#else +#define REDIRECT_SUB_TOPIC "/sys/%s/%s/thing/bootstrap/config/push" +#define REDIRECT_PUB_TOPIC "/sys/%s/%s/thing/bootstrap/config/push_reply" +#endif +#define REDIRECT_MSG_ID "id" +#define REDIRECT_MSG_IOTID "params.iotId" +#define REDIRECT_MSG_HOST "params.endpoint.mqtt.host" +#define REDIRECT_MSG_PORT "params.endpoint.mqtt.port" +#define REDIRECT_MSG_TOKEN "params.endpoint.mqtt.token" + +#define PUB_DATA_STR "{\"id\":%d,\"code\":%d,\"data\":{}}" + +#ifdef INFRA_LOG +#include "infra_log.h" +#define redirect_err(...) log_err("redirect", __VA_ARGS__) +#define redirect_warn(...) log_warning("redirect", __VA_ARGS__) +//#ifdef REDIRECT_DEBUG +#define redirect_info(...) log_info("redirect", __VA_ARGS__) +// #else +// #define redirect_info(...) +// #endif +#else +#define redirect_err(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define redirect_warn(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define redirect_info(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#endif + +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define REDIRECT_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "infra_redirect") + #define REDIRECT_FREE(ptr) LITE_free(ptr) +#else + #define REDIRECT_MALLOC(size) HAL_Malloc(size) + #define REDIRECT_FREE(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#define MEM_MAGIC (0x1234) + +int HAL_GetProductKey(char *product_key); +int HAL_GetProductSecret(char *product_secret); +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN]); +int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN]); + +enum _response_code +{ + SUCCESS = 200, + PARAM_ERROR = 2000, + JSON_PARSE_ERROR +}; + +iotx_conn_info_pt iotx_redirect_info_get(void) +{ + return &iotx_redir_info; +} + +int iotx_device_info_get(iotx_device_info_t *device_info) +{ + if (device_info == NULL) { + return -1; + } + memset(device_info, 0x0, sizeof(iotx_device_info_t)); + HAL_GetProductKey(device_info->product_key); + HAL_GetDeviceName(device_info->device_name); + HAL_GetDeviceSecret(device_info->device_secret); + // HAL_GetDeviceID(device_info->device_id); + + return 0; +} + +void iotx_redirect_info_release(void) +{ + redirect_region_flag = 0; + + if (iotx_redir_info.host_name != NULL) { + REDIRECT_FREE(iotx_redir_info.host_name); + } + if (iotx_redir_info.username != NULL) { + REDIRECT_FREE(iotx_redir_info.username); + } + if (iotx_redir_info.password != NULL) { + REDIRECT_FREE(iotx_redir_info.password); + } + if (iotx_redir_info.client_id != NULL) { + REDIRECT_FREE(iotx_redir_info.client_id); + } + memset(&iotx_redir_info, 0, sizeof(iotx_redir_info)); +} + +int iotx_redirect_set_flag(int flag) +{ + redirect_region_flag = flag; + redirect_region_retry_cnt = 0; + + return redirect_region_flag; +} + +int iotx_redirect_get_flag(void) +{ + if(redirect_region_flag == 1){ + if(redirect_region_retry_cnt <= REDIRECT_MAX_RETRY_CNT){ + redirect_region_retry_cnt++; + }else{ + redirect_region_retry_cnt = 0; + redirect_region_flag = 0; + } + } + + return redirect_region_flag; +} +/* +static int _response_cloud(int id, int code) +{ + int ret = 0; + char *p_topic = NULL; + char data[DATA_LENGTH] = {0}; + iotx_device_info_t *p_device = NULL; + + p_device = LITE_malloc(sizeof(iotx_device_info_t)); + if (!p_device) + { + redirect_err("no mem"); + goto ERROR; + } + + ret = iotx_device_info_get(p_device); + if (ret < 0) + { + redirect_err("get device info err"); + goto ERROR; + } + + p_topic = LITE_malloc(TOPIC_LENGTH); + if (!p_topic) + { + redirect_err("no mem"); + goto ERROR; + } + + memset(p_topic, 0, TOPIC_LENGTH); + snprintf(p_topic, TOPIC_LENGTH, REDIRECT_PUB_TOPIC, p_device->product_key, p_device->device_name); + redirect_info("pub p_topic:%s", p_topic); + + memset(data, 0, DATA_LENGTH); + snprintf(data, DATA_LENGTH, PUB_DATA_STR, id, code); + + ret = IOT_MQTT_Publish_Simple(NULL, p_topic, IOTX_MQTT_QOS1, data, strlen(data)); +ERROR: + if (p_topic) + LITE_free(p_topic); + if (p_device) + LITE_free(p_device); + + return ret; +} +*/ +static void redirect_msg_cb(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg) +{ + int id = 0; + int code = 200; + char *pvalue = NULL; + iotx_mqtt_topic_info_pt ptopic_info = NULL; + + char port_str[6] = {0}; + iotx_conn_info_pt conn = NULL; + char *payload = NULL; + void *callback = NULL; + + redirect_info("-----------------------"); + if (msg == NULL){ + redirect_err("params error"); + code = PARAM_ERROR; + goto ERROR; + } + + ptopic_info = (iotx_mqtt_topic_info_pt)msg->msg; + + if (ptopic_info == NULL){ + redirect_err("params error"); + code = PARAM_ERROR; + goto ERROR; + } + + payload = (char *)ptopic_info->payload; + if(payload == NULL){ + redirect_err("params error"); + goto ERROR; + } + + // print topic name and topic message + redirect_info("Event(%d)", msg->event_type); + if (msg->event_type != IOTX_MQTT_EVENT_PUBLISH_RECEIVED){ + redirect_info("do nothing"); + return; + } + + #ifdef REDIRECT_DEBUG + redirect_info("Topic: '%.*s' (Length: %d)", + ptopic_info->topic_len, + ptopic_info->ptopic, + ptopic_info->topic_len); + redirect_info("Payload: '%.*s' (Length: %d)", + ptopic_info->payload_len, + ptopic_info->payload, + ptopic_info->payload_len); + #endif + + iotx_redirect_info_release(); + + conn = iotx_redirect_info_get(); + if(conn == NULL){ + goto ERROR; + } + + + pvalue = LITE_json_value_of(REDIRECT_MSG_ID, payload, MEM_MAGIC,"redirect"); + if (!pvalue){ + redirect_err("id parse error"); + code = JSON_PARSE_ERROR; + goto ERROR; + } + + id = atoi(pvalue); + redirect_info("id=%d", id); + + REDIRECT_FREE(pvalue); + + pvalue = LITE_json_value_of(REDIRECT_MSG_IOTID, payload, MEM_MAGIC,"redirect"); + if (!pvalue){ + redirect_err("REDIRECT_MSG_IOTID parse error"); + code = JSON_PARSE_ERROR; + goto ERROR; + } + redirect_info("iotid = %s", pvalue); + conn->username = pvalue; + + pvalue = LITE_json_value_of(REDIRECT_MSG_TOKEN, payload, MEM_MAGIC,"redirect"); + if (NULL == pvalue){ + redirect_err("REDIRECT_MSG_TOKEN parse error"); + code = JSON_PARSE_ERROR; + goto ERROR; + } + redirect_info("token=%s", pvalue); + conn->password = pvalue; + + pvalue = LITE_json_value_of(REDIRECT_MSG_HOST, payload, MEM_MAGIC,"redirect"); + if (NULL == pvalue){ + redirect_err("REDIRECT_MSG_HOST parse error"); + code = JSON_PARSE_ERROR; + goto ERROR; + } + redirect_info("host = %s", pvalue); + conn->host_name = pvalue; + + pvalue = LITE_json_value_of(REDIRECT_MSG_PORT, payload, MEM_MAGIC,"redirect"); + if (NULL == pvalue){ + redirect_err("REDIRECT_MSG_PORT parse error"); + code = JSON_PARSE_ERROR; + goto ERROR; + } + redirect_info("port=%s", pvalue); + strcpy(port_str, pvalue); + pvalue = NULL; + conn->port = atoi(port_str); + REDIRECT_FREE(pvalue); + pvalue = NULL; + + iotx_redirect_set_flag(1); + redirect_info("set redirect region flag"); + + callback = iotx_event_callback(ITE_REDIRECT); + if (callback) { + ((int (*)(void))callback)(); + } + +ERROR: + if (code != 200){ + redirect_err("redirect parse error"); + } + + //_response_cloud(id, code); +} + +int iotx_redirect_region_subscribe(void) +{ + int ret = 0; + char *p_topic = NULL; + iotx_device_info_t p_device; + + ret = iotx_device_info_get(&p_device); + if (ret < 0){ + redirect_err("get device info err"); + goto ERROR; + } + + p_topic = REDIRECT_MALLOC(TOPIC_LENGTH); + if (!p_topic){ + redirect_err("no mem"); + goto ERROR; + } + + memset(p_topic, 0, TOPIC_LENGTH); + snprintf(p_topic, TOPIC_LENGTH, REDIRECT_SUB_TOPIC, p_device.product_key, p_device.device_name); + redirect_info("p_topic:%s", p_topic); + + ret = IOT_MQTT_Subscribe(NULL, p_topic, IOTX_MQTT_QOS0, redirect_msg_cb, NULL); + if (ret < 0){ + redirect_err("sub failed"); + }else{ + redirect_info("sub success"); + } + return ret; + +ERROR: + if (p_topic){ + REDIRECT_FREE(p_topic); + } + + iotx_redirect_info_release(); + + return -1; +} + +int iotx_redirect_get_iotId_iotToken(char *iot_id,char *iot_token,char *host,uint16_t *pport) +{ + iotx_conn_info_t *redir_conn = NULL; + + redir_conn = iotx_redirect_info_get(); + + if(redir_conn == NULL || + redir_conn->username == NULL || + redir_conn->password == NULL || + redir_conn->host_name == NULL || + iot_id == NULL || + iot_token == NULL || + host == NULL|| + pport == NULL){ + return -1; + } + + strcpy(iot_id, redir_conn->username); + strcpy(iot_token, redir_conn->password); + strcpy(host, redir_conn->host_name); + *pport = redir_conn->port; + + return 0; +} + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_redirect_region.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_redirect_region.h new file mode 100644 index 00000000..3985a837 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_redirect_region.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _INFRA_REDIRECT_REGION_H_ +#define _INFRA_REDIRECT_REGION_H_ + +#include "infra_types.h" + +int iotx_redirect_region_subscribe(void); +int iotx_redirect_set_flag(int flag); +int iotx_redirect_get_flag(void); +int iotx_redirect_get_iotId_iotToken(char *iot_id,char *iot_token,char *host, uint16_t *pport); + +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_report.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_report.c new file mode 100644 index 00000000..a989ae90 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_report.c @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "infra_config.h" + +#ifdef INFRA_REPORT + +#include +#include +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_string.h" +#include "infra_report.h" + +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); +void HAL_Printf(const char *fmt, ...); +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); +int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN]); +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN]); +uint64_t HAL_UptimeMs(void); +int HAL_GetFirmwareVersion(char *version); + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define SYS_REPORT_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "sys.report") + #define SYS_REPORT_FREE(ptr) LITE_free(ptr) +#else + #define SYS_REPORT_MALLOC(size) HAL_Malloc(size) + #define SYS_REPORT_FREE(ptr) HAL_Free(ptr) +#endif + +#ifdef INFRA_LOG + #include "infra_log.h" + #define VERSION_DEBUG(...) log_debug("version", __VA_ARGS__) + #define VERSION_ERR(...) log_err("version", __VA_ARGS__) +#else + #define VERSION_DEBUG(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define VERSION_ERR(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#endif + +static unsigned int g_report_id = 0; + +int iotx_report_id(void) +{ + return g_report_id++; +} + +static info_report_func_pt info_report_func = NULL; + +void iotx_set_report_func(info_report_func_pt func) +{ + info_report_func = func; +} +/* aos will implement this function */ +#if defined(BUILD_AOS) +extern void aos_get_version_hex(unsigned char version[VERSION_NUM_SIZE]); +#else +void aos_get_version_hex(unsigned char version[VERSION_NUM_SIZE]) +{ + const char *p_version = IOTX_SDK_VERSION; + int i = 0, j = 0; + unsigned char res = 0; + + for (j = 0; j < 3; j++) { + for (res = 0; p_version[i] <= '9' && p_version[i] >= '0'; i++) { + res = res * 10 + p_version[i] - '0'; + } + version[j] = res; + i++; + } + version[3] = 0x00; +} +#endif + + + +/* aos will implement this function */ +#if defined(BUILD_AOS) +extern void aos_get_mac_hex(unsigned char mac[MAC_ADDRESS_SIZE]); +#else +void aos_get_mac_hex(unsigned char mac[MAC_ADDRESS_SIZE]) +{ + memcpy(mac, "\x01\x02\x03\x04\x05\x06\x07\x08", MAC_ADDRESS_SIZE); +} +#endif + +/* aos will implement this function */ +#if defined(BUILD_AOS) +extern void aos_get_chip_code(unsigned char chip_code[CHIP_CODE_SIZE]); +#else +void aos_get_chip_code(unsigned char chip_code[CHIP_CODE_SIZE]) +{ + memcpy(chip_code, "\x01\x02\x03\x04", CHIP_CODE_SIZE); +} +#endif + +const char *DEVICE_INFO_UPDATE_FMT = "{\"id\":\"%d\",\"version\":\"1.0\",\"params\":[" + "{\"attrKey\":\"SYS_LP_SDK_VERSION\",\"attrValue\":\"%s\",\"domain\":\"SYSTEM\"}," + "{\"attrKey\":\"SYS_SDK_LANGUAGE\",\"attrValue\":\"C\",\"domain\":\"SYSTEM\"}" + "],\"method\":\"thing.deviceinfo.update\"}"; + +int iotx_report_devinfo(void *pclient) +{ + int ret = 0; + char topic_name[IOTX_URI_MAX_LEN + 1] = {0}; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + char *msg = NULL; + int msg_len = 0; + + + if (info_report_func == NULL) { + VERSION_ERR("report func not register!"); + return -1; + } + + HAL_GetProductKey(product_key); + HAL_GetDeviceName(device_name); + VERSION_DEBUG("devinfo report"); + + /* devinfo update topic name */ + ret = HAL_Snprintf(topic_name, + IOTX_URI_MAX_LEN, + "/sys/%s/%s/thing/deviceinfo/update", + product_key, + device_name); + if (ret <= 0) { + VERSION_ERR("topic generate err"); + return FAIL_RETURN; + } + VERSION_DEBUG("devinfo report topic: %s", topic_name); + + msg_len = strlen(DEVICE_INFO_UPDATE_FMT) + 10 + strlen(IOTX_SDK_VERSION) + 1; + msg = (char *)SYS_REPORT_MALLOC(msg_len); + if (msg == NULL) { + VERSION_ERR("malloc err"); + return FAIL_RETURN; + } + memset(msg, 0, msg_len); + + /* devinfo update message */ + ret = HAL_Snprintf(msg, + msg_len, + DEVICE_INFO_UPDATE_FMT, + iotx_report_id(), + IOTX_SDK_VERSION + ); + if (ret <= 0) { + VERSION_ERR("topic msg generate err"); + SYS_REPORT_FREE(msg); + return FAIL_RETURN; + } + VERSION_DEBUG("devinfo report data: %s", msg); + + if (info_report_func != NULL) { + info_report_func(pclient, topic_name, 1, msg, strlen(msg)); + } + + SYS_REPORT_FREE(msg); + if (ret < 0) { + VERSION_ERR("publish failed, ret = %d", ret); + return FAIL_RETURN; + } + VERSION_DEBUG("devinfo report succeed"); + + return SUCCESS_RETURN; +} + +/* report Firmware version */ +int iotx_report_firmware_version(void *pclient) +{ + int ret; + char topic_name[IOTX_URI_MAX_LEN + 1] = {0}; + char msg[FIRMWARE_VERSION_MSG_LEN] = {0}; + char version[IOTX_FIRMWARE_VERSION_LEN + 1] = {0}; + char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0}; + char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0}; + + if (info_report_func == NULL) { + VERSION_ERR("report func not register!"); + return -1; + } + + HAL_GetProductKey(product_key); + HAL_GetDeviceName(device_name); + + ret = HAL_GetFirmwareVersion(version); + if (ret <= 0) { + VERSION_ERR("firmware version does not implement"); + return FAIL_RETURN; + } + + VERSION_DEBUG("firmware version report start in MQTT"); + + /* firmware report topic name generate */ + ret = HAL_Snprintf(topic_name, + IOTX_URI_MAX_LEN, + "/ota/device/inform/%s/%s", + product_key, + device_name + ); + if (ret <= 0) { + VERSION_ERR("firmware report topic generate err"); + return FAIL_RETURN; + } + VERSION_DEBUG("firmware report topic: %s", topic_name); + + /* firmware report message json data generate */ + ret = HAL_Snprintf(msg, + FIRMWARE_VERSION_MSG_LEN, + "{\"id\":\"%d\",\"params\":{\"version\":\"%s\"}}", + iotx_report_id(), + version + ); + if (ret <= 0) { + VERSION_ERR("firmware report message json data generate err"); + return FAIL_RETURN; + } + VERSION_DEBUG("firmware report data: %s", msg); + + ret = info_report_func(pclient, topic_name, 1, msg, strlen(msg)); + + if (ret < 0) { + VERSION_ERR("publish failed, ret = %d", ret); + return ret; + } + + VERSION_DEBUG("firmware version report finished, iotx_publish() = %d", ret); + return SUCCESS_RETURN; +} + +/* report ModuleID */ +int iotx_report_mid(void *pclient) +{ + return SUCCESS_RETURN; +} + +#ifndef BUILD_AOS +unsigned int aos_get_version_info(unsigned char version_num[VERSION_NUM_SIZE], + unsigned char random_num[RANDOM_NUM_SIZE], unsigned char mac_address[MAC_ADDRESS_SIZE], + unsigned char chip_code[CHIP_CODE_SIZE], unsigned char *output_buffer, unsigned int output_buffer_size) +{ + char *p = (char *)output_buffer; + + if (output_buffer_size < AOS_ACTIVE_INFO_LEN) { + return 1; + } + + memset(p, 0, output_buffer_size); + + infra_hex2str(version_num, VERSION_NUM_SIZE, p); + p += VERSION_NUM_SIZE * 2; + infra_hex2str(random_num, RANDOM_NUM_SIZE, p); + p += RANDOM_NUM_SIZE * 2; + infra_hex2str(mac_address, MAC_ADDRESS_SIZE, p); + p += MAC_ADDRESS_SIZE * 2; + infra_hex2str(chip_code, CHIP_CODE_SIZE, p); + p += CHIP_CODE_SIZE * 2; + strcat(p, "1111111111222222222233333333334444444444"); + + return 0; +} +#endif +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_report.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_report.h new file mode 100644 index 00000000..8947fea5 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_report.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "infra_defs.h" + +#ifndef _INFRA_REPORT_H_ +#define _INFRA_REPORT_H_ + +#ifndef VERSION_NUM_SIZE + #define VERSION_NUM_SIZE 4 +#endif + +#ifndef RANDOM_NUM_SIZE + #define RANDOM_NUM_SIZE 4 +#endif + +#ifndef MAC_ADDRESS_SIZE + #define MAC_ADDRESS_SIZE 8 +#endif + +#ifndef CHIP_CODE_SIZE + #define CHIP_CODE_SIZE 4 +#endif + +#define AOS_ACTIVE_INFO_LEN (81) + +/* activation device type */ +typedef enum { + ACTIVE_SUBDEV, /* it's a subDevice */ + ACTIVE_SINGLE_GW /* it s a single or gateway device */ +} active_device_type_t; + +/* activation system type */ +typedef enum { + ACTIVE_LINKKIT_ONLY, /* only linkkit implement */ + ACTIVE_LINKKIT_AOS, /* both linkkit and AOS implement */ + ACTIVE_LINKKIT_OTHERS /* linkkit and 3-party OS implement */ +} active_system_type_t; + +typedef int (*info_report_func_pt)(void *handle, const char *topic_name,int req_ack,void *data, int len); + +#define MIDREPORT_PAYLOAD_LEN (62 + IOTX_PARTNER_ID_LEN + IOTX_MODULE_ID_LEN + 32 +1) +#define MIDREPORT_REQID_LEN (IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 6) +#define AOS_VERSON_MSG_LEN (256) +#define LINKKIT_VERSION_MSG_LEN (192) +#define FIRMWARE_VERSION_MSG_LEN (64) +#define DEBUG_REPORT_MID_DEVINFO_FIRMWARE (1) + +int iotx_report_id(void); +int iotx_midreport_reqid(char *requestId, char *product_key, char *device_name); +int iotx_midreport_payload(char *msg, char *requestId, char *mid, char *pid); +int iotx_midreport_topic(char *topic_name, char *topic_head, char *product_key, char *device_name); + +/* AOS version report API */ +int iotx_gen_aos_report_topic(char *topic_name, char *product_key, char *device_name); +int iotx_gen_aos_report_payload(char *msg, int requestId, char *versionData); + +void aos_get_version_hex(unsigned char version[VERSION_NUM_SIZE]); + +#ifndef BUILD_AOS +unsigned int aos_get_version_info(unsigned char version_num[VERSION_NUM_SIZE], + unsigned char random_num[RANDOM_NUM_SIZE], unsigned char mac_address[MAC_ADDRESS_SIZE], + unsigned char chip_code[CHIP_CODE_SIZE], unsigned char *output_buffer, unsigned int output_buffer_size); +#endif + +void iotx_set_report_func(info_report_func_pt func); +int iotx_report_devinfo(void *pclient); +int iotx_report_mid(void *pclient); +int iotx_report_firmware_version(void *pclient); + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_sha1.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_sha1.c new file mode 100644 index 00000000..eecb1a8b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_sha1.c @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "infra_config.h" + +#ifdef INFRA_SHA1 + +#include +#include +#include "infra_sha1.h" + +#define SHA1_KEY_IOPAD_SIZE (64) +#define SHA1_DIGEST_SIZE (20) + +/* Implementation that should never be optimized out by the compiler */ +static void utils_sha1_zeroize( void *v, uint32_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +void utils_sha1_init(iot_sha1_context *ctx) +{ + memset(ctx, 0, sizeof(iot_sha1_context)); +} + +void utils_sha1_free(iot_sha1_context *ctx) +{ + if (ctx == NULL) { + return; + } + + utils_sha1_zeroize(ctx, sizeof(iot_sha1_context)); +} + +void utils_sha1_clone(iot_sha1_context *dst, + const iot_sha1_context *src) +{ + *dst = *src; +} + +/* + * SHA-1 context setup + */ +void utils_sha1_starts(iot_sha1_context *ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64]) +{ + uint32_t temp, W[16], A, B, C, D, E; + + GET_UINT32_BE( W[ 0], data, 0 ); + GET_UINT32_BE( W[ 1], data, 4 ); + GET_UINT32_BE( W[ 2], data, 8 ); + GET_UINT32_BE( W[ 3], data, 12 ); + GET_UINT32_BE( W[ 4], data, 16 ); + GET_UINT32_BE( W[ 5], data, 20 ); + GET_UINT32_BE( W[ 6], data, 24 ); + GET_UINT32_BE( W[ 7], data, 28 ); + GET_UINT32_BE( W[ 8], data, 32 ); + GET_UINT32_BE( W[ 9], data, 36 ); + GET_UINT32_BE( W[10], data, 40 ); + GET_UINT32_BE( W[11], data, 44 ); + GET_UINT32_BE( W[12], data, 48 ); + GET_UINT32_BE( W[13], data, 52 ); + GET_UINT32_BE( W[14], data, 56 ); + GET_UINT32_BE( W[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ +( \ + temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \ + W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \ + ( W[t & 0x0F] = S(temp,1) ) \ +) + +#define P(a,b,c,d,e,x) \ +{ \ + e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P( A, B, C, D, E, W[0] ); + P( E, A, B, C, D, W[1] ); + P( D, E, A, B, C, W[2] ); + P( C, D, E, A, B, W[3] ); + P( B, C, D, E, A, W[4] ); + P( A, B, C, D, E, W[5] ); + P( E, A, B, C, D, W[6] ); + P( D, E, A, B, C, W[7] ); + P( C, D, E, A, B, W[8] ); + P( B, C, D, E, A, W[9] ); + P( A, B, C, D, E, W[10] ); + P( E, A, B, C, D, W[11] ); + P( D, E, A, B, C, W[12] ); + P( C, D, E, A, B, W[13] ); + P( B, C, D, E, A, W[14] ); + P( A, B, C, D, E, W[15] ); + P( E, A, B, C, D, R(16) ); + P( D, E, A, B, C, R(17) ); + P( C, D, E, A, B, R(18) ); + P( B, C, D, E, A, R(19) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P( A, B, C, D, E, R(20) ); + P( E, A, B, C, D, R(21) ); + P( D, E, A, B, C, R(22) ); + P( C, D, E, A, B, R(23) ); + P( B, C, D, E, A, R(24) ); + P( A, B, C, D, E, R(25) ); + P( E, A, B, C, D, R(26) ); + P( D, E, A, B, C, R(27) ); + P( C, D, E, A, B, R(28) ); + P( B, C, D, E, A, R(29) ); + P( A, B, C, D, E, R(30) ); + P( E, A, B, C, D, R(31) ); + P( D, E, A, B, C, R(32) ); + P( C, D, E, A, B, R(33) ); + P( B, C, D, E, A, R(34) ); + P( A, B, C, D, E, R(35) ); + P( E, A, B, C, D, R(36) ); + P( D, E, A, B, C, R(37) ); + P( C, D, E, A, B, R(38) ); + P( B, C, D, E, A, R(39) ); + +#undef K +#undef F + +#define F(x,y,z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P( A, B, C, D, E, R(40) ); + P( E, A, B, C, D, R(41) ); + P( D, E, A, B, C, R(42) ); + P( C, D, E, A, B, R(43) ); + P( B, C, D, E, A, R(44) ); + P( A, B, C, D, E, R(45) ); + P( E, A, B, C, D, R(46) ); + P( D, E, A, B, C, R(47) ); + P( C, D, E, A, B, R(48) ); + P( B, C, D, E, A, R(49) ); + P( A, B, C, D, E, R(50) ); + P( E, A, B, C, D, R(51) ); + P( D, E, A, B, C, R(52) ); + P( C, D, E, A, B, R(53) ); + P( B, C, D, E, A, R(54) ); + P( A, B, C, D, E, R(55) ); + P( E, A, B, C, D, R(56) ); + P( D, E, A, B, C, R(57) ); + P( C, D, E, A, B, R(58) ); + P( B, C, D, E, A, R(59) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P( A, B, C, D, E, R(60) ); + P( E, A, B, C, D, R(61) ); + P( D, E, A, B, C, R(62) ); + P( C, D, E, A, B, R(63) ); + P( B, C, D, E, A, R(64) ); + P( A, B, C, D, E, R(65) ); + P( E, A, B, C, D, R(66) ); + P( D, E, A, B, C, R(67) ); + P( C, D, E, A, B, R(68) ); + P( B, C, D, E, A, R(69) ); + P( A, B, C, D, E, R(70) ); + P( E, A, B, C, D, R(71) ); + P( D, E, A, B, C, R(72) ); + P( C, D, E, A, B, R(73) ); + P( B, C, D, E, A, R(74) ); + P( A, B, C, D, E, R(75) ); + P( E, A, B, C, D, R(76) ); + P( D, E, A, B, C, R(77) ); + P( C, D, E, A, B, R(78) ); + P( B, C, D, E, A, R(79) ); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} + +/* + * SHA-1 process buffer + */ +void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, uint32_t ilen) +{ + uint32_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + utils_sha1_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + utils_sha1_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha1_padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-1 final digest + */ +void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20]) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + utils_sha1_update( ctx, sha1_padding, padn ); + utils_sha1_update( ctx, msglen, 8 ); + + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); +} + + +/* + * output = SHA-1( input buffer ) + */ +void utils_sha1(const unsigned char *input, uint32_t ilen, unsigned char output[20]) +{ + iot_sha1_context ctx; + + utils_sha1_init(&ctx); + utils_sha1_starts(&ctx); + utils_sha1_update(&ctx, input, ilen); + utils_sha1_finish(&ctx, output); + utils_sha1_free(&ctx); +} + +static int8_t utils_hb2hex(uint8_t hb) +{ + hb = hb & 0xF; + return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a'); +} + +void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len) +{ + iot_sha1_context context; + unsigned char k_ipad[SHA1_KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[SHA1_KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + unsigned char out[SHA1_DIGEST_SIZE]; + int i; + + if ((NULL == msg) || (NULL == digest) || (NULL == key)) { + return; + } + + if (key_len > SHA1_KEY_IOPAD_SIZE) { + return; + } + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < SHA1_KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner SHA */ + utils_sha1_init(&context); /* init context for 1st pass */ + utils_sha1_starts(&context); /* setup context for 1st pass */ + utils_sha1_update(&context, k_ipad, SHA1_KEY_IOPAD_SIZE); /* start with inner pad */ + utils_sha1_update(&context, (unsigned char *) msg, msg_len); /* then text of datagram */ + utils_sha1_finish(&context, out); /* finish up 1st pass */ + + /* perform outer SHA */ + utils_sha1_init(&context); /* init context for 2nd pass */ + utils_sha1_starts(&context); /* setup context for 2nd pass */ + utils_sha1_update(&context, k_opad, SHA1_KEY_IOPAD_SIZE); /* start with outer pad */ + utils_sha1_update(&context, out, SHA1_DIGEST_SIZE); /* then results of 1st hash */ + utils_sha1_finish(&context, out); /* finish up 2nd pass */ + + for (i = 0; i < SHA1_DIGEST_SIZE; ++i) { + digest[i * 2] = utils_hb2hex(out[i] >> 4); + digest[i * 2 + 1] = utils_hb2hex(out[i]); + } +} + +void utils_hmac_sha1_hex(const char *msg, int msg_len, char *digest, const char *key, int key_len) +{ + iot_sha1_context context; + unsigned char k_ipad[SHA1_KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[SHA1_KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + unsigned char out[SHA1_DIGEST_SIZE]; + int i; + + if ((NULL == msg) || (NULL == digest) || (NULL == key)) { + return; + } + + if (key_len > SHA1_KEY_IOPAD_SIZE) { + return; + } + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < SHA1_KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner SHA */ + utils_sha1_init(&context); /* init context for 1st pass */ + utils_sha1_starts(&context); /* setup context for 1st pass */ + utils_sha1_update(&context, k_ipad, SHA1_KEY_IOPAD_SIZE); /* start with inner pad */ + utils_sha1_update(&context, (unsigned char *) msg, msg_len); /* then text of datagram */ + utils_sha1_finish(&context, out); /* finish up 1st pass */ + + /* perform outer SHA */ + utils_sha1_init(&context); /* init context for 2nd pass */ + utils_sha1_starts(&context); /* setup context for 2nd pass */ + utils_sha1_update(&context, k_opad, SHA1_KEY_IOPAD_SIZE); /* start with outer pad */ + utils_sha1_update(&context, out, SHA1_DIGEST_SIZE); /* then results of 1st hash */ + utils_sha1_finish(&context, out); /* finish up 2nd pass */ + memcpy(digest, out, SHA1_DIGEST_SIZE); +} + +#endif \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_sha1.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_sha1.h new file mode 100644 index 00000000..c3fd35d2 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_sha1.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#ifndef _INFRA_SHA1_H_ +#define _INFRA_SHA1_H_ + +#include "infra_types.h" + +#define SHA1_DIGEST_SIZE (20) + +/** + * \brief SHA-1 context structure + */ +typedef struct { + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} iot_sha1_context; + +/** + * \brief Initialize SHA-1 context + * + * \param ctx SHA-1 context to be initialized + */ +void utils_sha1_init(iot_sha1_context *ctx); + +/** + * \brief Clear SHA-1 context + * + * \param ctx SHA-1 context to be cleared + */ +void utils_sha1_free(iot_sha1_context *ctx); + +/** + * \brief Clone (the state of) a SHA-1 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void utils_sha1_clone(iot_sha1_context *dst, + const iot_sha1_context *src); + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void utils_sha1_starts(iot_sha1_context *ctx); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, uint32_t ilen); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20]); + +/* Internal use */ +void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64]); + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void utils_sha1(const unsigned char *input, uint32_t ilen, unsigned char output[20]); + +void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len); +void utils_hmac_sha1_hex(const char *msg, int msg_len, char *digest, const char *key, int key_len); + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_sha256.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_sha256.c new file mode 100644 index 00000000..f8cd83a5 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_sha256.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "infra_config.h" + +#ifdef INFRA_SHA256 + +#define INFRA_SHA256_SMALLER + +#include +#include +#include "infra_sha256.h" + +#define SHA256_KEY_IOPAD_SIZE (64) +#define SHA256_DIGEST_SIZE (32) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ + do { \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ + } while( 0 ) +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ + do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ + } while( 0 ) +#endif + + +static void utils_sha256_zeroize(void *v, uint32_t n) +{ + volatile unsigned char *p = v; + while (n--) { + *p++ = 0; + } +} + +void utils_sha256_init(iot_sha256_context *ctx) +{ + memset(ctx, 0, sizeof(iot_sha256_context)); +} + +void utils_sha256_free(iot_sha256_context *ctx) +{ + if (NULL == ctx) { + return; + } + + utils_sha256_zeroize(ctx, sizeof(iot_sha256_context)); +} + +void utils_sha256_starts(iot_sha256_context *ctx) +{ + int is224 = 0; + ctx->total[0] = 0; + ctx->total[1] = 0; + + if (is224 == 0) { + /* SHA-256 */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + } + + ctx->is224 = is224; +} + +static const uint32_t K[] = { + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, +}; + +#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define R(t) \ + ( \ + W[t] = S1(W[t - 2]) + W[t - 7] + \ + S0(W[t - 15]) + W[t - 16] \ + ) + +#define P(a,b,c,d,e,f,g,h,x,K) \ + { \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ + } + +void utils_sha256_process(iot_sha256_context *ctx, const unsigned char data[64]) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A[8]; + unsigned int i; + + for (i = 0; i < 8; i++) { + A[i] = ctx->state[i]; + } + +#if defined(INFRA_SHA256_SMALLER) + for (i = 0; i < 64; i++) { + if (i < 16) { + GET_UINT32_BE(W[i], data, 4 * i); + } else { + R(i); + } + + P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i]); + + temp1 = A[7]; + A[7] = A[6]; + A[6] = A[5]; + A[5] = A[4]; + A[4] = A[3]; + A[3] = A[2]; + A[2] = A[1]; + A[1] = A[0]; + A[0] = temp1; + } +#else /* INFRA_SHA256_SMALLER */ + for (i = 0; i < 16; i++) { + GET_UINT32_BE(W[i], data, 4 * i); + } + + for (i = 0; i < 16; i += 8) { + P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i + 0], K[i + 0]); + P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i + 1], K[i + 1]); + P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i + 2], K[i + 2]); + P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i + 3], K[i + 3]); + P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i + 4], K[i + 4]); + P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i + 5], K[i + 5]); + P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i + 6], K[i + 6]); + P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i + 7], K[i + 7]); + } + + for (i = 16; i < 64; i += 8) { + P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i + 0), K[i + 0]); + P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i + 1), K[i + 1]); + P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i + 2), K[i + 2]); + P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i + 3), K[i + 3]); + P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i + 4), K[i + 4]); + P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i + 5), K[i + 5]); + P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i + 6), K[i + 6]); + P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i + 7), K[i + 7]); + } +#endif /* INFRA_SHA256_SMALLER */ + + for (i = 0; i < 8; i++) { + ctx->state[i] += A[i]; + } +} +void utils_sha256_update(iot_sha256_context *ctx, const unsigned char *input, uint32_t ilen) +{ + size_t fill; + uint32_t left; + + if (ilen == 0) { + return; + } + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < (uint32_t) ilen) { + ctx->total[1]++; + } + + if (left && ilen >= fill) { + memcpy((void *)(ctx->buffer + left), input, fill); + utils_sha256_process(ctx, ctx->buffer); + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= 64) { + utils_sha256_process(ctx, input); + input += 64; + ilen -= 64; + } + + if (ilen > 0) { + memcpy((void *)(ctx->buffer + left), input, ilen); + } +} + +static const unsigned char sha256_padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +void utils_sha256_finish(iot_sha256_context *ctx, uint8_t output[32]) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = (ctx->total[0] >> 29) + | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + PUT_UINT32_BE(high, msglen, 0); + PUT_UINT32_BE(low, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + utils_sha256_update(ctx, sha256_padding, padn); + utils_sha256_update(ctx, msglen, 8); + + PUT_UINT32_BE(ctx->state[0], output, 0); + PUT_UINT32_BE(ctx->state[1], output, 4); + PUT_UINT32_BE(ctx->state[2], output, 8); + PUT_UINT32_BE(ctx->state[3], output, 12); + PUT_UINT32_BE(ctx->state[4], output, 16); + PUT_UINT32_BE(ctx->state[5], output, 20); + PUT_UINT32_BE(ctx->state[6], output, 24); + + if (ctx->is224 == 0) { + PUT_UINT32_BE(ctx->state[7], output, 28); + } +} + +void utils_sha256(const uint8_t *input, uint32_t ilen, uint8_t output[32]) +{ + iot_sha256_context ctx; + + utils_sha256_init(&ctx); + utils_sha256_starts(&ctx); + utils_sha256_update(&ctx, input, ilen); + utils_sha256_finish(&ctx, output); + utils_sha256_free(&ctx); +} + +void utils_hmac_sha256(const uint8_t *msg, uint32_t msg_len, const uint8_t *key, uint32_t key_len, uint8_t output[32]) +{ + iot_sha256_context context; + uint8_t k_ipad[SHA256_KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + uint8_t k_opad[SHA256_KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + int32_t i; + + if ((NULL == msg) || (NULL == key) || (NULL == output)) { + return; + } + + if (key_len > SHA256_KEY_IOPAD_SIZE) { + return; + } + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < SHA256_KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner SHA */ + utils_sha256_init(&context); /* init context for 1st pass */ + utils_sha256_starts(&context); /* setup context for 1st pass */ + utils_sha256_update(&context, k_ipad, SHA256_KEY_IOPAD_SIZE); /* start with inner pad */ + utils_sha256_update(&context, msg, msg_len); /* then text of datagram */ + utils_sha256_finish(&context, output); /* finish up 1st pass */ + + /* perform outer SHA */ + utils_sha256_init(&context); /* init context for 2nd pass */ + utils_sha256_starts(&context); /* setup context for 2nd pass */ + utils_sha256_update(&context, k_opad, SHA256_KEY_IOPAD_SIZE); /* start with outer pad */ + utils_sha256_update(&context, output, SHA256_DIGEST_SIZE); /* then results of 1st hash */ + utils_sha256_finish(&context, output); /* finish up 2nd pass */ +} + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_sha256.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_sha256.h new file mode 100644 index 00000000..7fc337d1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_sha256.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _IOTX_COMMON_SHA256_H_ +#define _IOTX_COMMON_SHA256_H_ + +#include + +#define SHA256_DIGEST_LENGTH (32) +#define SHA256_BLOCK_LENGTH (64) +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) + +/** + * \brief SHA-256 context structure + */ +typedef struct { + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + int is224; /*!< 0 => SHA-256, else SHA-224 */ +} iot_sha256_context; + +typedef union { + char sptr[8]; + uint64_t lint; +} u_retLen; + +/** + * \brief Initialize SHA-256 context + * + * \param ctx SHA-256 context to be initialized + */ +void utils_sha256_init(iot_sha256_context *ctx); + +/** + * \brief Clear SHA-256 context + * + * \param ctx SHA-256 context to be cleared + */ +void utils_sha256_free(iot_sha256_context *ctx); + + +/** + * \brief SHA-256 context setup + * + * \param ctx context to be initialized + */ +void utils_sha256_starts(iot_sha256_context *ctx); + +/** + * \brief SHA-256 process buffer + * + * \param ctx SHA-256 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void utils_sha256_update(iot_sha256_context *ctx, const unsigned char *input, uint32_t ilen); + +/** + * \brief SHA-256 final digest + * + * \param ctx SHA-256 context + * \param output SHA-256 checksum result + */ +void utils_sha256_finish(iot_sha256_context *ctx, uint8_t output[32]); + +/* Internal use */ +void utils_sha256_process(iot_sha256_context *ctx, const unsigned char data[64]); + +/** + * \brief Output = SHA-256( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-256 checksum result + */ +void utils_sha256(const uint8_t *input, uint32_t ilen, uint8_t output[32]); + +void utils_hmac_sha256(const uint8_t *msg, uint32_t msg_len, const uint8_t *key, uint32_t key_len, uint8_t output[32]); + +#endif + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_string.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_string.c new file mode 100644 index 00000000..2b65d561 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_string.c @@ -0,0 +1,207 @@ +#include "infra_config.h" + +#ifdef INFRA_STRING + +#include +#include +#include "infra_types.h" +#include "infra_string.h" + +int8_t infra_hex2char(uint8_t hex) +{ + hex = hex & 0xF; + return (int8_t)(hex < 10 ? '0' + hex : hex - 10 + 'a'); +} + +void infra_hex2str(uint8_t *input, uint16_t input_len, char *output) +{ + char *zEncode = "0123456789ABCDEF"; + int i = 0, j = 0; + + for (i = 0; i < input_len; i++) { + output[j++] = zEncode[(input[i] >> 4) & 0xf]; + output[j++] = zEncode[(input[i]) & 0xf]; + } +} + +void infra_int2str(uint32_t input, char output[10]) +{ + uint8_t i = 0, j = 0; + char tmp[10] = {0}; + + do { + tmp[i++] = input%10 + '0'; + }while((input/=10)>0); + + do { + output[--i] = tmp[j++]; + }while(i > 0); +} + +char *infra_strtok(char *str, const char *delim) +{ + int only_delim = 1; + static char *pos = NULL; + static char *target = NULL; + + pos = (str == NULL)?(pos):(str); + + if (pos == NULL || delim == NULL || + strlen(pos) <= strlen(delim)) { + return NULL; + } + + target = pos; + while (strlen(pos) >= strlen(delim)) { + if (memcmp(pos,delim,strlen(delim)) != 0) { + only_delim = 0; + pos++; + continue; + } + + if (strlen(pos) == strlen(delim)) { + memset(pos,0,strlen(delim)); + if (only_delim) { + return NULL; + } + return target; + } + + if (target == pos) { + pos += strlen(delim); + target = pos; + }else{ + memset(pos,0,strlen(delim)); + pos += strlen(delim); + break; + } + } + + return target; +} + +#define LITE_isdigit(c) (((c) <= '9' && (c) >= '0') ? (1) : (0)) + +static uint8_t _hexval_of_char(char hex) +{ + if (LITE_isdigit(hex)) { + return (hex - '0'); + } + if (hex >= 'a' && hex <= 'f') { + return (hex - 'a' + 10); + } + if (hex >= 'A' && hex <= 'F') { + return (hex - 'A' + 10); + } + + return 0; +} + +void LITE_hexstr_convert(char *input, int input_len, unsigned char *output, int output_len) +{ + int i = 0; + uint8_t ch0, ch1; + + if (input_len % 2 != 0) { + return; + } + + while (i < input_len / 2 && i < output_len) { + ch0 = _hexval_of_char((char)input[2 * i]); + ch1 = _hexval_of_char((char)input[2 * i + 1]); + output[i] = (ch0 << 4 | ch1); + i++; + } +} + +void LITE_hexbuf_convert(unsigned char *digest, char *out, int in_len, int uppercase) +{ + static char *zEncode[] = {"0123456789abcdef", "0123456789ABCDEF"}; + int j = 0; + int i = 0; + int idx = uppercase ? 1 : 0; + + for (i = 0; i < in_len; i ++) { + int a = digest[i]; + + out[j++] = zEncode[idx][(a >> 4) & 0xf]; + out[j++] = zEncode[idx][a & 0xf]; + } +} + +int infra_str2int(const char *input, int *val) +{ + int sign = 0; + int temp = 0; + + if (input == NULL || val == NULL) { + return -1; + } + + while(*input == ' ') { /* only support skipping space */ + input++; + } + + if (*input == '+') { + input++; + } + else if (*input == '-') { + input++; + sign = -1; + } + + while (*input != 0) { + if (*input < '0' || *input > '9') { + break; + } + + temp = temp * 10 + (*input - '0'); + input++; + } + + if (sign == -1) { + temp = -temp; + } + + *val = temp; + return 0; +} + +#endif + +#ifdef INFRA_RANDOM + +uint64_t HAL_UptimeMs(void); +void HAL_Srandom(uint32_t seed); +uint32_t HAL_Random(uint32_t region); + +int infra_randstr(char *random, int length) +{ + int index = 0; + + HAL_Srandom(HAL_UptimeMs()); + + for (index = 0; index < length; index++) { + switch (HAL_Random(3)) { + case 0: { + random[index] = 'A' + HAL_Random(26); + } + break; + case 1: { + random[index] = 'a' + HAL_Random(26); + } + break; + case 2: { + random[index] = '0' + HAL_Random(10); + } + break; + default: { + return -1; + } + } + } + + return 0; +} +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_string.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_string.h new file mode 100644 index 00000000..5026b2de --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_string.h @@ -0,0 +1,16 @@ +#ifndef _INFRA_STRING_H_ +#define _INFRA_STRING_H_ + +#include "infra_types.h" + +int8_t infra_hex2char(uint8_t hex); +void infra_hex2str(uint8_t *input, uint16_t input_len, char *output); +void infra_int2str(uint32_t input, char output[10]); +char *infra_strtok(char *str, const char *delim); +int infra_randstr(char *random, int length); +void LITE_hexstr_convert(char *input, int input_len, unsigned char *output, int output_len); +int infra_str2int(const char *input, int *val); +void LITE_hexbuf_convert(unsigned char *digest, char *out, int in_len, int uppercase); + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_timer.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_timer.c new file mode 100644 index 00000000..f1996cf6 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_timer.c @@ -0,0 +1,95 @@ +#include "infra_config.h" + +#ifdef INFRA_TIMER +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "infra_types.h" +#include "infra_timer.h" + +uint64_t HAL_UptimeMs(void); + +void iotx_time_start(iotx_time_t *timer) +{ + if (!timer) { + return; + } + + timer->time = HAL_UptimeMs(); +} + +uint32_t utils_time_spend(iotx_time_t *start) +{ + uint32_t now, res; + + if (!start) { + return 0; + } + + now = HAL_UptimeMs(); + res = now - start->time; + return res; +} + +uint32_t iotx_time_left(iotx_time_t *end) +{ + uint32_t now, res; + + if (!end) { + return 0; + } + + if (utils_time_is_expired(end)) { + return 0; + } + + now = HAL_UptimeMs(); + res = end->time - now; + return res; +} + +uint32_t utils_time_is_expired(iotx_time_t *timer) +{ + uint32_t cur_time; + + if (!timer) { + return 1; + } + + cur_time = HAL_UptimeMs(); + /* + * WARNING: Do NOT change the following code until you know exactly what it do! + * + * check whether it reach destination time or not. + */ + if ((cur_time - timer->time) < (UINT32_MAX / 2)) { + return 1; + } else { + return 0; + } +} + +void iotx_time_init(iotx_time_t *timer) +{ + if (!timer) { + return; + } + + timer->time = 0; +} + +void utils_time_countdown_ms(iotx_time_t *timer, uint32_t millisecond) +{ + if (!timer) { + return; + } + + timer->time = HAL_UptimeMs() + millisecond; +} + +uint32_t utils_time_get_ms(void) +{ + return HAL_UptimeMs(); +} +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_timer.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_timer.h new file mode 100644 index 00000000..e018aab2 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_timer.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + + +#ifndef _INFRA_TIMER_H_ +#define _INFRA_TIMER_H_ + +#include "infra_types.h" + +typedef struct { + uint32_t time; +} iotx_time_t; + + +void iotx_time_start(iotx_time_t *timer); + +uint32_t utils_time_spend(iotx_time_t *start); + +uint32_t iotx_time_left(iotx_time_t *end); + +uint32_t utils_time_is_expired(iotx_time_t *timer); + +void iotx_time_init(iotx_time_t *timer); + +void utils_time_countdown_ms(iotx_time_t *timer, uint32_t millisecond); + +uint32_t utils_time_get_ms(void); + +#endif /* _IOTX_COMMON_TIMER_H_ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_types.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_types.h new file mode 100644 index 00000000..7037296e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/infra/infra_types.h @@ -0,0 +1,29 @@ +#ifndef _INFRA_TYPES_H_ +#define _INFRA_TYPES_H_ + +#include +#include "infra_config.h" + +#define IOT_TRUE (1) /* indicate boolean value true */ +#define IOT_FALSE (0) /* indicate boolean value false */ + +#if !defined(PLATFORM_HAS_STDINT) + +typedef unsigned char uint8_t; +typedef signed char int8_t; +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned int uint32_t; +typedef signed int int32_t; +typedef unsigned long int uint64_t; +typedef signed long int int64_t; +typedef unsigned int uintptr_t; + +#else + +#include + +#endif /* #if !defined(PLATFORM_HAS_STDINT) */ + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTConnect.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTConnect.h new file mode 100644 index 00000000..20ec833d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTConnect.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef MQTTCONNECT_H_ +#define MQTTCONNECT_H_ + +#if !defined(DLLImport) + #define DLLImport +#endif +#if !defined(DLLExport) + #define DLLExport +#endif + + +#define MQTT_CONN_FLAG_USER_NAME (0x80) +#define MQTT_CONN_FLAG_PASSWORD (0x40) +#define MQTT_CONN_FLAG_WILL_RETAIN (0x20) +#define MQTT_CONN_FLAG_WILL_QOS (0x18) +#define MQTT_CONN_FLAG_WILL_FLAG (0x04) +#define MQTT_CONN_FLAG_CLEAN_SESSION (0x02) + +typedef union { + unsigned char all; /**< all connect flags */ +} MQTTConnectFlags; /**< connect flags byte */ + +/** + * Defines the MQTT "Last Will and Testament" (LWT) settings for + * the connect packet. + */ +typedef struct { + /** The eyecatcher for this structure. must be MQTW. */ + char struct_id[4]; + /** The version number of this structure. Must be 0 */ + int struct_version; + /** The LWT topic to which the LWT message will be published. */ + MQTTString topicName; + /** The LWT payload. */ + MQTTString message; + /** + * The retained flag for the LWT message (see MQTTAsync_message.retained). + */ + unsigned char retained; + /** + * The quality of service setting for the LWT message (see + * MQTTAsync_message.qos and @ref qos). + */ + char qos; +} MQTTPacket_willOptions; + + +#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 } + + +typedef struct { + /** The eyecatcher for this structure. must be MQTC. */ + char struct_id[4]; + /** The version number of this structure. Must be 0 */ + int struct_version; + /** Version of MQTT to be used. 3 = 3.1 4 = 3.1.1 + */ + unsigned char MQTTVersion; + MQTTString clientID; + unsigned short keepAliveInterval; /* 单位s */ + unsigned char cleansession; + unsigned char willFlag; + MQTTPacket_willOptions will; + MQTTString username; + MQTTString password; +} MQTTPacket_connectData; + +typedef union { + unsigned char all; /**< all connack flags */ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + struct { + unsigned int sessionpresent : 1; /**< session present flag */ + unsigned int : 7; /**< unused */ + } bits; +#else + struct { + unsigned int : 7; /**< unused */ + unsigned int sessionpresent : 1; /**< session present flag */ + } bits; +#endif +} MQTTConnackFlags; /**< connack flags byte */ + +#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, CONFIG_MQTT_KEEPALIVE_INTERVAL_MIN, 1, 0, \ + MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} } + +DLLExport int MQTTSerialize_connect(unsigned char *buf, int buflen, MQTTPacket_connectData *options); +DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData *data, unsigned char *buf, int len); + +DLLExport int MQTTSerialize_connack(unsigned char *buf, int buflen, unsigned char connack_rc, + unsigned char sessionPresent); +DLLExport int MQTTDeserialize_connack(unsigned char *sessionPresent, unsigned char *connack_rc, unsigned char *buf, + int buflen); + +DLLExport int MQTTSerialize_disconnect(unsigned char *buf, int buflen); +DLLExport int MQTTSerialize_pingreq(unsigned char *buf, int buflen); + +#endif /* MQTTCONNECT_H_ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTConnectClient.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTConnectClient.c new file mode 100644 index 00000000..71cb8ac9 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTConnectClient.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "MQTTPacket.h" + +#include + +/** + * Determines the length of the MQTT connect packet that would be produced using the supplied connect options. + * @param options the options to be used to build the connect packet + * @return the length of buffer needed to contain the serialized version of the packet + */ +int MQTTSerialize_connectLength(MQTTPacket_connectData *options) +{ + int len = 0; + + + if (options->MQTTVersion == 3) { + len = 12; /* variable depending on MQTT or MQIsdp */ + } else if (options->MQTTVersion == 4) { + len = 10; + } + + len += MQTTstrlen(options->clientID) + 2; + if (options->willFlag) { + len += MQTTstrlen(options->will.topicName) + 2 + MQTTstrlen(options->will.message) + 2; + } + if (options->username.cstring || options->username.lenstring.data) { + len += MQTTstrlen(options->username) + 2; + } + if (options->password.cstring || options->password.lenstring.data) { + len += MQTTstrlen(options->password) + 2; + } + + return len; +} + + +/** + * Serializes the connect options into the buffer. + * @param buf the buffer into which the packet will be serialized + * @param len the length in bytes of the supplied buffer + * @param options the options to be used to build the connect packet + * @return serialized length, or error if 0 + */ +int MQTTSerialize_connect(unsigned char *buf, int buflen, MQTTPacket_connectData *options) +{ + unsigned char *ptr = buf; + MQTTHeader header = {0}; + MQTTConnectFlags flags = {0}; + int len = 0; + int rc = -1; + + if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen) { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + + header.byte = 0; + MQTT_HEADER_SET_TYPE(header.byte, CONNECT); + + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, len); /* write remaining length */ + + if (options->MQTTVersion == 4) { + writeCString(&ptr, "MQTT"); + writeChar(&ptr, (char) 4); + } else { + writeCString(&ptr, "MQIsdp"); + writeChar(&ptr, (char) 3); + } + + flags.all = 0; + flags.all |= (options->cleansession) ? MQTT_CONN_FLAG_CLEAN_SESSION : 0; + flags.all |= (options->willFlag) ? MQTT_CONN_FLAG_WILL_FLAG : 0; + if (flags.all & MQTT_CONN_FLAG_WILL_FLAG) { + flags.all |= ((options->will.qos & 0x03) << 3); + flags.all |= (options->will.retained) ? MQTT_CONN_FLAG_WILL_RETAIN : 0; + } + + if (options->username.cstring || options->username.lenstring.data) { + flags.all |= MQTT_CONN_FLAG_USER_NAME; + } + if (options->password.cstring || options->password.lenstring.data) { + flags.all |= MQTT_CONN_FLAG_PASSWORD; + } + + writeChar(&ptr, flags.all); + writeInt(&ptr, options->keepAliveInterval); + writeMQTTString(&ptr, options->clientID); + if (options->willFlag) { + writeMQTTString(&ptr, options->will.topicName); + writeMQTTString(&ptr, options->will.message); + } + if (flags.all & MQTT_CONN_FLAG_USER_NAME) { + writeMQTTString(&ptr, options->username); + } + if (flags.all & MQTT_CONN_FLAG_PASSWORD) { + writeMQTTString(&ptr, options->password); + } + + rc = ptr - buf; + +exit: + return rc; +} + + +/** + * Deserializes the supplied (wire) buffer into connack data - return code + * @param sessionPresent the session present flag returned (only for MQTT 3.1.1) + * @param connack_rc returned integer value of the connack return code + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @param len the length in bytes of the data in the supplied buffer + * @return error code. 1 is success, 0 is failure + */ +int MQTTDeserialize_connack(unsigned char *sessionPresent, unsigned char *connack_rc, unsigned char *buf, int buflen) +{ + MQTTHeader header = {0}; + unsigned char *curdata = buf; + unsigned char *enddata = NULL; + int rc = 0; + int mylen; + MQTTConnackFlags flags = {0}; + + header.byte = readChar(&curdata); + if (MQTT_HEADER_GET_TYPE(header.byte) != CONNACK) { + goto exit; + } + + curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */ + enddata = curdata + mylen; + if (enddata - curdata < 2) { + goto exit; + } + + flags.all = readChar(&curdata); + *sessionPresent = flags.bits.sessionpresent; + *connack_rc = readChar(&curdata); + + rc = 1; +exit: + return rc; +} + + +/** + * Serializes a 0-length packet into the supplied buffer, ready for writing to a socket + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer, to avoid overruns + * @param packettype the message type + * @return serialized length, or error if 0 + */ +int MQTTSerialize_zero(unsigned char *buf, int buflen, unsigned char packettype) +{ + MQTTHeader header = {0}; + int rc = -1; + unsigned char *ptr = buf; + + if (buflen < 2) { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + header.byte = 0; + MQTT_HEADER_SET_TYPE(header.byte, packettype); + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */ + rc = ptr - buf; +exit: + return rc; +} + + +/** + * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer, to avoid overruns + * @return serialized length, or error if 0 + */ +int MQTTSerialize_disconnect(unsigned char *buf, int buflen) +{ + return MQTTSerialize_zero(buf, buflen, DISCONNECT); +} + + +/** + * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer, to avoid overruns + * @return serialized length, or error if 0 + */ +int MQTTSerialize_pingreq(unsigned char *buf, int buflen) +{ + return MQTTSerialize_zero(buf, buflen, PINGREQ); +} + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTDeserializePublish.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTDeserializePublish.c new file mode 100644 index 00000000..9713db3f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTDeserializePublish.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "MQTTPacket.h" +#include + +#define min(a, b) ((a < b) ? 1 : 0) + +/** + * Deserializes the supplied (wire) buffer into publish data + * @param dup returned integer - the MQTT dup flag + * @param qos returned integer - the MQTT QoS value + * @param retained returned integer - the MQTT retained flag + * @param packetid returned integer - the MQTT packet identifier + * @param topicName returned MQTTString - the MQTT topic in the publish + * @param payload returned byte buffer - the MQTT publish payload + * @param payloadlen returned integer - the length of the MQTT payload + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @param buflen the length in bytes of the data in the supplied buffer + * @return error code. 1 is success + */ +int MQTTDeserialize_publish(unsigned char *dup, int *qos, unsigned char *retained, unsigned short *packetid, + MQTTString *topicName, + unsigned char **payload, int *payloadlen, unsigned char *buf, int buflen) +{ + MQTTHeader header = {0}; + unsigned char *curdata = buf; + unsigned char *enddata = NULL; + int rc = 0; + int mylen = 0; + + header.byte = readChar(&curdata); + if (MQTT_HEADER_GET_TYPE(header.byte) != PUBLISH) { + goto exit; + } + *dup = MQTT_HEADER_GET_DUP(header.byte); + *qos = MQTT_HEADER_GET_QOS(header.byte); + *retained = MQTT_HEADER_GET_RETAIN(header.byte); + + curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */ + enddata = curdata + mylen; + + if (!readMQTTLenString(topicName, &curdata, enddata) || + enddata - curdata < 0) { /* do we have enough data to read the protocol version byte? */ + goto exit; + } + + if (*qos > 0) { + *packetid = readInt(&curdata); + } + + *payloadlen = enddata - curdata; + *payload = curdata; + rc = 1; +exit: + return rc; +} + + + +/** + * Deserializes the supplied (wire) buffer into an ack + * @param packettype returned integer - the MQTT packet type + * @param dup returned integer - the MQTT dup flag + * @param packetid returned integer - the MQTT packet identifier + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @param buflen the length in bytes of the data in the supplied buffer + * @return error code. 1 is success, 0 is failure + */ +int MQTTDeserialize_ack(unsigned char *packettype, unsigned char *dup, unsigned short *packetid, unsigned char *buf, + int buflen) +{ + MQTTHeader header = {0}; + unsigned char *curdata = buf; + unsigned char *enddata = NULL; + int rc = 0; + int mylen; + + header.byte = readChar(&curdata); + *dup = MQTT_HEADER_GET_DUP(header.byte); + *packettype = MQTT_HEADER_GET_TYPE(header.byte); + + curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */ + enddata = curdata + mylen; + + if (enddata - curdata < 2) { + goto exit; + } + *packetid = readInt(&curdata); + + rc = 1; +exit: + return rc; +} + + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTPacket.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTPacket.c new file mode 100644 index 00000000..931a9305 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTPacket.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "MQTTPacket.h" + +#include + +/** + * Encodes the message length according to the MQTT algorithm + * @param buf the buffer into which the encoded data is written + * @param length the length to be encoded + * @return the number of bytes written to buffer + */ +int MQTTPacket_encode(unsigned char *buf, int length) +{ + int rc = 0; + + do { + char d = length % 128; + length /= 128; + /* if there are more digits to encode, set the top bit of this digit */ + if (length > 0) { + d |= 0x80; + } + buf[rc++] = d; + } while (length > 0); + return rc; +} + + +/** + * Decodes the message length according to the MQTT algorithm + * @param getcharfn pointer to function to read the next character from the data source + * @param value the decoded length returned + * @return the number of bytes read from the socket + */ +int MQTTPacket_decode(int (*getcharfn)(unsigned char *, int), int *value) +{ + unsigned char c; + int multiplier = 1; + int len = 0; +#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4 + + *value = 0; + do { + int rc = MQTTPACKET_READ_ERROR; + + if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) { + rc = MQTTPACKET_READ_ERROR; /* bad data */ + goto exit; + } + rc = (*getcharfn)(&c, 1); + if (rc != 1) { + goto exit; + } + *value += (c & 127) * multiplier; + multiplier *= 128; + } while ((c & 128) != 0); +exit: + return len; +} + + +int MQTTPacket_len(int rem_len) +{ + rem_len += 1; /* header byte */ + + /* now remaining_length field */ + if (rem_len < 128) { + rem_len += 1; + } else if (rem_len < 16384) { + rem_len += 2; + } else if (rem_len < 2097151) { + rem_len += 3; + } else { + rem_len += 4; + } + return rem_len; +} + + +static unsigned char *bufptr; + +int bufchar(unsigned char *c, int count) +{ + int i; + + for (i = 0; i < count; ++i) { + *c = *bufptr++; + } + return count; +} + + +int MQTTPacket_decodeBuf(unsigned char *buf, int *value) +{ + bufptr = buf; + return MQTTPacket_decode(bufchar, value); +} + + +/** + * Calculates an integer from two bytes read from the input buffer + * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned + * @return the integer value calculated + */ +int readInt(unsigned char **pptr) +{ + unsigned char *ptr = *pptr; + int len = 256 * (*ptr) + (*(ptr + 1)); + *pptr += 2; + return len; +} + + +/** + * Reads one character from the input buffer. + * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned + * @return the character read + */ +char readChar(unsigned char **pptr) +{ + char c = **pptr; + (*pptr)++; + return c; +} + + +/** + * Writes one character to an output buffer. + * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned + * @param c the character to write + */ +void writeChar(unsigned char **pptr, char c) +{ + **pptr = c; + (*pptr)++; +} + + +/** + * Writes an integer as 2 bytes to an output buffer. + * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned + * @param anInt the integer to write + */ +void writeInt(unsigned char **pptr, int anInt) +{ + **pptr = (unsigned char)(anInt / 256); + (*pptr)++; + **pptr = (unsigned char)(anInt % 256); + (*pptr)++; +} + + +/** + * Writes a "UTF" string to an output buffer. Converts C string to length-delimited. + * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned + * @param string the C string to write + */ +void writeCString(unsigned char **pptr, const char *string) +{ + int len = strlen(string); + writeInt(pptr, len); + memcpy(*pptr, string, len); + *pptr += len; +} + + +int getLenStringLen(char *ptr) +{ + int len = 256 * ((unsigned char)(*ptr)) + (unsigned char)(*(ptr + 1)); + return len; +} + + +void writeMQTTString(unsigned char **pptr, MQTTString mqttstring) +{ + if (mqttstring.lenstring.len > 0) { + writeInt(pptr, mqttstring.lenstring.len); + memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len); + *pptr += mqttstring.lenstring.len; + } else if (mqttstring.cstring) { + writeCString(pptr, mqttstring.cstring); + } else { + writeInt(pptr, 0); + } +} + + +/** + * @param mqttstring the MQTTString structure into which the data is to be read + * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned + * @param enddata pointer to the end of the data: do not read beyond + * @return 1 if successful, 0 if not + */ +int readMQTTLenString(MQTTString *mqttstring, unsigned char **pptr, unsigned char *enddata) +{ + int rc = 0; + + /* the first two bytes are the length of the string */ + if (enddata - (*pptr) > 1) { /* enough length to read the integer? */ + mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */ + if (&(*pptr)[mqttstring->lenstring.len] <= enddata) { + mqttstring->lenstring.data = (char *)*pptr; + *pptr += mqttstring->lenstring.len; + rc = 1; + } + } + mqttstring->cstring = NULL; + return rc; +} + + +/** + * Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string + * @param mqttstring the string to return the length of + * @return the length of the string + */ +int MQTTstrlen(MQTTString mqttstring) +{ + int rc = 0; + + if (mqttstring.cstring) { + rc = strlen(mqttstring.cstring); + } else { + rc = mqttstring.lenstring.len; + } + return rc; +} + + +/** + * Compares an MQTTString to a C string + * @param a the MQTTString to compare + * @param bptr the C string to compare + * @return int - equal or not + */ +int MQTTPacket_equals(MQTTString *a, char *bptr) +{ + int alen = 0, + blen = 0; + char *aptr; +#if !(WITH_MQTT_ZIP_TOPIC) + if (a->cstring) { + aptr = a->cstring; + alen = strlen(a->cstring); + } else { + aptr = a->lenstring.data; + alen = a->lenstring.len; + } + blen = strlen(bptr); +#else + aptr = a->lenstring.data; + alen = a->lenstring.len; + blen = alen; +#endif + return (alen == blen) && (memcmp(aptr, bptr, alen) == 0); + +} + + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTPacket.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTPacket.h new file mode 100644 index 00000000..e93dfc50 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTPacket.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef MQTTPACKET_H_ +#define MQTTPACKET_H_ + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#if defined(WIN32_DLL) || defined(WIN64_DLL) +#define DLLImport __declspec(dllimport) +#define DLLExport __declspec(dllexport) +#elif defined(LINUX_SO) +#define DLLImport extern +#define DLLExport __attribute__ ((visibility ("default"))) +#else +#define DLLImport +#define DLLExport +#endif + +enum errors { + MQTTPACKET_BUFFER_TOO_SHORT = -2, + MQTTPACKET_READ_ERROR = -1, + MQTTPACKET_READ_COMPLETE +}; + + +/* CPT, control packet type */ +enum msgTypes { + MQTT_CPT_RESERVED = 0, CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, + PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, + PINGREQ, PINGRESP, DISCONNECT +}; + +#define MQTT_HEADER_BIT_MASK_TYPE (0xF0) +#define MQTT_HEADER_BIT_MASK_DUP (0x08) +#define MQTT_HEADER_BIT_MASK_QOS (0x06) +#define MQTT_HEADER_BIT_MASK_RETAIN (0x01) + +#define MQTT_HEADER_GET_TYPE(head) ((head & 0xF0) >> 4) +#define MQTT_HEADER_GET_DUP(head) ((head & 0x08) >> 3) +#define MQTT_HEADER_GET_QOS(head) ((head & 0x06) >> 1) +#define MQTT_HEADER_GET_RETAIN(head) (head & 0x01) + +#define MQTT_HEADER_SET_TYPE(head, type) do {head |= ((type << 4) & 0xF0); } while (0) +#define MQTT_HEADER_SET_DUP(head, dup) do {head |= ((dup << 3) & 0x08); } while (0) +#define MQTT_HEADER_SET_QOS(head, qos) do {head |= ((qos << 1) & 0x06); } while (0) +#define MQTT_HEADER_SET_RETAIN(head, retain) do {head |= (retain & 0x01); } while (0) + +/** + * Bitfields for the MQTT header byte. + */ +typedef union +{ + unsigned char byte; /**< the whole byte */ +} MQTTHeader; + +typedef struct { + int len; + char *data; +} MQTTLenString; + +typedef struct { + char *cstring; + MQTTLenString lenstring; +} MQTTString; + +#define MQTTString_initializer {NULL, {0, NULL}} + +int MQTTstrlen(MQTTString mqttstring); + +#include "MQTTConnect.h" +#include "MQTTPublish.h" +#include "MQTTSubscribe.h" +#include "MQTTUnsubscribe.h" + +int MQTTSerialize_ack(unsigned char *buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid); +int MQTTDeserialize_ack(unsigned char *packettype, unsigned char *dup, unsigned short *packetid, unsigned char *buf, + int buflen); + +int MQTTPacket_len(int rem_len); +int MQTTPacket_equals(MQTTString *a, char *b); + +int MQTTPacket_encode(unsigned char *buf, int length); +int MQTTPacket_decode(int (*getcharfn)(unsigned char *, int), int *value); +int MQTTPacket_decodeBuf(unsigned char *buf, int *value); + +int readInt(unsigned char **pptr); +char readChar(unsigned char **pptr); +void writeChar(unsigned char **pptr, char c); +void writeInt(unsigned char **pptr, int anInt); +int readMQTTLenString(MQTTString *mqttstring, unsigned char **pptr, unsigned char *enddata); +void writeCString(unsigned char **pptr, const char *string); +void writeMQTTString(unsigned char **pptr, MQTTString mqttstring); + +typedef struct { + int (*getfn)(void *, unsigned char *, + int); /* must return -1 for error, 0 for call again, or the number of bytes read */ + void *sck; /* pointer to whatever the system may use to identify the transport */ + int multiplier; + int rem_len; + int len; + char state; +} MQTTTransport; + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +} +#endif + + +#endif /* MQTTPACKET_H_ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTPublish.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTPublish.h new file mode 100644 index 00000000..4cb4e6a6 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTPublish.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef MQTTPUBLISH_H_ +#define MQTTPUBLISH_H_ + +#if !defined(DLLImport) + #define DLLImport +#endif +#if !defined(DLLExport) + #define DLLExport +#endif + +DLLExport int MQTTSerialize_publish(unsigned char *buf, int buflen, unsigned char dup, int qos, unsigned char retained, + unsigned short packetid, + MQTTString topicName, unsigned char *payload, int payloadlen); + +DLLExport int MQTTDeserialize_publish(unsigned char *dup, int *qos, unsigned char *retained, unsigned short *packetid, + MQTTString *topicName, + unsigned char **payload, int *payloadlen, unsigned char *buf, int len); + +/* DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid); */ +DLLExport int MQTTSerialize_pubrel(unsigned char *buf, int buflen, unsigned char dup, unsigned short packetid); +DLLExport int MQTTSerialize_pubcomp(unsigned char *buf, int buflen, unsigned short packetid); + +#endif /* MQTTPUBLISH_H_ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTSerializePublish.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTSerializePublish.c new file mode 100644 index 00000000..4c068b70 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTSerializePublish.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "MQTTPacket.h" + +#include + + +/** + * Determines the length of the MQTT publish packet that would be produced using the supplied parameters + * @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0) + * @param topicName the topic name to be used in the publish + * @param payloadlen the length of the payload to be sent + * @return the length of buffer needed to contain the serialized version of the packet + */ +int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen) +{ + int len = 0; + + len += 2 + MQTTstrlen(topicName) + payloadlen; + if (qos > 0) { + len += 2; /* packetid */ + } + return len; +} + + +/** + * Serializes the supplied publish data into the supplied buffer, ready for sending + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param dup integer - the MQTT dup flag + * @param qos integer - the MQTT QoS value + * @param retained integer - the MQTT retained flag + * @param packetid integer - the MQTT packet identifier + * @param topicName MQTTString - the MQTT topic in the publish + * @param payload byte buffer - the MQTT publish payload + * @param payloadlen integer - the length of the MQTT payload + * @return the length of the serialized data. <= 0 indicates error + */ +int MQTTSerialize_publish(unsigned char *buf, int buflen, unsigned char dup, int qos, unsigned char retained, + unsigned short packetid, + MQTTString topicName, unsigned char *payload, int payloadlen) +{ + unsigned char *ptr = buf; + MQTTHeader header = {0}; + int rem_len = 0; + int rc = 0; + + if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen) { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + + MQTT_HEADER_SET_TYPE(header.byte, PUBLISH); + MQTT_HEADER_SET_DUP(header.byte, dup); + MQTT_HEADER_SET_QOS(header.byte, qos); + MQTT_HEADER_SET_RETAIN(header.byte, retained); + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */; + + writeMQTTString(&ptr, topicName); + + if (qos > 0) { + writeInt(&ptr, packetid); + } + + memcpy(ptr, payload, payloadlen); + ptr += payloadlen; + + rc = ptr - buf; + +exit: + return rc; +} + + + +/** + * Serializes the ack packet into the supplied buffer. + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param type the MQTT packet type + * @param dup the MQTT dup flag + * @param packetid the MQTT packet identifier + * @return serialized length, or error if 0 + */ +int MQTTSerialize_ack(unsigned char *buf, int buflen, unsigned char packettype, unsigned char dup, + unsigned short packetid) +{ + MQTTHeader header = {0}; + int rc = 0; + unsigned char *ptr = buf; + + if (buflen < 4) { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + MQTT_HEADER_SET_TYPE(header.byte, packettype); + MQTT_HEADER_SET_DUP(header.byte, dup); + MQTT_HEADER_SET_QOS(header.byte, ((packettype == PUBREL) ? 1 : 0)); + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */ + writeInt(&ptr, packetid); + rc = ptr - buf; +exit: + return rc; +} + + +/** + * Serializes a puback packet into the supplied buffer. + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param packetid integer - the MQTT packet identifier + * @return serialized length, or error if 0 + */ +/* int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid) */ +/* { */ +/* return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid); */ +/* } */ + +#if WITH_MQTT_QOS2_PACKET +/** + * Serializes a pubrel packet into the supplied buffer. + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param dup integer - the MQTT dup flag + * @param packetid integer - the MQTT packet identifier + * @return serialized length, or error if 0 + */ +int MQTTSerialize_pubrel(unsigned char *buf, int buflen, unsigned char dup, unsigned short packetid) +{ + return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid); +} + + +/** + * Serializes a pubrel packet into the supplied buffer. + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param packetid integer - the MQTT packet identifier + * @return serialized length, or error if 0 + */ +int MQTTSerialize_pubcomp(unsigned char *buf, int buflen, unsigned short packetid) +{ + return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid); +} +#endif /* #if WITH_MQTT_QOS2_PACKET */ + + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTSubscribe.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTSubscribe.h new file mode 100644 index 00000000..ecd04d6a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTSubscribe.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef MQTTSUBSCRIBE_H_ +#define MQTTSUBSCRIBE_H_ + +#if !defined(DLLImport) + #define DLLImport +#endif +#if !defined(DLLExport) + #define DLLExport +#endif + +DLLExport int MQTTSerialize_subscribe(unsigned char *buf, int buflen, unsigned char dup, unsigned short packetid, + int count, MQTTString topicFilters[], int requestedQoSs[]); + +DLLExport int MQTTDeserialize_subscribe(unsigned char *dup, unsigned short *packetid, + int maxcount, int *count, MQTTString topicFilters[], int requestedQoSs[], unsigned char *buf, int len); + +DLLExport int MQTTSerialize_suback(unsigned char *buf, int buflen, unsigned short packetid, int count, + int *grantedQoSs); + +DLLExport int MQTTDeserialize_suback(unsigned short *packetid, int maxcount, int *count, int grantedQoSs[], + unsigned char *buf, int len); + + +#endif /* MQTTSUBSCRIBE_H_ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTSubscribeClient.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTSubscribeClient.c new file mode 100644 index 00000000..4a26ca29 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTSubscribeClient.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "MQTTPacket.h" + +#include + +/** + * Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters + * @param count the number of topic filter strings in topicFilters + * @param topicFilters the array of topic filter strings to be used in the publish + * @return the length of buffer needed to contain the serialized version of the packet + */ +int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[]) +{ + int i; + int len = 2; /* packetid */ + + for (i = 0; i < count; ++i) { + len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */ + } + return len; +} + + +/** + * Serializes the supplied subscribe data into the supplied buffer, ready for sending + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied bufferr + * @param dup integer - the MQTT dup flag + * @param packetid integer - the MQTT packet identifier + * @param count - number of members in the topicFilters and reqQos arrays + * @param topicFilters - array of topic filter names + * @param requestedQoSs - array of requested QoS + * @return the length of the serialized data. <= 0 indicates error + */ +int MQTTSerialize_subscribe(unsigned char *buf, int buflen, unsigned char dup, unsigned short packetid, int count, + MQTTString topicFilters[], int requestedQoSs[]) +{ + unsigned char *ptr = buf; + MQTTHeader header = {0}; + int rem_len = 0; + int rc = 0; + int i = 0; + + if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen) { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + + header.byte = 0; + MQTT_HEADER_SET_TYPE(header.byte, SUBSCRIBE); + MQTT_HEADER_SET_DUP(header.byte, dup); + MQTT_HEADER_SET_QOS(header.byte, 1); + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */; + + writeInt(&ptr, packetid); + + for (i = 0; i < count; ++i) { + writeMQTTString(&ptr, topicFilters[i]); + writeChar(&ptr, requestedQoSs[i]); + } + + rc = ptr - buf; +exit: + return rc; +} + + + +/** + * Deserializes the supplied (wire) buffer into suback data + * @param packetid returned integer - the MQTT packet identifier + * @param maxcount - the maximum number of members allowed in the grantedQoSs array + * @param count returned integer - number of members in the grantedQoSs array + * @param grantedQoSs returned array of integers - the granted qualities of service + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @param buflen the length in bytes of the data in the supplied buffer + * @return error code. 1 is success, 0 is failure + */ +int MQTTDeserialize_suback(unsigned short *packetid, int maxcount, int *count, int grantedQoSs[], unsigned char *buf, + int buflen) +{ + MQTTHeader header = {0}; + unsigned char *curdata = buf; + unsigned char *enddata = NULL; + int rc = 0; + int mylen; + + header.byte = readChar(&curdata); + if (MQTT_HEADER_GET_TYPE(header.byte) != SUBACK) { + goto exit; + } + + curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */ + enddata = curdata + mylen; + if (enddata - curdata < 2) { + goto exit; + } + + *packetid = readInt(&curdata); + + *count = 0; + while (curdata < enddata) { + if (*count >= maxcount) { + rc = -1; + goto exit; + } + grantedQoSs[(*count)++] = readChar(&curdata); + } + + rc = 1; +exit: + return rc; +} + + + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTUnsubscribe.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTUnsubscribe.h new file mode 100644 index 00000000..ab449115 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTUnsubscribe.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef MQTTUNSUBSCRIBE_H_ +#define MQTTUNSUBSCRIBE_H_ + +#if !defined(DLLImport) + #define DLLImport +#endif +#if !defined(DLLExport) + #define DLLExport +#endif + +DLLExport int MQTTSerialize_unsubscribe(unsigned char *buf, int buflen, unsigned char dup, unsigned short packetid, + int count, MQTTString topicFilters[]); + +DLLExport int MQTTDeserialize_unsubscribe(unsigned char *dup, unsigned short *packetid, int max_count, int *count, + MQTTString topicFilters[], + unsigned char *buf, int len); + +DLLExport int MQTTSerialize_unsuback(unsigned char *buf, int buflen, unsigned short packetid); + +DLLExport int MQTTDeserialize_unsuback(unsigned short *packetid, unsigned char *buf, int len); + +#endif /* MQTTUNSUBSCRIBE_H_ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTUnsubscribeClient.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTUnsubscribeClient.c new file mode 100644 index 00000000..2463a4d8 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/MQTTUnsubscribeClient.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "MQTTPacket.h" + +#include + +/** + * Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters + * @param count the number of topic filter strings in topicFilters + * @param topicFilters the array of topic filter strings to be used in the publish + * @return the length of buffer needed to contain the serialized version of the packet + */ +int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[]) +{ + int i; + int len = 2; /* packetid */ + + for (i = 0; i < count; ++i) { + len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/ + } + return len; +} + + +/** + * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @param buflen the length in bytes of the data in the supplied buffer + * @param dup integer - the MQTT dup flag + * @param packetid integer - the MQTT packet identifier + * @param count - number of members in the topicFilters array + * @param topicFilters - array of topic filter names + * @return the length of the serialized data. <= 0 indicates error + */ +int MQTTSerialize_unsubscribe(unsigned char *buf, int buflen, unsigned char dup, unsigned short packetid, + int count, MQTTString topicFilters[]) +{ + unsigned char *ptr = buf; + MQTTHeader header = {0}; + int rem_len = 0; + int rc = -1; + int i = 0; + + if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen) { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + + header.byte = 0; + MQTT_HEADER_SET_TYPE(header.byte, UNSUBSCRIBE); + MQTT_HEADER_SET_DUP(header.byte, dup); + MQTT_HEADER_SET_QOS(header.byte, 1); + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */; + + writeInt(&ptr, packetid); + + for (i = 0; i < count; ++i) { + writeMQTTString(&ptr, topicFilters[i]); + } + + rc = ptr - buf; +exit: + return rc; +} + + +/** + * Deserializes the supplied (wire) buffer into unsuback data + * @param packetid returned integer - the MQTT packet identifier + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @param buflen the length in bytes of the data in the supplied buffer + * @return error code. 1 is success, 0 is failure + */ +int MQTTDeserialize_unsuback(unsigned short *packetid, unsigned char *buf, int buflen) +{ + unsigned char type = 0; + unsigned char dup = 0; + int rc = 0; + + rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen); + if (type == UNSUBACK) { + rc = 1; + } + return rc; +} + + + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/iotx_mqtt_client.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/iotx_mqtt_client.c new file mode 100644 index 00000000..b36f35a6 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/iotx_mqtt_client.c @@ -0,0 +1,3174 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "mqtt_internal.h" + +#ifdef LOG_REPORT_TO_CLOUD + #include "iotx_log_report.h" +#endif +static int _in_yield_cb; + +#ifndef PLATFORM_HAS_DYNMEM +iotx_mc_client_t g_iotx_mc_client[IOTX_MC_CLIENT_MAX_COUNT] = {0}; +#endif + +static void iotx_mc_release(iotx_mc_client_t *pclient) +{ +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(pclient); +#else + memset(pclient, 0, sizeof(iotx_mc_client_t)); +#endif +} + +#if !WITH_MQTT_ONLY_QOS0 +static void iotx_mc_pub_wait_list_init(iotx_mc_client_t *pClient) +{ +#ifdef PLATFORM_HAS_DYNMEM + INIT_LIST_HEAD(&pClient->list_pub_wait_ack); +#else + memset(pClient->list_pub_wait_ack, 0, sizeof(iotx_mc_pub_info_t) * IOTX_MC_PUBWAIT_LIST_MAX_LEN); +#endif +} + +static void iotx_mc_pub_wait_list_deinit(iotx_mc_client_t *pClient) +{ +#ifdef PLATFORM_HAS_DYNMEM + iotx_mc_pub_info_t *node = NULL, *next_node = NULL; + list_for_each_entry_safe(node, next_node, &pClient->list_pub_wait_ack, linked_list, iotx_mc_pub_info_t) { + list_del(&node->linked_list); + mqtt_free(node); + } +#else + memset(pClient->list_pub_wait_ack, 0, sizeof(iotx_mc_pub_info_t) * IOTX_MC_PUBWAIT_LIST_MAX_LEN); +#endif +} +#endif +/* set MQTT connection parameter */ +static int iotx_mc_set_connect_params(iotx_mc_client_t *pClient, MQTTPacket_connectData *pConnectParams) +{ + if (NULL == pClient || NULL == pConnectParams) { + return NULL_VALUE_ERROR; + } + + memcpy(pClient->connect_data.struct_id, pConnectParams->struct_id, 4); + pClient->connect_data.struct_version = pConnectParams->struct_version; + pClient->connect_data.MQTTVersion = pConnectParams->MQTTVersion; + pClient->connect_data.clientID = pConnectParams->clientID; + pClient->connect_data.cleansession = pConnectParams->cleansession; + pClient->connect_data.willFlag = pConnectParams->willFlag; + pClient->connect_data.username = pConnectParams->username; + pClient->connect_data.password = pConnectParams->password; + memcpy(pClient->connect_data.will.struct_id, pConnectParams->will.struct_id, 4); + pClient->connect_data.will.struct_version = pConnectParams->will.struct_version; + pClient->connect_data.will.topicName = pConnectParams->will.topicName; + pClient->connect_data.will.message = pConnectParams->will.message; + pClient->connect_data.will.qos = pConnectParams->will.qos; + pClient->connect_data.will.retained = pConnectParams->will.retained; + + if (pConnectParams->keepAliveInterval < CONFIG_MQTT_KEEPALIVE_INTERVAL_MIN) { + mqtt_warning("Input heartbeat interval(%d ms) < Allowed minimum(%d ms)", + (pConnectParams->keepAliveInterval * 1000), + (CONFIG_MQTT_KEEPALIVE_INTERVAL_MIN * 1000) + ); + mqtt_warning("Reset heartbeat interval => %d Millisecond", + (CONFIG_MQTT_KEEPALIVE_INTERVAL * 1000) + ); + pClient->connect_data.keepAliveInterval = CONFIG_MQTT_KEEPALIVE_INTERVAL; + } else if (pConnectParams->keepAliveInterval > CONFIG_MQTT_KEEPALIVE_INTERVAL_MAX) { + mqtt_warning("Input heartbeat interval(%d ms) > Allowed maximum(%d ms)", + (pConnectParams->keepAliveInterval * 1000), + (CONFIG_MQTT_KEEPALIVE_INTERVAL_MAX * 1000) + ); + mqtt_warning("Reset heartbeat interval => %d Millisecond", + (CONFIG_MQTT_KEEPALIVE_INTERVAL * 1000) + ); + pClient->connect_data.keepAliveInterval = CONFIG_MQTT_KEEPALIVE_INTERVAL; + } else { + pClient->connect_data.keepAliveInterval = pConnectParams->keepAliveInterval; + } + + return SUCCESS_RETURN; +} + +/* set state of MQTT client */ +static void iotx_mc_set_client_state(iotx_mc_client_t *pClient, iotx_mc_state_t newState) +{ + HAL_MutexLock(pClient->lock_generic); + pClient->client_state = newState; + HAL_MutexUnlock(pClient->lock_generic); +} + +static iotx_mc_state_t iotx_mc_get_client_state(iotx_mc_client_t *pClient) +{ + iotx_mc_state_t state; + HAL_MutexLock(pClient->lock_generic); + state = pClient->client_state; + HAL_MutexUnlock(pClient->lock_generic); + + return state; +} + +/* Initialize MQTT client */ +static int iotx_mc_init(iotx_mc_client_t *pClient, iotx_mqtt_param_t *pInitParams) +{ + int rc = FAIL_RETURN; + iotx_mc_state_t mc_state = IOTX_MC_STATE_INVALID; + MQTTPacket_connectData connectdata = MQTTPacket_connectData_initializer; + + if (pClient == NULL || pInitParams == NULL || pInitParams->write_buf_size == 0 || pInitParams->read_buf_size == 0) { + return NULL_VALUE_ERROR; + } + + pClient->lock_generic = HAL_MutexCreate(); + if (!pClient->lock_generic) { + return FAIL_RETURN; + } + + pClient->lock_list_pub = HAL_MutexCreate(); + if (!pClient->lock_list_pub) { + goto RETURN; + } + + pClient->lock_yield = HAL_MutexCreate(); + if (!pClient->lock_yield) { + goto RETURN; + } + + pClient->lock_write_buf = HAL_MutexCreate(); + if (!pClient->lock_write_buf) { + goto RETURN; + } + + pClient->lock_read_buf = HAL_MutexCreate(); + if (!pClient->lock_read_buf) { + goto RETURN; + } + + connectdata.MQTTVersion = IOTX_MC_MQTT_VERSION; + connectdata.keepAliveInterval = pInitParams->keepalive_interval_ms / 1000; + + + connectdata.clientID.cstring = (char *)pInitParams->client_id; + connectdata.username.cstring = (char *)pInitParams->username; + connectdata.password.cstring = (char *)pInitParams->password; + connectdata.cleansession = pInitParams->clean_session; + + if (pInitParams->request_timeout_ms < CONFIG_MQTT_REQ_TIMEOUT_MIN + || pInitParams->request_timeout_ms > CONFIG_MQTT_REQ_TIMEOUT_MAX) { + + pClient->request_timeout_ms = CONFIG_MQTT_REQUEST_TIMEOUT; + } else { + pClient->request_timeout_ms = pInitParams->request_timeout_ms; + } + +#ifdef PLATFORM_HAS_DYNMEM +#if !( WITH_MQTT_DYN_BUF) + pClient->buf_send = mqtt_malloc(pInitParams->write_buf_size); + if (pClient->buf_send == NULL) { + goto RETURN; + } + pClient->buf_size_send = pInitParams->write_buf_size; + + pClient->buf_read = mqtt_malloc(pInitParams->read_buf_size); + if (pClient->buf_read == NULL) { + goto RETURN; + } + pClient->buf_size_read = pInitParams->read_buf_size; +#else + pClient->buf_size_send_max = pInitParams->write_buf_size; + pClient->buf_size_read_max = pInitParams->read_buf_size; +#endif +#else + pClient->buf_size_send = IOTX_MC_TX_MAX_LEN; + pClient->buf_size_read = IOTX_MC_RX_MAX_LEN; +#endif + + pClient->keepalive_probes = 0; + + pClient->handle_event.h_fp = pInitParams->handle_event.h_fp; + pClient->handle_event.pcontext = pInitParams->handle_event.pcontext; + + /* Initialize reconnect parameter */ + pClient->reconnect_param.reconnect_time_interval_ms = IOTX_MC_RECONNECT_INTERVAL_MIN_MS; +#if !WITH_MQTT_ONLY_QOS0 + iotx_mc_pub_wait_list_init(pClient); +#endif + +#ifdef PLATFORM_HAS_DYNMEM + INIT_LIST_HEAD(&pClient->list_sub_handle); + INIT_LIST_HEAD(&pClient->list_sub_sync_ack); +#endif + /* Initialize MQTT connect parameter */ + rc = iotx_mc_set_connect_params(pClient, &connectdata); + if (SUCCESS_RETURN != rc) { + mc_state = IOTX_MC_STATE_INVALID; + goto RETURN; + } + + iotx_time_init(&pClient->next_ping_time); + iotx_time_init(&pClient->reconnect_param.reconnect_next_time); + + memset(&pClient->ipstack, 0, sizeof(utils_network_t)); + +#ifdef SUPPORT_TLS + { + extern const char *iotx_ca_crt; + pInitParams->pub_key = iotx_ca_crt; + } +#endif + + rc = iotx_net_init(&pClient->ipstack, pInitParams->host, pInitParams->port, pInitParams->pub_key); + + if (SUCCESS_RETURN != rc) { + mc_state = IOTX_MC_STATE_INVALID; + goto RETURN; + } + + mc_state = IOTX_MC_STATE_INITIALIZED; + rc = SUCCESS_RETURN; + mqtt_info("MQTT init success!"); + +RETURN : + iotx_mc_set_client_state(pClient, mc_state); + if (rc != SUCCESS_RETURN) { +#ifdef PLATFORM_HAS_DYNMEM + if (pClient->buf_send != NULL) { + mqtt_free(pClient->buf_send); + pClient->buf_send = NULL; + } + if (pClient->buf_read != NULL) { + mqtt_free(pClient->buf_read); + pClient->buf_read = NULL; + } +#endif + if (pClient->lock_list_pub) { + HAL_MutexDestroy(pClient->lock_list_pub); + pClient->lock_list_pub = NULL; + } + if (pClient->lock_write_buf) { + HAL_MutexDestroy(pClient->lock_write_buf); + pClient->lock_write_buf = NULL; + } + if (pClient->lock_read_buf) { + HAL_MutexDestroy(pClient->lock_read_buf); + pClient->lock_read_buf = NULL; + } + if (pClient->lock_yield) { + HAL_MutexDestroy(pClient->lock_yield); + pClient->lock_yield = NULL; + } + } + + return rc; +} + +#ifdef PLATFORM_HAS_DYNMEM + #if WITH_MQTT_DYN_BUF + extern int MQTTPacket_len(int rem_len); + extern int MQTTSerialize_connectLength(MQTTPacket_connectData *options); + #endif +#endif + +static int _get_connect_length(MQTTPacket_connectData *options) +{ +#ifdef PLATFORM_HAS_DYNMEM +#if WITH_MQTT_DYN_BUF + return MQTTPacket_len(MQTTSerialize_connectLength(options)); +#else + return 0; +#endif +#else + return 0; +#endif +} + +static int _reset_send_buffer(iotx_mc_client_t *c) +{ +#ifdef PLATFORM_HAS_DYNMEM +#if WITH_MQTT_DYN_BUF + if (c == NULL || c->buf_send == NULL) { + return FAIL_RETURN; + } + + mqtt_free(c->buf_send); + c->buf_send = NULL; + c->buf_size_send = 0; + return 0; +#else + return 0; +#endif +#else + return 0; +#endif +} + +static int _reset_recv_buffer(iotx_mc_client_t *c) +{ +#ifdef PLATFORM_HAS_DYNMEM +#if WITH_MQTT_DYN_BUF + if (c == NULL || c->buf_read == NULL) { + return FAIL_RETURN; + } + + mqtt_free(c->buf_read); + c->buf_read = NULL; + c->buf_size_read = 0; + return 0; +#else + return 0; +#endif +#else + return 0; +#endif +} + +static int _alloc_send_buffer(iotx_mc_client_t *c, int len) +{ +#ifdef PLATFORM_HAS_DYNMEM +#if WITH_MQTT_DYN_BUF + int tmp_len; + + if (c == NULL) { + return FAIL_RETURN; + } + + tmp_len = MQTT_DYNBUF_SEND_MARGIN + len; + if (tmp_len > c->buf_size_send_max) { + tmp_len = c->buf_size_send_max; + } + if (c->buf_send != NULL) { + mqtt_warning("c->buf_send is not null,free it first!"); + mqtt_free(c->buf_send); + } + c->buf_send = mqtt_malloc(tmp_len); + if (c->buf_send == NULL) { + return ERROR_MALLOC; + } + memset(c->buf_send, 0, tmp_len); + c->buf_size_send = tmp_len; + return SUCCESS_RETURN; +#else + return 0; +#endif +#else + return 0; +#endif +} + +static int _alloc_recv_buffer(iotx_mc_client_t *c, int len) +{ +#ifdef PLATFORM_HAS_DYNMEM +#if WITH_MQTT_DYN_BUF + int tmp_len; + + if (c == NULL) { + return FAIL_RETURN; + } + + tmp_len = MQTT_DYNBUF_RECV_MARGIN + len; + if (tmp_len > c->buf_size_read_max) { + tmp_len = c->buf_size_read_max; + } + if (c->buf_read != NULL) { /* do realloc */ + char *temp = mqtt_malloc(tmp_len); + if (temp == NULL) { + mqtt_err("realloc err"); + return ERROR_MALLOC; + } + memset(temp, 0, tmp_len); + memcpy(temp, c->buf_read, c->buf_size_read < tmp_len ? c->buf_size_read : tmp_len); + mqtt_free(c->buf_read); + c->buf_read = temp; + } else { + c->buf_read = mqtt_malloc(tmp_len); + if (c->buf_read == NULL) { + mqtt_err("calloc err"); + return ERROR_MALLOC; + } + memset(c->buf_read, 0, tmp_len); + } + c->buf_size_read = tmp_len; + return SUCCESS_RETURN; +#else + return 0; +#endif +#else + return 0; +#endif +} + +static int iotx_mc_send_packet(iotx_mc_client_t *c, char *buf, int length, iotx_time_t *time) +{ + int rc = FAIL_RETURN; + int sent = 0; + unsigned int left_t = 0; + + if (!c || !buf || !time) { + return rc; + } + + while (sent < length && !utils_time_is_expired(time)) { + left_t = iotx_time_left(time); + left_t = (left_t == 0) ? 1 : left_t; + rc = c->ipstack.write(&c->ipstack, &buf[sent], length - sent, left_t); + if (rc < 0) { /* there was an error writing the data */ + break; + } + sent += rc; + } + + if (sent == length) { + rc = SUCCESS_RETURN; + } else { + rc = MQTT_NETWORK_ERROR; + } + return rc; +} + +int MQTTConnect(iotx_mc_client_t *pClient) +{ + MQTTPacket_connectData *pConnectParams; + iotx_time_t connectTimer; + int len = 0; + + if (!pClient) { + return FAIL_RETURN; + } + + pConnectParams = &pClient->connect_data; + HAL_MutexLock(pClient->lock_write_buf); + + len = _get_connect_length(pConnectParams); + + if (_alloc_send_buffer(pClient, len) != SUCCESS_RETURN) { + HAL_MutexUnlock(pClient->lock_write_buf); + return FAIL_RETURN; + } + + if ((len = MQTTSerialize_connect((unsigned char *)pClient->buf_send, pClient->buf_size_send, pConnectParams)) <= 0) { + mqtt_err("Serialize connect packet failed, len = %d", len); + _reset_send_buffer(pClient); + HAL_MutexUnlock(pClient->lock_write_buf); + return MQTT_CONNECT_PACKET_ERROR; + } + + /* send the connect packet */ + iotx_time_init(&connectTimer); + utils_time_countdown_ms(&connectTimer, pClient->request_timeout_ms); + if ((iotx_mc_send_packet(pClient, pClient->buf_send, len, &connectTimer)) != SUCCESS_RETURN) { + mqtt_err("send connect packet failed"); + _reset_send_buffer(pClient); + HAL_MutexUnlock(pClient->lock_write_buf); + return MQTT_NETWORK_ERROR; + } + _reset_send_buffer(pClient); + HAL_MutexUnlock(pClient->lock_write_buf); + return SUCCESS_RETURN; +} + +static int iotx_mc_decode_packet(iotx_mc_client_t *c, int *value, int timeout) +{ + char i; + int multiplier = 1; + int len = 0; + const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4; + + if (!c || !value) { + return FAIL_RETURN; + } + + *value = 0; + do { + int rc = MQTTPACKET_READ_ERROR; + + if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) { + return MQTTPACKET_READ_ERROR; /* bad data */ + } + + rc = c->ipstack.read(&c->ipstack, &i, 1, timeout == 0 ? 1 : timeout); + if (rc == 0) { + return FAIL_RETURN; + } else if (rc != 1) { + return MQTT_NETWORK_ERROR; + } + + *value += (i & 127) * multiplier; + multiplier *= 128; + } while ((i & 128) != 0); + + return len; +} + +static int _handle_event(iotx_mqtt_event_handle_pt handle, iotx_mc_client_t *c, iotx_mqtt_event_msg_pt msg) +{ + if (handle == NULL || handle->h_fp == NULL) { + return FAIL_RETURN; + } + + _in_yield_cb = 1; + handle->h_fp(handle->pcontext, c, msg); + _in_yield_cb = 0; + return 0; +} + +static int iotx_mc_read_packet(iotx_mc_client_t *c, iotx_time_t *timer, unsigned int *packet_type) +{ + MQTTHeader header = {0}; + int len = 0; + int rem_len = 0; + int rc = 0; + unsigned int left_t = 0; + + if (!c || !timer || !packet_type) { + return FAIL_RETURN; + } + HAL_MutexLock(c->lock_read_buf); + rc = _alloc_recv_buffer(c, 0); + if (rc < 0) { + HAL_MutexUnlock(c->lock_read_buf); + return FAIL_RETURN; + } + /* 1. read the header byte. This has the packet type in it */ + left_t = iotx_time_left(timer); + left_t = (left_t == 0) ? 1 : left_t; + rc = c->ipstack.read(&c->ipstack, c->buf_read, 1, left_t); + if (0 == rc) { /* timeout */ + *packet_type = 0; + HAL_MutexUnlock(c->lock_read_buf); + return SUCCESS_RETURN; + } else if (1 != rc) { + mqtt_err("mqtt read error, rc=%d", rc); + HAL_MutexUnlock(c->lock_read_buf); + return MQTT_NETWORK_ERROR; + } + + len = 1; + + /* 2. read the remaining length. This is variable in itself */ + left_t = iotx_time_left(timer); + left_t = (left_t == 0) ? 1 : left_t; + if ((rc = iotx_mc_decode_packet(c, &rem_len, left_t)) < 0) { + mqtt_err("decodePacket error,rc = %d", rc); + HAL_MutexUnlock(c->lock_read_buf); + return rc; + } + + len += MQTTPacket_encode((unsigned char *)c->buf_read + 1, + rem_len); /* put the original remaining length back into the buffer */ + + rc = _alloc_recv_buffer(c, rem_len + len); + if (rc < 0) { + HAL_MutexUnlock(c->lock_read_buf); + return FAIL_RETURN; + } + + /* Check if the received data length exceeds mqtt read buffer length */ + if ((rem_len > 0) && ((rem_len + len) > c->buf_size_read)) { + int needReadLen; + int remainDataLen; +#ifdef PLATFORM_HAS_DYNMEM + char *remainDataBuf; +#else + char remainDataBuf[IOTX_MC_RX_MAX_LEN] = {0}; +#endif + mqtt_err("mqtt read buffer is too short, mqttReadBufLen : %u, remainDataLen : %d", c->buf_size_read, rem_len); + needReadLen = c->buf_size_read - len; + left_t = iotx_time_left(timer); + left_t = (left_t == 0) ? 1 : left_t; + rc = c->ipstack.read(&c->ipstack, c->buf_read + len, needReadLen, left_t); + if (rc < 0) { + mqtt_err("mqtt read error"); + HAL_MutexUnlock(c->lock_read_buf); + return MQTT_NETWORK_ERROR; + } else if (rc != needReadLen) { + mqtt_warning("mqtt read timeout"); + HAL_MutexUnlock(c->lock_read_buf); + return FAIL_RETURN; + } + + /* drop data whitch over the length of mqtt buffer */ + remainDataLen = rem_len - needReadLen; +#ifdef PLATFORM_HAS_DYNMEM + remainDataBuf = mqtt_malloc(remainDataLen + 1); + if (!remainDataBuf) { + mqtt_err("allocate remain buffer failed"); + HAL_MutexUnlock(c->lock_read_buf); + return FAIL_RETURN; + } +#else + if (remainDataLen >= IOTX_MC_RX_MAX_LEN) { + mqtt_err("IOTX_MC_RX_MAX_LEN too short, remainDataLen: %d, IOTX_MC_RX_MAX_LEN: %d", remainDataLen, IOTX_MC_RX_MAX_LEN); + HAL_MutexUnlock(c->lock_read_buf); + return FAIL_RETURN; + } +#endif + + left_t = iotx_time_left(timer); + left_t = (left_t == 0) ? 1 : left_t; + rc = c->ipstack.read(&c->ipstack, remainDataBuf, remainDataLen, left_t); + if (rc < 0) { + mqtt_err("mqtt read error"); +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(remainDataBuf); + remainDataBuf = NULL; +#endif + HAL_MutexUnlock(c->lock_read_buf); + return MQTT_NETWORK_ERROR; + } else if (rc != remainDataLen) { + mqtt_warning("mqtt read timeout"); +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(remainDataBuf); + remainDataBuf = NULL; +#endif + HAL_MutexUnlock(c->lock_read_buf); + return FAIL_RETURN; + } + +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(remainDataBuf); + remainDataBuf = NULL; +#endif + HAL_MutexUnlock(c->lock_read_buf); + if (NULL != c->handle_event.h_fp) { + iotx_mqtt_event_msg_t msg; + + msg.event_type = IOTX_MQTT_EVENT_BUFFER_OVERFLOW; + msg.msg = "mqtt read buffer is too short"; + _handle_event(&c->handle_event, c, &msg); + } + + return SUCCESS_RETURN; + + } + + /* 3. read the rest of the buffer using a callback to supply the rest of the data */ + left_t = iotx_time_left(timer); + left_t = (left_t == 0) ? 1 : left_t; + + rc = c->ipstack.read(&c->ipstack, c->buf_read + len, rem_len, left_t); + if (rem_len > 0) { + if (rc < 0) { + mqtt_err("mqtt read error"); + HAL_MutexUnlock(c->lock_read_buf); + return MQTT_NETWORK_ERROR; + } else if (rc != rem_len) { + mqtt_warning("mqtt read timeout"); + HAL_MutexUnlock(c->lock_read_buf); + return FAIL_RETURN; + } + } + + header.byte = c->buf_read[0]; + *packet_type = MQTT_HEADER_GET_TYPE(header.byte); + if ((len + rem_len) < c->buf_size_read) { + c->buf_read[len + rem_len] = '\0'; + } + HAL_MutexUnlock(c->lock_read_buf); + return SUCCESS_RETURN; +} + +static int iotx_mc_handle_recv_CONNACK(iotx_mc_client_t *c) +{ + int rc = SUCCESS_RETURN; + unsigned char connack_rc = 255; + char sessionPresent = 0; + + if (!c) { + return FAIL_RETURN; + } + + if (MQTTDeserialize_connack((unsigned char *)&sessionPresent, &connack_rc, (unsigned char *)c->buf_read, + c->buf_size_read) != 1) { + mqtt_err("connect ack is error"); + return MQTT_CONNECT_ACK_PACKET_ERROR; + } + + switch (connack_rc) { + case IOTX_MC_CONNECTION_ACCEPTED: + rc = SUCCESS_RETURN; + break; + case IOTX_MC_CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION: + rc = MQTT_CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR; + break; + case IOTX_MC_CONNECTION_REFUSED_IDENTIFIER_REJECTED: + rc = MQTT_CONNACK_IDENTIFIER_REJECTED_ERROR; + break; + case IOTX_MC_CONNECTION_REFUSED_SERVER_UNAVAILABLE: + rc = MQTT_CONNACK_SERVER_UNAVAILABLE_ERROR; + break; + case IOTX_MC_CONNECTION_REFUSED_BAD_USERDATA: + rc = MQTT_CONNACK_BAD_USERDATA_ERROR; + break; + case IOTX_MC_CONNECTION_REFUSED_NOT_AUTHORIZED: + rc = MQTT_CONNACK_NOT_AUTHORIZED_ERROR; + break; + default: + rc = MQTT_CONNACK_UNKNOWN_ERROR; + break; + } + + return rc; +} + +static int iotx_mc_wait_CONNACK(iotx_mc_client_t *c) +{ +#define WAIT_CONNACK_MAX (10) + unsigned char wait_connack = 0; + unsigned int packetType = 0; + int rc = 0; + iotx_time_t timer; + + if (!c) { + return FAIL_RETURN; + } + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, c->request_timeout_ms); + + do { + /* read the socket, see what work is due */ + + rc = iotx_mc_read_packet(c, &timer, &packetType); + if (rc != SUCCESS_RETURN) { + mqtt_err("readPacket error,result = %d", rc); + HAL_MutexLock(c->lock_read_buf); + _reset_recv_buffer(c); + HAL_MutexUnlock(c->lock_read_buf); + return rc; + } + + if (++wait_connack > WAIT_CONNACK_MAX) { + mqtt_err("wait connack timeout"); + HAL_MutexLock(c->lock_read_buf); + _reset_recv_buffer(c); + HAL_MutexUnlock(c->lock_read_buf); + return MQTT_NETWORK_ERROR; + } + } while (packetType != CONNACK); + HAL_MutexLock(c->lock_read_buf); + + rc = iotx_mc_handle_recv_CONNACK(c); + _reset_recv_buffer(c); + HAL_MutexUnlock(c->lock_read_buf); + + if (SUCCESS_RETURN != rc) { + mqtt_err("recvConnackProc error,result = %d", rc); + } + + return rc; +} + +static int _mqtt_connect(void *client) +{ +#define RETRY_TIME_LIMIT (8+1) +#define RETRY_INTV_PERIOD (2000) + int rc = FAIL_RETURN; + int try_count = 1; + iotx_mc_client_t *pClient = (iotx_mc_client_t *)client; + + if (NULL == pClient) { + return NULL_VALUE_ERROR; + } + + mqtt_info("connect params: MQTTVersion=%d, clientID=%s, keepAliveInterval=%d, username=%s", + pClient->connect_data.MQTTVersion, + pClient->connect_data.clientID.cstring, + pClient->connect_data.keepAliveInterval, + pClient->connect_data.username.cstring); + + /* Establish TCP or TLS connection */ + do { + rc = MQTTConnect(pClient); + + if (rc != SUCCESS_RETURN) { + pClient->ipstack.disconnect(&pClient->ipstack); + mqtt_err("send connect packet failed, rc = %d", rc); + return rc; + } + + rc = iotx_mc_wait_CONNACK(pClient); + + if (rc <= MQTT_CONNACK_NOT_AUTHORIZED_ERROR && rc >= MQTT_CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR) { + mqtt_err("received reject ACK from MQTT server! rc = %d", rc); + pClient->ipstack.disconnect(&pClient->ipstack); + return MQTT_CONNECT_ERROR; + } + + if (SUCCESS_RETURN != rc) { + mqtt_err("wait connect ACK timeout! rc = %d", rc); + mqtt_warning("tried [%d/%d] times CONN, waiting for %d ms...", try_count, RETRY_TIME_LIMIT - 1, RETRY_INTV_PERIOD); + + HAL_SleepMs(RETRY_INTV_PERIOD); + + pClient->ipstack.disconnect(&pClient->ipstack); + pClient->ipstack.connect(&pClient->ipstack); + continue; + } else { + break; + } + + } while (++try_count < RETRY_TIME_LIMIT); + + if (try_count == RETRY_TIME_LIMIT) { + return MQTT_CONNECT_ERROR; + } + + iotx_mc_set_client_state(pClient, IOTX_MC_STATE_CONNECTED); + + utils_time_countdown_ms(&pClient->next_ping_time, pClient->connect_data.keepAliveInterval * 1000); + + mqtt_info("mqtt connect success!"); + return SUCCESS_RETURN; +} + +#if !WITH_MQTT_ONLY_QOS0 +static int iotx_mc_push_pubInfo_to(iotx_mc_client_t *c, int len, unsigned short msgId, iotx_mc_pub_info_t **node) +{ +#ifdef PLATFORM_HAS_DYNMEM + int list_number; + iotx_mc_pub_info_t *repubInfo; +#else + int idx; +#endif + + if (!c || !node) { + mqtt_err("the param of c is error!"); + return FAIL_RETURN; + } + + if ((len < 0) || (len > c->buf_size_send)) { + mqtt_err("the param of len is error!"); +#ifndef PLATFORM_HAS_DYNMEM + if (len >= c->buf_size_send) { + mqtt_err("IOTX_MC_TX_MAX_LEN is too short, len: %d, IOTX_MC_TX_MAX_LEN: %d", len, IOTX_MC_TX_MAX_LEN); + } +#endif + return FAIL_RETURN; + } + +#ifdef PLATFORM_HAS_DYNMEM + list_number = list_entry_number(&c->list_pub_wait_ack); + + if (list_number >= IOTX_MC_REPUB_NUM_MAX) { + mqtt_err("more than %u elements in republish list. List overflow!", list_number); + return FAIL_RETURN; + } + + repubInfo = (iotx_mc_pub_info_t *)mqtt_malloc(sizeof(iotx_mc_pub_info_t) + len); + if (NULL == repubInfo) { + mqtt_err("run iotx_memory_malloc is error!"); + return FAIL_RETURN; + } + + repubInfo->node_state = IOTX_MC_NODE_STATE_NORMANL; + repubInfo->msg_id = msgId; + repubInfo->len = len; + iotx_time_start(&repubInfo->pub_start_time); + repubInfo->buf = (unsigned char *)repubInfo + sizeof(iotx_mc_pub_info_t); + + memcpy(repubInfo->buf, c->buf_send, len); + INIT_LIST_HEAD(&repubInfo->linked_list); + + list_add_tail(&repubInfo->linked_list, &c->list_pub_wait_ack); + + *node = repubInfo; + return SUCCESS_RETURN; +#else + for (idx = 0; idx < IOTX_MC_PUBWAIT_LIST_MAX_LEN; idx++) { + if (c->list_pub_wait_ack[idx].used == 0) { + c->list_pub_wait_ack[idx].node_state = IOTX_MC_NODE_STATE_NORMANL; + c->list_pub_wait_ack[idx].msg_id = msgId; + c->list_pub_wait_ack[idx].len = len; + iotx_time_start(&c->list_pub_wait_ack[idx].pub_start_time); + memcpy(c->list_pub_wait_ack[idx].buf, c->buf_send, len); + c->list_pub_wait_ack[idx].used = 1; + *node = &c->list_pub_wait_ack[idx]; + return SUCCESS_RETURN; + } + } + + mqtt_err("IOTX_MC_PUBWAIT_LIST_MAX_LEN is too short"); + + return FAIL_RETURN; +#endif +} + +static int iotx_mc_mask_pubInfo_from(iotx_mc_client_t *c, uint16_t msgId) +{ +#ifdef PLATFORM_HAS_DYNMEM + iotx_mc_pub_info_t *node = NULL; + + if (!c) { + return FAIL_RETURN; + } + + HAL_MutexLock(c->lock_list_pub); + list_for_each_entry(node, &c->list_pub_wait_ack, linked_list, iotx_mc_pub_info_t) { + if (node->msg_id == msgId) { + node->node_state = IOTX_MC_NODE_STATE_INVALID; /* mark as invalid node */ + } + } + HAL_MutexUnlock(c->lock_list_pub); +#else + int idx; + + for (idx = 0; idx < IOTX_MC_PUBWAIT_LIST_MAX_LEN; idx++) { + if (c->list_pub_wait_ack[idx].used && + c->list_pub_wait_ack[idx].msg_id == msgId) { + c->list_pub_wait_ack[idx].node_state = IOTX_MC_NODE_STATE_INVALID; /* mark as invalid node */ + } + } +#endif + return SUCCESS_RETURN; +} + +static int MQTTRePublish(iotx_mc_client_t *c, char *buf, int len) +{ + iotx_time_t timer; + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, c->request_timeout_ms); + + HAL_MutexLock(c->lock_write_buf); + + if (iotx_mc_send_packet(c, buf, len, &timer) != SUCCESS_RETURN) { + HAL_MutexUnlock(c->lock_write_buf); + return MQTT_NETWORK_ERROR; + } + + HAL_MutexUnlock(c->lock_write_buf); + return SUCCESS_RETURN; +} + +static int MQTTPubInfoProc(iotx_mc_client_t *pClient) +{ + int rc = 0; + iotx_mc_state_t state = IOTX_MC_STATE_INVALID; +#ifdef PLATFORM_HAS_DYNMEM + iotx_mc_pub_info_t *node = NULL, *next_node = NULL; +#else + int idx; +#endif + + if (!pClient) { + return FAIL_RETURN; + } + + HAL_MutexLock(pClient->lock_list_pub); +#ifdef PLATFORM_HAS_DYNMEM + list_for_each_entry_safe(node, next_node, &pClient->list_pub_wait_ack, linked_list, iotx_mc_pub_info_t) { + /* remove invalid node */ + if (IOTX_MC_NODE_STATE_INVALID == node->node_state) { + list_del(&node->linked_list); + mqtt_free(node); + continue; + } + + state = iotx_mc_get_client_state(pClient); + if (state != IOTX_MC_STATE_CONNECTED) { + continue; + } + + /* check the request if timeout or not */ + if (utils_time_spend(&node->pub_start_time) <= (pClient->request_timeout_ms * 2)) { + continue; + } + + /* If wait ACK timeout, republish */ + rc = MQTTRePublish(pClient, (char *)node->buf, node->len); + iotx_time_start(&node->pub_start_time); + + if (MQTT_NETWORK_ERROR == rc) { + iotx_mc_set_client_state(pClient, IOTX_MC_STATE_DISCONNECTED); + break; + } + } +#else + for (idx = 0; idx < IOTX_MC_PUBWAIT_LIST_MAX_LEN; idx++) { + if (pClient->list_pub_wait_ack[idx].used == 0) { + continue; + } + + if (IOTX_MC_NODE_STATE_INVALID == pClient->list_pub_wait_ack[idx].node_state) { + memset(&pClient->list_pub_wait_ack[idx], 0, sizeof(iotx_mc_pub_info_t)); + continue; + } + + state = iotx_mc_get_client_state(pClient); + if (state != IOTX_MC_STATE_CONNECTED) { + continue; + } + + /* check the request if timeout or not */ + if (utils_time_spend(&pClient->list_pub_wait_ack[idx].pub_start_time) <= (pClient->request_timeout_ms * 2)) { + continue; + } + + /* If wait ACK timeout, republish */ + rc = MQTTRePublish(pClient, (char *)pClient->list_pub_wait_ack[idx].buf, pClient->list_pub_wait_ack[idx].len); + iotx_time_start(&pClient->list_pub_wait_ack[idx].pub_start_time); + + if (MQTT_NETWORK_ERROR == rc) { + iotx_mc_set_client_state(pClient, IOTX_MC_STATE_DISCONNECTED); + break; + } + } +#endif + HAL_MutexUnlock(pClient->lock_list_pub); + + return SUCCESS_RETURN; +} + +/* handle PUBACK packet received from remote MQTT broker */ +static int iotx_mc_handle_recv_PUBACK(iotx_mc_client_t *c) +{ + unsigned short mypacketid; + unsigned char dup = 0; + unsigned char type = 0; + + if (!c) { + return FAIL_RETURN; + } + + if (MQTTDeserialize_ack(&type, &dup, &mypacketid, (unsigned char *)c->buf_read, c->buf_size_read) != 1) { + return MQTT_PUBLISH_ACK_PACKET_ERROR; + } + + (void)iotx_mc_mask_pubInfo_from(c, mypacketid); + + /* call callback function to notify that PUBLISH is successful */ + if (NULL != c->handle_event.h_fp) { + iotx_mqtt_event_msg_t msg; + msg.event_type = IOTX_MQTT_EVENT_PUBLISH_SUCCESS; + msg.msg = (void *)(uintptr_t)mypacketid; + _handle_event(&c->handle_event, c, &msg); + } + + return SUCCESS_RETURN; +} +#endif + +static void _iotx_mqtt_event_handle_sub(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg) +{ + iotx_mc_client_t *client; + uintptr_t packet_id; +#ifdef PLATFORM_HAS_DYNMEM + mqtt_sub_sync_node_t *node = NULL; + mqtt_sub_sync_node_t *next = NULL; +#else + int idx; +#endif + + if (pclient == NULL || msg == NULL) { + return; + } + + client = (iotx_mc_client_t *)pclient; + packet_id = (uintptr_t) msg->msg; + + mqtt_debug("packet_id = %lu, event_type=%d", packet_id, msg->event_type); + + HAL_MutexLock(client->lock_generic); +#ifdef PLATFORM_HAS_DYNMEM + list_for_each_entry_safe(node, next, &client->list_sub_sync_ack, linked_list, mqtt_sub_sync_node_t) { + if (node->packet_id == packet_id) { + node->ack_type = msg->event_type; + } + } +#else + for (idx = 0; idx < IOTX_MC_SUBSYNC_LIST_MAX_LEN; idx++) { + if (client->list_sub_sync_ack[idx].used && + client->list_sub_sync_ack[idx].packet_id == packet_id) { + client->list_sub_sync_ack[idx].ack_type = msg->event_type; + } + } +#endif + HAL_MutexUnlock(client->lock_generic); +} + +static int iotx_mc_handle_recv_SUBACK(iotx_mc_client_t *c) +{ + unsigned short mypacketid; + iotx_mqtt_event_msg_t msg; + int i = 0, count = 0, fail_flag = -1, j = 0; + int grantedQoS[MUTLI_SUBSCIRBE_MAX]; + int rc; + + if (!c) { + return FAIL_RETURN; + } + + rc = MQTTDeserialize_suback(&mypacketid, MUTLI_SUBSCIRBE_MAX, &count, grantedQoS, (unsigned char *)c->buf_read, + c->buf_size_read); + + if (rc < 0) { + mqtt_err("Sub ack packet error, rc = MQTTDeserialize_suback() = %d", rc); + return MQTT_SUBSCRIBE_ACK_PACKET_ERROR; + } + + mqtt_debug("%20s : %d", "Return Value", rc); + mqtt_debug("%20s : %d", "Packet ID", mypacketid); + mqtt_debug("%20s : %d", "Count", count); + for (i = 0; i < count; ++i) { + mqtt_debug("%16s[%02d] : %d", "Granted QoS", i, grantedQoS[i]); + } + + for (j = 0; j < count; j++) { + fail_flag = 0; + /* In negative case, grantedQoS will be 0xFFFF FF80, which means -128 */ + if ((uint8_t)grantedQoS[j] == 0x80) { + fail_flag = 1; + mqtt_err("MQTT SUBSCRIBE failed, ack code is 0x80"); + } + } + + /* call callback function to notify that SUBSCRIBE is successful */ + msg.msg = (void *)(uintptr_t)mypacketid; + if (fail_flag == 1) { + msg.event_type = IOTX_MQTT_EVENT_SUBCRIBE_NACK; + } else { + msg.event_type = IOTX_MQTT_EVENT_SUBCRIBE_SUCCESS; + } + + _iotx_mqtt_event_handle_sub(c->handle_event.pcontext, c, &msg); + + if (NULL != c->handle_event.h_fp) { + _handle_event(&c->handle_event, c, &msg); + } + + return SUCCESS_RETURN; +} + +#if WITH_MQTT_ZIP_TOPIC +#define MQTT_ZIP_PATH_DEFAULT_LEN (32) + +static int iotx_mc_get_zip_topic(const char *path, int len, char outbuf[], int outlen) +{ + unsigned char comp_data[MQTT_ZIP_PATH_DEFAULT_LEN] = {0}; + if (!path || !len || !outbuf || !outlen) { + return -1; + } + + utils_sha256((unsigned char *)path, (size_t)len, comp_data); + + memcpy(outbuf, comp_data, outlen > MQTT_ZIP_PATH_DEFAULT_LEN ? MQTT_ZIP_PATH_DEFAULT_LEN : outlen); + return 0; +} +#endif + +static char iotx_mc_is_topic_matched(char *topicFilter, MQTTString *topicName) +{ + char *curf; + char *curn; + char *curn_end; + + if (!topicFilter || !topicName) { + return 0; + } + + curf = topicFilter; + curn = topicName->lenstring.data; + curn_end = curn + topicName->lenstring.len; + + while (*curf && curn < curn_end) { + if (*curn == '/' && *curf != '/') { + break; + } + + if (*curf != '+' && *curf != '#' && *curf != *curn) { + break; + } + + if (*curf == '+') { + /* skip until we meet the next separator, or end of string */ + char *nextpos = curn + 1; + while (nextpos < curn_end && *nextpos != '/') { + nextpos = ++curn + 1; + } + } else if (*curf == '#') { + curn = curn_end - 1; /* skip until end of string */ + } + curf++; + curn++; + } + + return (curn == curn_end) && (*curf == '\0'); +} + +static void iotx_mc_deliver_message(iotx_mc_client_t *c, MQTTString *topicName, iotx_mqtt_topic_info_pt topic_msg) +{ + int flag_matched = 0; + MQTTString *compare_topic = NULL; +#ifdef PLATFORM_HAS_DYNMEM + iotx_mc_topic_handle_t *node = NULL; +#else + int idx = 0; +#endif + +#if WITH_MQTT_ZIP_TOPIC + MQTTString md5_topic; + char md5_topic_data[MQTT_ZIP_PATH_DEFAULT_LEN] = {0}; + char *net_topic; + uint32_t net_topic_len; +#endif + + if (!c || !topicName || !topic_msg) { + return; + } + + topic_msg->ptopic = topicName->lenstring.data; + topic_msg->topic_len = topicName->lenstring.len; + +#if WITH_MQTT_ZIP_TOPIC + if (topicName->cstring) { + net_topic = topicName->cstring; + net_topic_len = strlen(topicName->cstring); + } else { + net_topic = topicName->lenstring.data; + net_topic_len = topicName->lenstring.len; + } + md5_topic.cstring = NULL; + md5_topic.lenstring.data = md5_topic_data; + md5_topic.lenstring.len = MQTT_ZIP_PATH_DEFAULT_LEN; + iotx_mc_get_zip_topic(net_topic, net_topic_len, md5_topic_data, MQTT_ZIP_PATH_DEFAULT_LEN); + compare_topic = &md5_topic; +#else + compare_topic = topicName; +#endif + + /* we have to find the right message handler - indexed by topic */ + HAL_MutexLock(c->lock_generic); +#ifdef PLATFORM_HAS_DYNMEM + list_for_each_entry(node, &c->list_sub_handle, linked_list, iotx_mc_topic_handle_t) { + if (MQTTPacket_equals(compare_topic, (char *)node->topic_filter) + || iotx_mc_is_topic_matched((char *)node->topic_filter, topicName)) { + mqtt_debug("topic be matched"); + + HAL_MutexUnlock(c->lock_generic); + if (NULL != node->handle.h_fp) { + iotx_mqtt_event_msg_t msg; + msg.event_type = IOTX_MQTT_EVENT_PUBLISH_RECEIVED; + msg.msg = (void *)topic_msg; + _handle_event(&node->handle, c, &msg); + flag_matched = 1; + } + HAL_MutexLock(c->lock_generic); + } + } +#else + for (idx = 0; idx < IOTX_MC_SUBHANDLE_LIST_MAX_LEN; idx++) { + if ((c->list_sub_handle[idx].used == 1) && + (MQTTPacket_equals(compare_topic, (char *)c->list_sub_handle[idx].topic_filter) + || iotx_mc_is_topic_matched((char *)c->list_sub_handle[idx].topic_filter, topicName))) { + mqtt_debug("topic be matched"); + + HAL_MutexUnlock(c->lock_generic); + if (NULL != c->list_sub_handle[idx].handle.h_fp) { + iotx_mqtt_event_msg_t msg; + msg.event_type = IOTX_MQTT_EVENT_PUBLISH_RECEIVED; + msg.msg = (void *)topic_msg; + _handle_event(&c->list_sub_handle[idx].handle, c, &msg); + flag_matched = 1; + } + HAL_MutexLock(c->lock_generic); + } + } +#endif + HAL_MutexUnlock(c->lock_generic); + + if (0 == flag_matched) { + mqtt_info("NO matching any topic, call default handle function"); + + if (NULL != c->handle_event.h_fp) { + iotx_mqtt_event_msg_t msg; + + msg.event_type = IOTX_MQTT_EVENT_PUBLISH_RECEIVED; + msg.msg = topic_msg; + _handle_event(&c->handle_event, c, &msg); + } + } +} + +static int MQTTPuback(iotx_mc_client_t *c, unsigned int msgId, enum msgTypes type) +{ + int rc = 0; + int len = 0; + iotx_time_t timer; + + if (!c) { + return FAIL_RETURN; + } + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, c->request_timeout_ms); + + HAL_MutexLock(c->lock_write_buf); + if (type == PUBACK) { + + if (_alloc_send_buffer(c, 0) < 0) { + HAL_MutexUnlock(c->lock_write_buf); + return FAIL_RETURN; + } + + len = MQTTSerialize_ack((unsigned char *)c->buf_send, c->buf_size_send, PUBACK, 0, msgId); +#if WITH_MQTT_QOS2_PACKET + } else if (type == PUBREC) { + if (_alloc_send_buffer(c, 0) < 0) { + HAL_MutexUnlock(c->lock_write_buf); + return FAIL_RETURN; + } + len = MQTTSerialize_ack((unsigned char *)c->buf_send, c->buf_size_send, PUBREC, 0, msgId); + } else if (type == PUBREL) { + if (_alloc_send_buffer(c, 0) < 0) { + HAL_MutexUnlock(c->lock_write_buf); + return FAIL_RETURN; + } + len = MQTTSerialize_ack((unsigned char *)c->buf_send, c->buf_size_send, PUBREL, 0, msgId); +#endif /* #if WITH_MQTT_QOS2_PACKET */ + } else { + HAL_MutexUnlock(c->lock_write_buf); + return MQTT_PUBLISH_ACK_TYPE_ERROR; + } + + if (len <= 0) { + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + return MQTT_PUBLISH_ACK_PACKET_ERROR; + } + + rc = iotx_mc_send_packet(c, c->buf_send, len, &timer); + if (rc != SUCCESS_RETURN) { + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + return MQTT_NETWORK_ERROR; + } + + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + return SUCCESS_RETURN; +} + +static int iotx_mc_handle_recv_PUBLISH(iotx_mc_client_t *c) +{ + int result = 0; + MQTTString topicName; + iotx_mqtt_topic_info_t topic_msg; + int qos = 0; + uint32_t payload_len = 0; +#ifdef INFRA_LOG_NETWORK_PAYLOAD + const char *json_payload = NULL; +#endif + + if (!c) { + return FAIL_RETURN; + } + + memset(&topic_msg, 0x0, sizeof(iotx_mqtt_topic_info_t)); + memset(&topicName, 0x0, sizeof(MQTTString)); + + if (1 != MQTTDeserialize_publish((unsigned char *)&topic_msg.dup, + (int *)&qos, + (unsigned char *)&topic_msg.retain, + (unsigned short *)&topic_msg.packet_id, + &topicName, + (unsigned char **)&topic_msg.payload, + (int *)&payload_len, + (unsigned char *)c->buf_read, + c->buf_size_read)) { + return MQTT_PUBLISH_PACKET_ERROR; + } + topic_msg.qos = (unsigned char)qos; + topic_msg.payload_len = payload_len; + +#ifdef INFRA_LOG_NETWORK_PAYLOAD + + json_payload = (const char *)topic_msg.payload; + mqtt_info("Downstream Topic: '%.*s'", topicName.lenstring.len, topicName.lenstring.data); + mqtt_info("Downstream Payload:"); + iotx_facility_json_print(json_payload, LOG_INFO_LEVEL, '<'); + +#endif /* #ifdef INFRA_LOG */ + + mqtt_debug("%20s : %08d", "Packet Ident", topic_msg.packet_id); + mqtt_debug("%20s : %d", "Topic Length", topicName.lenstring.len); + mqtt_debug("%20s : %.*s", + "Topic Name", + topicName.lenstring.len, + topicName.lenstring.data); + mqtt_debug("%20s : %u / %d", "Payload Len/Room", + (unsigned int)topic_msg.payload_len, + (int)(c->buf_read + c->buf_size_read - topic_msg.payload)); + mqtt_debug("%20s : %lu", "Receive Buflen", c->buf_size_read); + +#if defined(INSPECT_MQTT_FLOW) + mqtt_debug("%20s : %p", "Payload Buffer", topic_msg.payload); + mqtt_debug("%20s : %p", "Receive Buffer", c->buf_read); +#ifdef INFRA_LOG + HEXDUMP_DEBUG(topic_msg.payload, topic_msg.payload_len); +#endif +#endif +#ifdef LOG_REPORT_TO_CLOUD + get_msgid(topicName.lenstring.data, 1); +#endif + + topic_msg.ptopic = NULL; + topic_msg.topic_len = 0; + + mqtt_debug("delivering msg ..."); + +#if WITH_MQTT_FLOW_CTRL + /* flowControl for specific topic */ + static uint64_t time_prev = 0; + uint64_t time_curr = 0; + char *filterStr = "{\"method\":\"thing.service.property.set\""; + int filterLen = strlen(filterStr); + + if (0 == memcmp(topic_msg.payload, filterStr, filterLen)) { + time_curr = HAL_UptimeMs(); + if (time_curr < time_prev) { + time_curr = time_prev; + } + if ((time_curr - time_prev) <= (uint64_t)50) { + mqtt_info("MQTT over threshould"); + return SUCCESS_RETURN; + } else { + time_prev = time_curr; + } + } +#endif + + iotx_mc_deliver_message(c, &topicName, &topic_msg); + + if (topic_msg.qos == IOTX_MQTT_QOS0) { + return SUCCESS_RETURN; + } else if (topic_msg.qos == IOTX_MQTT_QOS1) { + result = MQTTPuback(c, topic_msg.packet_id, PUBACK); + } else if (topic_msg.qos == IOTX_MQTT_QOS2) { + result = MQTTPuback(c, topic_msg.packet_id, PUBREC); + } else { + mqtt_err("Invalid QOS, QOSvalue = %d", topic_msg.qos); + return MQTT_PUBLISH_QOS_ERROR; + } + + return result; +} + +static int iotx_mc_handle_recv_UNSUBACK(iotx_mc_client_t *c) +{ + unsigned short mypacketid = 0; /* should be the same as the packetid above */ + if (!c) { + return FAIL_RETURN; + } + + if (MQTTDeserialize_unsuback(&mypacketid, (unsigned char *)c->buf_read, c->buf_size_read) != 1) { + return MQTT_UNSUBSCRIBE_ACK_PACKET_ERROR; + } + + if (NULL != c->handle_event.h_fp) { + iotx_mqtt_event_msg_t msg; + msg.event_type = IOTX_MQTT_EVENT_UNSUBCRIBE_SUCCESS; + msg.msg = (void *)(uintptr_t)mypacketid; + _handle_event(&c->handle_event, c, &msg); + } + + return SUCCESS_RETURN; +} + +static int iotx_mc_cycle(iotx_mc_client_t *c, iotx_time_t *timer) +{ + unsigned int packetType; + iotx_mc_state_t state; + int rc = SUCCESS_RETURN; + + if (!c) { + return FAIL_RETURN; + } + + state = iotx_mc_get_client_state(c); + if (state != IOTX_MC_STATE_CONNECTED) { + mqtt_debug("state = %d", state); + return MQTT_STATE_ERROR; + } + + if (IOTX_MC_KEEPALIVE_PROBE_MAX < c->keepalive_probes) { + iotx_mc_set_client_state(c, IOTX_MC_STATE_DISCONNECTED); + c->keepalive_probes = 0; + mqtt_debug("keepalive_probes more than %u, disconnected\n", IOTX_MC_KEEPALIVE_PROBE_MAX); + } + + /* read the socket, see what work is due */ + rc = iotx_mc_read_packet(c, timer, &packetType); + if (rc != SUCCESS_RETURN) { + HAL_MutexLock(c->lock_read_buf); + _reset_recv_buffer(c); + HAL_MutexUnlock(c->lock_read_buf); + if (rc == MQTT_NETWORK_ERROR) { + iotx_mc_set_client_state(c, IOTX_MC_STATE_DISCONNECTED); + } + mqtt_err("readPacket error,result = %d", rc); + return MQTT_NETWORK_ERROR; + } + + if (MQTT_CPT_RESERVED == packetType) { + /* mqtt_debug("wait data timeout"); */ + HAL_MutexLock(c->lock_read_buf); + _reset_recv_buffer(c); + HAL_MutexUnlock(c->lock_read_buf); + return SUCCESS_RETURN; + } + + /* clear ping mark when any data received from MQTT broker */ + HAL_MutexLock(c->lock_generic); + c->ping_mark = 0; + c->keepalive_probes = 0; + HAL_MutexUnlock(c->lock_generic); + HAL_MutexLock(c->lock_read_buf); + switch (packetType) { + case CONNACK: { + mqtt_debug("CONNACK"); + break; + } +#if !WITH_MQTT_ONLY_QOS0 + case PUBACK: { + mqtt_debug("PUBACK"); + rc = iotx_mc_handle_recv_PUBACK(c); + if (SUCCESS_RETURN != rc) { + mqtt_err("recvPubackProc error,result = %d", rc); + } + + break; + } +#endif + case SUBACK: { + mqtt_debug("SUBACK"); + rc = iotx_mc_handle_recv_SUBACK(c); + if (SUCCESS_RETURN != rc) { + mqtt_err("recvSubAckProc error,result = %d", rc); + } + break; + } + case PUBLISH: { + mqtt_debug("PUBLISH"); + /* HEXDUMP_DEBUG(c->buf_read, 32); */ + + rc = iotx_mc_handle_recv_PUBLISH(c); + if (SUCCESS_RETURN != rc) { + mqtt_err("recvPublishProc error,result = %d", rc); + } + break; + } + case UNSUBACK: { + mqtt_debug("UNSUBACK"); + rc = iotx_mc_handle_recv_UNSUBACK(c); + if (SUCCESS_RETURN != rc) { + mqtt_err("recvUnsubAckProc error,result = %d", rc); + } + break; + } + case PINGRESP: { + rc = SUCCESS_RETURN; + mqtt_info("receive ping response!"); + break; + } + default: + mqtt_err("INVALID TYPE"); + _reset_recv_buffer(c); + HAL_MutexUnlock(c->lock_read_buf); + return FAIL_RETURN; + } + _reset_recv_buffer(c); + HAL_MutexUnlock(c->lock_read_buf); + return rc; +} + +void _mqtt_cycle(void *client) +{ + int rc = SUCCESS_RETURN; + iotx_time_t time; + iotx_mc_client_t *pClient = (iotx_mc_client_t *)client; + + iotx_time_init(&time); + utils_time_countdown_ms(&time, pClient->cycle_timeout_ms); + + do { + unsigned int left_t; + + if (SUCCESS_RETURN != rc) { + mqtt_err("error occur rc=%d", rc); + } + + HAL_MutexLock(pClient->lock_yield); + + /* acquire package in cycle, such as PINGRESP or PUBLISH */ + rc = iotx_mc_cycle(pClient, &time); + if (SUCCESS_RETURN == rc) { +#ifndef ASYNC_PROTOCOL_STACK +#if !WITH_MQTT_ONLY_QOS0 + /* check list of wait publish ACK to remove node that is ACKED or timeout */ + MQTTPubInfoProc(pClient); +#endif +#endif + } + HAL_MutexUnlock(pClient->lock_yield); + + left_t = iotx_time_left(&time); + if (left_t < 10) { + HAL_SleepMs(left_t); + } else { + HAL_SleepMs(10); + } + } while (!utils_time_is_expired(&time)); +} + +static int MQTTKeepalive(iotx_mc_client_t *pClient) +{ + int len = 0; + int rc = 0; + /* there is no ping outstanding - send ping packet */ + iotx_time_t timer; + + if (!pClient) { + return FAIL_RETURN; + } + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, 1000); + + HAL_MutexLock(pClient->lock_write_buf); + rc = _alloc_send_buffer(pClient, 0); + if (rc < 0) { + HAL_MutexUnlock(pClient->lock_write_buf); + return FAIL_RETURN; + } + + len = MQTTSerialize_pingreq((unsigned char *)pClient->buf_send, pClient->buf_size_send); + mqtt_debug("len = MQTTSerialize_pingreq() = %d", len); + + if (len <= 0) { + mqtt_err("Serialize ping request is error"); + _reset_send_buffer(pClient); + HAL_MutexUnlock(pClient->lock_write_buf); + return MQTT_PING_PACKET_ERROR; + } + + rc = iotx_mc_send_packet(pClient, pClient->buf_send, len, &timer); + if (SUCCESS_RETURN != rc) { + /* ping outstanding, then close socket unsubscribe topic and handle callback function */ + mqtt_err("ping outstanding is error,result = %d", rc); + + _reset_send_buffer(pClient); + HAL_MutexUnlock(pClient->lock_write_buf); + return MQTT_NETWORK_ERROR; + } + _reset_send_buffer(pClient); + HAL_MutexUnlock(pClient->lock_write_buf); + return SUCCESS_RETURN; +} + +static int iotx_mc_keepalive_sub(iotx_mc_client_t *pClient) +{ + + int rc = SUCCESS_RETURN; + + if (NULL == pClient) { + return NULL_VALUE_ERROR; + } + + /* if in disabled state, without having to send ping packets */ + if (!wrapper_mqtt_check_state(pClient)) { + return SUCCESS_RETURN; + } + + /* if there is no ping_timer timeout, then return success */ + if (!utils_time_is_expired(&pClient->next_ping_time)) { + return SUCCESS_RETURN; + } + + /* update to next time sending MQTT keep-alive */ + utils_time_countdown_ms(&pClient->next_ping_time, pClient->connect_data.keepAliveInterval * 1000); + + rc = MQTTKeepalive(pClient); + if (SUCCESS_RETURN != rc) { + if (rc == MQTT_NETWORK_ERROR) { + iotx_mc_set_client_state(pClient, IOTX_MC_STATE_DISCONNECTED); + } + mqtt_err("ping outstanding is error,result = %d", rc); + return rc; + } + + mqtt_info("send MQTT ping..."); + + HAL_MutexLock(pClient->lock_generic); + pClient->ping_mark = 1; + pClient->keepalive_probes++; + HAL_MutexUnlock(pClient->lock_generic); + + return SUCCESS_RETURN; +} + +static int iotx_mc_attempt_reconnect(iotx_mc_client_t *pClient) +{ + int rc; + if (pClient == NULL) { + return NULL_VALUE_ERROR; + } + + pClient->ipstack.disconnect(&pClient->ipstack); + + mqtt_info("reconnect params: MQTTVersion=%d, clientID=%s, keepAliveInterval=%d, username=%s", + pClient->connect_data.MQTTVersion, + pClient->connect_data.clientID.cstring, + pClient->connect_data.keepAliveInterval, + pClient->connect_data.username.cstring); + + /* Ignoring return code. failures expected if network is disconnected */ + rc = wrapper_mqtt_connect(pClient); + + if (SUCCESS_RETURN != rc && MQTT_CONNECT_BLOCK != rc) { + mqtt_err("run iotx_mqtt_connect() error!"); + } + + return rc; +} + +static int iotx_mc_handle_reconnect(iotx_mc_client_t *pClient) +{ + int rc = FAIL_RETURN; + uint32_t interval_ms = 0; + + if (NULL == pClient) { + return NULL_VALUE_ERROR; + } + mqtt_info("Waiting to reconnect..."); + if (!utils_time_is_expired(&(pClient->reconnect_param.reconnect_next_time))) { + /* Timer has not expired. Not time to attempt reconnect yet. Return attempting reconnect */ + HAL_SleepMs(100); + return FAIL_RETURN; + } + + mqtt_info("start to reconnect"); + /* + rc = _conn_info_dynamic_reload(pClient); + if (SUCCESS_RETURN != rc) { + mqtt_err("update connect info err"); + return -1; + } + */ + rc = iotx_mc_attempt_reconnect(pClient); + if (SUCCESS_RETURN == rc) { + iotx_mc_set_client_state(pClient, IOTX_MC_STATE_CONNECTED); + /* + _conn_info_dynamic_reload_clear(pClient); + */ + return SUCCESS_RETURN; + } else if (MQTT_CONNECT_BLOCK == rc) { + return rc; + } else { + /* if reconnect network failed, then increase currentReconnectWaitInterval */ + /* e.g. init currentReconnectWaitInterval=1s, reconnect failed, then 2s..4s..8s */ + if (IOTX_MC_RECONNECT_INTERVAL_MAX_MS > pClient->reconnect_param.reconnect_time_interval_ms) { + pClient->reconnect_param.reconnect_time_interval_ms *= 2; + } else { + pClient->reconnect_param.reconnect_time_interval_ms = IOTX_MC_RECONNECT_INTERVAL_MAX_MS; + } + } + /* + _conn_info_dynamic_reload_clear(pClient); + */ + interval_ms = pClient->reconnect_param.reconnect_time_interval_ms; + if (IOTX_MC_RECONNECT_INTERVAL_MAX_MS < interval_ms) { + interval_ms = IOTX_MC_RECONNECT_INTERVAL_MAX_MS; + } + utils_time_countdown_ms(&(pClient->reconnect_param.reconnect_next_time), interval_ms); + + mqtt_err("mqtt reconnect failed rc = %d", rc); + + return rc; +} + +static void iotx_mc_reconnect_callback(iotx_mc_client_t *pClient) +{ + + /* handle callback function */ + if (NULL != pClient->handle_event.h_fp) { + iotx_mqtt_event_msg_t msg; + msg.event_type = IOTX_MQTT_EVENT_RECONNECT; + msg.msg = NULL; + + pClient->handle_event.h_fp(pClient->handle_event.pcontext, + pClient, + &msg); + } +} + +static void iotx_mc_disconnect_callback(iotx_mc_client_t *pClient) +{ + + if (NULL != pClient->handle_event.h_fp) { + iotx_mqtt_event_msg_t msg; + msg.event_type = IOTX_MQTT_EVENT_DISCONNECT; + msg.msg = NULL; + + pClient->handle_event.h_fp(pClient->handle_event.pcontext, + pClient, + &msg); + } +} + +static void iotx_mc_keepalive(iotx_mc_client_t *pClient) +{ + int rc = 0; + iotx_mc_state_t currentState; + + if (!pClient) { + return; + } + + /* Periodic sending ping packet to detect whether the network is connected */ + iotx_mc_keepalive_sub(pClient); + + currentState = iotx_mc_get_client_state(pClient); + do { + /* if Exceeds the maximum delay time, then return reconnect timeout */ + if (IOTX_MC_STATE_DISCONNECTED_RECONNECTING == currentState || + IOTX_MC_STATE_CONNECT_BLOCK == currentState) { + /* Reconnection is successful, Resume regularly ping packets */ + HAL_MutexLock(pClient->lock_generic); + pClient->ping_mark = 0; + HAL_MutexUnlock(pClient->lock_generic); + rc = iotx_mc_handle_reconnect(pClient); + if (SUCCESS_RETURN != rc) { + mqtt_err("reconnect network fail, rc = %d", rc); + } else if (MQTT_CONNECT_BLOCK == rc) { + mqtt_debug("now using async protocol stack, wait network connected..."); + } else { + mqtt_info("network is reconnected!"); + iotx_mc_reconnect_callback(pClient); + pClient->reconnect_param.reconnect_time_interval_ms = IOTX_MC_RECONNECT_INTERVAL_MIN_MS; + } + + break; + } + + /* If network suddenly interrupted, stop pinging packet, try to reconnect network immediately */ + if (IOTX_MC_STATE_DISCONNECTED == currentState) { + mqtt_err("network is disconnected!"); + iotx_mc_disconnect_callback(pClient); + + pClient->reconnect_param.reconnect_time_interval_ms = IOTX_MC_RECONNECT_INTERVAL_MIN_MS; + utils_time_countdown_ms(&(pClient->reconnect_param.reconnect_next_time), + pClient->reconnect_param.reconnect_time_interval_ms); + + pClient->ipstack.disconnect(&pClient->ipstack); + iotx_mc_set_client_state(pClient, IOTX_MC_STATE_DISCONNECTED_RECONNECTING); + break; + } + + } while (0); +} + +static int iotx_mc_check_handle_is_identical_ex(iotx_mc_topic_handle_t *messageHandlers1, + iotx_mc_topic_handle_t *messageHandler2) +{ + int topicNameLen = 0; + + if (!messageHandlers1 || !messageHandler2) { + return 1; + } + + if (!(messageHandlers1->topic_filter) || !(messageHandler2->topic_filter)) { + return 1; + } + +#if !(WITH_MQTT_ZIP_TOPIC) + topicNameLen = strlen(messageHandlers1->topic_filter); + + if (topicNameLen != strlen(messageHandler2->topic_filter)) { + return 1; + } + + if (0 != strncmp(messageHandlers1->topic_filter, messageHandler2->topic_filter, topicNameLen)) { + return 1; + } +#else + + if (messageHandlers1->topic_type != messageHandler2->topic_type) { + return 1; + } + + if (messageHandlers1->topic_type == TOPIC_NAME_TYPE) { + int i; + for (i = 0; i < MQTT_ZIP_PATH_DEFAULT_LEN; i++) { + if (messageHandler2->topic_filter[i] != messageHandlers1->topic_filter[i]) { + return 1; + } + } + } else { + topicNameLen = strlen(messageHandlers1->topic_filter); + + if (topicNameLen != strlen(messageHandler2->topic_filter)) { + return 1; + } + + if (0 != strncmp(messageHandlers1->topic_filter, messageHandler2->topic_filter, topicNameLen)) { + return 1; + } + } +#endif + + return 0; +} + +static int iotx_mc_check_handle_is_identical(iotx_mc_topic_handle_t *messageHandlers1, + iotx_mc_topic_handle_t *messageHandler2) +{ + if (iotx_mc_check_handle_is_identical_ex(messageHandlers1, messageHandler2) != 0) { + return 1; + } + + if (messageHandlers1->handle.h_fp != messageHandler2->handle.h_fp) { + return 1; + } + + /* context must be identical also */ + if (messageHandlers1->handle.pcontext != messageHandler2->handle.pcontext) { + return 1; + } + + return 0; +} + +static int MQTTSubscribe(iotx_mc_client_t *c, const char *topicFilter, iotx_mqtt_qos_t qos, unsigned int msgId, + iotx_mqtt_event_handle_func_fpt messageHandler, void *pcontext) +{ + int len = 0; + iotx_time_t timer; + MQTTString topic = MQTTString_initializer; + /*iotx_mc_topic_handle_t handler = {topicFilter, {messageHandler, pcontext}};*/ + iotx_mc_topic_handle_t *handler = NULL; +#ifndef PLATFORM_HAS_DYNMEM + int idx = 0; +#endif + + if (!c || !topicFilter || !messageHandler) { + return FAIL_RETURN; + } +#if !( WITH_MQTT_DYN_BUF) + if (!c->buf_send) { + return FAIL_RETURN; + } +#endif + + topic.cstring = (char *)topicFilter; + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, c->request_timeout_ms); + +#ifdef PLATFORM_HAS_DYNMEM + handler = mqtt_malloc(sizeof(iotx_mc_topic_handle_t)); + if (NULL == handler) { + return FAIL_RETURN; + } + memset(handler, 0, sizeof(iotx_mc_topic_handle_t)); + INIT_LIST_HEAD(&handler->linked_list); +#else + for (idx = 0; idx < IOTX_MC_SUBHANDLE_LIST_MAX_LEN; idx++) { + if (c->list_sub_handle[idx].used == 0) { + handler = &c->list_sub_handle[idx]; + memset(handler, 0, sizeof(iotx_mc_topic_handle_t)); + c->list_sub_handle[idx].used = 1; + break; + } + } + + if (handler == NULL) { + return MQTT_SUBHANDLE_LIST_LEN_TOO_SHORT; + } +#endif + +#if !(WITH_MQTT_ZIP_TOPIC) +#ifdef PLATFORM_HAS_DYNMEM + handler->topic_filter = mqtt_malloc(strlen(topicFilter) + 1); + if (NULL == handler->topic_filter) { + mqtt_free(handler); + return FAIL_RETURN; + } + memset((char *)handler->topic_filter, 0, strlen(topicFilter) + 1); +#else + if (strlen(topicFilter) >= CONFIG_MQTT_TOPIC_MAXLEN) { + memset(handler, 0, sizeof(iotx_mc_topic_handle_t)); + return MQTT_TOPIC_LEN_TOO_SHORT; + } + + memset((char *)handler->topic_filter, 0, CONFIG_MQTT_TOPIC_MAXLEN); +#endif + memcpy((char *)handler->topic_filter, topicFilter, strlen(topicFilter) + 1); +#else + if (strstr(topicFilter, "/+") != NULL || strstr(topicFilter, "/#") != NULL) { +#ifdef PLATFORM_HAS_DYNMEM + handler->topic_filter = mqtt_malloc(strlen(topicFilter) + 1); + if (NULL == handler->topic_filter) { + mqtt_free(handler); + return FAIL_RETURN; + } + memset((char *)handler->topic_filter, 0, strlen(topicFilter) + 1); +#else + if (strlen(topicFilter) >= CONFIG_MQTT_TOPIC_MAXLEN) { + memset(handler, 0, sizeof(iotx_mc_topic_handle_t)); + return MQTT_TOPIC_LEN_TOO_SHORT; + } + memset((char *)handler->topic_filter, 0, CONFIG_MQTT_TOPIC_MAXLEN); +#endif + handler->topic_type = TOPIC_FILTER_TYPE; + memcpy((char *)handler->topic_filter, topicFilter, strlen(topicFilter) + 1); + } else { +#ifdef PLATFORM_HAS_DYNMEM + handler->topic_filter = mqtt_malloc(MQTT_ZIP_PATH_DEFAULT_LEN); + if (NULL == handler->topic_filter) { + mqtt_free(handler); + return FAIL_RETURN; + } + memset((char *)handler->topic_filter, 0, MQTT_ZIP_PATH_DEFAULT_LEN); +#else + if (MQTT_ZIP_PATH_DEFAULT_LEN >= CONFIG_MQTT_TOPIC_MAXLEN) { + memset(handler, 0, sizeof(iotx_mc_topic_handle_t)); + return MQTT_TOPIC_LEN_TOO_SHORT; + } + memset((char *)handler->topic_filter, 0, CONFIG_MQTT_TOPIC_MAXLEN); +#endif + handler->topic_type = TOPIC_NAME_TYPE; + if (iotx_mc_get_zip_topic(topicFilter, strlen(topicFilter), (char *)handler->topic_filter, + MQTT_ZIP_PATH_DEFAULT_LEN) != 0) { +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(handler->topic_filter); + mqtt_free(handler); +#else + memset(handler, 0, sizeof(iotx_mc_topic_handle_t)); +#endif + return FAIL_RETURN; + } + } +#endif + handler->handle.h_fp = messageHandler; + handler->handle.pcontext = pcontext; + +#ifdef SUB_PERSISTENCE_ENABLED + if (qos == IOTX_MQTT_QOS3_SUB_LOCAL) { + uint8_t dup = 0; +#ifdef PLATFORM_HAS_DYNMEM + iotx_mc_topic_handle_t *node; +#endif + HAL_MutexLock(c->lock_generic); +#ifdef PLATFORM_HAS_DYNMEM +#if defined(INSPECT_MQTT_FLOW) && defined (INFRA_LOG) +#if WITH_MQTT_ZIP_TOPIC + HEXDUMP_DEBUG(handler->topic_filter, MQTT_ZIP_PATH_DEFAULT_LEN); +#else + mqtt_warning("handler->topic: %s", handler->topic_filter); +#endif +#endif + list_for_each_entry(node, &c->list_sub_handle, linked_list, iotx_mc_topic_handle_t) { + /* If subscribe the same topic and callback function, then ignore */ +#if defined(INSPECT_MQTT_FLOW) && defined (INFRA_LOG) +#if WITH_MQTT_ZIP_TOPIC + HEXDUMP_DEBUG(node->topic_filter, MQTT_ZIP_PATH_DEFAULT_LEN); +#else + mqtt_warning("node->topic: %s", node->topic_filter); +#endif +#endif + if (0 == iotx_mc_check_handle_is_identical(node, handler)) { + mqtt_warning("dup sub,topic = %s", topicFilter); + dup = 1; + } + } +#else + for (idx = 0; idx < IOTX_MC_SUBHANDLE_LIST_MAX_LEN; idx++) { + /* If subscribe the same topic and callback function, then ignore */ + if (&c->list_sub_handle[idx] != handler && + 0 == iotx_mc_check_handle_is_identical(&c->list_sub_handle[idx], handler)) { + mqtt_warning("dup sub,topic = %s", topicFilter); + dup = 1; + } + } +#endif + if (dup == 0) { +#ifdef PLATFORM_HAS_DYNMEM + list_add_tail(&handler->linked_list, &c->list_sub_handle); +#endif + } else { +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(handler->topic_filter); + mqtt_free(handler); +#else + memset(handler, 0, sizeof(iotx_mc_topic_handle_t)); +#endif + } + HAL_MutexUnlock(c->lock_generic); + return SUCCESS_RETURN; + } +#endif + + HAL_MutexLock(c->lock_write_buf); + + if (_alloc_send_buffer(c, strlen(topicFilter)) < 0) { + HAL_MutexUnlock(c->lock_write_buf); +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(handler->topic_filter); + mqtt_free(handler); +#else + memset(handler, 0, sizeof(iotx_mc_topic_handle_t)); +#endif + return FAIL_RETURN; + } + + len = MQTTSerialize_subscribe((unsigned char *)c->buf_send, c->buf_size_send, 0, (unsigned short)msgId, 1, &topic, + (int *)&qos); + if (len <= 0) { +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(handler->topic_filter); + mqtt_free(handler); +#else + memset(handler, 0, sizeof(iotx_mc_topic_handle_t)); +#endif + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + return MQTT_SUBSCRIBE_PACKET_ERROR; + } + + mqtt_debug("%20s : %08d", "Packet Ident", msgId); + mqtt_debug("%20s : %s", "Topic", topicFilter); + mqtt_debug("%20s : %d", "QoS", (int)qos); + mqtt_debug("%20s : %d", "Packet Length", len); +#if defined(INSPECT_MQTT_FLOW) && defined (INFRA_LOG) + HEXDUMP_DEBUG(c->buf_send, len); +#endif + + if ((iotx_mc_send_packet(c, c->buf_send, len, &timer)) != SUCCESS_RETURN) { /* send the subscribe packet */ + /* If send failed, remove it */ + mqtt_err("run sendPacket error!"); +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(handler->topic_filter); + mqtt_free(handler); +#else + memset(handler, 0, sizeof(iotx_mc_topic_handle_t)); +#endif + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + return MQTT_NETWORK_ERROR; + } + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + + { + uint8_t dup = 0; +#ifdef PLATFORM_HAS_DYNMEM + iotx_mc_topic_handle_t *node; +#endif + HAL_MutexLock(c->lock_generic); +#ifdef PLATFORM_HAS_DYNMEM +#if defined(INSPECT_MQTT_FLOW) && defined (INFRA_LOG) +#if WITH_MQTT_ZIP_TOPIC + HEXDUMP_DEBUG(handler->topic_filter, MQTT_ZIP_PATH_DEFAULT_LEN); +#else + mqtt_warning("handler->topic: %s", handler->topic_filter); +#endif +#endif + list_for_each_entry(node, &c->list_sub_handle, linked_list, iotx_mc_topic_handle_t) { + /* If subscribe the same topic and callback function, then ignore */ +#if defined(INSPECT_MQTT_FLOW) && defined (INFRA_LOG) +#if WITH_MQTT_ZIP_TOPIC + HEXDUMP_DEBUG(node->topic_filter, MQTT_ZIP_PATH_DEFAULT_LEN); +#else + mqtt_warning("node->topic: %s", node->topic_filter); +#endif +#endif + if (0 == iotx_mc_check_handle_is_identical(node, handler)) { + mqtt_warning("dup sub,topic = %s", topicFilter); + dup = 1; + } + } +#else + for (idx = 0; idx < IOTX_MC_SUBHANDLE_LIST_MAX_LEN; idx++) { + /* If subscribe the same topic and callback function, then ignore */ + if (&c->list_sub_handle[idx] != handler && + 0 == iotx_mc_check_handle_is_identical(&c->list_sub_handle[idx], handler)) { + mqtt_warning("dup sub,topic = %s", topicFilter); + dup = 1; + } + } +#endif + if (dup == 0) { +#ifdef PLATFORM_HAS_DYNMEM + list_add_tail(&handler->linked_list, &c->list_sub_handle); +#endif + } else { +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(handler->topic_filter); + mqtt_free(handler); +#else + memset(handler, 0, sizeof(iotx_mc_topic_handle_t)); +#endif + } + HAL_MutexUnlock(c->lock_generic); + } + + return SUCCESS_RETURN; +} + +static int iotx_mc_get_next_packetid(iotx_mc_client_t *c) +{ + unsigned int id = 0; + + if (!c) { + return FAIL_RETURN; + } + + HAL_MutexLock(c->lock_generic); + c->packet_id = (c->packet_id == IOTX_MC_PACKET_ID_MAX) ? 1 : c->packet_id + 1; + id = c->packet_id; + HAL_MutexUnlock(c->lock_generic); + + return id; +} + +static int iotx_mc_check_rule(char *iterm, iotx_mc_topic_type_t type) +{ + int i = 0; + int len = 0; + + if (NULL == iterm) { + mqtt_err("iterm is NULL"); + return FAIL_RETURN; + } + + len = strlen(iterm); + + for (i = 0; i < len; i++) { + if (TOPIC_FILTER_TYPE == type) { + if ('+' == iterm[i] || '#' == iterm[i]) { + if (1 != len) { + mqtt_err("the character # and + is error"); + return FAIL_RETURN; + } + } + } else { + if ('+' == iterm[i] || '#' == iterm[i]) { + mqtt_err("has character # and + is error"); + return FAIL_RETURN; + } + } + + if (iterm[i] < 32 || iterm[i] >= 127) { + return FAIL_RETURN; + } + } + return SUCCESS_RETURN; +} + +static int iotx_mc_check_topic(const char *topicName, iotx_mc_topic_type_t type) +{ + int mask = 0; + char *delim = "/"; + char *iterm = NULL; + char topicString[CONFIG_MQTT_TOPIC_MAXLEN]; + if (NULL == topicName || '/' != topicName[0]) { + return FAIL_RETURN; + } + + if (strlen(topicName) > CONFIG_MQTT_TOPIC_MAXLEN) { + mqtt_err("len of topicName exceeds %d", CONFIG_MQTT_TOPIC_MAXLEN); + return FAIL_RETURN; + } + + memset(topicString, 0x0, CONFIG_MQTT_TOPIC_MAXLEN); + strncpy(topicString, topicName, CONFIG_MQTT_TOPIC_MAXLEN - 1); + + iterm = infra_strtok(topicString, delim); + + if (SUCCESS_RETURN != iotx_mc_check_rule(iterm, type)) { + mqtt_err("run iotx_check_rule error"); + return FAIL_RETURN; + } + + for (;;) { + iterm = infra_strtok(NULL, delim); + + if (iterm == NULL) { + break; + } + + /* The character '#' is not in the last */ + if (1 == mask) { + mqtt_err("the character # is error"); + return FAIL_RETURN; + } + + if (SUCCESS_RETURN != iotx_mc_check_rule(iterm, type)) { + mqtt_err("run iotx_check_rule error"); + return FAIL_RETURN; + } + + if (iterm[0] == '#') { + mask = 1; + } + } + + return SUCCESS_RETURN; +} + +static inline int _is_in_yield_cb() +{ + return _in_yield_cb; +} + +static int MQTTUnsubscribe(iotx_mc_client_t *c, const char *topicFilter, unsigned int msgId) +{ + MQTTString cur_topic; + iotx_time_t timer; + MQTTString topic = MQTTString_initializer; + int len = 0; + /*iotx_mc_topic_handle_t handler = {topicFilter, {NULL, NULL}};*/ + iotx_mc_topic_handle_t *handler = NULL; +#ifdef PLATFORM_HAS_DYNMEM + iotx_mc_topic_handle_t *node = NULL; + iotx_mc_topic_handle_t *next = NULL; +#else + int idx = 0; + iotx_mc_topic_handle_t s_handler; +#endif + if (!c || !topicFilter) { + return FAIL_RETURN; + } + + topic.cstring = (char *)topicFilter; + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, c->request_timeout_ms); + +#ifdef PLATFORM_HAS_DYNMEM + handler = mqtt_malloc(sizeof(iotx_mc_topic_handle_t)); + if (NULL == handler) { + return FAIL_RETURN; + } +#else + handler = &s_handler; +#endif + + memset(handler, 0, sizeof(iotx_mc_topic_handle_t)); + +#if !(WITH_MQTT_ZIP_TOPIC) +#ifdef PLATFORM_HAS_DYNMEM + handler->topic_filter = mqtt_malloc(strlen(topicFilter) + 1); + if (NULL == handler->topic_filter) { + mqtt_free(handler); + return FAIL_RETURN; + } + memset((char *)handler->topic_filter, 0, strlen(topicFilter) + 1); +#else + if (strlen(topicFilter) >= CONFIG_MQTT_TOPIC_MAXLEN) { + return MQTT_TOPIC_LEN_TOO_SHORT; + } + memset((char *)handler->topic_filter, 0, CONFIG_MQTT_TOPIC_MAXLEN); +#endif + memcpy((char *)handler->topic_filter, topicFilter, strlen(topicFilter) + 1); +#else + if (strstr(topicFilter, "/+") != NULL || strstr(topicFilter, "/#") != NULL) { +#ifdef PLATFORM_HAS_DYNMEM + handler->topic_filter = mqtt_malloc(strlen(topicFilter) + 1); + if (NULL == handler->topic_filter) { + mqtt_free(handler); + return FAIL_RETURN; + } + memset((char *)handler->topic_filter, 0, strlen(topicFilter) + 1); +#else + if (strlen(topicFilter) >= CONFIG_MQTT_TOPIC_MAXLEN) { + return MQTT_TOPIC_LEN_TOO_SHORT; + } + memset((char *)handler->topic_filter, 0, CONFIG_MQTT_TOPIC_MAXLEN); +#endif + handler->topic_type = TOPIC_FILTER_TYPE; + memcpy((char *)handler->topic_filter, topicFilter, strlen(topicFilter) + 1); + } else { +#ifdef PLATFORM_HAS_DYNMEM + handler->topic_filter = mqtt_malloc(MQTT_ZIP_PATH_DEFAULT_LEN); + if (NULL == handler->topic_filter) { + mqtt_free(handler); + return FAIL_RETURN; + } + memset((char *)handler->topic_filter, 0, MQTT_ZIP_PATH_DEFAULT_LEN); +#else + if (MQTT_ZIP_PATH_DEFAULT_LEN >= CONFIG_MQTT_TOPIC_MAXLEN) { + return MQTT_TOPIC_LEN_TOO_SHORT; + } + memset((char *)handler->topic_filter, 0, CONFIG_MQTT_TOPIC_MAXLEN); +#endif + handler->topic_type = TOPIC_NAME_TYPE; + if (iotx_mc_get_zip_topic(topicFilter, strlen(topicFilter), (char *)handler->topic_filter, + MQTT_ZIP_PATH_DEFAULT_LEN) != 0) { +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(handler->topic_filter); + mqtt_free(handler); +#endif + return FAIL_RETURN; + } + } +#endif + + HAL_MutexLock(c->lock_write_buf); + + if (_alloc_send_buffer(c, strlen(topicFilter)) < 0) { + HAL_MutexUnlock(c->lock_write_buf); +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(handler->topic_filter); + mqtt_free(handler); +#endif + return FAIL_RETURN; + } + + if ((len = MQTTSerialize_unsubscribe((unsigned char *)c->buf_send, c->buf_size_send, 0, (unsigned short)msgId, 1, + &topic)) <= 0) { +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(handler->topic_filter); + mqtt_free(handler); +#endif + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + return MQTT_UNSUBSCRIBE_PACKET_ERROR; + } + + if ((iotx_mc_send_packet(c, c->buf_send, len, &timer)) != SUCCESS_RETURN) { /* send the subscribe packet */ +#ifdef PLATFORM_HAS_DYNMEM + mqtt_free(handler->topic_filter); + mqtt_free(handler); +#endif + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + return MQTT_NETWORK_ERROR; + } + + cur_topic.cstring = NULL; + cur_topic.lenstring.data = (char *)handler->topic_filter; + +#if !(WITH_MQTT_ZIP_TOPIC) + cur_topic.lenstring.len = strlen(handler->topic_filter) + 1; +#else + if (handler->topic_type == TOPIC_FILTER_TYPE) { + cur_topic.lenstring.len = strlen(handler->topic_filter) + 1; + } else { + cur_topic.lenstring.len = MQTT_ZIP_PATH_DEFAULT_LEN; + } +#endif + /* we have to find the right message handler - indexed by topic */ + HAL_MutexLock(c->lock_generic); +#ifdef PLATFORM_HAS_DYNMEM + list_for_each_entry_safe(node, next, &c->list_sub_handle, linked_list, iotx_mc_topic_handle_t) { + if (MQTTPacket_equals(&cur_topic, (char *)node->topic_filter) + || iotx_mc_is_topic_matched((char *)node->topic_filter, &cur_topic)) { + mqtt_debug("topic be matched"); + list_del(&node->linked_list); + mqtt_free(node->topic_filter); + mqtt_free(node); + } + } + mqtt_free(handler->topic_filter); + mqtt_free(handler); +#else + for (idx = 0; idx < IOTX_MC_SUBHANDLE_LIST_MAX_LEN; idx++) { + if ((c->list_sub_handle[idx].used == 1) && + (MQTTPacket_equals(&cur_topic, (char *)c->list_sub_handle[idx].topic_filter) || + iotx_mc_is_topic_matched((char *)c->list_sub_handle[idx].topic_filter, &cur_topic))) { + mqtt_debug("topic be matched"); + memset(&c->list_sub_handle[idx], 0, sizeof(iotx_mc_topic_handle_t)); + } + } +#endif + HAL_MutexUnlock(c->lock_generic); + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + return SUCCESS_RETURN; +} + +int MQTTPublish(iotx_mc_client_t *c, const char *topicName, iotx_mqtt_topic_info_pt topic_msg) + +{ + iotx_time_t timer; + MQTTString topic = MQTTString_initializer; + int len = 0; +#if !WITH_MQTT_ONLY_QOS0 + iotx_mc_pub_info_t *node = NULL; +#endif +#ifdef INFRA_LOG_NETWORK_PAYLOAD + const char *json_payload = NULL; +#endif + + if (!c || !topicName || !topic_msg) { + return FAIL_RETURN; + } + + topic.cstring = (char *)topicName; + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, c->request_timeout_ms); + + HAL_MutexLock(c->lock_list_pub); + HAL_MutexLock(c->lock_write_buf); + + if (_alloc_send_buffer(c, strlen(topicName) + topic_msg->payload_len) < 0) { + HAL_MutexUnlock(c->lock_write_buf); + HAL_MutexUnlock(c->lock_list_pub); + return FAIL_RETURN; + } + + len = MQTTSerialize_publish((unsigned char *)c->buf_send, + c->buf_size_send, + 0, + topic_msg->qos, + topic_msg->retain, + topic_msg->packet_id, + topic, + (unsigned char *)topic_msg->payload, + topic_msg->payload_len); + if (len <= 0) { + mqtt_err("MQTTSerialize_publish is error, len=%d, buf_size_send=%u, payloadlen=%u", + len, + c->buf_size_send, + topic_msg->payload_len); + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + HAL_MutexUnlock(c->lock_list_pub); + return MQTT_PUBLISH_PACKET_ERROR; + } + +#if !WITH_MQTT_ONLY_QOS0 + node = NULL; + /* If the QOS >1, push the information into list of wait publish ACK */ + if (topic_msg->qos > IOTX_MQTT_QOS0) { + /* push into list */ + if (SUCCESS_RETURN != iotx_mc_push_pubInfo_to(c, len, topic_msg->packet_id, &node)) { + mqtt_err("push publish into to pubInfolist failed!"); + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + HAL_MutexUnlock(c->lock_list_pub); + return MQTT_PUSH_TO_LIST_ERROR; + } + } +#endif + /* send the publish packet */ + if (iotx_mc_send_packet(c, c->buf_send, len, &timer) != SUCCESS_RETURN) { +#if !WITH_MQTT_ONLY_QOS0 + if (topic_msg->qos > IOTX_MQTT_QOS0) { + /* If not even successfully sent to IP stack, meaningless to wait QOS1 ack, give up waiting */ +#ifdef PLATFORM_HAS_DYNMEM + list_del(&node->linked_list); + mqtt_free(node); +#else + memset(node, 0, sizeof(iotx_mc_pub_info_t)); +#endif + } +#endif + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + HAL_MutexUnlock(c->lock_list_pub); + return MQTT_NETWORK_ERROR; + } + +#ifdef INFRA_LOG_NETWORK_PAYLOAD + json_payload = (const char *)topic_msg->payload; + + mqtt_info("Upstream Topic: '%s'", topicName); + mqtt_info("Upstream Payload:"); + iotx_facility_json_print(json_payload, LOG_INFO_LEVEL, '>'); + +#endif /* #ifdef INFRA_LOG */ + + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + HAL_MutexUnlock(c->lock_list_pub); + + return SUCCESS_RETURN; +} + +static int MQTTDisconnect(iotx_mc_client_t *c) +{ + int rc = FAIL_RETURN; + int len = 0; + iotx_time_t timer; /* we might wait for incomplete incoming publishes to complete */ + + if (!c) { + return FAIL_RETURN; + } + + HAL_MutexLock(c->lock_write_buf); + + if (_alloc_send_buffer(c, 0) < 0) { + HAL_MutexUnlock(c->lock_write_buf); + return FAIL_RETURN; + } + + len = MQTTSerialize_disconnect((unsigned char *)c->buf_send, c->buf_size_send); + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, c->request_timeout_ms); + + if (len > 0) { + rc = iotx_mc_send_packet(c, c->buf_send, len, &timer); /* send the disconnect packet */ + } + _reset_send_buffer(c); + HAL_MutexUnlock(c->lock_write_buf); + return rc; +} + +static int iotx_mc_disconnect(iotx_mc_client_t *pClient) +{ + int rc = -1; + + if (NULL == pClient) { + return NULL_VALUE_ERROR; + } + + if (wrapper_mqtt_check_state(pClient)) { + rc = MQTTDisconnect(pClient); + mqtt_debug("rc = MQTTDisconnect() = %d", rc); + rc = rc; + } + + /* close tcp/ip socket or free tls resources */ + pClient->ipstack.disconnect(&pClient->ipstack); + + iotx_mc_set_client_state(pClient, IOTX_MC_STATE_INITIALIZED); + + mqtt_info("mqtt disconnect!"); + return SUCCESS_RETURN; +} + +/************************ Public Interface ************************/ +void *wrapper_mqtt_init(iotx_mqtt_param_t *mqtt_params) +{ + int err; + iotx_mc_client_t *pclient = NULL; +#ifndef PLATFORM_HAS_DYNMEM + int idx; +#endif + +#ifdef PLATFORM_HAS_DYNMEM + pclient = (iotx_mc_client_t *)mqtt_malloc(sizeof(iotx_mc_client_t)); + if (NULL == pclient) { + mqtt_err("not enough memory."); + return NULL; + } + memset(pclient, 0, sizeof(iotx_mc_client_t)); +#else + for (idx = 0; idx < IOTX_MC_CLIENT_MAX_COUNT; idx++) { + if (g_iotx_mc_client[idx].used == 0) { + g_iotx_mc_client[idx].used = 1; + pclient = &g_iotx_mc_client[idx]; + break; + } + } + + if (NULL == pclient) { + mqtt_err("IOTX_MC_CLIENT_MAX_COUNT too short: %d", IOTX_MC_CLIENT_MAX_COUNT); + return NULL; + } +#endif + + err = iotx_mc_init(pclient, mqtt_params); + + if (SUCCESS_RETURN != err) { + mqtt_err("iotx_mc_init failed"); + iotx_mc_release(pclient); + return NULL; + } + + return pclient; +} + +int wrapper_mqtt_connect(void *client) +{ + int rc = FAIL_RETURN; + int retry_max = 3; + int retry_cnt = 1; + int retry_interval = 1000; + iotx_mc_client_t *pClient = (iotx_mc_client_t *)client; + + if (NULL == pClient) { + return NULL_VALUE_ERROR; + } + + /* Establish TCP or TLS connection */ + do { + mqtt_debug("calling TCP or TLS connect HAL for [%d/%d] iteration", retry_cnt, retry_max); + + rc = pClient->ipstack.connect(&pClient->ipstack); + if (SUCCESS_RETURN != rc) { + pClient->ipstack.disconnect(&pClient->ipstack); + mqtt_err("TCP or TLS Connection failed"); + + if (ERROR_CERTIFICATE_EXPIRED == rc) { + mqtt_err("certificate is expired! rc = %d", rc); + rc = ERROR_CERT_VERIFY_FAIL; + HAL_SleepMs(retry_interval); + continue; + } else { + rc = MQTT_NETWORK_CONNECT_ERROR; + HAL_SleepMs(retry_interval); + continue; + } + } else { + mqtt_debug("rc = pClient->ipstack.connect() = %d, success @ [%d/%d] iteration", rc, retry_cnt, retry_max); + break; + } + } while (++retry_cnt <= retry_max); + +#ifdef ASYNC_PROTOCOL_STACK + iotx_mc_set_client_state(pClient, IOTX_MC_STATE_CONNECT_BLOCK); + rc = MQTT_CONNECT_BLOCK; +#else + rc = _mqtt_connect(pClient); +#endif + return rc; +} + +int wrapper_mqtt_release(void **c) +{ + iotx_mc_client_t *pClient; +#ifdef PLATFORM_HAS_DYNMEM + iotx_mc_topic_handle_t *node = NULL, *next = NULL; +#endif + if (NULL == c) { + return NULL_VALUE_ERROR; + } + + pClient = (iotx_mc_client_t *)*c; + if (NULL == pClient) { + return NULL_VALUE_ERROR; + } + /* iotx_delete_thread(pClient); */ + HAL_SleepMs(100); + + iotx_mc_disconnect(pClient); + iotx_mc_set_client_state(pClient, IOTX_MC_STATE_INVALID); + HAL_SleepMs(100); + +#ifdef PLATFORM_HAS_DYNMEM + list_for_each_entry_safe(node, next, &pClient->list_sub_handle, linked_list, iotx_mc_topic_handle_t) { + list_del(&node->linked_list); + mqtt_free(node->topic_filter); + mqtt_free(node); + } +#else + memset(pClient->list_sub_handle, 0, sizeof(iotx_mc_topic_handle_t) * IOTX_MC_SUBHANDLE_LIST_MAX_LEN); +#endif + HAL_MutexDestroy(pClient->lock_generic); + HAL_MutexDestroy(pClient->lock_list_pub); + HAL_MutexDestroy(pClient->lock_write_buf); + HAL_MutexDestroy(pClient->lock_yield); + HAL_MutexDestroy(pClient->lock_read_buf); + +#if !WITH_MQTT_ONLY_QOS0 + iotx_mc_pub_wait_list_deinit(pClient); +#endif +#ifdef PLATFORM_HAS_DYNMEM + if (pClient->buf_send != NULL) { + mqtt_free(pClient->buf_send); + pClient->buf_send = NULL; + } + if (pClient->buf_read != NULL) { + mqtt_free(pClient->buf_read); + pClient->buf_read = NULL; + } + mqtt_free(pClient); +#else + memset(pClient, 0, sizeof(iotx_mc_client_t)); +#endif + *c = NULL; + mqtt_info("mqtt release!"); + return SUCCESS_RETURN; +} + +int wrapper_mqtt_yield(void *client, int timeout_ms) +{ + iotx_mc_client_t *pClient = (iotx_mc_client_t *)client; + + if (pClient == NULL) { + return NULL_VALUE_ERROR; + } + + if (timeout_ms < 0) { + mqtt_err("Invalid argument, timeout_ms = %d", timeout_ms); + return -1; + } + if (timeout_ms == 0) { + timeout_ms = 10; + } + + HAL_MutexLock(pClient->lock_yield); + pClient->cycle_timeout_ms = timeout_ms; + /* Keep MQTT alive or reconnect if connection abort */ + iotx_mc_keepalive(pClient); + HAL_MutexUnlock(pClient->lock_yield); + +#ifndef ASYNC_PROTOCOL_STACK + _mqtt_cycle(client); +#else + if (pClient->client_state == IOTX_MC_STATE_CONNECTED) { +#if !WITH_MQTT_ONLY_QOS0 + /* check list of wait publish ACK to remove node that is ACKED or timeout */ + MQTTPubInfoProc(pClient); +#endif + } + HAL_SleepMs(timeout_ms); +#endif + + return 0; +} + + +/* check MQTT client is in normal state */ +/* 0, in abnormal state; 1, in normal state */ +int wrapper_mqtt_check_state(void *client) +{ + if (!client) { + return 0; + } + + if (iotx_mc_get_client_state((iotx_mc_client_t *)client) == IOTX_MC_STATE_CONNECTED) { + return 1; + } + + return 0; +} + +int wrapper_mqtt_subscribe(void *client, + const char *topicFilter, + iotx_mqtt_qos_t qos, + iotx_mqtt_event_handle_func_fpt topic_handle_func, + void *pcontext) +{ + int rc = FAIL_RETURN; + unsigned int msgId; + iotx_mc_client_t *c; + + if (NULL == client || NULL == topicFilter || strlen(topicFilter) == 0 || !topic_handle_func) { + mqtt_err(" paras error"); + return NULL_VALUE_ERROR; + } + + c = (iotx_mc_client_t *)client; + + msgId = iotx_mc_get_next_packetid(c); + + if (!wrapper_mqtt_check_state(c)) { + mqtt_err("mqtt client state is error,state = %d", iotx_mc_get_client_state(c)); + return MQTT_STATE_ERROR; + } + + if (0 != iotx_mc_check_topic(topicFilter, TOPIC_FILTER_TYPE)) { + mqtt_err("topic format is error,topicFilter = %s", topicFilter); + return MQTT_TOPIC_FORMAT_ERROR; + } + + mqtt_debug("PERFORM subscribe to '%s' (msgId=%d)", topicFilter, msgId); + rc = MQTTSubscribe(c, topicFilter, qos, msgId, topic_handle_func, pcontext); + if (rc != SUCCESS_RETURN) { + if (rc == MQTT_NETWORK_ERROR) { + iotx_mc_set_client_state(c, IOTX_MC_STATE_DISCONNECTED); + } + + mqtt_err("run MQTTSubscribe error, rc = %d", rc); + return rc; + } + + mqtt_info("mqtt subscribe packet sent,topic = %s!", topicFilter); + return msgId; +} + +int wrapper_mqtt_subscribe_sync(void *c, + const char *topic_filter, + iotx_mqtt_qos_t qos, + iotx_mqtt_event_handle_func_fpt topic_handle_func, + void *pcontext, + int timeout_ms) +{ + int subed; + int ret; + iotx_time_t timer; + iotx_mc_client_t *client = (iotx_mc_client_t *)c; + int cnt = 0; + mqtt_sub_sync_node_t *node = NULL; +#ifdef PLATFORM_HAS_DYNMEM + mqtt_sub_sync_node_t *next = NULL; +#else + int idx = 0; +#endif + if (client == NULL) { + return NULL_VALUE_ERROR; + } + +#ifdef SUB_PERSISTENCE_ENABLED + if (qos > IOTX_MQTT_QOS3_SUB_LOCAL) { + mqtt_warning("Invalid qos(%d) out of [%d, %d], using %d", + qos, + IOTX_MQTT_QOS0, IOTX_MQTT_QOS3_SUB_LOCAL, IOTX_MQTT_QOS0); + qos = IOTX_MQTT_QOS0; + } +#else + if (qos > IOTX_MQTT_QOS2) { + mqtt_warning("Invalid qos(%d) out of [%d, %d], using %d", + qos, + IOTX_MQTT_QOS0, IOTX_MQTT_QOS2, IOTX_MQTT_QOS0); + qos = IOTX_MQTT_QOS0; + } +#endif + + iotx_time_init(&timer); + utils_time_countdown_ms(&timer, timeout_ms); + + ret = -1; + subed = 0; + cnt = 0; + cnt = cnt; + do { +#ifdef PLATFORM_HAS_DYNMEM + mqtt_sub_sync_node_t *node = NULL; + mqtt_sub_sync_node_t *next = NULL; +#else + int idx = 0; +#endif + if (ret < 0) { + ret = wrapper_mqtt_subscribe(client, topic_filter, qos, topic_handle_func, pcontext); + if (_is_in_yield_cb() != 0 || qos == IOTX_MQTT_QOS3_SUB_LOCAL) { + return ret; + } + } + + if (!subed && ret >= 0) { + mqtt_sub_sync_node_t *node = NULL; +#ifndef PLATFORM_HAS_DYNMEM + int idx = 0; +#endif +#ifdef PLATFORM_HAS_DYNMEM + node = (mqtt_sub_sync_node_t *)mqtt_malloc(sizeof(mqtt_sub_sync_node_t)); +#else + for (idx = 0; idx < IOTX_MC_SUBSYNC_LIST_MAX_LEN; idx++) { + if (client->list_sub_sync_ack[idx].used == 0) { + memset(&client->list_sub_sync_ack[idx], 0, sizeof(mqtt_sub_sync_node_t)); + client->list_sub_sync_ack[idx].used = 1; + node = &client->list_sub_sync_ack[idx]; + break; + } + } +#endif + if (node != NULL) { + mqtt_debug("packet_id = %d", ret); + node->packet_id = ret; + node->ack_type = IOTX_MQTT_EVENT_UNDEF; +#ifdef PLATFORM_HAS_DYNMEM + HAL_MutexLock(client->lock_generic); + list_add_tail(&node->linked_list, &client->list_sub_sync_ack); + HAL_MutexUnlock(client->lock_generic); +#endif + subed = 1; + } + + } + wrapper_mqtt_yield(client, 100); + + HAL_MutexLock(client->lock_generic); +#ifdef PLATFORM_HAS_DYNMEM + list_for_each_entry_safe(node, next, &client->list_sub_sync_ack, linked_list, mqtt_sub_sync_node_t) { + if (node->packet_id == ret) { + mqtt_debug("node->ack_type=%d cnt=%d", node->ack_type, cnt++); + if (node->ack_type == IOTX_MQTT_EVENT_SUBCRIBE_SUCCESS) { + list_del(&node->linked_list); + mqtt_free(node); + mqtt_debug("success!!"); + HAL_MutexUnlock(client->lock_generic); + return ret; + } else if (node->ack_type == IOTX_MQTT_EVENT_SUBCRIBE_NACK) { + list_del(&node->linked_list); + mqtt_free(node); + ret = -1; /* resub */ + subed = 0; + } else if (node->ack_type == IOTX_MQTT_EVENT_SUBCRIBE_TIMEOUT) { + list_del(&node->linked_list); + mqtt_free(node); + ret = -1; /* resub */ + subed = 0; + } + } + break; + } +#else + for (idx = 0; idx < IOTX_MC_SUBSYNC_LIST_MAX_LEN; idx++) { + if (client->list_sub_sync_ack[idx].used == 0) { + continue; + } + + if (client->list_sub_sync_ack[idx].packet_id == ret) { + mqtt_debug("client->list_sub_sync_ack[%d].ack_type=%d cnt=%d", idx, client->list_sub_sync_ack[idx].ack_type, cnt++); + if (client->list_sub_sync_ack[idx].ack_type == IOTX_MQTT_EVENT_SUBCRIBE_SUCCESS) { + memset(&client->list_sub_sync_ack[idx], 0, sizeof(mqtt_sub_sync_node_t)); + mqtt_debug("success!!"); + HAL_MutexUnlock(client->lock_generic); + return ret; + } else if (client->list_sub_sync_ack[idx].ack_type == IOTX_MQTT_EVENT_SUBCRIBE_NACK) { + memset(&client->list_sub_sync_ack[idx], 0, sizeof(mqtt_sub_sync_node_t)); + ret = -1; /* resub */ + subed = 0; + } else if (client->list_sub_sync_ack[idx].ack_type == IOTX_MQTT_EVENT_SUBCRIBE_TIMEOUT) { + memset(&client->list_sub_sync_ack[idx], 0, sizeof(mqtt_sub_sync_node_t)); + ret = -1; /* resub */ + subed = 0; + } + } + break; + } +#endif + HAL_MutexUnlock(client->lock_generic); + } while (!utils_time_is_expired(&timer)); + mqtt_warning("sync subscribe time out!!"); + + HAL_MutexLock(client->lock_generic); +#ifdef PLATFORM_HAS_DYNMEM + list_for_each_entry_safe(node, next, &client->list_sub_sync_ack, linked_list, mqtt_sub_sync_node_t) { + if (node->packet_id == ret) { + list_del(&node->linked_list); + mqtt_free(node); + } + } +#else + for (idx = 0; idx < IOTX_MC_SUBSYNC_LIST_MAX_LEN; idx++) { + if (client->list_sub_sync_ack[idx].used && node->packet_id == ret) { + memset(&client->list_sub_sync_ack[idx], 0, sizeof(mqtt_sub_sync_node_t)); + } + } +#endif + HAL_MutexUnlock(client->lock_generic); + + return -1; +} + +int wrapper_mqtt_unsubscribe(void *client, const char *topicFilter) +{ + int rc = FAIL_RETURN; + iotx_mc_client_t *c = (iotx_mc_client_t *)client; + unsigned int msgId; + + if (NULL == c || NULL == topicFilter) { + return NULL_VALUE_ERROR; + } + msgId = iotx_mc_get_next_packetid(c); + + if (0 != iotx_mc_check_topic(topicFilter, TOPIC_FILTER_TYPE)) { + mqtt_err("topic format is error,topicFilter = %s", topicFilter); + return MQTT_TOPIC_FORMAT_ERROR; + } + + if (!wrapper_mqtt_check_state(c)) { + mqtt_err("mqtt client state is error,state = %d", iotx_mc_get_client_state(c)); + return MQTT_STATE_ERROR; + } + + rc = MQTTUnsubscribe(c, topicFilter, msgId); + if (rc != SUCCESS_RETURN) { + if (rc == MQTT_NETWORK_ERROR) { /* send the subscribe packet */ + iotx_mc_set_client_state(c, IOTX_MC_STATE_DISCONNECTED); + } + + mqtt_err("run MQTTUnsubscribe error!, rc = %d", rc); + return rc; + } + + mqtt_info("mqtt unsubscribe packet sent,topic = %s!", topicFilter); + return (int)msgId; +} + +int wrapper_mqtt_publish(void *client, const char *topicName, iotx_mqtt_topic_info_pt topic_msg) +{ + uint16_t msg_id = 0; + int rc = FAIL_RETURN; + iotx_mc_client_t *c = (iotx_mc_client_t *)client; + if (c == NULL || topicName == NULL || topic_msg == NULL || topic_msg->payload == NULL) { + return NULL_VALUE_ERROR; + } + + if (0 != iotx_mc_check_topic(topicName, TOPIC_NAME_TYPE)) { + mqtt_err("topic format is error,topicFilter = %s", topicName); + return MQTT_TOPIC_FORMAT_ERROR; + } + + if (!wrapper_mqtt_check_state(c)) { + mqtt_err("mqtt client state is error,state = %d", iotx_mc_get_client_state(c)); + return MQTT_STATE_ERROR; + } + +#if !WITH_MQTT_ONLY_QOS0 + if (topic_msg->qos == IOTX_MQTT_QOS1 || topic_msg->qos == IOTX_MQTT_QOS2) { + msg_id = iotx_mc_get_next_packetid(c); + topic_msg->packet_id = msg_id; + } + if (topic_msg->qos == IOTX_MQTT_QOS2) { + mqtt_err("MQTTPublish return error,MQTT_QOS2 is now not supported."); + return MQTT_PUBLISH_QOS_ERROR; + } +#else + topic_msg->qos = IOTX_MQTT_QOS0; +#endif + +#if defined(INSPECT_MQTT_FLOW) && defined(INFRA_LOG) + HEXDUMP_DEBUG(topicName, strlen(topicName)); + HEXDUMP_DEBUG(topic_msg->payload, topic_msg->payload_len); +#endif + + rc = MQTTPublish(c, topicName, topic_msg); + if (rc != SUCCESS_RETURN) { /* send the subscribe packet */ + if (rc == MQTT_NETWORK_ERROR) { + iotx_mc_set_client_state(c, IOTX_MC_STATE_DISCONNECTED); + } + mqtt_err("MQTTPublish is error, rc = %d", rc); + return rc; + } + + return (int)msg_id; +} + +#ifdef ASYNC_PROTOCOL_STACK +int wrapper_mqtt_nwk_event_handler(void *client, iotx_mqtt_nwk_event_t event, iotx_mqtt_nwk_param_t *param) +{ + int rc = FAIL_RETURN; + iotx_mc_client_t *pClient = (iotx_mc_client_t *)client; + if (client == NULL || event >= IOTX_MQTT_SOC_MAX) { + return NULL_VALUE_ERROR; + } + + switch (event) { + case IOTX_MQTT_SOC_CONNECTED: { + rc = _mqtt_connect(pClient); + if (rc == SUCCESS_RETURN) { + iotx_mc_set_client_state(pClient, IOTX_MC_STATE_CONNECTED); + } + } + break; + case IOTX_MQTT_SOC_CLOSE: { + iotx_mc_set_client_state(pClient, IOTX_MC_STATE_DISCONNECTED); + } + break; + case IOTX_MQTT_SOC_READ: { + HAL_MutexLock(pClient->lock_yield); + _mqtt_cycle(pClient); + HAL_MutexUnlock(pClient->lock_yield); + rc = SUCCESS_RETURN; + } + break; + case IOTX_MQTT_SOC_WRITE: { + + } + break; + default: { + mqtt_err("unknown event: %d", event); + } + break; + } + + return rc; +} +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/iotx_mqtt_client.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/iotx_mqtt_client.h new file mode 100644 index 00000000..09011c43 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/iotx_mqtt_client.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + + +#ifndef __IOTX_MQTT_H__ +#define __IOTX_MQTT_H__ + +#include "infra_types.h" +#include "infra_list.h" +#include "infra_timer.h" +#include "iotx_mqtt_config.h" +#include "mqtt_api.h" + +#include "MQTTPacket.h" + +#ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define mqtt_malloc(size) LITE_malloc(size, MEM_MAGIC, "mqtt") + #define mqtt_free(ptr) LITE_free(ptr) +#else + #define mqtt_malloc(size) HAL_Malloc(size) + #define mqtt_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#define MQTT_DYNBUF_SEND_MARGIN (64) + +#define MQTT_DYNBUF_RECV_MARGIN (8) + +typedef enum { + IOTX_MC_CONNECTION_ACCEPTED = 0, + IOTX_MC_CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION = 1, + IOTX_MC_CONNECTION_REFUSED_IDENTIFIER_REJECTED = 2, + IOTX_MC_CONNECTION_REFUSED_SERVER_UNAVAILABLE = 3, + IOTX_MC_CONNECTION_REFUSED_BAD_USERDATA = 4, + IOTX_MC_CONNECTION_REFUSED_NOT_AUTHORIZED = 5 +} iotx_mc_connect_ack_code_t; + +/* State of MQTT client */ +typedef enum { + IOTX_MC_STATE_INVALID = 0, /* MQTT in invalid state */ + IOTX_MC_STATE_INITIALIZED = 1, /* MQTT in initializing state */ + IOTX_MC_STATE_CONNECTED = 2, /* MQTT in connected state */ + IOTX_MC_STATE_DISCONNECTED = 3, /* MQTT in disconnected state */ + IOTX_MC_STATE_DISCONNECTED_RECONNECTING = 4, /* MQTT in reconnecting state */ + IOTX_MC_STATE_CONNECT_BLOCK = 5 /* MQTT in connecting state when using async protocol stack */ +} iotx_mc_state_t; + +typedef enum MQTT_NODE_STATE { + IOTX_MC_NODE_STATE_NORMANL = 0, + IOTX_MC_NODE_STATE_INVALID, +} iotx_mc_node_t; + +typedef enum { + TOPIC_NAME_TYPE = 0, + TOPIC_FILTER_TYPE +} iotx_mc_topic_type_t; + +/* Handle structure of subscribed topic */ +typedef struct iotx_mc_topic_handle_s { + iotx_mc_topic_type_t topic_type; + iotx_mqtt_event_handle_t handle; +#ifdef PLATFORM_HAS_DYNMEM + const char *topic_filter; + struct list_head linked_list; +#else + const char topic_filter[CONFIG_MQTT_TOPIC_MAXLEN]; + int used; +#endif +} iotx_mc_topic_handle_t; + +#if !WITH_MQTT_ONLY_QOS0 +/* Information structure of published topic */ +typedef struct REPUBLISH_INFO { + iotx_time_t pub_start_time; /* start time of publish request */ + iotx_mc_node_t node_state; /* state of this node */ + uint16_t msg_id; /* packet id of publish */ + uint32_t len; /* length of publish message */ +#ifdef PLATFORM_HAS_DYNMEM + unsigned char *buf; /* publish message */ + struct list_head linked_list; +#else + unsigned char buf[IOTX_MC_TX_MAX_LEN]; /* publish message */ + int used; +#endif +} iotx_mc_pub_info_t, *iotx_mc_pub_info_pt; +#endif +/* Reconnected parameter of MQTT client */ +typedef struct { + iotx_time_t reconnect_next_time; /* the next time point of reconnect */ + uint32_t reconnect_time_interval_ms; /* time interval of this reconnect */ +} iotx_mc_reconnect_param_t; + +typedef struct { + uintptr_t packet_id; + uint8_t ack_type; + iotx_mqtt_event_handle_func_fpt sub_state_cb; +#ifdef PLATFORM_HAS_DYNMEM + struct list_head linked_list; +#else + int used; +#endif +} mqtt_sub_sync_node_t; + +/* structure of MQTT client */ +typedef struct Client { + void *lock_generic; /* generic lock */ + uint32_t packet_id; /* packet id */ + uint32_t request_timeout_ms; /* request timeout in millisecond */ + uint32_t cycle_timeout_ms; + uint32_t buf_size_send; /* send buffer size in byte */ +#ifdef PLATFORM_HAS_DYNMEM +#if WITH_MQTT_DYN_BUF + uint32_t buf_size_send_max; /* send buffer size max limit in byte */ + uint32_t buf_size_read_max; /* recv buffer size max limit in byte */ +#endif +#endif + uint32_t buf_size_read; /* read buffer size in byte */ + uint8_t keepalive_probes; /* keepalive probes */ +#ifdef PLATFORM_HAS_DYNMEM + char *buf_send; /* pointer of send buffer */ + char *buf_read; /* pointer of read buffer */ +#else + char buf_send[IOTX_MC_TX_MAX_LEN]; + char buf_read[IOTX_MC_RX_MAX_LEN]; +#endif +#ifdef PLATFORM_HAS_DYNMEM + struct list_head list_sub_handle; /* list of subscribe handle */ +#else + iotx_mc_topic_handle_t list_sub_handle[IOTX_MC_SUBHANDLE_LIST_MAX_LEN]; +#endif + utils_network_t ipstack; /* network parameter */ + iotx_time_t next_ping_time; /* next ping time */ + int ping_mark; /* flag of ping */ + iotx_mc_state_t client_state; /* state of MQTT client */ + iotx_mc_reconnect_param_t reconnect_param; /* reconnect parameter */ + MQTTPacket_connectData connect_data; /* connection parameter */ +#if !WITH_MQTT_ONLY_QOS0 +#ifdef PLATFORM_HAS_DYNMEM + struct list_head list_pub_wait_ack; /* list of wait publish ack */ +#else + iotx_mc_pub_info_t list_pub_wait_ack[IOTX_MC_PUBWAIT_LIST_MAX_LEN]; +#endif +#endif +#ifdef PLATFORM_HAS_DYNMEM + struct list_head list_sub_sync_ack; +#else + mqtt_sub_sync_node_t list_sub_sync_ack[IOTX_MC_SUBSYNC_LIST_MAX_LEN]; +#endif + void *lock_list_pub; /* lock for list of QoS1 pub */ + void *lock_write_buf; /* lock of write */ + void *lock_read_buf; /* lock of write */ + void *lock_yield; + iotx_mqtt_event_handle_t handle_event; /* event handle */ +#ifndef PLATFORM_HAS_DYNMEM + int used; +#endif +} iotx_mc_client_t, *iotx_mc_client_pt; + +/* Information structure of mutli-subscribe */ +typedef struct { + const char *topicFilter; + iotx_mqtt_qos_t qos; + iotx_mqtt_event_handle_func_fpt messageHandler; +} iotx_mutli_sub_info_t, *iotx_mutli_sub_info_pt; + + +#endif /* __IOTX_MQTT_H__ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/iotx_mqtt_config.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/iotx_mqtt_config.h new file mode 100644 index 00000000..3e3d60d1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/iotx_mqtt_config.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef IOTX_MQTT_CONFIG_H__ +#define IOTX_MQTT_CONFIG_H__ + +#ifndef WITH_MQTT_DYN_BUF + #define WITH_MQTT_DYN_BUF (1) +#endif + +#ifndef WITH_MQTT_QOS2_PACKET + #define WITH_MQTT_QOS2_PACKET (0) +#endif + +#ifndef WITH_MQTT_FLOW_CTRL + #define WITH_MQTT_FLOW_CTRL (0) +#endif + +#ifndef WITH_MQTT_ONLY_QOS0 + #define WITH_MQTT_ONLY_QOS0 (0) +#endif + +#ifndef WITH_MQTT_DYN_CONNINFO + #define WITH_MQTT_DYN_CONNINFO (1) +#endif + +#ifndef WITH_MQTT_ZIP_TOPIC + #define WITH_MQTT_ZIP_TOPIC (0) +#endif + +/* maximum republish elements in list */ +#define IOTX_MC_REPUB_NUM_MAX (20) + +/* MQTT client version number */ +#define IOTX_MC_MQTT_VERSION (4) + +/* maximum MQTT packet-id */ +#define IOTX_MC_PACKET_ID_MAX (65535) + +/* maximum number of simultaneously invoke subscribe request */ +#define IOTX_MC_SUB_REQUEST_NUM_MAX (256) + +/* Minimum interval of MQTT reconnect in millisecond */ +#define IOTX_MC_RECONNECT_INTERVAL_MIN_MS (1000) + +/* Maximum interval of MQTT reconnect in millisecond */ +#define IOTX_MC_RECONNECT_INTERVAL_MAX_MS (16000) + +/* Max times of keepalive which has been send and did not received response package */ +#define IOTX_MC_KEEPALIVE_PROBE_MAX (1) + + +/* Linked List Params When PLATFORM_HAS_DYNMEN Disabled */ +#ifndef PLATFORM_HAS_DYNMEN + + /* mqtt pub wait list max length, for QoS 1 */ + #ifndef IOTX_MC_PUBWAIT_LIST_MAX_LEN + #define IOTX_MC_PUBWAIT_LIST_MAX_LEN (5) + #endif + + /* mqtt sub sync list max length */ + #ifndef IOTX_MC_SUBSYNC_LIST_MAX_LEN + #define IOTX_MC_SUBSYNC_LIST_MAX_LEN (5) + #endif + + /* mqtt sub handle list max length */ + #ifndef IOTX_MC_SUBHANDLE_LIST_MAX_LEN + #define IOTX_MC_SUBHANDLE_LIST_MAX_LEN (5) + #endif + + /* mqtt client max count */ + #ifndef IOTX_MC_CLIENT_MAX_COUNT + #define IOTX_MC_CLIENT_MAX_COUNT (1) + #endif + + #ifndef IOTX_MC_TX_MAX_LEN + #define IOTX_MC_TX_MAX_LEN (512) + #endif + + #ifndef IOTX_MC_RX_MAX_LEN + #define IOTX_MC_RX_MAX_LEN (512) + #endif + +#endif /* PLATFORM_HAS_DYNMEM */ + +#endif /* IOTX_MQTT_CONFIG_H__ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/mqtt_api.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/mqtt_api.c new file mode 100644 index 00000000..9947c393 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/mqtt_api.c @@ -0,0 +1,809 @@ +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_string.h" +#include "infra_list.h" +#include "infra_report.h" +#include "infra_sha256.h" +#include "infra_compat.h" + +#include "dev_sign_api.h" +#include "mqtt_api.h" +#include "mqtt_wrapper.h" +#include "infra_redirect_region.h" + +#ifdef PLATFORM_HAS_DYNMEM + #ifdef INFRA_MEM_STATS + #include "infra_mem_stats.h" + #define mqtt_api_malloc(size) LITE_malloc(size, MEM_MAGIC, "mqtt-api") + #define mqtt_api_free(ptr) LITE_free(ptr) + #else + #define mqtt_api_malloc(size) HAL_Malloc(size) + #define mqtt_api_free(ptr) {HAL_Free((void *)ptr);ptr = NULL;} + #endif + +#else + static iotx_mqtt_param_t g_iotx_mqtt_param; +#endif + +#ifdef INFRA_LOG + #include "infra_log.h" + #define mqtt_emerg(...) log_emerg("MQTT", __VA_ARGS__) + #define mqtt_crit(...) log_crit("MQTT", __VA_ARGS__) + #define mqtt_err(...) log_err("MQTT", __VA_ARGS__) + #define mqtt_warning(...) log_warning("MQTT", __VA_ARGS__) + #define mqtt_info(...) log_info("MQTT", __VA_ARGS__) + #define mqtt_debug(...) log_debug("MQTT", __VA_ARGS__) +#else + #define mqtt_emerg(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define mqtt_crit(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define mqtt_err(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define mqtt_warning(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define mqtt_info(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define mqtt_debug(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#endif + +static void *g_mqtt_client = NULL; +iotx_sign_mqtt_t g_default_sign; + +/* Handle structure of subscribed topic */ +typedef struct { +#ifdef PLATFORM_HAS_DYNMEM + char *topic_filter; +#else + char topic_filter[CONFIG_MQTT_TOPIC_MAXLEN]; +#endif + iotx_mqtt_event_handle_func_fpt handle; + void *user_data; + iotx_mqtt_qos_t qos; +#ifdef PLATFORM_HAS_DYNMEM + struct list_head linked_list; +#else + int used; +#endif +} iotx_mc_offline_subs_t; + +typedef struct { + int init; + void *mutex; +#ifdef PLATFORM_HAS_DYNMEM + struct list_head offline_sub_list; +#else + iotx_mc_offline_subs_t offline_sub_list[CONFIG_MQTT_OFFLINE_TOPIC_MAXNUM]; +#endif + +} offline_sub_list_t; + +static offline_sub_list_t g_mqtt_offline_subs_list = {0}; + +static int _offline_subs_list_init(void) +{ + if (g_mqtt_offline_subs_list.init) { + return SUCCESS_RETURN; + } + + memset(&g_mqtt_offline_subs_list, 0, sizeof(offline_sub_list_t)); + g_mqtt_offline_subs_list.init = 1; + +#ifdef PLATFORM_HAS_DYNMEM + INIT_LIST_HEAD(&g_mqtt_offline_subs_list.offline_sub_list); +#endif + + g_mqtt_offline_subs_list.mutex = HAL_MutexCreate(); + + return SUCCESS_RETURN; +} + +static int _offline_subs_list_deinit(void) +{ +#ifdef PLATFORM_HAS_DYNMEM + iotx_mc_offline_subs_t *node = NULL, *next_node = NULL; + list_for_each_entry_safe(node, next_node, &g_mqtt_offline_subs_list.offline_sub_list, linked_list, + iotx_mc_offline_subs_t) { + list_del(&node->linked_list); + mqtt_api_free(node->topic_filter); + mqtt_api_free(node); + } +#endif + + if (g_mqtt_offline_subs_list.mutex) { + HAL_MutexDestroy(g_mqtt_offline_subs_list.mutex); + } + memset(&g_mqtt_offline_subs_list, 0, sizeof(offline_sub_list_t)); + + return 0; +} + +static int iotx_mqtt_offline_subscribe(const char *topic_filter, iotx_mqtt_qos_t qos, + iotx_mqtt_event_handle_func_fpt topic_handle_func, void *pcontext) +{ + int ret; +#ifdef PLATFORM_HAS_DYNMEM + iotx_mc_offline_subs_t *sub_info = NULL; +#else + int idx = 0; +#endif + + if (topic_filter == NULL || topic_handle_func == NULL) { + return NULL_VALUE_ERROR; + } + + _offline_subs_list_init(); + +#ifdef PLATFORM_HAS_DYNMEM + HAL_MutexLock(g_mqtt_offline_subs_list.mutex); + list_for_each_entry(sub_info, &g_mqtt_offline_subs_list.offline_sub_list, linked_list, iotx_mc_offline_subs_t) { + if ((strlen(sub_info->topic_filter) == strlen(topic_filter)) && + memcmp(sub_info->topic_filter, topic_filter, strlen(topic_filter)) == 0) { + sub_info->qos = qos; + sub_info->handle = topic_handle_func; + sub_info->user_data = pcontext; + HAL_MutexUnlock(g_mqtt_offline_subs_list.mutex); + return SUCCESS_RETURN; + } + } + + sub_info = mqtt_api_malloc(sizeof(iotx_mc_offline_subs_t)); + if (sub_info == NULL) { + HAL_MutexUnlock(g_mqtt_offline_subs_list.mutex); + return ERROR_MALLOC; + } + + memset(sub_info, 0, sizeof(iotx_mc_offline_subs_t)); + sub_info->topic_filter = mqtt_api_malloc(strlen(topic_filter) + 1); + if (sub_info->topic_filter == NULL) { + mqtt_api_free(sub_info); + HAL_MutexUnlock(g_mqtt_offline_subs_list.mutex); + return ERROR_MALLOC; + } + memset(sub_info->topic_filter, 0, strlen(topic_filter) + 1); + strncpy(sub_info->topic_filter, topic_filter, strlen(topic_filter)); + sub_info->qos = qos; + sub_info->handle = topic_handle_func; + sub_info->user_data = pcontext; + INIT_LIST_HEAD(&sub_info->linked_list); + + list_add_tail(&sub_info->linked_list, &g_mqtt_offline_subs_list.offline_sub_list); + HAL_MutexUnlock(g_mqtt_offline_subs_list.mutex); + ret = SUCCESS_RETURN; +#else + if (strlen(topic_filter) >= CONFIG_MQTT_TOPIC_MAXLEN) { + return MQTT_TOPIC_LEN_TOO_SHORT; + } + + HAL_MutexLock(g_mqtt_offline_subs_list.mutex); + for (idx = 0; idx < CONFIG_MQTT_OFFLINE_TOPIC_MAXNUM; idx++) { + if (g_mqtt_offline_subs_list.offline_sub_list[idx].used && + (strlen(g_mqtt_offline_subs_list.offline_sub_list[idx].topic_filter) == strlen(topic_filter)) && + memcmp(g_mqtt_offline_subs_list.offline_sub_list[idx].topic_filter, topic_filter, strlen(topic_filter)) == 0) { + g_mqtt_offline_subs_list.offline_sub_list[idx].qos = qos; + g_mqtt_offline_subs_list.offline_sub_list[idx].handle = topic_handle_func; + g_mqtt_offline_subs_list.offline_sub_list[idx].user_data = pcontext; + HAL_MutexUnlock(g_mqtt_offline_subs_list.mutex); + return SUCCESS_RETURN; + } + } + for (idx = 0; idx < CONFIG_MQTT_OFFLINE_TOPIC_MAXNUM; idx++) { + if (g_mqtt_offline_subs_list.offline_sub_list[idx].used == 0) { + memset(&g_mqtt_offline_subs_list.offline_sub_list[idx], 0, sizeof(iotx_mc_offline_subs_t)); + memcpy(g_mqtt_offline_subs_list.offline_sub_list[idx].topic_filter, topic_filter, strlen(topic_filter)); + g_mqtt_offline_subs_list.offline_sub_list[idx].qos = qos; + g_mqtt_offline_subs_list.offline_sub_list[idx].handle = topic_handle_func; + g_mqtt_offline_subs_list.offline_sub_list[idx].user_data = pcontext; + g_mqtt_offline_subs_list.offline_sub_list[idx].used = 1; + HAL_MutexUnlock(g_mqtt_offline_subs_list.mutex); + return SUCCESS_RETURN; + } + } + HAL_MutexUnlock(g_mqtt_offline_subs_list.mutex); + ret = MQTT_OFFLINE_LIST_LEN_TOO_SHORT; +#endif + + return ret; +} + +static int iotx_mqtt_deal_offline_subs(void *client) +{ +#ifdef PLATFORM_HAS_DYNMEM + iotx_mc_offline_subs_t *node = NULL, *next_node = NULL; +#else + int idx; +#endif + if (g_mqtt_offline_subs_list.init == 0) { + return SUCCESS_RETURN; + } + + HAL_MutexLock(g_mqtt_offline_subs_list.mutex); +#ifdef PLATFORM_HAS_DYNMEM + list_for_each_entry_safe(node, next_node, &g_mqtt_offline_subs_list.offline_sub_list, linked_list, + iotx_mc_offline_subs_t) { + list_del(&node->linked_list); + wrapper_mqtt_subscribe(client, node->topic_filter, node->qos, node->handle, node->user_data); + mqtt_api_free(node->topic_filter); + mqtt_api_free(node); + } +#else + for (idx = 0; idx < CONFIG_MQTT_OFFLINE_TOPIC_MAXNUM; idx++) { + if (g_mqtt_offline_subs_list.offline_sub_list[idx].used) { + wrapper_mqtt_subscribe(client, g_mqtt_offline_subs_list.offline_sub_list[idx].topic_filter, + g_mqtt_offline_subs_list.offline_sub_list[idx].qos, + g_mqtt_offline_subs_list.offline_sub_list[idx].handle, + g_mqtt_offline_subs_list.offline_sub_list[idx].user_data); + g_mqtt_offline_subs_list.offline_sub_list[idx].used = 0; + } + } +#endif + HAL_MutexUnlock(g_mqtt_offline_subs_list.mutex); + + _offline_subs_list_deinit(); + + return SUCCESS_RETURN; +} + +static void iotx_mqtt_report_funcs(void *pclient) +{ + int err; + + iotx_mqtt_deal_offline_subs(pclient); + +#ifndef ATHOST_MQTT_REPORT_DISBALED + iotx_set_report_func(IOT_MQTT_Publish_Simple); + /* report module id */ + err = iotx_report_mid(pclient); + if (SUCCESS_RETURN != err) { +#ifdef DEBUG_REPORT_MID_DEVINFO_FIRMWARE + mqtt_err("failed to report mid"); +#endif + } + + /* report device info */ + err = iotx_report_devinfo(pclient); + if (SUCCESS_RETURN != err) { +#ifdef DEBUG_REPORT_MID_DEVINFO_FIRMWARE + mqtt_err("failed to report devinfo"); +#endif + } + + /* report firmware version */ +#if !defined(BUILD_AOS) && !defined(MUTE_VERSION_REPORT) + err = iotx_report_firmware_version(pclient); + + if (SUCCESS_RETURN != err) { +#ifdef DEBUG_REPORT_MID_DEVINFO_FIRMWARE + mqtt_err("failed to report firmware version"); +#endif + } +#endif + +#endif +} + +#ifdef DYNAMIC_REGISTER +#include "dynreg_api.h" +int HAL_SetDeviceSecret(char *device_secret); +int HAL_GetProductSecret(char *product_secret); +int HAL_Kv_Set(const char *key, const void *val, int len, int sync); +int HAL_Kv_Get(const char *key, void *val, int *buffer_len); + +#define DYNAMIC_REG_KV_PREFIX "DYNAMIC_REG_" +#define DYNAMIC_REG_KV_PREFIX_LEN 12 + +static int _iotx_dynamic_register(iotx_http_region_types_t region, iotx_dev_meta_info_t *meta_info) +{ + char device_secret_kv[IOTX_DEVICE_SECRET_LEN + 1] = {0}; + int device_secret_len = IOTX_DEVICE_SECRET_LEN; + char kv_key[IOTX_DEVICE_NAME_LEN + DYNAMIC_REG_KV_PREFIX_LEN] = DYNAMIC_REG_KV_PREFIX; + int res = FAIL_RETURN; + + memcpy(kv_key + strlen(kv_key), meta_info->device_name, strlen(meta_info->device_name)); + + /* Check if Device Secret exist in KV */ + if (HAL_Kv_Get(kv_key, device_secret_kv, &device_secret_len) == 0) { + mqtt_info("Get DeviceSecret from KV succeed"); + + *(device_secret_kv + device_secret_len) = 0; + HAL_SetDeviceSecret(device_secret_kv); + memset(meta_info->device_secret, 0, IOTX_DEVICE_SECRET_LEN + 1); + memcpy(meta_info->device_secret, device_secret_kv, strlen(device_secret_kv)); + } else { + char product_secret[IOTX_PRODUCT_SECRET_LEN + 1] = {0}; + + /* KV not exit, goto dynamic register */ + mqtt_info("DeviceSecret KV not exist, Now We Need Dynamic Register..."); + + res = IOT_Dynamic_Register(region, meta_info); + if (res != SUCCESS_RETURN) { + mqtt_err("Dynamic Register Failed"); + return FAIL_RETURN; + } + + device_secret_len = strlen(meta_info->device_secret); + if (HAL_Kv_Set(kv_key, meta_info->device_secret, device_secret_len, 1) != 0) { + mqtt_err("Save Device Secret to KV Failed"); + return FAIL_RETURN; + } + + HAL_SetDeviceSecret(meta_info->device_secret); + } + + return SUCCESS_RETURN; +} +#endif /* #ifdef DYNAMIC_REGISTER */ + +#ifdef MQTT_PRE_AUTH +#include "infra_preauth.h" +extern int _sign_get_clientid(char *clientid_string, const char *device_id); +extern int _iotx_generate_sign_string(const char *device_id, const char *device_name, const char *product_key, + const char *device_secret, char *sign_string); + +static int _iotx_preauth(iotx_mqtt_region_types_t region, iotx_dev_meta_info_t *meta, + iotx_sign_mqtt_t *preauth_out) +{ + uint16_t length = 0; + char device_id[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 1] = {0}; + char sign_string[65] = {0}; + int res; + + memset(preauth_out, 0, sizeof(iotx_sign_mqtt_t)); + + /* setup device_id */ + memcpy(device_id, meta->product_key, strlen(meta->product_key)); + memcpy(device_id + strlen(device_id), ".", strlen(".")); + memcpy(device_id + strlen(device_id), meta->device_name, strlen(meta->device_name)); + + /* setup clientid */ + if (_sign_get_clientid(preauth_out->clientid, device_id) != SUCCESS_RETURN) { + return ERROR_DEV_SIGN_CLIENT_ID_TOO_SHORT; + } + + /* setup sign_string */ + res = _iotx_generate_sign_string(device_id, meta->device_name, meta->product_key, meta->device_secret, sign_string); + if (res < SUCCESS_RETURN) { + return res; + } + + return preauth_get_connection_info(region, meta, sign_string, device_id, preauth_out); +} +#endif /* #ifdef MQTT_PRE_AUTH */ + +/************************ Public Interface ************************/ +void *IOT_MQTT_Construct(iotx_mqtt_param_t *pInitParams) +{ + void *pclient; + iotx_dev_meta_info_t meta_info; + iotx_mqtt_param_t mqtt_params; + int region = 0; + int dynamic = 0; + int ret; + void *callback; + + if (g_mqtt_client != NULL) { + mqtt_err("Already exist default MQTT connection, won't proceed another one"); + return g_mqtt_client; + } + + /* get region */ + IOT_Ioctl(IOTX_IOCTL_GET_REGION, (void *)®ion); + + /* get dynamic option */ + IOT_Ioctl(IOTX_IOCTL_GET_DYNAMIC_REGISTER, (void *)&dynamic); + + /* get meta_info from hal */ + memset(&meta_info, 0, sizeof(iotx_dev_meta_info_t)); + HAL_GetProductKey(meta_info.product_key); + HAL_GetDeviceName(meta_info.device_name); + + if (meta_info.product_key[0] == '\0' || meta_info.product_key[IOTX_PRODUCT_KEY_LEN] != '\0') { + mqtt_err("Invalid product key, abort!"); + return NULL; + } + if (meta_info.device_name[0] == '\0' || meta_info.device_name[IOTX_DEVICE_NAME_LEN] != '\0') { + mqtt_err("Invalid device name, abort!"); + return NULL; + } + +#ifdef DYNAMIC_REGISTER /* get device secret through https dynamic register */ + if (dynamic) { + HAL_GetProductSecret(meta_info.product_secret); + if (meta_info.product_secret[0] == '\0' || meta_info.product_secret[IOTX_PRODUCT_SECRET_LEN] != '\0') { + mqtt_err("Product Secret doesn't exist"); + return NULL; + } + + ret = _iotx_dynamic_register(region, &meta_info); + if (ret < SUCCESS_RETURN) { + mqtt_err("ret = _iotx_dynamic_register() = %d, abort", ret); + return NULL; + } + } else { + HAL_GetDeviceSecret(meta_info.device_secret); + if (meta_info.device_secret[0] == '\0' || meta_info.device_secret[IOTX_DEVICE_SECRET_LEN] != '\0') { + mqtt_err("Invalid device secret, abort!"); + return NULL; + } + } +#else /* get device secret from hal */ + HAL_GetDeviceSecret(meta_info.device_secret); + if (meta_info.device_secret[0] == '\0' || meta_info.device_secret[IOTX_DEVICE_SECRET_LEN] != '\0') { + mqtt_err("Invalid device secret, abort!"); + return NULL; + } +#endif /* #ifdef DYNAMIC_REGISTER */ + +#ifdef MQTT_PRE_AUTH /* preauth mode through https */ + ret = _iotx_preauth(region, &meta_info, (iotx_sign_mqtt_t *)&g_default_sign); /* type convert */ + if (ret < SUCCESS_RETURN) { + mqtt_err("ret = _iotx_preauth() = %d, abort", ret); + return NULL; + } +#else /* direct mode */ + ret = IOT_Sign_MQTT(region, &meta_info, &g_default_sign); + if (ret < SUCCESS_RETURN) { + mqtt_err("ret = IOT_Sign_MQTT() = %d, abort", ret); + return NULL; + } +#endif /* #ifdef MQTT_PRE_AUTH */ + + /* Initialize MQTT parameter */ + memset(&mqtt_params, 0x0, sizeof(iotx_mqtt_param_t)); + +#ifdef SUPPORT_TLS + { + extern const char *iotx_ca_crt; + mqtt_params.pub_key = iotx_ca_crt; + } +#endif + mqtt_params.request_timeout_ms = CONFIG_MQTT_REQUEST_TIMEOUT; + mqtt_params.clean_session = 0; + mqtt_params.keepalive_interval_ms = CONFIG_MQTT_KEEPALIVE_INTERVAL * 1000; + mqtt_params.read_buf_size = CONFIG_MQTT_MESSAGE_MAXLEN; + mqtt_params.write_buf_size = CONFIG_MQTT_MESSAGE_MAXLEN; + mqtt_params.handle_event.h_fp = NULL; + mqtt_params.handle_event.pcontext = NULL; + + /* optional configuration */ + if (pInitParams != NULL) { + if (pInitParams->host && strlen(pInitParams->host)) { + mqtt_params.host = pInitParams->host; + } else { + mqtt_warning("Using default hostname: '%s'", g_default_sign.hostname); + mqtt_params.host = g_default_sign.hostname; + } + + if (pInitParams->port) { + mqtt_params.port = pInitParams->port; + } else { + mqtt_warning("Using default port: [%d]", g_default_sign.port); + mqtt_params.port = g_default_sign.port; + } + + if (pInitParams->client_id && strlen(pInitParams->client_id)) { + mqtt_params.client_id = pInitParams->client_id; + } else { + mqtt_warning("Using default client_id: %s", g_default_sign.clientid); + mqtt_params.client_id = g_default_sign.clientid; + } + + if (pInitParams->username && strlen(pInitParams->username)) { + mqtt_params.username = pInitParams->username; + } else { + mqtt_warning("Using default username: %s", g_default_sign.username); + mqtt_params.username = g_default_sign.username; + } + + if (pInitParams->password && strlen(pInitParams->password)) { + mqtt_params.password = pInitParams->password; + } else { +#if 1 + mqtt_warning("Using default password: %s", "******"); +#else + mqtt_warning("Using default password: %s", g_default_sign.password); +#endif + mqtt_params.password = g_default_sign.password; + } + + if (pInitParams->request_timeout_ms < CONFIG_MQTT_REQ_TIMEOUT_MIN || + pInitParams->request_timeout_ms > CONFIG_MQTT_REQ_TIMEOUT_MAX) { + mqtt_warning("Using default request_timeout_ms: %d, configured value(%d) out of [%d, %d]", + mqtt_params.request_timeout_ms, + pInitParams->request_timeout_ms, + CONFIG_MQTT_REQ_TIMEOUT_MIN, + CONFIG_MQTT_REQ_TIMEOUT_MAX); + } else { + mqtt_params.request_timeout_ms = pInitParams->request_timeout_ms; + } + + if (pInitParams->clean_session == 0 || pInitParams->clean_session == 1) { + mqtt_params.clean_session = pInitParams->clean_session; + } + + if (pInitParams->keepalive_interval_ms < CONFIG_MQTT_KEEPALIVE_INTERVAL_MIN * 1000 || + pInitParams->keepalive_interval_ms > CONFIG_MQTT_KEEPALIVE_INTERVAL_MAX * 1000) { + mqtt_warning("Using default keepalive_interval_ms: %d, configured value(%d) out of [%d, %d]", + mqtt_params.keepalive_interval_ms, + pInitParams->keepalive_interval_ms, + CONFIG_MQTT_KEEPALIVE_INTERVAL_MIN * 1000, + CONFIG_MQTT_KEEPALIVE_INTERVAL_MAX * 1000); + } else { + mqtt_params.keepalive_interval_ms = pInitParams->keepalive_interval_ms; + } + + if (!pInitParams->read_buf_size) { + mqtt_warning("Using default read_buf_size: %d", mqtt_params.read_buf_size); + } else { + mqtt_params.read_buf_size = pInitParams->read_buf_size; + } + + if (!pInitParams->write_buf_size) { + mqtt_warning("Using default write_buf_size: %d", mqtt_params.write_buf_size); + } else { + mqtt_params.write_buf_size = pInitParams->write_buf_size; + } + + if (pInitParams->handle_event.h_fp != NULL) { + mqtt_params.handle_event.h_fp = pInitParams->handle_event.h_fp; + } + + if (pInitParams->handle_event.pcontext != NULL) { + mqtt_params.handle_event.pcontext = pInitParams->handle_event.pcontext; + } + } else { + mqtt_warning("Using default port: [%d]", g_default_sign.port); + mqtt_params.port = g_default_sign.port; + + mqtt_warning("Using default hostname: '%s'", g_default_sign.hostname); + mqtt_params.host = g_default_sign.hostname; + + mqtt_warning("Using default client_id: %s", g_default_sign.clientid); + mqtt_params.client_id = g_default_sign.clientid; + + mqtt_warning("Using default username: %s", g_default_sign.username); + mqtt_params.username = g_default_sign.username; + +#if 1 + mqtt_warning("Using default password: %s", "******"); +#else + mqtt_warning("Using default password: %s", g_default_sign.password); +#endif + mqtt_params.password = g_default_sign.password; + } + + pclient = wrapper_mqtt_init(&mqtt_params); + if (pclient == NULL) { + mqtt_err("wrapper_mqtt_init error"); + return NULL; + } + + ret = wrapper_mqtt_connect(pclient); + if (SUCCESS_RETURN != ret) { + if (MQTT_CONNECT_BLOCK != ret) { + mqtt_err("wrapper_mqtt_connect failed"); + wrapper_mqtt_release(&pclient); + return NULL; + } + } + +#ifndef ASYNC_PROTOCOL_STACK + iotx_mqtt_report_funcs(pclient); +#endif + + g_mqtt_client = pclient; + + /* Mqtt Connect Callback */ + callback = iotx_event_callback(ITE_MQTT_CONNECT_SUCC); + if (callback) { + ((int (*)(void))callback)(); + } + + ret = iotx_redirect_region_subscribe(); + if (ret < 0) { + mqtt_err("failed to subscribe mqtt redirect resgion topic.");; + } + + return pclient; +} + +int IOT_MQTT_Destroy(void **phandler) +{ + void *client; + if (phandler != NULL) { + client = *phandler; + *phandler = NULL; + } else { + client = g_mqtt_client; + } + + if (client == NULL) { + mqtt_err("handler is null"); + return NULL_VALUE_ERROR; + } + + wrapper_mqtt_release(&client); + g_mqtt_client = NULL; + + return SUCCESS_RETURN; +} + +int IOT_MQTT_Yield(void *handle, int timeout_ms) +{ + void *pClient = (handle ? handle : g_mqtt_client); + return wrapper_mqtt_yield(pClient, timeout_ms); +} + +/* check whether MQTT connection is established or not */ +int IOT_MQTT_CheckStateNormal(void *handle) +{ + void *pClient = (handle ? handle : g_mqtt_client); + if (pClient == NULL) { + mqtt_err("handler is null"); + return NULL_VALUE_ERROR; + } + + return wrapper_mqtt_check_state(pClient); +} + +int IOT_MQTT_Subscribe(void *handle, + const char *topic_filter, + iotx_mqtt_qos_t qos, + iotx_mqtt_event_handle_func_fpt topic_handle_func, + void *pcontext) +{ + void *client = handle ? handle : g_mqtt_client; + + if (client == NULL) { /* do offline subscribe */ + return iotx_mqtt_offline_subscribe(topic_filter, qos, topic_handle_func, pcontext); + } + + if (topic_filter == NULL || strlen(topic_filter) == 0 || topic_handle_func == NULL) { + mqtt_err("params err"); + return NULL_VALUE_ERROR; + } + +#ifdef SUB_PERSISTENCE_ENABLED + if (qos > IOTX_MQTT_QOS3_SUB_LOCAL) { + mqtt_warning("Invalid qos(%d) out of [%d, %d], using %d", + qos, + IOTX_MQTT_QOS0, IOTX_MQTT_QOS3_SUB_LOCAL, IOTX_MQTT_QOS0); + qos = IOTX_MQTT_QOS0; + } +#else + if (qos > IOTX_MQTT_QOS2) { + mqtt_warning("Invalid qos(%d) out of [%d, %d], using %d", + qos, + IOTX_MQTT_QOS0, IOTX_MQTT_QOS2, IOTX_MQTT_QOS0); + qos = IOTX_MQTT_QOS0; + } +#endif + + return wrapper_mqtt_subscribe(client, topic_filter, qos, topic_handle_func, pcontext); +} + +#define SUBSCRIBE_SYNC_TIMEOUT_MAX 10000 +int IOT_MQTT_Subscribe_Sync(void *handle, + const char *topic_filter, + iotx_mqtt_qos_t qos, + iotx_mqtt_event_handle_func_fpt topic_handle_func, + void *pcontext, + int timeout_ms) +{ + void *client = handle ? handle : g_mqtt_client; + + if (client == NULL) { /* do offline subscribe */ + return iotx_mqtt_offline_subscribe(topic_filter, qos, topic_handle_func, pcontext); + } + if (timeout_ms > SUBSCRIBE_SYNC_TIMEOUT_MAX) { + timeout_ms = SUBSCRIBE_SYNC_TIMEOUT_MAX; + } + + if (topic_filter == NULL || strlen(topic_filter) == 0 || topic_handle_func == NULL) { + mqtt_err("params err"); + return NULL_VALUE_ERROR; + } + +#ifdef SUB_PERSISTENCE_ENABLED + if (qos > IOTX_MQTT_QOS3_SUB_LOCAL) { + mqtt_warning("Invalid qos(%d) out of [%d, %d], using %d", + qos, + IOTX_MQTT_QOS0, IOTX_MQTT_QOS3_SUB_LOCAL, IOTX_MQTT_QOS0); + qos = IOTX_MQTT_QOS0; + } +#else + if (qos > IOTX_MQTT_QOS2) { + mqtt_warning("Invalid qos(%d) out of [%d, %d], using %d", + qos, + IOTX_MQTT_QOS0, IOTX_MQTT_QOS2, IOTX_MQTT_QOS0); + qos = IOTX_MQTT_QOS0; + } +#endif + + return wrapper_mqtt_subscribe_sync(client, topic_filter, qos, topic_handle_func, pcontext, timeout_ms); +} + +int IOT_MQTT_Unsubscribe(void *handle, const char *topic_filter) +{ + void *client = handle ? handle : g_mqtt_client; + + + if (client == NULL || topic_filter == NULL || strlen(topic_filter) == 0) { + mqtt_err("params err"); + return NULL_VALUE_ERROR; + } + + return wrapper_mqtt_unsubscribe(client, topic_filter); +} + +int IOT_MQTT_Publish(void *handle, const char *topic_name, iotx_mqtt_topic_info_pt topic_msg) +{ + void *client = handle ? handle : g_mqtt_client; + int rc = -1; + + if (client == NULL || topic_name == NULL || strlen(topic_name) == 0) { + mqtt_err("params err"); + return NULL_VALUE_ERROR; + } + + rc = wrapper_mqtt_publish(client, topic_name, topic_msg); + return rc; +} + +int IOT_MQTT_Publish_Simple(void *handle, const char *topic_name, int qos, void *data, int len) +{ + iotx_mqtt_topic_info_t mqtt_msg; + void *client = handle ? handle : g_mqtt_client; + int rc = -1; + + if (client == NULL || topic_name == NULL || strlen(topic_name) == 0) { + mqtt_err("params err"); + return NULL_VALUE_ERROR; + } + + memset(&mqtt_msg, 0x0, sizeof(iotx_mqtt_topic_info_t)); + + mqtt_msg.qos = qos; + mqtt_msg.retain = 0; + mqtt_msg.dup = 0; + mqtt_msg.payload = (void *)data; + mqtt_msg.payload_len = len; + + rc = wrapper_mqtt_publish(client, topic_name, &mqtt_msg); + + if (rc < 0) { + mqtt_err("IOT_MQTT_Publish failed\n"); + return -1; + } + + return rc; +} + +int IOT_MQTT_Nwk_Event_Handler(void *handle, iotx_mqtt_nwk_event_t event, iotx_mqtt_nwk_param_t *param) +{ +#ifdef ASYNC_PROTOCOL_STACK + void *client = handle ? handle : g_mqtt_client; + int rc = -1; + + if (client == NULL || event >= IOTX_MQTT_SOC_MAX || param == NULL) { + mqtt_err("params err"); + return NULL_VALUE_ERROR; + } + + rc = wrapper_mqtt_nwk_event_handler(client, event, param); + + if (rc < 0) { + mqtt_err("IOT_MQTT_Nwk_Event_Handler failed\n"); + return -1; + } + + switch (event) { + case IOTX_MQTT_SOC_CONNECTED: { + iotx_mqtt_report_funcs(client); + } + break; + default: { + } + break; + } + + return rc; +#else + return -1; +#endif +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/mqtt_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/mqtt_api.h new file mode 100644 index 00000000..45204167 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/mqtt_api.h @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _IOT_EXPORT_MQTT_H_ +#define _IOT_EXPORT_MQTT_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +#include "infra_types.h" +#include "infra_defs.h" + +#define MUTLI_SUBSCIRBE_MAX (5) + +/* From mqtt_client.h */ +typedef enum { + IOTX_MQTT_QOS0 = 0, + IOTX_MQTT_QOS1, + IOTX_MQTT_QOS2, + IOTX_MQTT_QOS3_SUB_LOCAL +} iotx_mqtt_qos_t; + +typedef enum { + + /* Undefined event */ + IOTX_MQTT_EVENT_UNDEF = 0, + + /* MQTT disconnect event */ + IOTX_MQTT_EVENT_DISCONNECT = 1, + + /* MQTT reconnect event */ + IOTX_MQTT_EVENT_RECONNECT = 2, + + /* A ACK to the specific subscribe which specify by packet-id be received */ + IOTX_MQTT_EVENT_SUBCRIBE_SUCCESS = 3, + + /* No ACK to the specific subscribe which specify by packet-id be received in timeout period */ + IOTX_MQTT_EVENT_SUBCRIBE_TIMEOUT = 4, + + /* A failed ACK to the specific subscribe which specify by packet-id be received*/ + IOTX_MQTT_EVENT_SUBCRIBE_NACK = 5, + + /* A ACK to the specific unsubscribe which specify by packet-id be received */ + IOTX_MQTT_EVENT_UNSUBCRIBE_SUCCESS = 6, + + /* No ACK to the specific unsubscribe which specify by packet-id be received in timeout period */ + IOTX_MQTT_EVENT_UNSUBCRIBE_TIMEOUT = 7, + + /* A failed ACK to the specific unsubscribe which specify by packet-id be received*/ + IOTX_MQTT_EVENT_UNSUBCRIBE_NACK = 8, + + /* A ACK to the specific publish which specify by packet-id be received */ + IOTX_MQTT_EVENT_PUBLISH_SUCCESS = 9, + + /* No ACK to the specific publish which specify by packet-id be received in timeout period */ + IOTX_MQTT_EVENT_PUBLISH_TIMEOUT = 10, + + /* A failed ACK to the specific publish which specify by packet-id be received*/ + IOTX_MQTT_EVENT_PUBLISH_NACK = 11, + + /* MQTT packet published from MQTT remote broker be received */ + IOTX_MQTT_EVENT_PUBLISH_RECEIVED = 12, + + /* MQTT packet buffer overflow which the remaining space less than to receive byte */ + IOTX_MQTT_EVENT_BUFFER_OVERFLOW = 13, +} iotx_mqtt_event_type_t; + +/* topic information */ +typedef struct { + uint16_t packet_id; + uint8_t qos; + uint8_t dup; + uint8_t retain; + uint16_t topic_len; + uint32_t payload_len; + const char *ptopic; + const char *payload; +} iotx_mqtt_topic_info_t, *iotx_mqtt_topic_info_pt; + + +typedef struct { + + /* Specify the event type */ + iotx_mqtt_event_type_t event_type; + + /* + * Specify the detail event information. @msg means different to different event types: + * + * 1) IOTX_MQTT_EVENT_UNKNOWN, + * IOTX_MQTT_EVENT_DISCONNECT, + * IOTX_MQTT_EVENT_RECONNECT : + * Its data type is string and the value is detail information. + * + * 2) IOTX_MQTT_EVENT_SUBCRIBE_SUCCESS, + * IOTX_MQTT_EVENT_SUBCRIBE_TIMEOUT, + * IOTX_MQTT_EVENT_SUBCRIBE_NACK, + * IOTX_MQTT_EVENT_UNSUBCRIBE_SUCCESS, + * IOTX_MQTT_EVENT_UNSUBCRIBE_TIMEOUT, + * IOTX_MQTT_EVENT_UNSUBCRIBE_NACK + * IOTX_MQTT_EVENT_PUBLISH_SUCCESS, + * IOTX_MQTT_EVENT_PUBLISH_TIMEOUT, + * IOTX_MQTT_EVENT_PUBLISH_NACK : + * Its data type is @uint32_t and the value is MQTT packet identifier. + * + * 3) IOTX_MQTT_EVENT_PUBLISH_RECEIVED: + * Its data type is @iotx_mqtt_topic_info_pt and see detail at the declare of this type. + * + * */ + void *msg; +} iotx_mqtt_event_msg_t, *iotx_mqtt_event_msg_pt; + + +/** + * @brief It define a datatype of function pointer. + * This type of function will be called when a related event occur. + * + * @param pcontext : The program context. + * @param pclient : The MQTT client. + * @param msg : The event message. + * + * @return none + */ +typedef void (*iotx_mqtt_event_handle_func_fpt)(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg); + + +/* The structure of MQTT event handle */ +typedef struct { + iotx_mqtt_event_handle_func_fpt h_fp; + void *pcontext; +} iotx_mqtt_event_handle_t, *iotx_mqtt_event_handle_pt; + + +/* The structure of MQTT initial parameter */ +typedef struct { + + uint16_t port; /* Specify MQTT broker port */ + const char *host; /* Specify MQTT broker host */ + const char *client_id; /* Specify MQTT connection client id*/ + const char *username; /* Specify MQTT user name */ + const char *password; /* Specify MQTT password */ + + /* Specify MQTT transport channel and key. + * If the value is NULL, it means that use TCP channel, + * If the value is NOT NULL, it means that use SSL/TLS channel and + * @pub_key point to the CA certification */ + + const char *pub_key; + + uint8_t clean_session; /* Specify MQTT clean session or not*/ + uint32_t request_timeout_ms; /* Specify timeout of a MQTT request in millisecond */ + uint32_t keepalive_interval_ms; /* Specify MQTT keep-alive interval in millisecond */ + uint32_t write_buf_size; /* Specify size of write-buffer in byte */ + uint32_t read_buf_size; /* Specify size of read-buffer in byte */ + + iotx_mqtt_event_handle_t handle_event; /* Specify MQTT event handle */ + +} iotx_mqtt_param_t, *iotx_mqtt_param_pt; + +typedef enum { + IOTX_MQTT_SOC_CONNECTED, + IOTX_MQTT_SOC_CLOSE, + IOTX_MQTT_SOC_READ, + IOTX_MQTT_SOC_WRITE, + IOTX_MQTT_SOC_MAX +} iotx_mqtt_nwk_event_t; + +typedef struct { + uintptr_t fd; +} iotx_mqtt_nwk_param_t; + +/** @defgroup group_api api + * @{ + */ + +/** @defgroup group_api_mqtt mqtt + * @{ + */ + +/** + * @brief Construct the MQTT client + * This function initialize the data structures, establish MQTT connection. + * + * @param [in] pInitParams: specify the MQTT client parameter. + * + * @retval NULL : Construct failed. + * @retval NOT_NULL : The handle of MQTT client. + * @see None. + */ +void *IOT_MQTT_Construct(iotx_mqtt_param_t *pInitParams); + + +/** + * @brief Deconstruct the MQTT client + * This function disconnect MQTT connection and release the related resource. + * + * @param [in] phandle: pointer of handle, specify the MQTT client. + * + * @retval 0 : Deconstruct success. + * @retval -1 : Deconstruct failed. + * @see None. + */ +int IOT_MQTT_Destroy(void **phandle); + + +/** + * @brief Handle MQTT packet from remote server and process timeout request + * which include the MQTT subscribe, unsubscribe, publish(QOS >= 1), reconnect, etc.. + * + * @param [in] handle: specify the MQTT client. + * @param [in] timeout_ms: specify the timeout in millisecond in this loop. + * + * @return status. + * @see None. + */ +int IOT_MQTT_Yield(void *handle, int timeout_ms); + +/** + * @brief check whether MQTT connection is established or not. + * + * @param [in] handle: specify the MQTT client. + * + * @retval true : MQTT in normal state. + * @retval false : MQTT in abnormal state. + * @see None. + */ +int IOT_MQTT_CheckStateNormal(void *handle); + + +/** + * @brief Subscribe MQTT topic. + * + * @param [in] handle: specify the MQTT client. + * @param [in] topic_filter: specify the topic filter. + * @param [in] qos: specify the MQTT Requested QoS. + * @param [in] topic_handle_func: specify the topic handle callback-function. + * @param [in] pcontext: specify context. When call 'topic_handle_func', it will be passed back. + * + * @retval -1 : Subscribe failed. + * @retval >=0 : Subscribe successful. + The value is a unique ID of this request. + The ID will be passed back when callback 'iotx_mqtt_param_t:handle_event'. + * @see None. + */ +int IOT_MQTT_Subscribe(void *handle, + const char *topic_filter, + iotx_mqtt_qos_t qos, + iotx_mqtt_event_handle_func_fpt topic_handle_func, + void *pcontext); + +/** + * @brief Subscribe MQTT topic and wait suback. + * + * @param [in] handle: specify the MQTT client. + * @param [in] topic_filter: specify the topic filter. + * @param [in] qos: specify the MQTT Requested QoS. + * @param [in] topic_handle_func: specify the topic handle callback-function. + * @param [in] pcontext: specify context. When call 'topic_handle_func', it will be passed back. + * @param [in] timeout_ms: time in ms to wait. + * + * @retval -1 : Subscribe failed. + * @retval >=0 : Subscribe successful. + The value is a unique ID of this request. + The ID will be passed back when callback 'iotx_mqtt_param_t:handle_event'. + * @see None. + */ +int IOT_MQTT_Subscribe_Sync(void *handle, + const char *topic_filter, + iotx_mqtt_qos_t qos, + iotx_mqtt_event_handle_func_fpt topic_handle_func, + void *pcontext, + int timeout_ms); + + +/** + * @brief Unsubscribe MQTT topic. + * + * @param [in] handle: specify the MQTT client. + * @param [in] topic_filter: specify the topic filter. + * + * @retval -1 : Unsubscribe failed. + * @retval >=0 : Unsubscribe successful. + The value is a unique ID of this request. + The ID will be passed back when callback 'iotx_mqtt_param_t:handle_event'. + * @see None. + */ +int IOT_MQTT_Unsubscribe(void *handle, const char *topic_filter); + + +/** + * @brief Publish message to specific topic. + * + * @param [in] handle: specify the MQTT client. + * @param [in] topic_name: specify the topic name. + * @param [in] topic_msg: specify the topic message. + * + * @retval -1 : Publish failed. + * @retval 0 : Publish successful, where QoS is 0. + * @retval >0 : Publish successful, where QoS is >= 0. + The value is a unique ID of this request. + The ID will be passed back when callback 'iotx_mqtt_param_t:handle_event'. + * @see None. + */ +int IOT_MQTT_Publish(void *handle, const char *topic_name, iotx_mqtt_topic_info_pt topic_msg); +/** + * @brief Publish message to specific topic. + * + * @param [in] handle: specify the MQTT client. + * @param [in] topic_name: specify the topic name. + * @param [in] qos: specify the MQTT Requested QoS. + * @param [in] data: specify the topic message payload. + * @param [in] len: specify the topic message payload len. + * + * @retval -1 : Publish failed. + * @retval 0 : Publish successful, where QoS is 0. + * @retval >0 : Publish successful, where QoS is >= 0. + The value is a unique ID of this request. + The ID will be passed back when callback 'iotx_mqtt_param_t:handle_event'. + * @see None. + */ +int IOT_MQTT_Publish_Simple(void *handle, const char *topic_name, int qos, void *data, int len); +/* From mqtt_client.h */ +/** @} */ /* end of api_mqtt */ + +/** @} */ /* end of api */ + +/** + * @brief Only used in async network stack and FEATURE_ASYNC_PROTOCOL_STACK must be selected + * + * @param [in] handle: specify the MQTT client. + * @param [in] event: specify the network event. + * @param [in] param: specify the network params. + * + * @retval -1 : Handle failed. + * @retval 0 : Handle successful. + * + */ +int IOT_MQTT_Nwk_Event_Handler(void *handle, iotx_mqtt_nwk_event_t event, iotx_mqtt_nwk_param_t *param); + +/* MQTT Configurations + * + * These switches will affect mqtt_api.c and IOT_MQTT_XXX() functions' behaviour + * + */ + +/* Default message length in bytes when PLATFORM_HAS_DYNMEM is not set */ +#define CONFIG_MQTT_MESSAGE_MAXLEN (1024) + +/* Default maximum length of topic name in byte when PLATFORM_HAS_DYNMEM is not set */ +#ifdef PLATFORM_HAS_DYNMEM +#define CONFIG_MQTT_TOPIC_MAXLEN (128) +#else +#define CONFIG_MQTT_TOPIC_MAXLEN (50) +#endif + +/* Default keepalive interval of MQTT request in second */ +#define CONFIG_MQTT_KEEPALIVE_INTERVAL (60) + + +/* Default offline subscribe list max length when PLATFORM_HAS_DYNMEM is not set */ +#ifndef CONFIG_MQTT_OFFLINE_TOPIC_MAXNUM +#define CONFIG_MQTT_OFFLINE_TOPIC_MAXNUM (5) +#endif + +/* Default timeout interval of MQTT request in millisecond */ +#define CONFIG_MQTT_REQUEST_TIMEOUT (2000) + +/* Minimum timeout interval of MQTT request in millisecond */ +#define CONFIG_MQTT_REQ_TIMEOUT_MIN (500) + +/* Maximum timeout interval of MQTT request in millisecond */ +#define CONFIG_MQTT_REQ_TIMEOUT_MAX (5000) + +/* Minimum keepalive interval of MQTT request in second */ +#define CONFIG_MQTT_KEEPALIVE_INTERVAL_MIN (30) + +/* Maximum keepalive interval of MQTT request in second */ +#define CONFIG_MQTT_KEEPALIVE_INTERVAL_MAX (180) + +#if defined(__cplusplus) +} +#endif +#endif + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/mqtt_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/mqtt_internal.h new file mode 100644 index 00000000..92522504 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/mqtt_internal.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __IOTX_MQTT_INTERNAL_H__ +#define __IOTX_MQTT_INTERNAL_H__ + +#include +#include +#include +#include + +#include "infra_types.h" +#include "infra_defs.h" +#include "infra_string.h" +#include "infra_list.h" +#include "infra_log.h" +#include "infra_report.h" +#include "infra_net.h" +#include "infra_sha256.h" + +#include "dev_sign_api.h" +#include "mqtt_wrapper.h" +#include "iotx_mqtt_config.h" +#include "iotx_mqtt_client.h" + +#include "MQTTPacket.h" + +#ifdef INFRA_LOG + #include "infra_log.h" + #define mqtt_emerg(...) log_emerg("MQTT", __VA_ARGS__) + #define mqtt_crit(...) log_crit("MQTT", __VA_ARGS__) + #define mqtt_err(...) log_err("MQTT", __VA_ARGS__) + #define mqtt_warning(...) log_warning("MQTT", __VA_ARGS__) + #define mqtt_info(...) log_info("MQTT", __VA_ARGS__) + #define mqtt_debug(...) log_debug("MQTT", __VA_ARGS__) +#else + #define mqtt_emerg(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define mqtt_crit(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define mqtt_err(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define mqtt_warning(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define mqtt_info(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) + #define mqtt_debug(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#endif + +#endif /* __IOTX_MQTT_INTERNAL_H__ */ + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/mqtt_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/mqtt_wrapper.h new file mode 100644 index 00000000..08a68acb --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/mqtt/mqtt_wrapper.h @@ -0,0 +1,65 @@ +#include "infra_types.h" +#include "infra_defs.h" +#include "wrappers_defs.h" + +#include "mqtt_api.h" + +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); +void HAL_Printf(const char *fmt, ...); +uint64_t HAL_UptimeMs(void); +void HAL_SleepMs(uint32_t ms); +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); + +void *HAL_MutexCreate(void); +void HAL_MutexDestroy(void *mutex); +void HAL_MutexLock(void *mutex); +void HAL_MutexUnlock(void *mutex); + +int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN + 1]); +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN + 1]); +int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN + 1]); +int HAL_GetFirmwareVersion(char *version); + +#ifdef DYNAMIC_REGISTER +int HAL_SetDeviceSecret(char *device_secret); +int HAL_GetProductSecret(char product_secret[IOTX_PRODUCT_SECRET_LEN + 1]); +int HAL_Kv_Set(const char *key, const void *val, int len, int sync); +int HAL_Kv_Get(const char *key, void *val, int *buffer_len); +#endif + +#ifdef SUPPORT_TLS + uintptr_t HAL_SSL_Establish(const char *host, uint16_t port, const char *ca_crt, uint32_t ca_crt_len); + int32_t HAL_SSL_Destroy(uintptr_t handle); + int HAL_SSL_Write(uintptr_t handle, const char *buf, int len, int timeout_ms); + int HAL_SSL_Read(uintptr_t handle, char *buf, int len, int timeout_ms); +#else + int HAL_SSLHooks_set(ssl_hooks_t *hooks); + uintptr_t HAL_TCP_Establish(const char *host, uint16_t port); + int HAL_TCP_Destroy(uintptr_t fd); + int32_t HAL_TCP_Write(uintptr_t fd, const char *buf, uint32_t len, uint32_t timeout_ms); + int32_t HAL_TCP_Read(uintptr_t fd, char *buf, uint32_t len, uint32_t timeout_ms); +#endif + +/* mqtt protocol wrapper */ +void *wrapper_mqtt_init(iotx_mqtt_param_t *mqtt_params); +int wrapper_mqtt_connect(void *client); +int wrapper_mqtt_yield(void *client, int timeout_ms); +int wrapper_mqtt_check_state(void *client); +int wrapper_mqtt_subscribe(void *client, + const char *topicFilter, + iotx_mqtt_qos_t qos, + iotx_mqtt_event_handle_func_fpt topic_handle_func, + void *pcontext); +int wrapper_mqtt_subscribe_sync(void *client, + const char *topic_filter, + iotx_mqtt_qos_t qos, + iotx_mqtt_event_handle_func_fpt topic_handle_func, + void *pcontext, + int timeout_ms); +int wrapper_mqtt_unsubscribe(void *client, const char *topicFilter); +int wrapper_mqtt_publish(void *client, const char *topicName, iotx_mqtt_topic_info_pt topic_msg); +int wrapper_mqtt_release(void **pclient); +int wrapper_mqtt_nwk_event_handler(void *client, iotx_mqtt_nwk_event_t event, iotx_mqtt_nwk_param_t *param); + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/iotx_ota.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/iotx_ota.c new file mode 100644 index 00000000..f130a310 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/iotx_ota.c @@ -0,0 +1,1029 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "iotx_ota_internal.h" + +#if (OTA_SIGNAL_CHANNEL) == 1 + #include "ota_mqtt.c" +#elif (OTA_SIGNAL_CHANNEL) == 2 + #include "ota_coap.c" +#else + #error "NOT support yet!" +#endif + + +typedef struct { + const char *product_key; /* point to product key */ + const char *device_name; /* point to device name */ + + uint32_t id; /* message id */ + IOT_OTA_State_t state; /* OTA state */ + IOT_OTA_Type_t type; /* OTA Type */ + uint32_t size_last_fetched; /* size of last downloaded */ + uint32_t size_fetched; /* size of already downloaded */ + uint32_t size_file; /* size of file */ + char *purl; /* point to URL */ + char *version; /* point to string */ + char md5sum[33]; /* MD5 string */ + + void *md5; /* MD5 handle */ + void *sha256; /* Sha256 handle */ + void *ch_signal; /* channel handle of signal exchanged with OTA server */ + void *ch_fetch; /* channel handle of download */ + + /* cota */ + char *configId; + uint32_t configSize; + char *sign; + char *signMethod; + char *cota_url; + char *getType; + + char *digestsign; /* security ota*/ + int err; /* last error code */ + + ota_fetch_cb_fpt fetch_cb; /* fetch_callback */ + void *user_data; /* fetch_callback's user_data */ + + cota_fetch_cb_fpt fetch_cota_cb; + void *cota_user_data; + +} OTA_Struct_t, *OTA_Struct_pt; + + +/* check whether the progress state is valid or not */ +/* return: true, valid progress state; false, invalid progress state. */ +static int ota_check_progress(IOT_OTA_Progress_t progress) +{ + return ((progress >= IOT_OTAP_BURN_FAILED) + && (progress <= IOT_OTAP_FETCH_PERCENTAGE_MAX)); +} + + +int iotx_ota_set_fetch_callback(void *pt, ota_fetch_cb_fpt fetch_cb, void *user_data) +{ + OTA_Struct_pt ota_pt = (OTA_Struct_pt)pt; + + if (NULL == ota_pt || NULL == fetch_cb) { + return -1; + } + + ota_pt->fetch_cb = fetch_cb; + ota_pt->user_data = user_data; + return 0; +} + + +int iotx_ota_set_cota_fetch_callback(void *pt, cota_fetch_cb_fpt fetch_cb, void *user_data) +{ + OTA_Struct_pt ota_pt = (OTA_Struct_pt)pt; + + if (NULL == ota_pt || NULL == fetch_cb) { + return -1; + } + + ota_pt->fetch_cota_cb = fetch_cb; + ota_pt->cota_user_data = user_data; + return 0; +} + +#ifdef SUPPORT_SECURITY_OTA +static int ota_security_ota_check(void *pcontext) +{ + OTA_Struct_pt h_ota = (OTA_Struct_pt) pcontext; + if (h_ota->digestsign) { + printf("enter security check\n"); + HAL_Firmware_Need_Check_Security_Ota(1); + return HAL_OTA_Security_check(h_ota->digestsign, h_ota->sign, h_ota->signMethod); + } else { + HAL_Firmware_Need_Check_Security_Ota(0); + } + + return 0; +} +#endif + +static int ota_callback(void *pcontext, const char *msg, uint32_t msg_len, iotx_ota_topic_types_t type) +{ + const char *pvalue; + uint32_t val_len; + + OTA_Struct_pt h_ota = (OTA_Struct_pt) pcontext; + + if (h_ota->state == IOT_OTAS_FETCHING) { + OTA_LOG_INFO("In downloading state"); + return -1; + } + + switch (type) { + case IOTX_OTA_TOPIC_TYPE_DEVICE_REQUEST: + case IOTX_OTA_TOPIC_TYPE_DEVICE_UPGRATE: { + pvalue = otalib_JsonValueOf(msg, msg_len, "message", &val_len); + if (NULL == pvalue) { + OTA_LOG_ERROR("invalid json doc of OTA "); + return -1; + } + + /* check whether is positive message */ + if (!((strlen("success") == val_len) && (0 == strncmp(pvalue, "success", val_len)))) { + OTA_LOG_ERROR("fail state of json doc of OTA"); + return -1; + } + + /* get value of 'data' key */ + pvalue = otalib_JsonValueOf(msg, msg_len, "data", &val_len); + if (NULL == pvalue) { + OTA_LOG_ERROR("Not 'data' key in json doc of OTA"); + return -1; + } + + if (NULL != h_ota->digestsign) { + OTA_FREE(h_ota->digestsign); + h_ota->digestsign = NULL; + } + + if (0 != otalib_GetFotaParams(pvalue, val_len, &h_ota->version, &h_ota->size_file, + &h_ota->sign, &h_ota->signMethod, &h_ota->purl, &h_ota->digestsign)) { + OTA_LOG_ERROR("Get firmware parameter failed"); + return -1; + } +#ifdef SUPPORT_SECURITY_OTA + if (0 != ota_security_ota_check(pcontext)) { + OTA_LOG_ERROR("Check ota security failed"); + IOT_OTA_ReportProgress(pcontext, IOT_OTAP_CHECK_FALIED, NULL); + return -1; + } +#endif + h_ota->size_fetched = 0; + if (NULL != h_ota->md5) { + otalib_MD5Deinit(h_ota->md5); + } + h_ota->md5 = otalib_MD5Init(); + + if (NULL != h_ota->sha256) { + otalib_Sha256Deinit(h_ota->sha256); + } + h_ota->sha256 = otalib_Sha256Init(); + + if (NULL == (h_ota->ch_fetch = ofc_Init(h_ota->purl))) { + OTA_LOG_ERROR("Initialize fetch module failed"); + return -1; + } + + h_ota->type = IOT_OTAT_FOTA; + h_ota->state = IOT_OTAS_FETCHING; + + if (h_ota->fetch_cb) { + h_ota->fetch_cb(h_ota->user_data, 0, h_ota->size_file, h_ota->purl, h_ota->version); + } + } + break; + + case IOTX_OTA_TOPIC_TYPE_CONFIG_GET: { + pvalue = otalib_JsonValueOf(msg, msg_len, "code", &val_len); + if (NULL == pvalue) { + OTA_LOG_ERROR("invalid json doc of OTA "); + return -1; + } + + /* check whether is positive message */ + if (!((strlen("200") == val_len) && (0 == strncmp(pvalue, "200", val_len)))) { + OTA_LOG_ERROR("fail state of json doc of OTA"); + return -1; + } + + /* get value of 'data' key */ + pvalue = otalib_JsonValueOf(msg, msg_len, "data", &val_len); + if (NULL == pvalue) { + OTA_LOG_ERROR("Not 'data' key in json doc of OTA"); + return -1; + } + + if (0 != otalib_GetConfigParams(pvalue, val_len, &h_ota->configId, &h_ota->configSize, + &h_ota->sign, &h_ota->signMethod, &h_ota->cota_url, &h_ota->getType)) { + OTA_LOG_ERROR("Get firmware parameter failed"); + return -1; + } + + h_ota->size_file = h_ota->configSize; + h_ota->size_fetched = 0; + if (NULL != h_ota->md5) { + otalib_MD5Deinit(h_ota->md5); + } + h_ota->md5 = otalib_MD5Init(); + + if (NULL != h_ota->sha256) { + otalib_Sha256Deinit(h_ota->sha256); + } + h_ota->sha256 = otalib_Sha256Init(); + + if (NULL == (h_ota->ch_fetch = ofc_Init(h_ota->cota_url))) { + OTA_LOG_ERROR("Initialize fetch module failed"); + return -1; + } + + h_ota->type = IOT_OTAT_COTA; + h_ota->state = IOT_OTAS_FETCHING; + + if (h_ota->fetch_cota_cb) { + h_ota->fetch_cota_cb(h_ota->user_data, 0, h_ota->configId, h_ota->configSize, h_ota->sign, h_ota->signMethod, + h_ota->cota_url, h_ota->getType); + } + } + break; + + case IOTX_OTA_TOPIC_TYPE_CONFIG_PUSH: { + /* get value of 'params' key */ + pvalue = otalib_JsonValueOf(msg, msg_len, "params", &val_len); + if (NULL == pvalue) { + OTA_LOG_ERROR("Not 'data' key in json doc of OTA"); + return -1; + } + + if (0 != otalib_GetConfigParams(pvalue, val_len, &h_ota->configId, &h_ota->configSize, + &h_ota->sign, &h_ota->signMethod, &h_ota->cota_url, &h_ota->getType)) { + OTA_LOG_ERROR("Get firmware parameter failed"); + return -1; + } + + h_ota->size_file = h_ota->configSize; + h_ota->size_fetched = 0; + if (NULL != h_ota->md5) { + otalib_MD5Deinit(h_ota->md5); + } + h_ota->md5 = otalib_MD5Init(); + + if (NULL != h_ota->sha256) { + otalib_Sha256Deinit(h_ota->sha256); + } + h_ota->sha256 = otalib_Sha256Init(); + + if (NULL == (h_ota->ch_fetch = ofc_Init(h_ota->cota_url))) { + OTA_LOG_ERROR("Initialize fetch module failed"); + return -1; + } + + h_ota->type = IOT_OTAT_COTA; + h_ota->state = IOT_OTAS_FETCHING; + + if (h_ota->fetch_cota_cb) { + h_ota->fetch_cota_cb(h_ota->user_data, 0, h_ota->configId, h_ota->configSize, h_ota->sign, h_ota->signMethod, + h_ota->cota_url, h_ota->getType); + } + } + break; + + default: + return -1; + break; + } + + return 0; +} + +static int g_ota_is_initialized = 0; + +/* Initialize OTA module */ +void *IOT_OTA_Init(const char *product_key, const char *device_name, void *ch_signal) +{ + OTA_Struct_pt h_ota = NULL; + + if (1 == g_ota_is_initialized) { + OTA_LOG_ERROR("iot ota has been initialized"); + return NULL; + } + + if ((NULL == product_key) || (NULL == device_name)) { + OTA_LOG_ERROR("one or more parameters is invalid"); + return NULL; + } + + if (NULL == (h_ota = OTA_MALLOC(sizeof(OTA_Struct_t)))) { + OTA_LOG_ERROR("allocate failed"); + return NULL; + } + memset(h_ota, 0, sizeof(OTA_Struct_t)); + h_ota->type = IOT_OTAT_NONE; + h_ota->state = IOT_OTAS_UNINITED; + + h_ota->ch_signal = osc_Init(product_key, device_name, ch_signal, ota_callback, h_ota); + if (NULL == h_ota->ch_signal) { + OTA_LOG_ERROR("initialize signal channel failed"); + goto do_exit; + } + + h_ota->md5 = otalib_MD5Init(); + if (NULL == h_ota->md5) { + OTA_LOG_ERROR("initialize md5 failed"); + goto do_exit; + } + h_ota->sha256 = otalib_Sha256Init(); + if (NULL == h_ota->sha256) { + OTA_LOG_ERROR("initialize sha256 failed"); + goto do_exit; + } + + h_ota->product_key = product_key; + h_ota->device_name = device_name; + h_ota->state = IOT_OTAS_INITED; + g_ota_is_initialized = 1; + return h_ota; + +do_exit: + + if (NULL != h_ota->ch_signal) { + osc_Deinit(h_ota->ch_signal); + } + + if (NULL != h_ota->md5) { + otalib_MD5Deinit(h_ota->md5); + } + + if (NULL != h_ota->sha256) { + otalib_Sha256Deinit(h_ota->sha256); + } + + if (NULL != h_ota) { + OTA_FREE(h_ota); + } + + return NULL; + +#undef AOM_INFO_MSG_LEN +} + + +/* deinitialize OTA module */ +int IOT_OTA_Deinit(void *handle) +{ + OTA_Struct_pt h_ota = (OTA_Struct_pt) handle; + + if (NULL == h_ota) { + OTA_LOG_ERROR("handle is NULL"); + return IOT_OTAE_INVALID_PARAM; + } + + if (IOT_OTAS_UNINITED == h_ota->state) { + OTA_LOG_ERROR("handle is uninitialized"); + h_ota->err = IOT_OTAE_INVALID_STATE; + return -1; + } + + g_ota_is_initialized = 0; + + if (NULL != h_ota->ch_signal) { + osc_Deinit(h_ota->ch_signal); + } + + if (NULL != h_ota->ch_fetch) { + ofc_Deinit(h_ota->ch_fetch); + } + + if (NULL != h_ota->md5) { + otalib_MD5Deinit(h_ota->md5); + } + + if (NULL != h_ota->sha256) { + otalib_Sha256Deinit(h_ota->sha256); + } + + if (NULL != h_ota->purl) { + OTA_FREE(h_ota->purl); + } + + if (NULL != h_ota->version) { + OTA_FREE(h_ota->version); + } + + if (NULL != h_ota->configId) { + OTA_FREE(h_ota->configId); + } + + if (NULL != h_ota->sign) { + OTA_FREE(h_ota->sign); + } + + if (NULL != h_ota->signMethod) { + OTA_FREE(h_ota->signMethod); + } + + if (NULL != h_ota->cota_url) { + OTA_FREE(h_ota->cota_url); + } + + if (NULL != h_ota->getType) { + OTA_FREE(h_ota->getType); + } + + if (NULL != h_ota->digestsign) { + OTA_FREE(h_ota->digestsign); + } + + OTA_FREE(h_ota); + return 0; +} + + +#define OTA_VERSION_STR_LEN_MIN (1) +#define OTA_VERSION_STR_LEN_MAX (32) + +int IOT_OTA_ReportVersion(void *handle, const char *version) +{ +#define MSG_INFORM_LEN (128) + + int ret, len; + char *msg_informed; + OTA_Struct_pt h_ota = (OTA_Struct_pt) handle; + + if ((NULL == h_ota) || (NULL == version)) { + OTA_LOG_ERROR("one or more invalid parameter"); + return IOT_OTAE_INVALID_PARAM; + } + + len = strlen(version); + if ((len < OTA_VERSION_STR_LEN_MIN) || (len > OTA_VERSION_STR_LEN_MAX)) { + OTA_LOG_ERROR("version string is invalid: must be [1, 32] chars"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } + + if (IOT_OTAS_UNINITED == h_ota->state) { + OTA_LOG_ERROR("handle is uninitialized"); + h_ota->err = IOT_OTAE_INVALID_STATE; + return -1; + } + + if (NULL == (msg_informed = OTA_MALLOC(MSG_INFORM_LEN))) { + OTA_LOG_ERROR("allocate for msg_informed failed"); + h_ota->err = IOT_OTAE_NOMEM; + return -1; + } + + ret = otalib_GenInfoMsg(msg_informed, MSG_INFORM_LEN, h_ota->id, version); + if (ret != 0) { + OTA_LOG_ERROR("generate inform message failed"); + h_ota->err = ret; + ret = -1; + goto do_exit; + } + + ret = osc_ReportVersion(h_ota->ch_signal, msg_informed); + if (0 != ret) { + OTA_LOG_ERROR("Report version failed"); + h_ota->err = ret; + ret = -1; + goto do_exit; + } + ret = 0; + +do_exit: + if (NULL != msg_informed) { + OTA_FREE(msg_informed); + } + return ret; + +#undef MSG_INFORM_LEN +} + +int iotx_req_image(void *handle, const char *version) +{ +#define MSG_REQUEST_LEN (128) + + int ret, len; + char *msg_informed; + OTA_Struct_pt h_ota = (OTA_Struct_pt) handle; + + if ((NULL == h_ota) || (NULL == version)) { + OTA_LOG_ERROR("one or more invalid parameter"); + return IOT_OTAE_INVALID_PARAM; + } + + len = strlen(version); + if ((len < OTA_VERSION_STR_LEN_MIN) || (len > OTA_VERSION_STR_LEN_MAX)) { + OTA_LOG_ERROR("version string is invalid: must be [1, 32] chars"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } + + if (IOT_OTAS_UNINITED == h_ota->state) { + OTA_LOG_ERROR("handle is uninitialized"); + h_ota->err = IOT_OTAE_INVALID_STATE; + return -1; + } + + if (IOT_OTAS_FETCHING == h_ota->state) { + OTA_LOG_ERROR("ota is busying"); + h_ota->err = IOT_OTAE_INVALID_STATE; + return -1; + } + + if (NULL == (msg_informed = OTA_MALLOC(MSG_REQUEST_LEN))) { + OTA_LOG_ERROR("allocate for msg_informed failed"); + h_ota->err = IOT_OTAE_NOMEM; + return -1; + } + + ret = otalib_GenInfoMsg(msg_informed, MSG_REQUEST_LEN, h_ota->id, version); + if (ret != 0) { + OTA_LOG_ERROR("generate request image message failed"); + h_ota->err = ret; + ret = -1; + goto do_exit; + } + + ret = osc_RequestImage(h_ota->ch_signal, msg_informed); + if (0 != ret) { + OTA_LOG_ERROR("Request image failed"); + h_ota->err = ret; + ret = -1; + goto do_exit; + } + ret = 0; + +do_exit: + if (NULL != msg_informed) { + OTA_FREE(msg_informed); + } + return ret; + +#undef MSG_REQUEST_LEN +} + + +int IOT_OTA_ReportProgress(void *handle, IOT_OTA_Progress_t progress, const char *msg) +{ +#define MSG_REPORT_LEN (256) + + int ret = -1; + char *msg_reported; + OTA_Struct_pt h_ota = (OTA_Struct_pt) handle; + + if (NULL == handle) { + OTA_LOG_ERROR("handle is NULL"); + return IOT_OTAE_INVALID_PARAM; + } + + if (IOT_OTAS_UNINITED == h_ota->state) { + OTA_LOG_ERROR("handle is uninitialized"); + h_ota->err = IOT_OTAE_INVALID_STATE; + return -1; + } + if (!ota_check_progress(progress)) { + OTA_LOG_ERROR("progress is a invalid parameter"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } + + if (NULL == (msg_reported = OTA_MALLOC(MSG_REPORT_LEN))) { + OTA_LOG_ERROR("allocate for msg_reported failed"); + h_ota->err = IOT_OTAE_NOMEM; + return -1; + } + + ret = otalib_GenReportMsg(msg_reported, MSG_REPORT_LEN, h_ota->id, progress, msg); + if (0 != ret) { + OTA_LOG_ERROR("generate reported message failed"); + h_ota->err = ret; + goto do_exit; + } + + ret = osc_ReportProgress(h_ota->ch_signal, msg_reported); + if (0 != ret) { + OTA_LOG_ERROR("Report progress failed"); + h_ota->err = ret; + goto do_exit; + } + + ret = 0; + +do_exit: + if (NULL != msg_reported) { + OTA_FREE(msg_reported); + } + return ret; + +#undef MSG_REPORT_LEN +} + +int iotx_ota_get_config(void *handle, const char *configScope, const char *getType, const char *attributeKeys) +{ +#define MSG_REPORT_LEN (256) + + int ret = -1; + char *msg_get; + char topic[OTA_MQTT_TOPIC_LEN] = {0}; + OTA_Struct_pt h_ota = (OTA_Struct_pt) handle; + iotx_mqtt_topic_info_t topic_info; + + memset(&topic_info, 0, sizeof(iotx_mqtt_topic_info_t)); + + if (NULL == handle) { + OTA_LOG_ERROR("handle is NULL"); + return IOT_OTAE_INVALID_PARAM; + } + + if (IOT_OTAS_UNINITED == h_ota->state) { + OTA_LOG_ERROR("handle is uninitialized"); + h_ota->err = IOT_OTAE_INVALID_STATE; + return -1; + } + + if (IOT_OTAS_FETCHING == h_ota->state) { + OTA_LOG_ERROR("ota is busying"); + h_ota->err = IOT_OTAE_INVALID_STATE; + return -1; + } + + if (NULL == (msg_get = OTA_MALLOC(MSG_REPORT_LEN))) { + OTA_LOG_ERROR("allocate for msg_reported failed"); + h_ota->err = IOT_OTAE_NOMEM; + return -1; + } + + if (0 > HAL_Snprintf(topic, + OTA_MQTT_TOPIC_LEN, + "/sys/%s/%s/thing/config/get", + h_ota->product_key, + h_ota->device_name)) { + goto do_exit; + }; + + if (0 > HAL_Snprintf(msg_get, + MSG_REPORT_LEN, + "{\"id\" : %d,\"version\":\"1.0\",\"params\":{\"configScope\":\"%s\",\"getType\":\"%s\",\"attributeKeys\":\"%s\"},\"method\":\"thing.config.get\"}", + h_ota->id, + configScope, + getType, + attributeKeys)) { + goto do_exit; + }; + OTA_LOG_INFO(msg_get); + topic_info.qos = IOTX_MQTT_QOS0; + topic_info.payload = (void *)msg_get; + topic_info.payload_len = strlen(msg_get); + + ret = osc_RequestConfig(h_ota->ch_signal, topic, &topic_info); + if (ret < 0) { + OTA_LOG_ERROR("publish failed"); + return IOT_OTAE_OSC_FAILED; + } + + ret = 0; + +do_exit: + if (NULL != msg_get) { + OTA_FREE(msg_get); + } + return ret; + +#undef MSG_REPORT_LEN +} + + +/* check whether is downloading */ +int IOT_OTA_IsFetching(void *handle) +{ + OTA_Struct_pt h_ota = (OTA_Struct_pt)handle; + + if (NULL == handle) { + OTA_LOG_ERROR("handle is NULL"); + return 0; + } + + if (IOT_OTAS_UNINITED == h_ota->state) { + OTA_LOG_ERROR("handle is uninitialized"); + h_ota->err = IOT_OTAE_INVALID_STATE; + return 0; + } + + return (IOT_OTAS_FETCHING == h_ota->state); +} + + +/* check whether fetch over */ +int IOT_OTA_IsFetchFinish(void *handle) +{ + OTA_Struct_pt h_ota = (OTA_Struct_pt) handle; + + if (NULL == handle) { + OTA_LOG_ERROR("handle is NULL"); + return 0; + } + + if (IOT_OTAS_UNINITED == h_ota->state) { + OTA_LOG_ERROR("handle is uninitialized"); + h_ota->err = IOT_OTAE_INVALID_STATE; + return 0; + } + + return (IOT_OTAS_FETCHED == h_ota->state); +} + + +int IOT_OTA_FetchYield(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s) +{ + int ret; + OTA_Struct_pt h_ota = (OTA_Struct_pt) handle; + + if ((NULL == handle) || (NULL == buf) || (0 == buf_len)) { + OTA_LOG_ERROR("invalid parameter"); + return IOT_OTAE_INVALID_PARAM; + } + + if (IOT_OTAS_FETCHING != h_ota->state) { + h_ota->err = IOT_OTAE_INVALID_STATE; + return IOT_OTAE_INVALID_STATE; + } + + ret = ofc_Fetch(h_ota->ch_fetch, buf, buf_len, timeout_s); + if (ret < 0) { + OTA_LOG_ERROR("Fetch firmware failed"); + h_ota->state = IOT_OTAS_FETCHED; + h_ota->type = IOT_OTAT_NONE; + h_ota->err = IOT_OTAE_FETCH_FAILED; + + if (h_ota->fetch_cb && h_ota->purl) { + h_ota->fetch_cb(h_ota->user_data, 1, h_ota->size_file, h_ota->purl, h_ota->version); + /* remove */ + h_ota->purl = NULL; + } else if (h_ota->fetch_cota_cb && h_ota->cota_url) { + h_ota->fetch_cota_cb(h_ota->user_data, 1, h_ota->configId, h_ota->configSize, h_ota->sign, h_ota->signMethod, + h_ota->cota_url, h_ota->getType); + /* remove */ + h_ota->cota_url = NULL; + } + h_ota->size_fetched = 0; + return -1; + } else if (0 == h_ota->size_fetched) { + /* force report status in the first */ + IOT_OTA_ReportProgress(h_ota, IOT_OTAP_FETCH_PERCENTAGE_MIN, "Enter in downloading state"); + } + + otalib_MD5Update(h_ota->md5, buf, ret); + otalib_Sha256Update(h_ota->sha256, buf, ret); + h_ota->size_last_fetched = ret; + h_ota->size_fetched += ret; + + if (h_ota->size_fetched >= h_ota->size_file) { + h_ota->type = IOT_OTAT_NONE; + h_ota->state = IOT_OTAS_FETCHED; + if (h_ota->fetch_cb && h_ota->purl) { + h_ota->fetch_cb(h_ota->user_data, 1, h_ota->size_file, h_ota->purl, h_ota->version); + /* remove */ + h_ota->purl = NULL; + } else if (h_ota->fetch_cota_cb && h_ota->cota_url) { + h_ota->fetch_cota_cb(h_ota->user_data, 1, h_ota->configId, h_ota->configSize, h_ota->sign, h_ota->signMethod, + h_ota->cota_url, h_ota->getType); + /* remove */ + h_ota->cota_url = NULL; + } + } + + return ret; +} + + +int IOT_OTA_Ioctl(void *handle, IOT_OTA_CmdType_t type, void *buf, int buf_len) +{ + OTA_Struct_pt h_ota = (OTA_Struct_pt) handle; + + if ((NULL == handle) || (NULL == buf) || (0 == buf_len)) { + OTA_LOG_ERROR("invalid parameter"); + return IOT_OTAE_INVALID_PARAM; + } + + if (h_ota->state < IOT_OTAS_FETCHING) { + h_ota->err = IOT_OTAE_INVALID_STATE; + return IOT_OTAE_INVALID_STATE; + } + + switch (type) { + case IOT_OTAG_COTA_CONFIG_ID: { + char **value = (char **)buf; + if (value == NULL || *value != NULL || h_ota->configId == NULL) { + OTA_LOG_ERROR("Invalid parameter"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } else { + *value = OTA_API_MALLOC(strlen(h_ota->configId) + 1); + if (*value == NULL) { + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } + memset(*value, 0, strlen(h_ota->configId) + 1); + memcpy(*value, h_ota->configId, strlen(h_ota->configId)); + return 0; + } + } + break; + case IOT_OTAG_COTA_CONFIG_SIZE: { + if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) { + OTA_LOG_ERROR("Invalid parameter"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } else { + *((uint32_t *)buf) = h_ota->configSize; + return 0; + } + } + break; + case IOT_OTAG_COTA_SIGN: { + char **value = (char **)buf; + if (value == NULL || *value != NULL || h_ota->sign == NULL) { + OTA_LOG_ERROR("Invalid parameter"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } else { + *value = OTA_API_MALLOC(strlen(h_ota->sign) + 1); + if (*value == NULL) { + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } + memset(*value, 0, strlen(h_ota->sign) + 1); + memcpy(*value, h_ota->sign, strlen(h_ota->sign)); + return 0; + } + } + break; + case IOT_OTAG_COTA_SIGN_METHOD: { + char **value = (char **)buf; + if (value == NULL || *value != NULL || h_ota->signMethod == NULL) { + OTA_LOG_ERROR("Invalid parameter"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } else { + *value = OTA_API_MALLOC(strlen(h_ota->signMethod) + 1); + if (*value == NULL) { + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } + memset(*value, 0, strlen(h_ota->signMethod) + 1); + memcpy(*value, h_ota->signMethod, strlen(h_ota->signMethod)); + return 0; + } + } + break; + case IOT_OTAG_COTA_URL: { + char **value = (char **)buf; + if (value == NULL || *value != NULL || h_ota->cota_url == NULL) { + OTA_LOG_ERROR("Invalid parameter"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } else { + *value = OTA_API_MALLOC(strlen(h_ota->cota_url) + 1); + if (*value == NULL) { + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } + memset(*value, 0, strlen(h_ota->cota_url) + 1); + memcpy(*value, h_ota->cota_url, strlen(h_ota->cota_url)); + return 0; + } + } + break; + case IOT_OTAG_COTA_GETTYPE: { + char **value = (char **)buf; + if (value == NULL || *value != NULL || h_ota->getType == NULL) { + OTA_LOG_ERROR("Invalid parameter"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } else { + *value = OTA_API_MALLOC(strlen(h_ota->getType) + 1); + if (*value == NULL) { + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } + memset(*value, 0, strlen(h_ota->getType) + 1); + memcpy(*value, h_ota->getType, strlen(h_ota->getType)); + return 0; + } + } + break; + case IOT_OTAG_OTA_TYPE: { + if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) { + OTA_LOG_ERROR("Invalid parameter"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } else { + *((uint32_t *)buf) = h_ota->type; + return 0; + } + } + break; + case IOT_OTAG_FETCHED_SIZE: + if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) { + OTA_LOG_ERROR("Invalid parameter"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } else { + *((uint32_t *)buf) = h_ota->size_fetched; + return 0; + } + + case IOT_OTAG_FILE_SIZE: + if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) { + OTA_LOG_ERROR("Invalid parameter"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } else { + *((uint32_t *)buf) = h_ota->size_file; + return 0; + }; + + case IOT_OTAG_VERSION: { + strncpy(buf, h_ota->version, buf_len); + ((char *)buf)[buf_len - 1] = '\0'; + } + break; + + case IOT_OTAG_MD5SUM: + strncpy(buf, h_ota->md5sum, buf_len); + ((char *)buf)[buf_len - 1] = '\0'; + break; + + case IOT_OTAG_CHECK_FIRMWARE: + if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) { + OTA_LOG_ERROR("Invalid parameter"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } else if (h_ota->state != IOT_OTAS_FETCHED) { + h_ota->err = IOT_OTAE_INVALID_STATE; + OTA_LOG_ERROR("Firmware can be checked in IOT_OTAS_FETCHED state only"); + return -1; + } else { + char md5_str[33]; + otalib_MD5Finalize(h_ota->md5, md5_str); + OTA_LOG_DEBUG("origin=%s, now=%s", h_ota->md5sum, md5_str); + if (0 == strcmp(h_ota->md5sum, md5_str)) { + *((uint32_t *)buf) = 1; + } else { + *((uint32_t *)buf) = 0; + IOT_OTA_ReportProgress(h_ota, IOT_OTAP_CHECK_FALIED, NULL); + OTA_LOG_ERROR("image checksum compare failed"); + } + return 0; + } + case IOT_OTAG_CHECK_CONFIG: + if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) { + OTA_LOG_ERROR("Invalid parameter"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } else if (h_ota->state != IOT_OTAS_FETCHED) { + h_ota->err = IOT_OTAE_INVALID_STATE; + OTA_LOG_ERROR("Config can be checked in IOT_OTAS_FETCHED state only"); + return -1; + } else { + if (0 == strncmp(h_ota->signMethod, "Md5", strlen(h_ota->signMethod))) { + char md5_str[33]; + otalib_MD5Finalize(h_ota->md5, md5_str); + OTA_LOG_DEBUG("origin=%s, now=%s", h_ota->sign, md5_str); + printf("MD5:origin=%s, now=%s\n", h_ota->sign, md5_str); + if (0 == strcmp(h_ota->sign, md5_str)) { + *((uint32_t *)buf) = 1; + } else { + *((uint32_t *)buf) = 0; + } + } + if (0 == strncmp(h_ota->signMethod, "SHA256", strlen(h_ota->signMethod))) { + char sha256_str[65]; + otalib_Sha256Finalize(h_ota->sha256, sha256_str); + OTA_LOG_DEBUG("origin=%s, now=%s", h_ota->sign, sha256_str); + printf("SHA256:origin=%s, now=%s\n", h_ota->sign, sha256_str); + if (0 == strcmp(h_ota->sign, sha256_str)) { + *((uint32_t *)buf) = 1; + } else { + *((uint32_t *)buf) = 0; + } + } + return 0; + } + case IOT_OTAG_RESET_FETCHED_SIZE: { + h_ota->size_fetched = 0; + return 0; + } + default: + OTA_LOG_ERROR("invalid cmd type"); + h_ota->err = IOT_OTAE_INVALID_PARAM; + return -1; + } + + return 0; +} + + +/* Get last error code */ +int IOT_OTA_GetLastError(void *handle) +{ + OTA_Struct_pt h_ota = (OTA_Struct_pt) handle; + + if (NULL == handle) { + OTA_LOG_ERROR("handle is NULL"); + return IOT_OTAE_INVALID_PARAM; + } + + return h_ota->err; +} + + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/iotx_ota.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/iotx_ota.h new file mode 100644 index 00000000..816e31ea --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/iotx_ota.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __IOTX_OTA_H__ +#define __IOTX_OTA_H__ + +int iotx_ota_get_config(void *handle, const char *configScope, const char *getType, + const char *attributeKeys); + +int iotx_req_image(void *handle, const char *version); + +#endif /* #ifndef __IOTX_OTA_H__ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/iotx_ota_config.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/iotx_ota_config.h new file mode 100644 index 00000000..3536a436 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/iotx_ota_config.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __IOTX_OTA_CONFIG_H__ +#define __IOTX_OTA_CONFIG_H__ + +#ifndef OTA_SIGNAL_CHANNEL + #define OTA_SIGNAL_CHANNEL (1) +#endif + +#endif /* __IOTX_OTA_CONFIG_H__ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/iotx_ota_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/iotx_ota_internal.h new file mode 100644 index 00000000..e08cfa3a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/iotx_ota_internal.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef _IOTX_OTA_INTERNAL_H_ +#define _IOTX_OTA_INTERNAL_H_ + +#include +#include +#include + +#include "infra_httpc.h" +#include "infra_string.h" +#include "infra_md5.h" +#include "infra_sha256.h" +#include "infra_json_parser.h" +#include "ota_api.h" +#include "iotx_ota_config.h" +#include "ota_wrapper.h" + +#ifdef INFRA_MEM_STATS +#include "infra_mem_stats.h" +#define OTA_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "ota") +#define OTA_FREE(ptr) LITE_free(ptr) +#define OTA_API_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "ota.api") +#define OTA_API_FREE(ptr) LITE_free(ptr) +#else +#define OTA_MALLOC(size) HAL_Malloc(size) +#define OTA_FREE(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#define OTA_API_MALLOC(size) HAL_Malloc(size) +#define OTA_API_FREE(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +#define OTA_SNPRINTF HAL_Snprintf + +#ifdef INFRA_LOG +#include "infra_log.h" +#define OTA_LOG_CRIT(...) log_crit("ota", __VA_ARGS__) +#define OTA_LOG_ERROR(...) log_err("ota", __VA_ARGS__) +#define OTA_LOG_WRN(...) log_warning("ota", __VA_ARGS__) +#define OTA_LOG_INFO(...) log_info("ota", __VA_ARGS__) +#define OTA_LOG_DEBUG(...) log_debug("ota", __VA_ARGS__) +#else +#define OTA_LOG_CRIT(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define OTA_LOG_ERROR(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define OTA_LOG_WRN(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define OTA_LOG_INFO(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#define OTA_LOG_DEBUG(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0) +#endif + +typedef enum { + IOTX_OTA_TOPIC_TYPE_DEVICE_REQUEST = 1, + IOTX_OTA_TOPIC_TYPE_DEVICE_UPGRATE = 2, + IOTX_OTA_TOPIC_TYPE_CONFIG_GET = 3, + IOTX_OTA_TOPIC_TYPE_CONFIG_PUSH = 4, + IOTX_OTA_TOPIC_TYPE_MAX +} iotx_ota_topic_types_t; + +typedef int (*ota_cb_fpt)(void *pcontext, const char *msg, uint32_t msg_len, iotx_ota_topic_types_t type); +/* is_fetch = 0; start fetch */ +/* is_fetch = 1; stop fetch */ +typedef void(*ota_fetch_cb_fpt)(void *user_data, int is_fetch, uint32_t size_file, char *purl, char *version); +/* is_fetch = 0; start fetch */ +/* is_fetch = 1; stop fetch */ +typedef void(*cota_fetch_cb_fpt)(void *user_data, int is_fetch, char *configId, uint32_t configSize, char *sign, \ + char *signMethod, char *url, char *getType); + +int iotx_ota_set_fetch_callback(void *pt, ota_fetch_cb_fpt fetch_cb, void *user_data); +int iotx_ota_set_cota_fetch_callback(void *pt, cota_fetch_cb_fpt fetch_cb, void *user_data); + +const char *otalib_JsonValueOf(const char *json, uint32_t json_len, const char *key, uint32_t *val_len); +void *otalib_MD5Init(void); +void otalib_MD5Update(void *md5, const char *buf, size_t buf_len); +void otalib_MD5Finalize(void *md5, char *output_str); +void otalib_MD5Deinit(void *md5); +void *otalib_Sha256Init(void); +void otalib_Sha256Update(void *sha256, const char *buf, size_t buf_len); +void otalib_Sha256Finalize(void *sha256, char *output_str); +void otalib_Sha256Deinit(void *sha256); +int otalib_GetFirmwareFixlenPara(const char *json_doc, + size_t json_doc_len, + const char *key, + char *dest, + size_t dest_len); +int otalib_GetFirmwareVarlenPara(const char *json_doc, + size_t json_doc_len, + const char *key, + char **dest); +int otalib_GetParams(const char *json_doc, uint32_t json_len, char **url, char **version, char *md5, + uint32_t *file_size); +int otalib_GetConfigParams(const char *json_doc, uint32_t json_len, char **configId, uint32_t *configSize, char **sign, + char **signMethod, char **url, char **getType); +int otalib_GetFotaParams(const char *json_doc, uint32_t json_len, char **version, uint32_t *file_size, char **sign, + char **signMethod, char **url, char **digestsign); +int otalib_GenInfoMsg(char *buf, size_t buf_len, uint32_t id, const char *version); +int otalib_GenReportMsg(char *buf, size_t buf_len, uint32_t id, int progress, const char *msg_detail); + +void *ofc_Init(char *url); +int32_t ofc_Fetch(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s); +int ofc_Deinit(void *handle); +#ifdef SUPPORT_SECURITY_OTA +int HAL_OTA_Security_check(const char *digest, const char *sign, const char *signMethod); +int HAL_Firmware_Check_Rsa_Key(char *buffer, uint32_t length); +void HAL_Firmware_Need_Check_Security_Ota(uint8_t flag); +#endif +#endif /* _IOTX_OTA_INTERNAL_H_ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_api.h new file mode 100644 index 00000000..0ff36ca8 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_api.h @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __OTA_EXPORT_H__ +#define __OTA_EXPORT_H__ + +#include "infra_types.h" +#include "infra_defs.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#define OTA_CH_SIGNAL_MQTT (0) +#define OTA_CH_SIGNAL_COAP (1) +#define OTA_CH_FETCH_HTTP (1) + + +typedef enum { + + IOT_OTAE_GENERAL = -1, + IOT_OTAE_INVALID_PARAM = -2, + IOT_OTAE_INVALID_STATE = -3, + IOT_OTAE_STR_TOO_LONG = -4, + IOT_OTAE_FETCH_FAILED = -5, + IOT_OTAE_NOMEM = -6, + IOT_OTAE_OSC_FAILED = -7, + IOT_OTAE_NONE = 0, + +} IOT_OTA_Err_t; + + +/* State of OTA */ +typedef enum { + IOT_OTAS_UNINITED = 0, /* Uninitialized State */ + IOT_OTAS_INITED, /* Initialized State */ + IOT_OTAS_FETCHING, /* Fetching firmware */ + IOT_OTAS_FETCHED /* Fetching firmware finish */ +} IOT_OTA_State_t; + +typedef enum { + IOT_OTAT_NONE, + IOT_OTAT_COTA, + IOT_OTAT_FOTA +} IOT_OTA_Type_t; + +/* Progress of OTA */ +typedef enum { + + /* Burn firmware file failed */ + IOT_OTAP_BURN_FAILED = -4, + + /* Check firmware file failed */ + IOT_OTAP_CHECK_FALIED = -3, + + /* Fetch firmware file failed */ + IOT_OTAP_FETCH_FAILED = -2, + + /* Initialized failed */ + IOT_OTAP_GENERAL_FAILED = -1, + + + /* [0, 100], percentage of fetch progress */ + + /* The minimum percentage of fetch progress */ + IOT_OTAP_FETCH_PERCENTAGE_MIN = 0, + + /* The maximum percentage of fetch progress */ + IOT_OTAP_FETCH_PERCENTAGE_MAX = 100 + +} IOT_OTA_Progress_t; + + +typedef enum { + IOT_OTAG_COTA_CONFIG_ID, + IOT_OTAG_COTA_CONFIG_SIZE, + IOT_OTAG_COTA_SIGN, + IOT_OTAG_COTA_SIGN_METHOD, + IOT_OTAG_COTA_URL, + IOT_OTAG_COTA_GETTYPE, + IOT_OTAG_OTA_TYPE, + IOT_OTAG_FETCHED_SIZE, /* option for get already fetched size */ + IOT_OTAG_FILE_SIZE, /* size of file */ + IOT_OTAG_MD5SUM, /* md5 in string format */ + IOT_OTAG_VERSION, /* version in string format */ + IOT_OTAG_CHECK_FIRMWARE, /* Check firmware is valid or not */ + IOT_OTAG_CHECK_CONFIG, /* Check config file is valid or not */ + IOT_OTAG_RESET_FETCHED_SIZE /* reset the size_fetched parameter to be 0 */ +} IOT_OTA_CmdType_t; + +/** @defgroup group_api api + * @{ + */ + +/** @defgroup group_api_ota ota + * @{ + */ + +/** + * @brief Initialize OTA module, and return handle. + * The MQTT client must be construct before calling this interface. + * + * @param [in] product_key: specify the product key. + * @param [in] device_name: specify the device name. + * @param [in] ch_signal: specify the signal channel. + * + * @retval 0 : Successful. + * @retval -1 : Failed. + * @see None. + */ +DLL_IOT_API void *IOT_OTA_Init(const char *product_key, const char *device_name, void *ch_signal); + + +/** + * @brief Deinitialize OTA module specified by the 'handle', and release the related resource. + * You must call this interface to release resource if reboot is not invoked after downloading. + * + * @param [in] handle: specify the OTA module. + * + * @retval 0 : Successful. + * @retval < 0 : Failed, the value is error code. + * @see None. + */ +DLL_IOT_API int IOT_OTA_Deinit(void *handle); + + +/** + * @brief Report firmware version information to OTA server (optional). + * NOTE: please + * + * @param [in] handle: specify the OTA module. + * @param [in] version: specify the firmware version in string format. + * + * @retval 0 : Successful. + * @retval < 0 : Failed, the value is error code. + * @see None. + */ +DLL_IOT_API int IOT_OTA_ReportVersion(void *handle, const char *version); + +/** + * @brief Report detail progress to OTA server (optional). + * NOTE: please + * + * @param [in] handle: specify the OTA module. + * @param [in] progress: specify the progress defined by 'IOT_OTA_Progress_t'. + * @param [in] msg: detail progress information in string. + * + * @retval 0 : Successful. + * @retval < 0 : Failed, the value is error code. + * @see None. + */ +DLL_IOT_API int IOT_OTA_ReportProgress(void *handle, IOT_OTA_Progress_t progress, const char *msg); + + +/** + * @brief Check whether is on fetching state + * + * @param [in] handle: specify the OTA module. + * + * @retval 1 : Yes. + * @retval 0 : No. + * @see None. + */ +DLL_IOT_API int IOT_OTA_IsFetching(void *handle); + + +/** + * @brief Check whether is on end-of-fetch state. + * + * @param [in] handle: specify the OTA module. + * + * @retval 1 : Yes. + * @retval 0 : False. + * @see None. + */ +DLL_IOT_API int IOT_OTA_IsFetchFinish(void *handle); + + +/** + * @brief fetch firmware from remote server with specific timeout value. + * NOTE: If you want to download more faster, the bigger 'buf' should be given. + * + * @param [in] handle: specify the OTA module. + * @param [out] buf: specify the space for storing firmware data. + * @param [in] buf_len: specify the length of 'buf' in bytes. + * @param [in] timeout_s: specify the timeout value in second. + * + * @retval < 0 : Error occur.. + * @retval 0 : No any data be downloaded in 'timeout_s' timeout period. + * @retval (0, len] : The length of data be downloaded in 'timeout_s' timeout period in bytes. + * @see None. + */ +DLL_IOT_API int IOT_OTA_FetchYield(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s); + + +/** + * @brief Get OTA information specified by 'type'. + * By this interface, you can get information like state, size of file, md5 of file, etc. + * + * @param [in] handle: handle of the specific OTA + * @param [in] type: specify what information you want, see detail 'IOT_OTA_CmdType_t' + * @param [out] buf: specify buffer for data exchange + * @param [in] buf_len: specify the length of 'buf' in byte. + * @return + @verbatim + NOTE: + 1) When type is IOT_OTAG_FETCHED_SIZE, 'buf' should be pointer of uint32_t, and 'buf_len' should be 4. + 2) When type is IOT_OTAG_FILE_SIZE, 'buf' should be pointer of uint32_t, and 'buf_len' should be 4. + 3) When type is IOT_OTAG_MD5SUM, 'buf' should be a buffer, and 'buf_len' should be 33. + 4) When type is IOT_OTAG_VERSION, 'buf' should be a buffer, and 'buf_len' should be OTA_VERSION_LEN_MAX. + 5) When type is IOT_OTAG_CHECK_FIRMWARE, 'buf' should be pointer of uint32_t, and 'buf_len' should be 4. + 0, firmware is invalid; 1, firmware is valid. + @endverbatim + * + * @retval 0 : Successful. + * @retval < 0 : Failed, the value is error code. + * @see None. + */ +DLL_IOT_API int IOT_OTA_Ioctl(void *handle, IOT_OTA_CmdType_t type, void *buf, int buf_len); + + +/** + * @brief Get last error code. + * + * @param [in] handle: specify the OTA module. + * + * @return The error code. + * @see None. + */ +DLL_IOT_API int IOT_OTA_GetLastError(void *handle); + +/** @} */ /* end of api_ota */ +/** @} */ /* end of api */ + +#if defined(__cplusplus) +} +#endif + +#endif /* __OTA_EXPORT_H__ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_coap.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_coap.c new file mode 100644 index 00000000..70ce80a6 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_coap.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __OTA_COAP_C_H__ +#define __OTA_COAP_C_H__ +#if (OTA_SIGNAL_CHANNEL) == 2 + +#include "iotx_ota_internal.h" + +/* OSC, OTA signal channel */ + +/* Specify the maximum characters of version */ +#define OSC_COAP_URI_MAX_LEN (135) /* IoTx CoAP uri maximal length */ + + +typedef struct { + void *coap; + const char *product_key; + const char *device_name; + ota_cb_fpt cb; + void *context; +} otacoap_Struct_t, *otacoap_Struct_pt; + + +static otacoap_Struct_pt h_osc_coap = NULL; + +static void otacoap_response_handler(void *arg, void *p_response) +{ + int len = 0; + unsigned char *p_payload = NULL; + iotx_coap_resp_code_t resp_code; + IOT_CoAP_GetMessageCode(p_response, &resp_code); + IOT_CoAP_GetMessagePayload(p_response, &p_payload, &len); + OTA_LOG_DEBUG("CoAP response code = %d", resp_code); + OTA_LOG_DEBUG("[CoAP msg_len=%d, msg=%s\r\n", len, p_payload); + + if ((NULL != h_osc_coap) && (NULL != p_payload)) { + h_osc_coap->cb(h_osc_coap->context, (const char *)p_payload, (uint32_t)len); + } +} + + +/* Generate topic name according to @ota_topic_type, @product_key, @device_name */ +/* and then copy to @buf. */ +/* 0, successful; -1, failed */ +static int otacoap_GenTopicName(char *buf, size_t buf_len, const char *ota_topic_type, const char *product_key, + const char *device_name) +{ + int ret; + + ret = OTA_SNPRINTF(buf, + buf_len, + "/topic/ota/device/%s/%s/%s", + ota_topic_type, + product_key, + device_name); + + if (ret >= buf_len) { + return -1; + } + + if (ret < 0) { + OTA_LOG_ERROR("snprintf failed"); + return -1; + } + + return 0; +} + +/* report progress of OTA */ +static int otacoap_Publish(otacoap_Struct_pt handle, const char *topic_type, const char *msg) +{ + int ret; + char uri[IOTX_URI_MAX_LEN + 1] = {0}; + iotx_message_t message; + message.p_payload = (unsigned char *)msg; + message.payload_len = (unsigned short)strlen(msg); + message.resp_callback = otacoap_response_handler; + message.msg_type = IOTX_MESSAGE_CON; + message.content_type = IOTX_CONTENT_TYPE_JSON; + + /* topic name: /topic/ota/device/${topic_type}/${productKey}/${deviceName} */ + ret = otacoap_GenTopicName(uri, OSC_COAP_URI_MAX_LEN, topic_type, handle->product_key, handle->device_name); + if (ret < 0) { + OTA_LOG_ERROR("generate topic name failed"); + return -1; + } + + if (IOTX_SUCCESS != (ret = IOT_CoAP_SendMessage(handle->coap, (char *)uri, &message))) { + OTA_LOG_ERROR("send CoAP msg failed%d", ret); + return -1; + } + + return 0; +} + + +void *osc_Init(const char *product_key, const char *device_name, void *ch_signal, ota_cb_fpt cb, void *context) +{ + otacoap_Struct_pt h_osc = NULL; + + if (NULL == (h_osc = OTA_MALLOC(sizeof(otacoap_Struct_t)))) { + OTA_LOG_ERROR("allocate for h_osc failed"); + return NULL; + } + + memset(h_osc, 0, sizeof(otacoap_Struct_t)); + + h_osc->coap = ch_signal; + h_osc->product_key = product_key; + h_osc->device_name = device_name; + h_osc->cb = cb; + h_osc->context = context; + + h_osc_coap = h_osc; + + return h_osc; +} + + +int osc_Deinit(void *handle) +{ + if (NULL != handle) { + OTA_FREE(handle); + } + + return 0; +} + +/* report progress of OTA */ +int osc_ReportProgress(void *handle, const char *msg) +{ + return otacoap_Publish(handle, "progress", msg); +} + + +/* report version of OTA firmware */ +int osc_ReportVersion(void *handle, const char *msg) +{ + static int state = 0; + int ret; + + if (0 == state) { /* report version in initial state */ + ret = otacoap_Publish(handle, "inform", msg); + if (0 != ret) { + return ret; + } + state = 1; + } + + /* request new firmware after initial state */ + return otacoap_Publish(handle, "request", msg); +} + +#endif /* #if (OTA_SIGNAL_CHANNEL) == 2 */ +#endif + + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_fetch.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_fetch.c new file mode 100644 index 00000000..12dece8f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_fetch.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "iotx_ota_internal.h" + +/* ofc, OTA fetch channel */ + +typedef struct { + + const char *url; + httpclient_t http; /* http client */ + httpclient_data_t http_data; /* http client data */ + +} otahttp_Struct_t, *otahttp_Struct_pt; + +extern int httpclient_common(httpclient_t *client, + const char *url, + int port, + const char *ca_crt, + HTTPCLIENT_REQUEST_TYPE method, + uint32_t timeout_ms, + httpclient_data_t *client_data); + +void *ofc_Init(char *url) +{ + otahttp_Struct_pt h_odc; + + if (NULL == (h_odc = OTA_MALLOC(sizeof(otahttp_Struct_t)))) { + OTA_LOG_ERROR("allocate for h_odc failed"); + return NULL; + } + + memset(h_odc, 0, sizeof(otahttp_Struct_t)); + + /* set http request-header parameter */ + h_odc->http.header = "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" \ + "Accept-Encoding: gzip, deflate\r\n"; +#if defined(SUPPORT_ITLS) + char *s_ptr = strstr(url, "://"); + if (strlen("https") == (s_ptr - url) && (0 == strncmp(url, "https", strlen("https")))) { + strncpy(url + 1, url, strlen("http")); + url++; + } +#endif + h_odc->url = url; + + return h_odc; +} + + +extern const char *iotx_ca_crt; + +int32_t ofc_Fetch(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s) +{ + int diff; + otahttp_Struct_pt h_odc = (otahttp_Struct_pt)handle; + + h_odc->http_data.response_buf = buf; + h_odc->http_data.response_buf_len = buf_len; + diff = h_odc->http_data.response_content_len - h_odc->http_data.retrieve_len; + +#if !defined(SUPPORT_TLS) || defined(SUPPORT_TCP) + if (0 != httpclient_common(&h_odc->http, h_odc->url, 80, 0, HTTPCLIENT_GET, timeout_s * 1000, + &h_odc->http_data)) { +#else + if (0 != httpclient_common(&h_odc->http, h_odc->url, 443, iotx_ca_crt, HTTPCLIENT_GET, timeout_s * 1000, + &h_odc->http_data)) { +#endif + OTA_LOG_ERROR("fetch firmware failed"); + return -1; + } + + return h_odc->http_data.response_content_len - h_odc->http_data.retrieve_len - diff; +} + + +int ofc_Deinit(void *handle) +{ + if (NULL != handle) { + OTA_FREE(handle); + } + + return 0; +} + + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_lib.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_lib.c new file mode 100644 index 00000000..010f5929 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_lib.c @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "iotx_ota_internal.h" + +const char *otalib_JsonValueOf(const char *json, uint32_t json_len, const char *key, uint32_t *val_len) +{ + int length; + const char *val; + val = json_get_value_by_name((char *)json, json_len, (char *)key, &length, NULL); + if (NULL != val) { + *val_len = (uint32_t) length; + } + return val; +} + +void *otalib_MD5Init(void) +{ + iot_md5_context *ctx = OTA_MALLOC(sizeof(iot_md5_context)); + if (NULL == ctx) { + return NULL; + } + + utils_md5_init(ctx); + utils_md5_starts(ctx); + + return ctx; +} + +void otalib_MD5Update(void *md5, const char *buf, size_t buf_len) +{ + utils_md5_update(md5, (unsigned char *)buf, buf_len); +} + +void otalib_MD5Finalize(void *md5, char *output_str) +{ + int i; + unsigned char buf_out[16]; + utils_md5_finish(md5, buf_out); + + for (i = 0; i < 16; ++i) { + output_str[i * 2] = infra_hex2char(buf_out[i] >> 4); + output_str[i * 2 + 1] = infra_hex2char(buf_out[i]); + } + output_str[32] = '\0'; +} + +void otalib_MD5Deinit(void *md5) +{ + if (NULL != md5) { + OTA_FREE(md5); + } +} + +void *otalib_Sha256Init(void) +{ + iot_sha256_context *ctx = OTA_MALLOC(sizeof(iot_sha256_context)); + if (NULL == ctx) { + return NULL; + } + + utils_sha256_init(ctx); + utils_sha256_starts(ctx); + + return ctx; +} + +void otalib_Sha256Update(void *sha256, const char *buf, size_t buf_len) +{ + utils_sha256_update(sha256, (unsigned char *)buf, buf_len); +} + +void otalib_Sha256Finalize(void *sha256, char *output_str) +{ + int i; + unsigned char buf_out[32]; + utils_sha256_finish(sha256, buf_out); + + for (i = 0; i < 32; ++i) { + output_str[i * 2] = infra_hex2char(buf_out[i] >> 4); + output_str[i * 2 + 1] = infra_hex2char(buf_out[i]); + } + output_str[64] = '\0'; +} + +void otalib_Sha256Deinit(void *sha256) +{ + utils_sha256_free(sha256); + if (NULL != sha256) { + OTA_FREE(sha256); + } +} +/* Get the specific @key value, and copy to @dest */ +/* 0, successful; -1, failed */ +int otalib_GetFirmwareFixlenPara(const char *json_doc, + size_t json_doc_len, + const char *key, + char *dest, + size_t dest_len) +{ + const char *pvalue; + uint32_t val_len; + + if (NULL == (pvalue = otalib_JsonValueOf(json_doc, json_doc_len, key, &val_len))) { + OTA_LOG_ERROR("Not '%s' key in json doc of OTA", key); + return -1; + } + + if (val_len > dest_len) { + OTA_LOG_ERROR("value length of the key is too long"); + return -1; + } + + memcpy(dest, pvalue, val_len); + + return 0; +} + + +/* Get variant length parameter of firmware, and copy to @dest */ +/* 0, successful; -1, failed */ +int otalib_GetFirmwareVarlenPara(const char *json_doc, + size_t json_doc_len, + const char *key, + char **dest) +{ + const char *pvalue; + uint32_t val_len; + + if (NULL == (pvalue = otalib_JsonValueOf(json_doc, json_doc_len, key, &val_len))) { + OTA_LOG_ERROR("Not %s key in json doc of OTA", key); + return -1; + } + + if (NULL == (*dest = OTA_MALLOC(val_len + 1))) { + OTA_LOG_ERROR("allocate for dest failed"); + return -1; + } + + memcpy(*dest, pvalue, val_len); + (*dest)[val_len] = '\0'; + + return 0; +} + +int otalib_GetParams(const char *json_doc, uint32_t json_len, char **url, char **version, char *md5, + uint32_t *file_size) +{ +#define OTA_FILESIZE_STR_LEN (16) + char file_size_str[OTA_FILESIZE_STR_LEN + 1]; + + /* get version */ + if (0 != otalib_GetFirmwareVarlenPara(json_doc, json_len, "version", version)) { + OTA_LOG_ERROR("get value of version key failed"); + return -1; + } + + /* get URL */ + if (0 != otalib_GetFirmwareVarlenPara(json_doc, json_len, "url", url)) { + OTA_LOG_ERROR("get value of url key failed"); + return -1; + } + + /* get md5 */ + if (0 != otalib_GetFirmwareFixlenPara(json_doc, json_len, "md5", md5, 32)) { + OTA_LOG_ERROR("get value of md5 key failed"); + return -1; + } + + /* get file size */ + if (0 != otalib_GetFirmwareFixlenPara(json_doc, json_len, "size", file_size_str, OTA_FILESIZE_STR_LEN)) { + OTA_LOG_ERROR("get value of size key failed"); + return -1; + } + file_size_str[OTA_FILESIZE_STR_LEN] = '\0'; + *file_size = atoi(file_size_str); + + return 0; + +#undef OTA_FILESIZE_STR_LEN +} + +int otalib_GetConfigParams(const char *json_doc, uint32_t json_len, char **configId, uint32_t *configSize, char **sign, + char **signMethod, char **url, char **getType) +{ +#define OTA_FILESIZE_STR_LEN (16) + char file_size_str[OTA_FILESIZE_STR_LEN + 1]; + + /* get configId */ + if (0 != otalib_GetFirmwareVarlenPara(json_doc, json_len, "configId", configId)) { + OTA_LOG_ERROR("get value of configId key failed"); + return -1; + } + + /* get configSize */ + if (0 != otalib_GetFirmwareFixlenPara(json_doc, json_len, "configSize", file_size_str, OTA_FILESIZE_STR_LEN)) { + OTA_LOG_ERROR("get value of size key failed"); + return -1; + } + file_size_str[OTA_FILESIZE_STR_LEN] = '\0'; + *configSize = atoi(file_size_str); + + /* get sign */ + if (0 != otalib_GetFirmwareVarlenPara(json_doc, json_len, "sign", sign)) { + OTA_LOG_ERROR("get value of sign key failed"); + return -1; + } + + /* get signMethod */ + if (0 != otalib_GetFirmwareVarlenPara(json_doc, json_len, "signMethod", signMethod)) { + OTA_LOG_ERROR("get value of signMethod key failed"); + return -1; + } + + /* get url */ + if (0 != otalib_GetFirmwareVarlenPara(json_doc, json_len, "url", url)) { + OTA_LOG_ERROR("get value of url key failed"); + return -1; + } + + /* get getType */ + if (0 != otalib_GetFirmwareVarlenPara(json_doc, json_len, "getType", getType)) { + OTA_LOG_ERROR("get value of getType key failed"); + return -1; + } + return 0; + +#undef OTA_FILESIZE_STR_LEN +} + +int otalib_GetFotaParams(const char *json_doc, uint32_t json_len, char **version, uint32_t *file_size, char **sign, + char **signMethod, char **url, char **digestsign) +{ +#define OTA_FILESIZE_STR_LEN (16) + char file_size_str[OTA_FILESIZE_STR_LEN + 1]; + + /* get version */ + if (0 != otalib_GetFirmwareVarlenPara(json_doc, json_len, "version", version)) { + OTA_LOG_ERROR("get value of version failed"); + return -1; + } + + /* get file size */ + if (0 != otalib_GetFirmwareFixlenPara(json_doc, json_len, "size", file_size_str, OTA_FILESIZE_STR_LEN)) { + OTA_LOG_ERROR("get value of size key failed"); + return -1; + } + file_size_str[OTA_FILESIZE_STR_LEN] = '\0'; + *file_size = atoi(file_size_str); + + /* get sign */ + if (0 != otalib_GetFirmwareVarlenPara(json_doc, json_len, "sign", sign)) { + OTA_LOG_ERROR("get value of sign key failed"); + return -1; + } + + /* get signMethod */ + if (0 != otalib_GetFirmwareVarlenPara(json_doc, json_len, "signMethod", signMethod)) { + OTA_LOG_ERROR("get value of signMethod key failed"); + return -1; + } + + /* get url */ + if (0 != otalib_GetFirmwareVarlenPara(json_doc, json_len, "url", url)) { + OTA_LOG_ERROR("get value of url key failed"); + return -1; + } + + /* get digestsign */ + if (0 != otalib_GetFirmwareVarlenPara(json_doc, json_len, "digestSign", digestsign)) { + OTA_LOG_ERROR("get value of digestSign key failed, maybe not security ota"); + } + + return 0; + +#undef OTA_FILESIZE_STR_LEN +} + +/* Generate firmware information according to @id, @version */ +/* and then copy to @buf. */ +/* 0, successful; -1, failed */ +int otalib_GenInfoMsg(char *buf, size_t buf_len, uint32_t id, const char *version) +{ + int ret; + ret = HAL_Snprintf(buf, + buf_len, + "{\"id\":%d,\"params\":{\"version\":\"%s\"}}", + id, + version); + + if (ret < 0) { + OTA_LOG_ERROR("HAL_Snprintf failed"); + return -1; + } + + return 0; +} + +/* Generate report information according to @id, @msg */ +/* and then copy to @buf. */ +/* 0, successful; -1, failed */ +int otalib_GenReportMsg(char *buf, size_t buf_len, uint32_t id, int progress, const char *msg_detail) +{ + int ret; + if (NULL == msg_detail) { + ret = HAL_Snprintf(buf, + buf_len, + "{\"id\":%d,\"params\":{\"step\":\"%d\",\"desc\":\"\"}}", + id, + progress); + } else { + ret = HAL_Snprintf(buf, + buf_len, + "{\"id\":%d,\"params\":{\"step\":\"%d\",\"desc\":\"%s\"}}", + id, + progress, + msg_detail); + } + + + if (ret < 0) { + OTA_LOG_ERROR("HAL_Snprintf failed"); + return -1; + } else if (ret >= buf_len) { + OTA_LOG_ERROR("msg is too long"); + return IOT_OTAE_STR_TOO_LONG; + } + + return 0; +} + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_mqtt.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_mqtt.c new file mode 100644 index 00000000..ceea75c7 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_mqtt.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __OTA_MQTT_C_H__ +#define __OTA_MQTT_C_H__ + +#if (OTA_SIGNAL_CHANNEL) == 1 + +#include "mqtt_api.h" +#include "ota_api.h" +#include "iotx_ota_internal.h" + +/* OSC, OTA signal channel */ + +/* Specify the maximum characters of version */ +#define OTA_MQTT_TOPIC_LEN (128) + +typedef struct { + void *mqtt; + const char *product_key; + const char *device_name; + char topic_upgrade[OTA_MQTT_TOPIC_LEN]; + char topic_request[OTA_MQTT_TOPIC_LEN]; + char topic_config_get[OTA_MQTT_TOPIC_LEN]; + char topic_config_push[OTA_MQTT_TOPIC_LEN]; + ota_cb_fpt cb; + void *context; +} otamqtt_Struct_t, *otamqtt_Struct_pt; + + +/* Generate topic name according to @ota_topic_type, @product_key, @device_name */ +/* and then copy to @buf. */ +/* 0, successful; -1, failed */ +static int otamqtt_GenTopicName(char *buf, size_t buf_len, const char *ota_topic_type, const char *product_key, + const char *device_name) +{ + int ret; + + ret = HAL_Snprintf(buf, + buf_len, + "/ota/device/%s/%s/%s", + ota_topic_type, + product_key, + device_name); + + if (ret >= buf_len) { + return -1; + } + + if (ret < 0) { + OTA_LOG_ERROR("HAL_Snprintf failed"); + return -1; + } + + return 0; +} + +/* report progress of OTA */ +static int otamqtt_Publish(otamqtt_Struct_pt handle, const char *topic_type, int qos, const char *msg) +{ + int ret; + char topic_name[OTA_MQTT_TOPIC_LEN]; + iotx_mqtt_topic_info_t topic_info; + + memset(&topic_info, 0, sizeof(iotx_mqtt_topic_info_t)); + + if (0 == qos) { + topic_info.qos = IOTX_MQTT_QOS0; + } else { + topic_info.qos = IOTX_MQTT_QOS1; + } + topic_info.payload = (void *)msg; + topic_info.payload_len = strlen(msg); + + /* inform OTA to topic: "/ota/device/progress/$(product_key)/$(device_name)" */ + ret = otamqtt_GenTopicName(topic_name, OTA_MQTT_TOPIC_LEN, topic_type, handle->product_key, handle->device_name); + if (ret < 0) { + OTA_LOG_ERROR("generate topic name of info failed"); + return -1; + } + + ret = IOT_MQTT_Publish(handle->mqtt, topic_name, &topic_info); + if (ret < 0) { + OTA_LOG_ERROR("publish failed"); + return IOT_OTAE_OSC_FAILED; + } + + return 0; +} + +static int otamqtt_publish_full_topic(otamqtt_Struct_pt handle, const char *topic_name, + iotx_mqtt_topic_info_pt topic_msg) +{ + if (IOT_MQTT_Publish(handle->mqtt, topic_name, topic_msg) < 0) { + OTA_LOG_ERROR("publish failed"); + return IOT_OTAE_OSC_FAILED; + } + + return 0; +} + + +/* decode JSON string to get firmware information, like firmware version, URL, file size, MD5. */ +/* return NONE */ +static void otamqtt_UpgrageCb(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg) +{ + otamqtt_Struct_pt handle = (otamqtt_Struct_pt) pcontext; + iotx_mqtt_topic_info_pt topic_info = (iotx_mqtt_topic_info_pt)msg->msg; + + OTA_LOG_DEBUG("topic=%.*s", topic_info->topic_len, topic_info->ptopic); + OTA_LOG_DEBUG("len=%u, topic_msg=%.*s", topic_info->payload_len, topic_info->payload_len, (char *)topic_info->payload); + + if (IOTX_MQTT_EVENT_PUBLISH_RECEIVED != msg->event_type) { + return; + } + + if (NULL != strstr(topic_info->ptopic, "/ota/device/request")) { + OTA_LOG_DEBUG("receive device request"); + /*if(NULL != HAL_strnstr(topic_info->payload, topic_info->payload_len, + "url", strlen("url")))*/ + if (NULL != strstr(topic_info->payload, "url")) { + OTA_LOG_INFO("get request reply for new version image"); + if (NULL != handle->cb) { + handle->cb(handle->context, topic_info->payload, topic_info->payload_len, IOTX_OTA_TOPIC_TYPE_DEVICE_REQUEST); + } + } + } else if (NULL != strstr(topic_info->ptopic, "/ota/device/upgrade")) { + OTA_LOG_DEBUG("receive device upgrade"); + if (NULL != handle->cb) { + handle->cb(handle->context, topic_info->payload, topic_info->payload_len, IOTX_OTA_TOPIC_TYPE_DEVICE_UPGRATE); + } + } else if (NULL != strstr(topic_info->ptopic, "/thing/config/get_reply")) { + OTA_LOG_DEBUG("receive config get_reply"); + if (NULL != handle->cb) { + handle->cb(handle->context, topic_info->payload, topic_info->payload_len, IOTX_OTA_TOPIC_TYPE_CONFIG_GET); + } + } else if (NULL != strstr(topic_info->ptopic, "/thing/config/push")) { + OTA_LOG_DEBUG("receive config push"); + if (NULL != handle->cb) { + if (0 != handle->cb(handle->context, topic_info->payload, topic_info->payload_len, IOTX_OTA_TOPIC_TYPE_CONFIG_PUSH)) { + /* fail, send fail response code:400 */ + const char *pvalue; + uint32_t val_len; + char topic[OTA_MQTT_TOPIC_LEN] = {0}; + char message[OTA_MQTT_TOPIC_LEN] = {0}; + iotx_mqtt_topic_info_t message_info; + + memset(&message_info, 0, sizeof(iotx_mqtt_topic_info_t)); + + pvalue = otalib_JsonValueOf(topic_info->payload, topic_info->payload_len, "id", &val_len); + + HAL_Snprintf(topic, + OTA_MQTT_TOPIC_LEN, + "/sys/%s/%s/thing/config/push_reply", + handle->product_key, + handle->device_name); + HAL_Snprintf(message, + OTA_MQTT_TOPIC_LEN, + "\"id\":%.*s,\"code\":\"%d\",\"data\":{}", + val_len, + pvalue, + 400); + message_info.qos = IOTX_MQTT_QOS0; + message_info.payload = (void *)message; + message_info.payload_len = strlen(message); + + if (IOT_MQTT_Publish(handle->mqtt, topic, &message_info) < 0) { + OTA_LOG_ERROR("publish failed"); + } + } + } + } +} + +void *osc_Init(const char *product_key, const char *device_name, void *ch_signal, ota_cb_fpt cb, void *context) +{ + int ret; + otamqtt_Struct_pt h_osc = NULL; + + if (NULL == (h_osc = OTA_MALLOC(sizeof(otamqtt_Struct_t)))) { + OTA_LOG_ERROR("allocate for h_osc failed"); + return NULL; + } + + memset(h_osc, 0, sizeof(otamqtt_Struct_t)); + + /* subscribe the OTA topic: "/ota/device/request/$(product_key)/$(device_name)" */ + ret = otamqtt_GenTopicName(h_osc->topic_request, OTA_MQTT_TOPIC_LEN, "request", product_key, device_name); + if (ret < 0) { + OTA_LOG_ERROR("generate topic name of request failed"); + goto do_exit; + } + + ret = IOT_MQTT_Subscribe(ch_signal, h_osc->topic_request, IOTX_MQTT_QOS1, otamqtt_UpgrageCb, h_osc); + if (ret < 0) { + OTA_LOG_ERROR("mqtt subscribe failed"); + goto do_exit; + } + + /* subscribe the OTA topic: "/ota/device/upgrade/$(product_key)/$(device_name)" */ + ret = otamqtt_GenTopicName(h_osc->topic_upgrade, OTA_MQTT_TOPIC_LEN, "upgrade", product_key, device_name); + if (ret < 0) { + OTA_LOG_ERROR("generate topic name of upgrade failed"); + goto do_exit; + } + + ret = IOT_MQTT_Subscribe(ch_signal, h_osc->topic_upgrade, IOTX_MQTT_QOS1, otamqtt_UpgrageCb, h_osc); + if (ret < 0) { + OTA_LOG_ERROR("mqtt subscribe failed"); + goto do_exit; + } + + /* subscribe the OTA topic: "/sys/{productKey}/{deviceName}/thing/config/get_reply" */ + ret = HAL_Snprintf(h_osc->topic_config_get, + OTA_MQTT_TOPIC_LEN, + "/sys/%s/%s/thing/config/get_reply", + product_key, + device_name); + if (ret < 0) { + OTA_LOG_ERROR("generate topic name of config get failed"); + goto do_exit; + } + + ret = IOT_MQTT_Subscribe(ch_signal, h_osc->topic_config_get, IOTX_MQTT_QOS0, otamqtt_UpgrageCb, h_osc); + if (ret < 0) { + OTA_LOG_ERROR("mqtt subscribe failed"); + goto do_exit; + } + + /* subscribe the OTA topic: "/sys/{productKey}/{deviceName}/thing/config/push" */ + ret = HAL_Snprintf(h_osc->topic_config_push, + OTA_MQTT_TOPIC_LEN, + "/sys/%s/%s/thing/config/push", + product_key, + device_name); + if (ret < 0) { + OTA_LOG_ERROR("generate topic name of config get failed"); + goto do_exit; + } + + ret = IOT_MQTT_Subscribe(ch_signal, h_osc->topic_config_push, IOTX_MQTT_QOS0, otamqtt_UpgrageCb, h_osc); + if (ret < 0) { + OTA_LOG_ERROR("mqtt subscribe failed"); + goto do_exit; + } + + h_osc->mqtt = ch_signal; + h_osc->product_key = product_key; + h_osc->device_name = device_name; + h_osc->cb = cb; + h_osc->context = context; + + return h_osc; + +do_exit: + if (NULL != h_osc) { + OTA_FREE(h_osc); + } + + return NULL; +} + +int osc_Deinit(void *handle) +{ + if (NULL != handle) { + OTA_FREE(handle); + } + + return 0; +} + +/* report progress of OTA */ +int osc_ReportProgress(void *handle, const char *msg) +{ + return otamqtt_Publish(handle, "progress", 0, msg); +} + + +/* report version of OTA firmware */ +int osc_ReportVersion(void *handle, const char *msg) +{ + return otamqtt_Publish(handle, "inform", 1, msg); +} + +/* request the OTA firmware pushed by user*/ +int osc_RequestImage(void *handle, const char *msg) +{ + return otamqtt_Publish(handle, "request", 1, msg); +} + +/* request the config */ +int osc_RequestConfig(void *handle, const char *topic_name, iotx_mqtt_topic_info_pt topic_msg) +{ + return otamqtt_publish_full_topic(handle, topic_name, topic_msg); +} + +#endif /* #if (OTA_SIGNAL_CHANNEL) == 1 */ +#endif /* #ifndef __OTA_MQTT_C_H__ */ + + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_wrapper.h new file mode 100644 index 00000000..d5a0794b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/ota/ota_wrapper.h @@ -0,0 +1,16 @@ +#ifndef _OTA_WRAPPER_H_ +#define _OTA_WRAPPER_H_ + +#include "infra_types.h" + +void *HAL_Malloc(uint32_t size); +void HAL_Free(void *ptr); +void HAL_Printf(const char *fmt, ...); +int HAL_Snprintf(char *str, const int len, const char *fmt, ...); + +int HAL_SetProductKey(char *product_key); +int HAL_SetDeviceName(char *device_name); +int HAL_SetDeviceSecret(char *device_secret); + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/dev_ap/awss_dev_ap.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/dev_ap/awss_dev_ap.c new file mode 100644 index 00000000..7d05cd4d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/dev_ap/awss_dev_ap.c @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#ifdef AWSS_SUPPORT_DEV_AP + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif +#define AWSS_DEV_AP_WAIT_TIME_MAX_MS (2000) + +static void *g_awss_dev_ap_mutex = NULL; +static char awss_dev_ap_switchap_done = 0; +static char awss_dev_ap_switchap_resp_suc = 0; +static char awss_dev_ap_ongoing = 0; + +static int awss_dev_ap_setup() +{ + char ssid[PLATFORM_MAX_SSID_LEN + 1] = {0}; + char passwd[PLATFORM_MAX_PASSWD_LEN + 1] = {0}; + + do { /* reduce stack used */ + char pk[OS_PRODUCT_KEY_LEN + 1] = {0}; + char mac_str[OS_MAC_LEN + 1] = {0}; + + HAL_GetProductKey(pk); + os_wifi_get_mac_str(mac_str); + memmove(mac_str + 11, mac_str + 12, 2); + memmove(mac_str + 13, mac_str + 15, 2); + mac_str[15] = '\0'; + HAL_Snprintf(ssid, PLATFORM_MAX_SSID_LEN, "adh_%s_%s", pk, &mac_str[9]); + } while (0); + + awss_trace("ssid:%s\n", ssid); + + return HAL_Awss_Open_Ap(ssid, passwd, 100, 0); +} + +extern int awss_success_notify(void); +int awss_dev_ap_start(void) +{ + int ret = -1; + + if (g_awss_dev_ap_mutex || awss_dev_ap_ongoing) { + awss_trace("dev ap already running"); + return -1; + } + + if (g_awss_dev_ap_mutex == NULL) + g_awss_dev_ap_mutex = HAL_MutexCreate(); + if (g_awss_dev_ap_mutex == NULL) { + awss_trace("awss dev ap start fail"); + goto AWSS_DEV_AP_FAIL; + } + + HAL_MutexLock(g_awss_dev_ap_mutex); + + awss_dev_ap_ongoing = 1; + awss_dev_ap_switchap_done = 0; + awss_dev_ap_switchap_resp_suc = 0; + + ret = awss_dev_ap_setup(); + HAL_MutexUnlock(g_awss_dev_ap_mutex); + HAL_SleepMs(1000); /* wait for dev ap to work well */ + HAL_MutexLock(g_awss_dev_ap_mutex); + if (awss_dev_ap_ongoing) { + awss_cmp_local_init(AWSS_LC_INIT_DEV_AP); + } + while (awss_dev_ap_ongoing) { + HAL_MutexUnlock(g_awss_dev_ap_mutex); + HAL_SleepMs(200); + HAL_MutexLock(g_awss_dev_ap_mutex); + if (awss_dev_ap_switchap_done) + break; + } + HAL_MutexUnlock(g_awss_dev_ap_mutex); + + ret = awss_dev_ap_switchap_done == 0 ? -1 : 0; + + if (awss_dev_ap_ongoing == 0) { /* interrupt by user */ + HAL_SleepMs(1000); + return -1; + } + + awss_dev_ap_ongoing = 0; + awss_success_notify(); + +AWSS_DEV_AP_FAIL: + if (g_awss_dev_ap_mutex) { + HAL_MutexUnlock(g_awss_dev_ap_mutex); + HAL_MutexDestroy(g_awss_dev_ap_mutex); + } + g_awss_dev_ap_mutex = NULL; + return ret; +} + +extern int HAL_Awss_Close_Ap(void); +int awss_dev_ap_stop(void) +{ + if (awss_dev_ap_ongoing == 0) + return 0; + + awss_dev_ap_ongoing = 0; + + awss_trace("%s", __func__); + + if (g_awss_dev_ap_mutex) + HAL_MutexLock(g_awss_dev_ap_mutex); + + HAL_Awss_Close_Ap(); + + awss_cmp_local_deinit(1); + + if (g_awss_dev_ap_mutex) { + HAL_MutexUnlock(g_awss_dev_ap_mutex); + HAL_MutexDestroy(g_awss_dev_ap_mutex); + g_awss_dev_ap_mutex = NULL; + } + + awss_dev_ap_switchap_done = 0; + awss_dev_ap_switchap_resp_suc = 0; + + awss_trace("%s exit", __func__); + + return 0; +} + +static int awss_dev_ap_switchap_resp(void *context, int result, + void *userdata, void *remote, + void *message) { + if (result == 2) { /* success */ + awss_dev_ap_switchap_resp_suc = 1; + } + return 0; +} + +int softap_decrypt_password(const char *cipher, const uint8_t *random, char *passwd) +{ + uint8_t cipher_hex[AES128_KEY_LEN] = {0}; + uint8_t aes_key[SHA256_DIGEST_SIZE + 1] = {0}; + uint8_t iv[AES128_KEY_LEN] = {0}; + p_aes128_t aes_ctx = NULL; + + /* get cipher hex */ + utils_str_to_hex((char *)cipher, 32, cipher_hex, 16); + + /* setup iv */ + utils_str_to_hex((char *)random, RANDOM_MAX_LEN * 2, iv, RANDOM_MAX_LEN); + + /* generate aes key */ + utils_sha256(random, RANDOM_MAX_LEN * 2, aes_key); + + /* aes decryption with cbc mode */ + aes_ctx = HAL_Aes128_Init((const uint8_t *)aes_key, iv, PLATFORM_AES_DECRYPTION); + HAL_Aes128_Cbc_Decrypt(aes_ctx, cipher_hex, sizeof(cipher_hex) / AES128_KEY_LEN, passwd); + HAL_Aes128_Destroy(aes_ctx); + + return 0; +} + +int wifimgr_process_dev_ap_switchap_request(void *ctx, void *resource, void *remote, void *request) +{ +#define AWSS_DEV_AP_SWITCHA_RSP_LEN (512) + char ssid[PLATFORM_MAX_SSID_LEN * 2 + 1] = {0}, passwd[PLATFORM_MAX_PASSWD_LEN + 1] = {0}; + int str_len = 0, success = 1, len = 0; + char req_msg_id[MSG_REQ_ID_LEN] = {0}; + char random[RANDOM_MAX_LEN + 1] = {0}; + char *msg = NULL, *dev_info = NULL; + char *str = NULL, *buf = NULL; + char bssid[ETH_ALEN] = {0}; + char ssid_found = 0; + uint8_t token[RANDOM_MAX_LEN + 1]; + char token_found = 0; + uint8_t isRandomKey = 0; + const char *p_ranodm_str = NULL; + int ret = -1; + + static char dev_ap_switchap_parsed = 0; + char topic[TOPIC_LEN_MAX] = {0}; + uint16_t msgid = -1; + int result = 0; + + if (0 == awss_dev_ap_ongoing) { + awss_trace("not in awss mode"); + return -1; + } + + if (dev_ap_switchap_parsed != 0) + goto DEV_AP_SWITCHAP_END; + dev_ap_switchap_parsed = 1; + + AWSS_UPDATE_STATIS(AWSS_STATIS_DAP_IDX, AWSS_STATIS_TYPE_TIME_START); + + msg = os_zalloc(AWSS_DEV_AP_SWITCHA_RSP_LEN); + if (msg == NULL) { + awss_trace("switchap resp alloc fail"); + goto DEV_AP_SWITCHAP_END; + } + dev_info = os_zalloc(AWSS_DEV_AP_SWITCHA_RSP_LEN); + if (dev_info == NULL) { + awss_trace("switchap resp alloc fail"); + goto DEV_AP_SWITCHAP_END; + } + + buf = awss_cmp_get_coap_payload(request, &len); + str = json_get_value_by_name(buf, len, "id", &str_len, 0); + memcpy(req_msg_id, str, str_len > MSG_REQ_ID_LEN - 1 ? MSG_REQ_ID_LEN - 1 : str_len); + awss_trace("dev ap, len:%u, %s\r\n", len, buf); + buf = json_get_value_by_name(buf, len, "params", &len, 0); + if (buf == NULL) { + awss_trace("switchap req param fail"); + goto DEV_AP_SWITCHAP_END; + } + + do { + /* get security version */ + str_len = 0; + str = json_get_value_by_name(buf, len, "security", &str_len, 0); + if (str && str_len == 3 && !memcmp("2.0", str, str_len)) { + awss_trace("security ver = %.*s\r\n", str_len, str); + isRandomKey = 1; + } + + str_len = 0; + str = json_get_value_by_name(buf, len, "ssid", &str_len, 0); + awss_trace("ssid, len:%u, %s\r\n", str_len, str != NULL ? str : "NULL"); + if (str && (str_len < PLATFORM_MAX_SSID_LEN)) { + memcpy(ssid, str, str_len); + ssid_found = 1; + } + + if (!ssid_found) { + str_len = 0; + str = json_get_value_by_name(buf, len, "xssid", &str_len, 0); + if (str && (str_len < PLATFORM_MAX_SSID_LEN * 2 - 1)) { + uint8_t decoded[OS_MAX_SSID_LEN] = {0}; + int len = str_len / 2; + memcpy(ssid, str, str_len); + utils_str_to_hex(ssid, str_len, decoded, OS_MAX_SSID_LEN); + memcpy(ssid, (const char *)decoded, len); + ssid[len] = '\0'; + } else { + awss_trace("witchap req ssid err"); + HAL_Snprintf(msg, AWSS_DEV_AP_SWITCHA_RSP_LEN, AWSS_ACK_FMT, req_msg_id, -1, "\"ssid error\""); + awss_event_post(IOTX_AWSS_CS_ERR); + success = 0; + break; + } + } + + str_len = 0; + str = json_get_value_by_name(buf, len, "random", &str_len, 0); + if (str && str_len == RANDOM_MAX_LEN * 2) { + utils_str_to_hex(str, str_len, (unsigned char *)random, RANDOM_MAX_LEN); + p_ranodm_str = str; + } else { + HAL_Snprintf(msg, AWSS_DEV_AP_SWITCHA_RSP_LEN, AWSS_ACK_FMT, req_msg_id, -4, "\"random len error\""); + awss_event_post(IOTX_AWSS_CS_ERR); + success = 0; + break; + } + + str_len = 0; + str = json_get_value_by_name(buf, len, "token", &str_len, 0); + if (str && str_len == RANDOM_MAX_LEN * 2) { /* token len equal to random len */ + utils_str_to_hex(str, str_len, (unsigned char *)token, RANDOM_MAX_LEN); + token_found = 1; + } + + str_len = 0; + str = json_get_value_by_name(buf, len, "bssid", &str_len, 0); + if (str) os_wifi_str2mac(str, bssid); + + str_len = 0; + str = json_get_value_by_name(buf, len, "passwd", &str_len, 0); + + if (str_len < (PLATFORM_MAX_PASSWD_LEN * 2) - 1) { + char encoded[PLATFORM_MAX_PASSWD_LEN * 2 + 1] = {0}; + memcpy(encoded, str, str_len); + // aes_decrypt_string(encoded, passwd, str_len, + // 0, awss_get_encrypt_type(), 1, random); /* 64bytes=2x32bytes */ + if (isRandomKey) { + if (softap_decrypt_password(encoded, (const uint8_t*)p_ranodm_str, passwd) < 0) { + success = 0; + awss_trace("randomkey passwd decode fail"); + awss_event_post(IOTX_AWSS_PASSWD_ERR); + } + } + else { + if (aes_decrypt_string(encoded, passwd, str_len, 0, HAL_Awss_Get_Encrypt_Type(), 1, random) < 0) { + /* 64bytes=2x32bytes */ + success = 0; + awss_trace("non-random passwd decode"); + awss_event_post(IOTX_AWSS_PASSWD_ERR); + } + } + } else { + awss_trace("passwd len err"); + HAL_Snprintf(msg, AWSS_DEV_AP_SWITCHA_RSP_LEN, AWSS_ACK_FMT, req_msg_id, -3, "\"passwd len error\""); + awss_event_post(IOTX_AWSS_PASSWD_ERR); + success = 0; + AWSS_UPDATE_STATIS(AWSS_STATIS_DAP_IDX, AWSS_STATIS_TYPE_PASSWD_ERR); + } + + if (success && is_utf8(passwd, strlen(passwd)) == 0) { + awss_trace("passwd content err"); + HAL_Snprintf(msg, AWSS_DEV_AP_SWITCHA_RSP_LEN, AWSS_ACK_FMT, req_msg_id, -3 , "\"passwd content error\""); + awss_event_post(IOTX_AWSS_PASSWD_ERR); + success = 0; + AWSS_UPDATE_STATIS(AWSS_STATIS_DAP_IDX, AWSS_STATIS_TYPE_PASSWD_ERR); + } + } while (0); + + if (success == 1) { + if (token_found == 0) { + // no token found in switchap request, produce new token by dev itself + produce_random(aes_random, sizeof(aes_random)); + } else { + // token found in switchap request, no need to produce dev token + awss_set_token((uint8_t *)token); + } + dev_info[0] = '{'; + awss_build_dev_info(token_found == 1 ? AWSS_NOTIFY_TYPE_MAX : AWSS_NOTIFY_DEV_BIND_TOKEN, dev_info + 1, + AWSS_DEV_AP_SWITCHA_RSP_LEN - 1); + dev_info[strlen(dev_info)] = '}'; + dev_info[AWSS_DEV_AP_SWITCHA_RSP_LEN - 1] = '\0'; + snprintf(msg, AWSS_DEV_AP_SWITCHA_RSP_LEN, AWSS_ACK_FMT, req_msg_id, 200, dev_info); + } + + awss_trace("Sending message to app: %s", msg); + awss_trace("switch to ap: '%s'", ssid); + awss_build_topic((const char *)TOPIC_AWSS_DEV_AP_SWITCHAP, topic, TOPIC_LEN_MAX); + result = awss_cmp_coap_send_resp(msg, strlen(msg), remote, topic, request, awss_dev_ap_switchap_resp, &msgid, 1); + // (void)result; /* remove complier warnings */ + awss_trace("sending %s.", result == 0 ? "success" : "fail"); + + if (success == 1) { + awss_event_post(IOTX_AWSS_GOT_SSID_PASSWD); + } + + do { + int wait_ms = AWSS_DEV_AP_WAIT_TIME_MAX_MS; + if (!success) + break; + + while (wait_ms > 0 && awss_dev_ap_switchap_resp_suc == 0 && awss_dev_ap_ongoing) { + HAL_SleepMs(100); + wait_ms -= 100; + } + awss_cmp_coap_cancel_packet(msgid); + AWSS_UPDATE_STATIS(AWSS_STATIS_CONN_ROUTER_IDX, AWSS_STATIS_TYPE_TIME_START); + if (awss_dev_ap_ongoing == 0) { /* interrupt by user */ + ret = -1; + goto DEV_AP_SWITCHAP_END; + } + HAL_Awss_Close_Ap(); + + ret = HAL_Awss_Connect_Ap(WLAN_CONNECTION_TIMEOUT_MS, ssid, passwd, 0, 0, (uint8_t *)bssid, 0); + if (ret == 0) { + AWSS_UPDATE_STATIS(AWSS_STATIS_CONN_ROUTER_IDX, AWSS_STATIS_TYPE_TIME_SUC); + awss_dev_ap_switchap_done = 1; + AWSS_UPDATE_STATIS(AWSS_STATIS_DAP_IDX, AWSS_STATIS_TYPE_TIME_SUC); + } else { + awss_dev_ap_setup(); + } + awss_trace("connect '%s' %s\r\n", ssid, ret == 0 ? "success" : "fail"); + } while (0); + +DEV_AP_SWITCHAP_END: + dev_ap_switchap_parsed = 0; + if (dev_info) HAL_Free(dev_info); + if (msg) HAL_Free(msg); + return ret; +} +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/dev_ap/awss_dev_ap.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/dev_ap/awss_dev_ap.h new file mode 100644 index 00000000..0250ca2b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/dev_ap/awss_dev_ap.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_DEV_AP_H__ +#define __AWSS_DEV_AP_H__ + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +int awss_dev_ap_stop(void); +int awss_dev_ap_start(void); +int wifimgr_process_dev_ap_switchap_request(void *ctx, void *resource, void *remote, void *request); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/dev_ap/dev_ap_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/dev_ap/dev_ap_wrapper.h new file mode 100644 index 00000000..a073de82 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/dev_ap/dev_ap_wrapper.h @@ -0,0 +1,62 @@ +#include "infra_types.h" +#include "infra_defs.h" +#include "wrappers_defs.h" +/*************************************** common hals ***************************************/ +int HAL_Timer_Stop(void *timer); +int HAL_Timer_Delete(void *timer); +void *HAL_Timer_Create(const char *name, void (*func)(void *), void *user_data); +int HAL_Timer_Start(void *timer, int ms); +void HAL_SleepMs(uint32_t ms); +void *HAL_Malloc(uint32_t size); +void HAL_MutexLock(void *mutex); +void HAL_MutexUnlock(void *mutex); +uint64_t HAL_UptimeMs(void); +void HAL_Free(void *ptr); +void *HAL_MutexCreate(void); +void HAL_MutexDestroy(void *mutex); + +/*************************************** wifi provision frameworks hals ***************************************/ +/* frameworks/awss.c*/ +int HAL_Awss_Get_Timeout_Interval_Ms(void); +int HAL_Sys_Net_Is_Ready(); +int HAL_Wifi_Get_Ap_Info(char ssid[HAL_MAX_SSID_LEN],char passwd[HAL_MAX_PASSWD_LEN],uint8_t bssid[ETH_ALEN]); +/* awss_crypt.c */ +int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN]); +int HAL_GetProductSecret(char *product_secret); +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN]); +int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN]); +void HAL_Awss_Close_Monitor(void); +void HAL_Awss_Open_Monitor(_IN_ awss_recv_80211_frame_cb_t cb); +void HAL_Awss_Switch_Channel(char primary_channel, char secondary_channel, uint8_t bssid[ETH_ALEN]); +int HAL_Awss_Get_Channelscan_Interval_Ms(void); +/* zconfig_vendor_common.c */ +DLL_HAL_API p_HAL_Aes128_t HAL_Aes128_Init( + _IN_ const uint8_t *key, + _IN_ const uint8_t *iv, + _IN_ AES_DIR_t dir); +DLL_HAL_API int HAL_Aes128_Destroy(_IN_ p_HAL_Aes128_t aes); +DLL_HAL_API int HAL_Aes128_Cbc_Decrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t blockNum, + _OU_ void *dst); +DLL_HAL_API int HAL_Aes128_Cfb_Decrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t length, + _OU_ void *dst); +DLL_HAL_API int HAL_Awss_Get_Encrypt_Type(void); +DLL_HAL_API int HAL_Awss_Get_Conn_Encrypt_Type(void); +/* os_misc.c */ +char *HAL_Wifi_Get_Mac(_OU_ char mac_str[HAL_MAC_LEN]); +/* awss_main.c */ +int HAL_Awss_Connect_Ap( + _IN_ uint32_t connection_timeout_ms, + _IN_ char ssid[HAL_MAX_SSID_LEN], + _IN_ char passwd[HAL_MAX_PASSWD_LEN], + _IN_OPT_ enum AWSS_AUTH_TYPE auth, + _IN_OPT_ enum AWSS_ENC_TYPE encry, + _IN_OPT_ uint8_t bssid[ETH_ALEN], + _IN_OPT_ uint8_t channel); +/*************************************** dev-ap special hals ***************************************/ +int HAL_Awss_Open_Ap(const char *ssid, const char *passwd, int beacon_interval, int hide); diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/aplist/awss_aplist.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/aplist/awss_aplist.c new file mode 100644 index 00000000..15f0367b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/aplist/awss_aplist.c @@ -0,0 +1,405 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +#ifdef AWSS_SUPPORT_APLIST + +#define CLR_APLIST_MONITOR_TIMEOUT_MS (24 * 60 *60 * 1000) +/* storage to store apinfo */ +struct ap_info *zconfig_aplist = NULL; +/* aplist num, less than MAX_APLIST_NUM */ +uint8_t zconfig_aplist_num = 0; + +static uint8_t clr_aplist = 0; +static void *clr_aplist_timer = NULL; + +static void awss_clr_aplist_monitor() +{ + clr_aplist = 1; + HAL_Timer_Start(clr_aplist_timer, CLR_APLIST_MONITOR_TIMEOUT_MS); +} + +int awss_is_ready_clr_aplist(void) +{ + return clr_aplist; +} + +int awss_clear_aplist(void) +{ + memset(zconfig_aplist, 0, sizeof(struct ap_info) * MAX_APLIST_NUM); +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + memset(adha_aplist, 0, sizeof(*adha_aplist)); +#endif + zconfig_aplist_num = 0; + clr_aplist = 0; + + return 0; +} + +int awss_open_aplist_monitor(void) +{ + if (clr_aplist_timer == NULL) + clr_aplist_timer = HAL_Timer_Create("clr_aplist", (void (*)(void *))awss_clr_aplist_monitor, (void *)NULL); + if (clr_aplist_timer == NULL) + return -1; + + HAL_Timer_Stop(clr_aplist_timer); + HAL_Timer_Start(clr_aplist_timer, CLR_APLIST_MONITOR_TIMEOUT_MS); + return 0; +} + +int awss_close_aplist_monitor(void) +{ + if (clr_aplist_timer == NULL) + return 0; + awss_stop_timer(clr_aplist_timer); + clr_aplist_timer = NULL; + return 0; +} + +int awss_init_ieee80211_aplist(void) +{ + if (zconfig_aplist) + return 0; + zconfig_aplist = (struct ap_info *)os_zalloc(sizeof(struct ap_info) * MAX_APLIST_NUM); + if (zconfig_aplist == NULL) + return -1; + zconfig_aplist_num = 0; + return 0; +} + +int awss_deinit_ieee80211_aplist(void) +{ + if (zconfig_aplist == NULL) + return 0; + HAL_Free(zconfig_aplist); + zconfig_aplist = NULL; + zconfig_aplist_num = 0; + return 0; +} + +struct ap_info *zconfig_get_apinfo(uint8_t *mac) +{ + int i; + + for (i = 1; i < zconfig_aplist_num; i++) { + if (!memcmp(zconfig_aplist[i].mac, mac, ETH_ALEN)) + return &zconfig_aplist[i]; + } + + return NULL; +} + +struct ap_info *zconfig_get_apinfo_by_ssid(uint8_t *ssid) +{ + int i; + + for (i = 1; i < zconfig_aplist_num; i ++) { + if (!strcmp((char *)zconfig_aplist[i].ssid, (char *)ssid)) + return &zconfig_aplist[i]; + } + + return NULL; +} + +/* 通过ssid前缀 */ +struct ap_info *zconfig_get_apinfo_by_ssid_prefix(uint8_t *ssid_prefix) +{ + int i; + int len = strlen((const char *)ssid_prefix); + if (!len) + return NULL; + + for (i = 1; i < zconfig_aplist_num; i++) { + if (!strncmp((char *)zconfig_aplist[i].ssid, (char *)ssid_prefix, len)) { + /* TODO: first match or best match??? */ + return &zconfig_aplist[i];/* first match */ + } + } + + return NULL; +} + +int str_end_with(const char *str, const char *suffix) +{ + int lenstr, lensuffix; + if (!str || !suffix) + return 0; + lenstr = strlen(str); + lensuffix = strlen(suffix); + if (lensuffix > lenstr) + return 0; + return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0; +} + +/* 通过ssid后缀 */ +struct ap_info *zconfig_get_apinfo_by_ssid_suffix(uint8_t *ssid_suffix) +{ + int i; + int len = strlen((const char *)ssid_suffix); + if (!len) + return NULL; + + for (i = 1; i < zconfig_aplist_num; i++) { + if (str_end_with((char *)zconfig_aplist[i].ssid, (char *)ssid_suffix)) { + /* TODO: first match or best match??? */ + return &zconfig_aplist[i];/* first match */ + } + } + + return NULL; +} + +/** + * save apinfo + * + * @ssid: [IN] ap ssid + * @bssid: [IN] ap bssid + * @channel: [IN] ap channel + * @auth: [IN] optional, ap auth mode, like OPEN/WEP/WPA/WPA2/WPAWPA2 + * @encry: [IN], ap encryption mode, i.e. NONE/WEP/TKIP/AES/TKIP-AES + * + * Note: + * 1) if ap num exceed zconfig_aplist[], always save at [0] + * but why...I forgot... + * 2) always update channel if channel != 0 + * 3) if chn is locked, save ssid to zc_ssid, because zc_ssid + * can be used for ssid-auto-completion + * Return: + * 0/success, -1/invalid params(empty ssid/bssid) + */ + +int awss_save_apinfo(uint8_t *ssid, uint8_t* bssid, uint8_t channel, uint8_t auth, + uint8_t pairwise_cipher, uint8_t group_cipher, signed char rssi) +{ + int i; + + /* ssid, bssid cannot empty, channel can be 0, auth/encry can be invalid */ + if (!(ssid && bssid)) + return -1; + + /* sanity check */ + if (channel > ZC_MAX_CHANNEL || channel < ZC_MIN_CHANNEL) + channel = 0; + else + zconfig_add_active_channel(channel); + + if (auth > ZC_AUTH_TYPE_MAX) + auth = ZC_AUTH_TYPE_INVALID; + + if (pairwise_cipher > ZC_ENC_TYPE_MAX) + pairwise_cipher = ZC_ENC_TYPE_INVALID; + if (group_cipher > ZC_ENC_TYPE_MAX) + group_cipher = ZC_ENC_TYPE_INVALID; + + /* FIXME: */ + if (pairwise_cipher == ZC_ENC_TYPE_TKIPAES) + pairwise_cipher = ZC_ENC_TYPE_AES; /* tods */ + + /* + * start from zconfig_aplist[1], leave [0] for temp use + * if zconfig_aplist[] is full, always replace [0] + */ + if (!zconfig_aplist_num) { + zconfig_aplist_num = 1; + } + + for (i = 1; i < zconfig_aplist_num; i++) { + if(!strncmp(zconfig_aplist[i].ssid, (char *)ssid, ZC_MAX_SSID_LEN) + && !memcmp(zconfig_aplist[i].mac, bssid, ETH_ALEN)) { + /* FIXME: useless? */ + /* found the same bss */ + if (!zconfig_aplist[i].channel) + zconfig_aplist[i].channel = channel; + if (zconfig_aplist[i].auth == ZC_AUTH_TYPE_INVALID) + zconfig_aplist[i].auth = auth; + if (zconfig_aplist[i].encry[0] == ZC_ENC_TYPE_INVALID) + zconfig_aplist[i].encry[0] = group_cipher; + if (zconfig_aplist[i].encry[1] == ZC_ENC_TYPE_INVALID) + zconfig_aplist[i].encry[1] = pairwise_cipher; + + return 0;/* duplicated ssid */ + } + } + + if (i < MAX_APLIST_NUM) { + zconfig_aplist_num ++; + } else { + i = 0; /* [0] for temp use, always replace [0] */ + } + + strncpy((char *)&zconfig_aplist[i].ssid, (const char *)&ssid[0], ZC_MAX_SSID_LEN - 1); + memcpy(&zconfig_aplist[i].mac, bssid, ETH_ALEN); + zconfig_aplist[i].auth = auth; + zconfig_aplist[i].rssi = rssi; + zconfig_aplist[i].channel = channel; + zconfig_aplist[i].encry[0] = group_cipher; + zconfig_aplist[i].encry[1] = pairwise_cipher; + +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + do { + char save_adha = 0; +#ifdef AWSS_SUPPORT_ADHA + if (!strcmp((void *)ssid, zc_adha_ssid)) + save_adha = 1; +#endif +#ifdef AWSS_SUPPORT_AHA + if (!strcmp((void *)ssid, zc_default_ssid)) + save_adha = 1; +#endif + if (save_adha) { + if (adha_aplist->cnt < MAX_APLIST_NUM) + adha_aplist->aplist[adha_aplist->cnt ++] = i; + } + } while(0); +#endif + + do { + char adha = 0; +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + adha = adha_aplist->cnt; +#endif + awss_debug("[%d] ssid:%s, mac:%02x%02x%02x%02x%02x%02x, chn:%d, rssi:%d, adha:%d\r\n", + i, ssid, bssid[0], bssid[1], bssid[2], + bssid[3], bssid[4], bssid[5], channel, + rssi > 0 ? rssi - 256 : rssi, adha); + } while (0); + /* + * if chn already locked(zc_bssid set), + * copy ssid to zc_ssid for ssid-auto-completiont + */ + if (!memcmp(zc_bssid, bssid, ETH_ALEN) && ssid[0] != '\0') { + strncpy((char *)zc_ssid, (char const *)ssid, ZC_MAX_SSID_LEN - 1); + } + + return 0; +} + +/* + * [IN] ssid or bssid + * [OUT] auth, encry, channel + */ +int awss_get_auth_info(uint8_t *ssid, uint8_t *bssid, uint8_t *auth, + uint8_t *encry, uint8_t *channel) +{ + uint8_t *valid_bssid = NULL; + struct ap_info *ap_info = NULL; + + /* sanity check */ + if (!bssid || !memcmp(bssid, zero_mac, ETH_ALEN)) { + valid_bssid = NULL; + } else { + valid_bssid = bssid; + } + + /* use mac or ssid to search apinfo */ + if (valid_bssid) { + ap_info = zconfig_get_apinfo(valid_bssid); + } else { + ap_info = zconfig_get_apinfo_by_ssid(ssid); + } + + if (!ap_info) + return 0; + + if (auth) + *auth = ap_info->auth; + if (encry) + *encry = ap_info->encry[1]; /* tods side */ + if (!valid_bssid && bssid) + memcpy(bssid, ap_info->mac, ETH_ALEN); + if (channel) + *channel = ap_info->channel; + + return 1; + +} + +void aws_try_adjust_chan(void) +{ + struct ap_info *ap = NULL; + char ssid[ZC_MAX_SSID_LEN] = {0}; + ap = zconfig_get_apinfo(zc_bssid); + if (ap == NULL) + return; + if (zconfig_get_lock_chn() == ap->channel) + return; + if (!zconfig_is_valid_channel(ap->channel)) + return; + strncpy(ssid, (const char *)ap->ssid, ZC_MAX_SSID_LEN - 1); + +#ifdef AWSS_SUPPORT_AHA + if (strlen(ssid) == strlen(zc_default_ssid) && + strncmp(ap->ssid, zc_default_ssid, strlen(zc_default_ssid)) == 0) + return; +#endif +#ifdef AWSS_SUPPORT_ADHA + if (strlen(ssid) == strlen(zc_adha_ssid) && + strncmp(ap->ssid, zc_adha_ssid, strlen(zc_adha_ssid)) == 0) + return; +#endif + + aws_set_dst_chan(ap->channel); + aws_switch_channel(); +} + +int awss_ieee80211_aplist_process(uint8_t *mgmt_header, int len, int link_type, struct parser_res *res, signed char rssi) +{ + uint8_t ssid[ZC_MAX_SSID_LEN] = {0}, bssid[ETH_ALEN] = {0}; + uint8_t auth, pairwise_cipher, group_cipher; + struct ieee80211_hdr *hdr; + int fc, ret, channel; + + if (mgmt_header == NULL) + return ALINK_INVALID; + + hdr = (struct ieee80211_hdr *)mgmt_header; + fc = hdr->frame_control; + + /* + * just for save ap in aplist for ssid amend. + */ + if (!ieee80211_is_beacon(fc) && !ieee80211_is_probe_resp(fc)) + return ALINK_INVALID; + + ret = ieee80211_get_bssid(mgmt_header, bssid); + if (ret < 0) + return ALINK_INVALID; + + ret = ieee80211_get_ssid(mgmt_header, len, ssid); + if (ret < 0) + return ALINK_INVALID; + + /* + * skip all the adha and aha + */ +#ifdef AWSS_SUPPORT_AHA + if (strcmp((const char *)ssid, zc_default_ssid) == 0) + return ALINK_INVALID; +#endif +#ifdef AWSS_SUPPORT_ADHA + if (strcmp((const char *)ssid, zc_adha_ssid) == 0) + return ALINK_INVALID; +#endif + + channel = cfg80211_get_bss_channel(mgmt_header, len); + rssi = rssi > 0 ? rssi - 256 : rssi; + + cfg80211_get_cipher_info(mgmt_header, len, &auth, + &pairwise_cipher, &group_cipher); + awss_save_apinfo(ssid, bssid, channel, auth, + pairwise_cipher, group_cipher, rssi); + return ALINK_INVALID; +} + +#endif + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/aplist/awss_aplist.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/aplist/awss_aplist.h new file mode 100644 index 00000000..8ec3927b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/aplist/awss_aplist.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_APLIST_H__ +#define __AWSS_APLIST_H__ + +#include +#include "os.h" +#include "zconfig_protocol.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif +#ifdef AWSS_SUPPORT_APLIST +struct ap_info { + uint8_t auth; + uint8_t channel; + uint8_t encry[2]; + uint8_t mac[ETH_ALEN]; + char ssid[ZC_MAX_SSID_LEN]; + signed char rssi; +}; + +void aws_try_adjust_chan(void); + +int awss_clear_aplist(void); +int awss_is_ready_clr_aplist(void); +int awss_open_aplist_monitor(void); +int awss_close_aplist_monitor(void); +int awss_init_ieee80211_aplist(void); +int awss_deinit_ieee80211_aplist(void); +int awss_get_auth_info(uint8_t *ssid, uint8_t *bssid, uint8_t *auth, + uint8_t *encry, uint8_t *channel); +int awss_ieee80211_aplist_process(uint8_t *mgmt_header, int len, int link_type, + struct parser_res *res, signed char rssi); +int awss_save_apinfo(uint8_t *ssid, uint8_t* bssid, uint8_t channel, uint8_t auth, + uint8_t pairwise_cipher, uint8_t group_cipher, signed char rssi); + +/* storage to store apinfo */ +extern struct ap_info *zconfig_aplist; +/* aplist num, less than MAX_APLIST_NUM */ +extern uint8_t zconfig_aplist_num; +#endif + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/aws_lib.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/aws_lib.h new file mode 100644 index 00000000..a713a8bb --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/aws_lib.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWS_LIB_H__ +#define __AWS_LIB_H__ + +#include + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +/* auth type */ +enum AWS_AUTH_TYPE { + AWS_AUTH_TYPE_OPEN, + AWS_AUTH_TYPE_SHARED, + AWS_AUTH_TYPE_WPAPSK, + AWS_AUTH_TYPE_WPA8021X, + AWS_AUTH_TYPE_WPA2PSK, + AWS_AUTH_TYPE_WPA28021X, + AWS_AUTH_TYPE_WPAPSKWPA2PSK, + AWS_AUTH_TYPE_MAX = AWS_AUTH_TYPE_WPAPSKWPA2PSK, + AWS_AUTH_TYPE_INVALID = 0xff, +}; + +/* encry type */ +enum AWS_ENC_TYPE { + AWS_ENC_TYPE_NONE, + AWS_ENC_TYPE_WEP, + AWS_ENC_TYPE_TKIP, + AWS_ENC_TYPE_AES, + AWS_ENC_TYPE_TKIPAES, + AWS_ENC_TYPE_MAX = AWS_ENC_TYPE_TKIPAES, + AWS_ENC_TYPE_INVALID = 0xff, +}; + +/* link type */ +enum AWS_LINK_TYPE { + AWS_LINK_TYPE_NONE, + AWS_LINK_TYPE_PRISM, + AWS_LINK_TYPE_80211_RADIO, + AWS_LINK_TYPE_80211_RADIO_AVS +}; + +#if 0 +/* 将monitor模式下抓到的包传入该函数进行处理 + * 参数: + * buf: frame buffer + * length: frame len + * link_type: see enum AWS_LINK_TYPE + * with_fcs: frame include 80211 fcs field, the tailing 4bytes + * + * 说明: + * 适配前执行以下命令, 检查link_type和with_fcs参数 + * a) iwconfig wlan0 mode monitor #进入monitor模式 + * b) iwconfig wlan0 channel 6 #切换到信道6(以路由器信道为准) + * c) tcpdump -i wlan0 -s0 -w file.pacp #抓包保存文件 + * d) 用wireshark或者omnipeek打开,检查包头格式,及包尾是否包含FCS 4字节 + * + * 常见的包头类型为: + * 无额外的包头:AWS_LINK_TYPE_NONE + * radio header: hdr_len = *(uint16_t *)(buf + 2) + * avs header: hdr_len = *(unsigned long *)(buf + 4) + * prism header: hdr_len = 144 + */ +int aws_80211_frame_handler(char *buf, int length, + int link_type, int with_fcs); +#endif + +/* 启动一键配网服务, 该函数会block,直到配网成功或者超时退出, + * 超时时间由aws_timeout_period_ms设置 + * 参数: + * pk: product key + * dn: device name + * ds: device security + * ps: product security + */ +void aws_start(char *pk, char *dn, char *ds, char *ps); +/* {该函数大致流程如下: + * init(); + * platform_monitor_open(); + * aws_main_thread_func(); + * platform_monitor_close(); + * destroy(); + * } + + * aws_start返回后,调用该函数,获取ssid和passwd等信息 + * aws成功时,ssid & passwd一定会返回非NULL字符串, 但bssid和auth, encry, channel + * 有可能会返回NULL或者INVALID值(取决于是否能在wifi列表里搜索命中) + * aws失败超时后,该函数会返回0, 且所有参数为NULL或INVALID VALUE + * + * auth defined by enum AWS_AUTH_TYPE + * encry defined by enum AWS_ENC_TYPE + * + * 返回值:1--成功,0--失败 + */ +int aws_get_ssid_passwd(char ssid[32 + 1], char passwd[64 + 1], uint8_t bssid[6], + char *auth, char *encry, uint8_t *channel); + +/* 配网结束(成功或失败)后,调用该函数,释放配网库占用的资源 */ +void aws_destroy(void); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/awss.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/awss.c new file mode 100644 index 00000000..117df17a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/awss.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#define AWSS_PRESS_TIMEOUT_MS (60000) + +extern int switch_ap_done; +static uint8_t awss_stopped = 1; +static uint8_t g_user_press = 0; +static void *press_timer = NULL; + +static void awss_press_timeout(void); + +int awss_success_notify(void) +{ + g_user_press = 0; + awss_press_timeout(); + + awss_cmp_local_init(AWSS_LC_INIT_SUC); + awss_suc_notify_stop(); + awss_suc_notify(); + awss_start_connectap_monitor(); + AWSS_DISP_STATIS(); + return 0; +} + +int awss_start(void) +{ + if (awss_stopped == 0) { + awss_debug("awss already running\n"); + return -1; + } + + awss_stopped = 0; + awss_event_post(IOTX_AWSS_START); + produce_random(aes_random, sizeof(aes_random)); + + do { + __awss_start(); +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + do { + char ssid[PLATFORM_MAX_SSID_LEN + 1] = {0}; +#ifdef AWSS_SUPPORT_ADHA + while (1) { + memset(ssid, 0, sizeof(ssid)); + HAL_Wifi_Get_Ap_Info(ssid, NULL, NULL); + awss_debug("start, ssid:%s, strlen:%lu\n", ssid, strlen(ssid)); + if (strlen(ssid) > 0 && strcmp(ssid, ADHA_SSID)) { /* not adha AP */ + break; + } + + if (HAL_Sys_Net_Is_Ready()) { /* skip the adha failed */ + awss_cmp_local_init(AWSS_LC_INIT_ROUTER); + + awss_open_adha_monitor(); + while (!awss_is_ready_switch_next_adha()) { + if (awss_stopped) { + break; + } + HAL_SleepMs(50); + } + awss_cmp_local_deinit(0); + } + + if (switch_ap_done || awss_stopped) { + break; + } + __awss_start(); + } +#endif + if (awss_stopped) { + break; + } + + if (switch_ap_done) { + break; + } + + HAL_Wifi_Get_Ap_Info(ssid, NULL, NULL); + if (strlen(ssid) > 0 && strcmp(ssid, DEFAULT_SSID)) { /* not AHA */ + break; + } + + if (HAL_Sys_Net_Is_Ready()) { + char dest_ap = 0; + awss_open_aha_monitor(); + + awss_cmp_local_init(AWSS_LC_INIT_PAP); + while (!awss_aha_monitor_is_timeout()) { + memset(ssid, 0, sizeof(ssid)); + HAL_Wifi_Get_Ap_Info(ssid, NULL, NULL); + if (HAL_Sys_Net_Is_Ready() && + strlen(ssid) > 0 && strcmp(ssid, DEFAULT_SSID)) { /* not AHA */ + dest_ap = 1; + break; + } + if (awss_stopped) { + break; + } + HAL_SleepMs(50); + } + + awss_cmp_local_deinit(0); + + if (switch_ap_done || awss_stopped) { + break; + } + + if (dest_ap == 1) { + break; + } + } + awss_event_post(IOTX_AWSS_ENABLE_TIMEOUT); + __awss_start(); + } while (1); +#endif + if (awss_stopped) { + break; + } + + if (HAL_Sys_Net_Is_Ready()) { + break; + } + } while (1); + + if (awss_stopped) { + return -1; + } + +#ifdef AWSS_SUPPORT_AHA + awss_close_aha_monitor(); +#endif +#ifdef AWSS_SUPPORT_ADHA + awss_close_adha_monitor(); +#endif + + awss_success_notify(); + awss_stopped = 1; + + return 0; +} + +int awss_stop(void) +{ + awss_stopped = 1; +#ifdef AWSS_SUPPORT_AHA + awss_close_aha_monitor(); +#endif +#ifdef AWSS_SUPPORT_ADHA + awss_close_adha_monitor(); +#endif + awss_stop_connectap_monitor(); + g_user_press = 0; + awss_press_timeout(); + + __awss_stop(); + + return 0; +} + +static void awss_press_timeout(void) +{ + awss_stop_timer(press_timer); + press_timer = NULL; + if (g_user_press) { + awss_event_post(IOTX_AWSS_ENABLE_TIMEOUT); + } + g_user_press = 0; +} + +int awss_config_press(void) +{ + int timeout = HAL_Awss_Get_Timeout_Interval_Ms(); + + awss_trace("enable awss\r\n"); + + g_user_press = 1; + + awss_event_post(IOTX_AWSS_ENABLE); + + if (press_timer == NULL) { + press_timer = HAL_Timer_Create("press", (void (*)(void *))awss_press_timeout, NULL); + } + if (press_timer == NULL) { + return -1; + } + + HAL_Timer_Stop(press_timer); + + if (timeout < AWSS_PRESS_TIMEOUT_MS) { + timeout = AWSS_PRESS_TIMEOUT_MS; + } + HAL_Timer_Start(press_timer, timeout); + + return 0; +} + +uint8_t awss_get_config_press(void) +{ + return g_user_press; +} + +void awss_set_config_press(uint8_t press) +{ + g_user_press = press; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/awss_main.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/awss_main.c new file mode 100644 index 00000000..e1fc1ac4 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/awss_main.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +char awss_finished = 2; +char awss_stop_connecting = 0; +int __awss_start(void) +{ + char ssid[OS_MAX_SSID_LEN + 1] = {0}, passwd[OS_MAX_PASSWD_LEN + 1] = {0}; + enum AWSS_AUTH_TYPE auth = AWSS_AUTH_TYPE_INVALID; + enum AWSS_ENC_TYPE encry = AWSS_ENC_TYPE_INVALID; + uint8_t bssid[OS_ETH_ALEN] = {0}; + uint8_t channel = 0; + int ret; + + awss_stop_connecting = 0; + awss_finished = 0; + /* these params is useless, keep it for compatible reason */ + aws_start(NULL, NULL, NULL, NULL); + + ret = aws_get_ssid_passwd(&ssid[0], &passwd[0], &bssid[0], + (char *)&auth, (char *)&encry, &channel); + if (!ret) { + awss_warn("awss timeout!"); + } + + if (awss_stop_connecting) { + awss_finished = 1; + return -1; + } + + aws_destroy(); + + do { +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + char awss_notify_needed = 1; + int adha = 0; +#endif + + if (awss_stop_connecting || strlen(ssid) == 0) { + break; + } +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + if ((adha = strcmp(ssid, ADHA_SSID)) == 0 || strcmp(ssid, DEFAULT_SSID) == 0) { + awss_notify_needed = 0; + awss_event_post(adha != 0 ? IOTX_AWSS_CONNECT_AHA : IOTX_AWSS_CONNECT_ADHA); + } else +#endif + { + awss_event_post(IOTX_AWSS_CONNECT_ROUTER); + AWSS_UPDATE_STATIS(AWSS_STATIS_CONN_ROUTER_IDX, AWSS_STATIS_TYPE_TIME_START); + } + + ret = HAL_Awss_Connect_Ap(WLAN_CONNECTION_TIMEOUT_MS, ssid, passwd, + auth, encry, bssid, channel); + if (!ret) { + awss_debug("awss connect ssid:%s success", ssid); + awss_event_post(IOTX_AWSS_GOT_IP); + +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + if (awss_notify_needed == 0) { + awss_dev_bind_notify_stop(); + awss_suc_notify_stop(); + awss_cmp_local_init(adha == 0 ? AWSS_LC_INIT_ROUTER : AWSS_LC_INIT_PAP); + awss_devinfo_notify(); + if (adha == 0) { + AWSS_UPDATE_STATIS(AWSS_STATIS_ROUTE_IDX, AWSS_STATIS_TYPE_TIME_SUC); + } + awss_event_post(IOTX_AWSS_SETUP_NOTIFY); + } else +#endif + { + AWSS_UPDATE_STATIS(AWSS_STATIS_CONN_ROUTER_IDX, AWSS_STATIS_TYPE_TIME_SUC); + awss_devinfo_notify_stop(); + produce_random(aes_random, sizeof(aes_random)); + } + } else { + awss_debug("awss connect ssid:%s fail", ssid); +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + if (awss_notify_needed == 0) { + awss_event_post(adha != 0 ? IOTX_AWSS_CONNECT_AHA_FAIL : IOTX_AWSS_CONNECT_ADHA_FAIL); + } else +#endif + { + awss_event_post(IOTX_AWSS_CONNECT_ROUTER_FAIL); + } + } + } while (0); + + AWSS_DISP_STATIS(); + awss_finished = 1; + return 0; +} + +int __awss_stop(void) +{ + awss_stop_connecting = 1; + aws_destroy(); +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + awss_devinfo_notify_stop(); +#endif + awss_suc_notify_stop(); +#ifndef AWSS_DISABLE_REGISTRAR + awss_registrar_deinit(); +#endif + if (awss_finished < 2) { + awss_cmp_local_deinit(1); + } else { + awss_cmp_local_deinit(0); + } + + while (1) { + if (awss_finished) { + break; + } + HAL_SleepMs(300); + } + aws_release_mutex(); + awss_finished = 2; + return 0; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/awss_main.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/awss_main.h new file mode 100644 index 00000000..6175213a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/awss_main.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_MAIN_H__ +#define __AWSS_MAIN_H__ + +#include "awss_log.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +#define DEFAULT_SSID zc_default_ssid +#define DEFAULT_PASSWD zc_default_passwd +#define ADHA_SSID zc_adha_ssid +#define ADHA_PASSWD zc_adha_passwd + +extern const char *zc_default_ssid; +extern const char *zc_default_passwd; +extern const char *zc_adha_ssid; +extern const char *zc_adha_passwd; + +int __awss_start(void); +int __awss_stop(void); + +int awss_cancel_aha_monitor(void); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/awss_smartconfig.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/awss_smartconfig.h new file mode 100644 index 00000000..13e0a7e4 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/awss_smartconfig.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_SMARTCONFIG_H__ +#define __AWSS_SMARTCONFIG_H__ + +#include +#include "os.h" +#include "zconfig_lib.h" +#include "zconfig_ieee80211.h" +#include "zconfig_protocol.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +/* invalid channel, neither 0, 0xff, nor 1-13 */ +#define INVALID_CHANNEL (0) +#define PAYLOAD_BITS_CNT (7) +#define PAYLOAD_BITS_MASK ((1 << PAYLOAD_BITS_CNT) - 1) + +extern const uint8_t zconfig_fixed_offset[ZC_ENC_TYPE_MAX + 1][2]; +extern const uint16_t zconfig_hint_frame[]; + +uint8_t is_data_frame(uint16_t len); +uint8_t is_start_frame(uint16_t len); +uint8_t is_group_frame(uint16_t len); +uint8_t get_data_index(uint16_t len); +uint8_t get_group_index(uint16_t len); + +int zconfig_recv_completed(uint8_t tods); +int zconfig_get_ssid_passwd(uint8_t tods); +int package_cmp(uint8_t *package, uint8_t *src, uint8_t *dst, uint8_t tods, uint16_t len); +int package_save(uint8_t *package, uint8_t *src, uint8_t *dst, uint8_t tods, uint16_t len); +int awss_recv_callback_smartconfig(struct parser_res *res); +int awss_ieee80211_smartconfig_process(uint8_t *ieee80211, int len, int link_type, + struct parser_res *res, signed char rssi); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/ieee80211/zconfig_ieee80211.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/ieee80211/zconfig_ieee80211.c new file mode 100644 index 00000000..07f4a9f8 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/ieee80211/zconfig_ieee80211.c @@ -0,0 +1,825 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +/** + * ieee80211_is_mgmt - check if type is IEEE80211_FTYPE_MGMT + * @fc: frame control bytes in little-endian byteorder + */ +#if 0 +int ieee80211_is_mgmt(uint16_t fc) +{ + return (fc & os_htole16(IEEE80211_FCTL_FTYPE)) == + os_htole16(IEEE80211_FTYPE_MGMT); +} +#endif + +/** + * ieee80211_is_ctl - check if type is IEEE80211_FTYPE_CTL + * @fc: frame control bytes in little-endian byteorder + */ +int ieee80211_is_ctl(uint16_t fc) +{ + return (fc & os_htole16(IEEE80211_FCTL_FTYPE)) == + os_htole16(IEEE80211_FTYPE_CTL); +} + +/** + * ieee80211_is_data - check if type is IEEE80211_FTYPE_DATA + * @fc: frame control bytes in little-endian byteorder + */ +int ieee80211_is_data(uint16_t fc) +{ + return (fc & os_htole16(IEEE80211_FCTL_FTYPE)) == + os_htole16(IEEE80211_FTYPE_DATA); +} + + +/** + * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set + * @fc: frame control bytes in little-endian byteorder + */ +int ieee80211_has_tods(uint16_t fc) +{ + return (fc & os_htole16(IEEE80211_FCTL_TODS)) != 0; +} + +/** + * ieee80211_has_fromds - check if IEEE80211_FCTL_FROMDS is set + * @fc: frame control bytes in little-endian byteorder + */ +int ieee80211_has_fromds(uint16_t fc) +{ + return (fc & os_htole16(IEEE80211_FCTL_FROMDS)) != 0; +} + +/** + * ieee80211_has_a4 - check if IEEE80211_FCTL_TODS and IEEE80211_FCTL_FROMDS are set + * @fc: frame control bytes in little-endian byteorder + */ +int ieee80211_has_a4(uint16_t fc) +{ + uint16_t tmp = os_htole16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); + return (fc & tmp) == tmp; +} + +/** + * ieee80211_has_order - check if IEEE80211_FCTL_ORDER is set + * @fc: frame control bytes in little-endian byteorder + */ +int ieee80211_has_order(uint16_t fc) +{ + return (fc & os_htole16(IEEE80211_FCTL_ORDER)) != 0; +} + +/** + * ieee80211_has_protected - check if IEEE80211_FCTL_PROTECTED is set + * @fc: frame control bytes in little-endian byteorder + */ +int ieee80211_has_protected(uint16_t fc) +{ + return (fc & os_htole16(IEEE80211_FCTL_PROTECTED)) != 0; +} + +/** + * ieee80211_is_data_qos - check if type is IEEE80211_FTYPE_DATA and IEEE80211_STYPE_QOS_DATA is set + * @fc: frame control bytes in little-endian byteorder + */ +int ieee80211_is_data_qos(uint16_t fc) +{ + /* + * mask with QOS_DATA rather than IEEE80211_FCTL_STYPE as we just need + * to check the one bit + */ + return (fc & os_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_STYPE_QOS_DATA)) == + os_htole16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA); +} + +/** + * ieee80211_is_data_present - check if type is IEEE80211_FTYPE_DATA and has data + * @fc: frame control bytes in little-endian byteorder + */ +#if 0 +int ieee80211_is_data_present(uint16_t fc) +{ + /* + * mask with 0x40 and test that that bit is clear to only return true + * for the data-containing substypes. + */ + return (fc & os_htole16(IEEE80211_FCTL_FTYPE | 0x40)) == + os_htole16(IEEE80211_FTYPE_DATA); +} +#endif + +/** + * ieee80211_is_data_present - check if type is IEEE80211_FTYPE_DATA and only data + * @fc: frame control bytes in little-endian byteorder + */ +int ieee80211_is_data_exact(uint16_t fc) +{ + uint16_t tmp = fc & os_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); + + return (tmp == os_htole16(IEEE80211_FTYPE_DATA)) || + (tmp == os_htole16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)); +} + +/** + * ieee80211_is_beacon - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_BEACON + * @fc: frame control bytes in little-endian byteorder + */ +int ieee80211_is_beacon(uint16_t fc) +{ + return (fc & os_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + os_htole16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); +} + +/** + * ieee80211_is_action - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ACTION + * @fc: frame control bytes in little-endian byteorder + */ +#if 0 +int ieee80211_is_action(uint16_t fc) +{ + return (fc & os_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + os_htole16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); +} +#endif + +/** + * ieee80211_is_probe_req - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_PROBE_REQ + * @fc: frame control bytes in little-endian byteorder + */ +int ieee80211_is_probe_req(uint16_t fc) +{ + return (fc & os_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + os_htole16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ); +} + +/** + * ieee80211_is_probe_resp - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_PROBE_RESP + * @fc: frame control bytes in little-endian byteorder + */ +int ieee80211_is_probe_resp(uint16_t fc) +{ + return (fc & os_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + os_htole16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); +} + + +/** + * ieee80211_get_SA - get pointer to SA + * @hdr: the frame + * + * Given an 802.11 frame, this function returns the offset + * to the source address (SA). It does not verify that the + * header is long enough to contain the address, and the + * header must be long enough to contain the frame control + * field. + */ +uint8_t *ieee80211_get_SA(struct ieee80211_hdr *hdr) +{ + if (ieee80211_has_a4(hdr->frame_control)) + return hdr->addr4; + if (ieee80211_has_fromds(hdr->frame_control)) + return hdr->addr3; + return hdr->addr2; +} + +/** + * ieee80211_get_DA - get pointer to DA + * @hdr: the frame + * + * Given an 802.11 frame, this function returns the offset + * to the destination address (DA). It does not verify that + * the header is long enough to contain the address, and the + * header must be long enough to contain the frame control + * field. + */ +uint8_t *ieee80211_get_DA(struct ieee80211_hdr *hdr) +{ + if (ieee80211_has_tods(hdr->frame_control)) + return hdr->addr3; + else + return hdr->addr1; +} + +uint8_t *ieee80211_get_BSSID(struct ieee80211_hdr *hdr) +{ + if (ieee80211_has_tods(hdr->frame_control)) { + if (!ieee80211_has_fromds(hdr->frame_control)) + return hdr->addr1; + else + return NULL; + } else { + if (ieee80211_has_fromds(hdr->frame_control)) + return hdr->addr2; + else + return hdr->addr3; + } +} + +int ieee80211_get_bssid(uint8_t *in, uint8_t *mac) +{ + uint8_t *bssid = ieee80211_get_BSSID((struct ieee80211_hdr *)in); + + if (bssid) + memcpy(mac, bssid, ETH_ALEN); + else + return -1; + + return 0; +} + +int ieee80211_has_frags(uint16_t fc) +{ + uint16_t tmp = fc & os_htole16(IEEE80211_FCTL_MOREFRAGS | IEEE80211_FCTL_ORDER); + + return !!tmp; +} + +/* DATA: 24B */ +/* QOS-DATA: 26B */ +int ieee80211_hdrlen(uint16_t fc) +{ + uint32_t hdrlen = 24; + + if (ieee80211_is_data(fc)) { + if (ieee80211_has_a4(fc)) + hdrlen = 30; + if (ieee80211_is_data_qos(fc)) { + hdrlen += IEEE80211_QOS_CTL_LEN; + if (ieee80211_has_order(fc)) + hdrlen += IEEE80211_HT_CTL_LEN; + } + goto out; + } + + if (ieee80211_is_ctl(fc)) { + /* + * ACK and CTS are 10 bytes, all others 16. To see how + * to get this condition consider + * subtype mask: 0b0000000011110000 (0x00F0) + * ACK subtype: 0b0000000011010000 (0x00D0) + * CTS subtype: 0b0000000011000000 (0x00C0) + * bits that matter: ^^^ (0x00E0) + * value of those: 0b0000000011000000 (0x00C0) + */ + if ((fc & os_htole16(0x00E0)) == os_htole16(0x00C0)) + hdrlen = 10; + else + hdrlen = 16; + } + +out: + return hdrlen; +} + +/* helpers */ +int ieee80211_get_radiotap_len(uint8_t *data) +{ + struct ieee80211_radiotap_header *hdr = + (struct ieee80211_radiotap_header *)data; + + return os_get_unaligned_le16((uint8_t *)&hdr->it_len); +} + +const uint8_t *cfg80211_find_ie(uint8_t eid, const uint8_t *ies, int len) +{ + while (len > 2 && ies[0] != eid) { + len -= ies[1] + 2; + ies += ies[1] + 2; + } + if (len < 2) + return NULL; + if (len < 2 + ies[1]) + return NULL; + return ies; +} + +/** + * cfg80211_find_vendor_ie - find vendor specific information element in data + * + * @oui: vendor OUI + * @oui_type: vendor-specific OUI type + * @ies: data consisting of IEs + * @len: length of data + * + * Return: %NULL if the vendor specific element ID could not be found or if the + * element is invalid (claims to be longer than the given data), or a pointer to + * the first byte of the requested element, that is the byte containing the + * element ID. + * + * Note: There are no checks on the element length other than having to fit into + * the given data. + */ +const uint8_t *cfg80211_find_vendor_ie(uint32_t oui, uint8_t oui_type, const uint8_t *ies, int len) +{ + struct ieee80211_vendor_ie *ie; + const uint8_t *pos = ies, *end = ies + len; + int ie_oui; + + while (pos < end) { + pos = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, pos, + end - pos); + if (!pos) + return NULL; + + ie = (struct ieee80211_vendor_ie *)pos; + + /* make sure we can access ie->len */ + /* BUILD_BUG_ON(offsetof(struct ieee80211_vendor_ie, len) != 1); */ + + if (ie->len < sizeof(*ie)) + goto cont; + + ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2]; + /* awss_trace("oui=%x, type=%x, len=%d\r\n", ie_oui, oui_type, ie->len); */ + if (ie_oui == oui && ie->oui_type == oui_type) + return pos; +cont: + pos += 2 + ie->len; + } + return NULL; +} + +/** + * extract ssid from beacon frame or probe resp frame + * + * @beacon_frame: [IN] original 80211 beacon frame + * @frame_len: [IN] len of beacon frame + * @ssid: [OUT] null-terminated string, max len 32 bytes + * + * Return: + * 0/success, -1/failed + */ +int ieee80211_get_ssid(uint8_t *beacon_frame, uint16_t frame_len, uint8_t *ssid) +{ + uint16_t ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);/* same as u.probe_resp.variable */ + const uint8_t *ptr = cfg80211_find_ie(WLAN_EID_SSID, + beacon_frame + ieoffset, frame_len - ieoffset); + if (ptr) { + uint8_t ssid_len = ptr[1]; + if (ssid_len <= 32) { /* ssid 32 octets at most */ + memcpy(ssid, ptr + 2, ssid_len);/* eating EID & len */ + ssid[ssid_len] = '\0'; + return 0; + } + } + + return -1; +} + +/** + * extract channel from beacon frame or probe resp frame + * + * @beacon_frame: [IN] original 80211 beacon frame + * @frame_len: [IN] len of beacon frame + * + * Return: + * bss channel 1-13, 0--means invalid channel + */ +int cfg80211_get_bss_channel(uint8_t *beacon_frame, uint16_t frame_len) +{ + uint16_t ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);/* same as u.probe_resp.variable */ + const uint8_t *ie = beacon_frame + ieoffset; + uint16_t ielen = frame_len - ieoffset; + + const uint8_t *tmp; + int channel_number = 0; + + tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen); + if (tmp && tmp[1] == 1) { + channel_number = tmp[2]; + } else { + tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen); + if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) { + struct ieee80211_ht_operation *htop = (void *)(tmp + 2); + + channel_number = htop->primary_chan; + } + } + + return channel_number; +} + +static const uint8_t WPA_OUI23A_TYPE[] = {0x00, 0x50, 0xf2, 0x01}; +static const uint8_t RSN_SUITE_1X[] = {0x00, 0x0f, 0xac, 0x01}; + +static const uint8_t WPA_CIPHER_SUITE_NONE23A[] = {0x00, 0x50, 0xf2, 0x00}; +static const uint8_t WPA_CIPHER_SUITE_WEP4023A[] = {0x00, 0x50, 0xf2, 0x01}; +static const uint8_t WPA_CIPHER_SUITE_TKIP23A[] = {0x00, 0x50, 0xf2, 0x02}; +/* static const uint8_t WPA_CIPHER_SUITE_WRAP23A[] = {0x00, 0x50, 0xf2, 0x03}; */ +static const uint8_t WPA_CIPHER_SUITE_CCMP23A[] = {0x00, 0x50, 0xf2, 0x04}; +static const uint8_t WPA_CIPHER_SUITE_WEP10423A[] = {0x00, 0x50, 0xf2, 0x05}; + +static const uint8_t RSN_CIPHER_SUITE_NONE23A[] = {0x00, 0x0f, 0xac, 0x00}; +static const uint8_t RSN_CIPHER_SUITE_WEP4023A[] = {0x00, 0x0f, 0xac, 0x01}; +static const uint8_t RSN_CIPHER_SUITE_TKIP23A[] = {0x00, 0x0f, 0xac, 0x02}; +/* static const uint8_t RSN_CIPHER_SUITE_WRAP23A[] = {0x00, 0x0f, 0xac, 0x03}; */ +static const uint8_t RSN_CIPHER_SUITE_CCMP23A[] = {0x00, 0x0f, 0xac, 0x04}; +static const uint8_t RSN_CIPHER_SUITE_WEP10423A[] = {0x00, 0x0f, 0xac, 0x05}; + +#define WPA_SELECTOR_LEN (4) +#define RSN_SELECTOR_LEN (4) + +#define BIT(x) (1 << (x)) +#define WPA_CIPHER_NONE BIT(0) +#define WPA_CIPHER_WEP40 BIT(1) +#define WPA_CIPHER_WEP104 BIT(2) +#define WPA_CIPHER_TKIP BIT(3) +#define WPA_CIPHER_CCMP BIT(4) + +static uint8_t map_cipher_to_encry(uint8_t cipher) +{ + switch (cipher) { + case WPA_CIPHER_CCMP: + return ZC_ENC_TYPE_AES; + case WPA_CIPHER_TKIP: + return ZC_ENC_TYPE_TKIP; + case WPA_CIPHER_WEP40: + case WPA_CIPHER_WEP104: + return ZC_ENC_TYPE_WEP; + case WPA_CIPHER_NONE: + return ZC_ENC_TYPE_NONE; + case (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP): + return ZC_ENC_TYPE_TKIPAES; + default: + awss_warn("unknow cipher type: %x\r\n", cipher); + return ZC_ENC_TYPE_INVALID; + } +} + +static int get_wpa_cipher_suite(const uint8_t *s) +{ + if (!memcmp(s, WPA_CIPHER_SUITE_NONE23A, WPA_SELECTOR_LEN)) + return WPA_CIPHER_NONE; + if (!memcmp(s, WPA_CIPHER_SUITE_WEP4023A, WPA_SELECTOR_LEN)) + return WPA_CIPHER_WEP40; + if (!memcmp(s, WPA_CIPHER_SUITE_TKIP23A, WPA_SELECTOR_LEN)) + return WPA_CIPHER_TKIP; + if (!memcmp(s, WPA_CIPHER_SUITE_CCMP23A, WPA_SELECTOR_LEN)) + return WPA_CIPHER_CCMP; + if (!memcmp(s, WPA_CIPHER_SUITE_WEP10423A, WPA_SELECTOR_LEN)) + return WPA_CIPHER_WEP104; + + return 0; +} + +static int get_wpa2_cipher_suite(const uint8_t *s) +{ + if (!memcmp(s, RSN_CIPHER_SUITE_NONE23A, RSN_SELECTOR_LEN)) + return WPA_CIPHER_NONE; + if (!memcmp(s, RSN_CIPHER_SUITE_WEP4023A, RSN_SELECTOR_LEN)) + return WPA_CIPHER_WEP40; + if (!memcmp(s, RSN_CIPHER_SUITE_TKIP23A, RSN_SELECTOR_LEN)) + return WPA_CIPHER_TKIP; + if (!memcmp(s, RSN_CIPHER_SUITE_CCMP23A, RSN_SELECTOR_LEN)) + return WPA_CIPHER_CCMP; + if (!memcmp(s, RSN_CIPHER_SUITE_WEP10423A, RSN_SELECTOR_LEN)) + return WPA_CIPHER_WEP104; + + return 0; +} + +int cfg80211_parse_wpa_info(const uint8_t *wpa_ie, int wpa_ie_len, + uint8_t *group_cipher, uint8_t *pairwise_cipher, + uint8_t *is_8021x) +{ + int i, ret = 0; + int left, count; + const uint8_t *pos; + + if (wpa_ie_len <= 0) { + /* No WPA IE - fail silently */ + return -1; + } + + if (wpa_ie[1] != (uint8_t)(wpa_ie_len - 2)) + return -1; + + pos = wpa_ie; + + pos += 8; + left = wpa_ie_len - 8; + + /* group_cipher */ + if (left >= WPA_SELECTOR_LEN) { + + *group_cipher = get_wpa_cipher_suite(pos); + + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } else if (left > 0) { + return -1; + } + + /* pairwise_cipher */ + if (left >= 2) { + /* count = le16_to_cpu(*(uint16_t*)pos); */ + count = os_get_unaligned_le16((uint8_t *)pos); + pos += 2; + left -= 2; + + if (count == 0 || left < count * WPA_SELECTOR_LEN) { + return -1; + } + + for (i = 0; i < count; i++) { + *pairwise_cipher |= get_wpa_cipher_suite(pos); + + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } + } else if (left == 1) { + return -1; + } + + if (is_8021x) { + if (left >= 6) { + pos += 2; + if (!memcmp(pos, WPA_OUI23A_TYPE, 4)) { + *is_8021x = 1; + } + } + } + + return ret; +} + +int cfg80211_parse_wpa2_info(const uint8_t* rsn_ie, int rsn_ie_len, uint8_t *group_cipher, + uint8_t *pairwise_cipher, uint8_t *is_8021x) +{ + int i, ret = 0; + int left, count; + const uint8_t *pos; + + if (rsn_ie_len <= 0) { + /* No RSN IE - fail silently */ + return -1; + } + + if (*rsn_ie != WLAN_EID_RSN || *(rsn_ie+1) != (uint8_t)(rsn_ie_len - 2)) { + return -1; + } + + pos = rsn_ie; + pos += 4; + left = rsn_ie_len - 4; + + /* group_cipher */ + if (left >= RSN_SELECTOR_LEN) { + *group_cipher = get_wpa2_cipher_suite(pos); + + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } else if (left > 0) { + return -1; + } + + /* pairwise_cipher */ + if (left >= 2) { + /* count = le16_to_cpu(*(uint16_t*)pos); */ + count = os_get_unaligned_le16((uint8_t *)pos); + pos += 2; + left -= 2; + + if (count == 0 || left < count * RSN_SELECTOR_LEN) { + return -1; + } + + for (i = 0; i < count; i++) { + *pairwise_cipher |= get_wpa2_cipher_suite(pos); + + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } + } else if (left == 1) { + return -1; + } + + if (is_8021x) { + if (left >= 6) { + pos += 2; + if (!memcmp(pos, RSN_SUITE_1X, 4)) { + *is_8021x = 1; + } + } + } + + return ret; +} + +/** + * extract auth/encry type from beacon frame or probe resp frame + * + * @beacon_frame: [IN] original 80211 beacon frame + * @frame_len: [IN] len of beacon frame + * + * Return: + * bss channel 1-13, 0--means invalid channel + */ +int cfg80211_get_cipher_info(uint8_t *beacon_frame, uint16_t frame_len, + uint8_t *auth_type, uint8_t *pairwise_cipher_type, + uint8_t *group_cipher_type) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon_frame; + uint8_t is_privacy = !!(mgmt->u.beacon.capab_info & WLAN_CAPABILITY_PRIVACY); + + uint16_t ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);/* same as u.probe_resp.variable */ + const uint8_t *ie = beacon_frame + ieoffset; + uint16_t ielen = frame_len - ieoffset; + + uint8_t auth = 0, group_cipher = 0, pairwise_cipher = 0, is80211X = 0; + const uint8_t *tmp; + int ret = 0; + + tmp = cfg80211_find_ie(WLAN_EID_RSN, ie, ielen); + if (tmp && tmp[1]) { + ret = cfg80211_parse_wpa2_info(tmp, tmp[1] + 2, &group_cipher, &pairwise_cipher, &is80211X); + if (is80211X) + auth = ZC_AUTH_TYPE_WPA28021X; + else + auth = ZC_AUTH_TYPE_WPA2PSK; + group_cipher = map_cipher_to_encry(group_cipher); + pairwise_cipher = map_cipher_to_encry(pairwise_cipher); + } else { +#ifdef AWSS_SUPPORT_SMARTCONFIG_WPS + tmp = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WPA, ie, ielen); + if (tmp) { + ret = cfg80211_parse_wpa_info(tmp, tmp[1] + 2, &group_cipher, &pairwise_cipher, &is80211X); + if (is80211X) + auth = ZC_AUTH_TYPE_WPA8021X; + else + auth = ZC_AUTH_TYPE_WPAPSK; + group_cipher = map_cipher_to_encry(group_cipher); + pairwise_cipher = map_cipher_to_encry(pairwise_cipher); + } else +#endif + { + if (is_privacy) { + auth = ZC_AUTH_TYPE_SHARED; /* TODO: WEP */ + pairwise_cipher = ZC_ENC_TYPE_WEP; + group_cipher = ZC_ENC_TYPE_WEP; + } else { + auth = ZC_AUTH_TYPE_OPEN; + pairwise_cipher = ZC_ENC_TYPE_NONE; + group_cipher = ZC_ENC_TYPE_NONE; + } + } + } + + if (auth_type) + *auth_type = auth; + if (pairwise_cipher_type) + *pairwise_cipher_type = pairwise_cipher; + if (group_cipher_type) + *group_cipher_type = group_cipher; + + return ret; +} + +/* + * make sure 80211 frame is word align, otherwise struct ieee80211_hdr will bug + * TODO: code refactor, avoid using memmove + */ +#define check_ieee80211_buf_alignment(buf_addr, len) \ +do {\ + if (((unsigned long)(buf_addr) & 0x1) && len > 0) {\ + uint8_t *word_align_addr = (uint8_t *)((unsigned long)(buf_addr) & ~0x1);\ + memmove(word_align_addr, buf_addr, len);\ + buf_addr = word_align_addr;\ + }\ +} while (0) + +uint8_t *zconfig_remove_link_header(uint8_t **in, int *len, int link_type) +{ + int lt_len = 0; + + switch (link_type) { + case AWS_LINK_TYPE_NONE: + break; + case AWS_LINK_TYPE_PRISM: +#define PRISM_HDR_LEN 144 + *in += PRISM_HDR_LEN; + *len -= PRISM_HDR_LEN; + /* 144, no need to check buf aligment */ + break; + case AWS_LINK_TYPE_80211_RADIO: + lt_len = ieee80211_get_radiotap_len(*in); + *in += lt_len; + *len -= lt_len; + check_ieee80211_buf_alignment(*in, *len); + break; + case AWS_LINK_TYPE_80211_RADIO_AVS: +#define WLANCAP_MAGIC_COOKIE_V1 0x80211001 +#define WLANCAP_MAGIC_COOKIE_V2 0x80211002 + lt_len = *(uint32_t *)(*in + 4);/* first 4 byte is magic code */ + *in += lt_len; + *len -= lt_len; + check_ieee80211_buf_alignment(*in, *len); + break; + default: + awss_debug("un-supported link type!\r\n"); + break; + } + + return *in; +} + +struct awss_protocol_couple_type awss_protocol_couple_array[] = { +#ifdef AWSS_SUPPORT_HT40 + {ALINK_HT_CTRL, awss_ieee80211_ht_ctrl_process, awss_recv_callback_ht_ctrl}, +#endif +#ifdef AWSS_SUPPORT_APLIST + {ALINK_APLIST, awss_ieee80211_aplist_process, NULL}, +#endif +#ifdef AWSS_SUPPORT_AHA + {ALINK_DEFAULT_SSID, awss_ieee80211_aha_process, awss_recv_callback_aha_ssid}, +#endif +#ifdef AWSS_SUPPORT_ADHA + {ALINK_ADHA_SSID, awss_ieee80211_adha_process, awss_recv_callback_adha_ssid}, +#endif +#ifndef AWSS_DISABLE_ENROLLEE + {ALINK_ZERO_CONFIG, awss_ieee80211_zconfig_process, awss_recv_callback_zconfig}, +#endif +#ifdef AWSS_SUPPORT_SMARTCONFIG_WPS + {ALINK_WPS, awss_ieee80211_wps_process, awss_recv_callback_wps}, +#endif +#ifdef AWSS_SUPPORT_SMARTCONFIG + {ALINK_BROADCAST, awss_ieee80211_smartconfig_process, awss_recv_callback_smartconfig} +#endif +}; + +/** + * ieee80211_data_extratct - extract 80211 frame info + * + * @in: [IN] 80211 frame + * @len: [IN] 80211 frame len + * @link_type: [IN] link type @see enum AWS_LINK_TYPE + * @res: [OUT] 80211 frame parser result, see struct parser_res. + * + * @warning: encry_type may collision with aes & tpip in some cases, + * then encry_type will be set to INVALID. + * @Return: + * @see enum ALINK_TYPE + * + * @Note: howto deal with radio RSSI signal + */ +int ieee80211_data_extract(uint8_t *in, int len, int link_type, struct parser_res *res, signed char rssi) +{ + struct ieee80211_hdr *hdr; + int alink_type = ALINK_INVALID; + int pkt_type = PKG_INVALID; + int i, fc; + + hdr = (struct ieee80211_hdr *)zconfig_remove_link_header(&in, &len, link_type); + if (len <= 0) + goto drop; + fc = hdr->frame_control; + + for (i = 0; i < sizeof(awss_protocol_couple_array) / sizeof(awss_protocol_couple_array[0]); i ++) { + awss_protocol_process_func_type protocol_func = awss_protocol_couple_array[i].awss_protocol_process_func; + if (protocol_func == NULL) + continue; + alink_type = protocol_func((uint8_t *)hdr, len, link_type, res, rssi); + if (alink_type != ALINK_INVALID) + break; + } + + if (alink_type == ALINK_INVALID) + goto drop; + + if (alink_type != ALINK_HT_CTRL) { + /* convert IEEE 802.11 header + possible LLC headers into Ethernet header + * IEEE 802.11 address fields: + * ToDS FromDS Addr1 Addr2 Addr3 Addr4 + * 0 0 DA SA BSSID n/a + * 0 1 DA BSSID SA n/a + * 1 0 BSSID SA DA n/a + * 1 1 RA TA DA SA + */ + res->src = ieee80211_get_SA(hdr); + res->dst = ieee80211_get_DA(hdr); + res->bssid = ieee80211_get_BSSID(hdr); + res->tods = ieee80211_has_tods(fc); + } + + do { + awss_protocol_finish_func_type finish_func = awss_protocol_couple_array[i].awss_protocol_finish_func; + if (finish_func) + pkt_type = finish_func(res); + } while(0); + +drop: + return pkt_type; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/ieee80211/zconfig_ieee80211.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/ieee80211/zconfig_ieee80211.h new file mode 100644 index 00000000..bf329fb6 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/ieee80211/zconfig_ieee80211.h @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __ZCONFIG_IEEE80211_H__ +#define __ZCONFIG_IEEE80211_H__ + +#include "zconfig_utils.h" +#include "zconfig_protocol.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +#define WIFI_RX_SENSITIVITY (-85) +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif + +/* + * DS bit usage + * + * TA = transmitter address + * RA = receiver address + * DA = destination address + * SA = source address + * + * ToDS FromDS A1(RA) A2(TA) A3 A4 Use + * ----------------------------------------------------------------- + * 0 0 DA SA BSSID - IBSS/DLS + * 0 1 DA BSSID SA - AP -> STA + * 1 0 BSSID SA DA - AP <- STA + * 1 1 RA TA DA SA unspecified (WDS) + */ +#define FCS_LEN (4) + +#define IEEE80211_FCTL_VERS (0x0003) +#define IEEE80211_FCTL_FTYPE (0x000c) +#define IEEE80211_FCTL_STYPE (0x00f0) +#define IEEE80211_FCTL_TODS (0x0100) +#define IEEE80211_FCTL_FROMDS (0x0200) +#define IEEE80211_FCTL_MOREFRAGS (0x0400) +#define IEEE80211_FCTL_RETRY (0x0800) +#define IEEE80211_FCTL_PM (0x1000) +#define IEEE80211_FCTL_MOREDATA (0x2000) +#define IEEE80211_FCTL_PROTECTED (0x4000) +#define IEEE80211_FCTL_ORDER (0x8000) +#define IEEE80211_FCTL_CTL_EXT (0x0f00) + +#define IEEE80211_SCTL_FRAG (0x000F) +#define IEEE80211_SCTL_SEQ (0xFFF0) + +#define IEEE80211_FTYPE_MGMT (0x0000) +#define IEEE80211_FTYPE_CTL (0x0004) +#define IEEE80211_FTYPE_DATA (0x0008) +#define IEEE80211_FTYPE_EXT (0x000c) + +#define IEEE80211_STYPE_DATA (0x0000) +#define IEEE80211_STYPE_QOS_DATA (0x0080) +#define IEEE80211_STYPE_PROBE_REQ (0x0040) +#define IEEE80211_STYPE_PROBE_RESP (0x0050) +#define IEEE80211_STYPE_BEACON (0x0080) +#define IEEE80211_STYPE_ACTION (0x00D0) + +#define IEEE80211_QOS_CTL_LEN (2) +#define IEEE80211_HT_CTL_LEN (4) + +/* beacon capab_info */ +#define WLAN_CAPABILITY_PRIVACY (1 << 4) + +#define IEEE80211_SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) +#define IEEE80211_SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) + +#define WLAN_CATEGORY_VENDOR_SPECIFIC (127) + +#define WLAN_EID_SSID (0) +#define WLAN_EID_DS_PARAMS (3) +#define WLAN_EID_RSN (48) +#define WLAN_EID_HT_OPERATION (61) +#define WLAN_EID_VENDOR_SPECIFIC (221) + +#define WLAN_OUI_ALIBABA (0xD896E0) +#define WLAN_OUI_TYPE_ALIBABA (1) +#define WLAN_OUI_TYPE_ENROLLEE (0xAA) +#define WLAN_OUI_TYPE_REGISTRAR (0xAB) + +enum ALINK_TYPE { + ALINK_INVALID = 0, + ALINK_BROADCAST = 1, + ALINK_ROUTER = 2, + ALINK_ACTION = 3, + ALINK_WPS = 4, + ALINK_DEFAULT_SSID = 5, + ALINK_ZERO_CONFIG = 6, + ALINK_ADHA_SSID = 7, + ALINK_APLIST, + ALINK_HT_CTRL, +}; + +/* 80211 frame parser result */ +struct parser_res { + union _alink_type_ { + /* for broadcast data frame */ + struct broadcast_info { + uint8_t encry_type;/* none/wep/tkip/aes */ + uint16_t data_len;/* framelen - 80211 hdr - fcs(4) */ + uint16_t sn; + } br; + /* for alink ie frame */ + struct ie_info { + uint8_t *alink_ie; + uint16_t alink_ie_len; + } ie; + /* for p2p action frame */ + struct action_info { + uint8_t *data; + uint16_t data_len; + } action; + /* for p2p wps frame */ + struct wps_info { + uint8_t *data; + uint16_t data_len; + } wps; + /* for ht40 ctrl frame */ + struct ht_ctrl_info { + signed char rssi; + uint8_t filter; + uint16_t data_len; + } ht_ctrl; + } u; + + uint8_t *src; /* src mac of sender */ + uint8_t *dst; /* ff:ff:ff:ff:ff:ff */ + uint8_t *bssid; /* mac of AP */ + + uint8_t tods; /* fromDs or toDs */ + uint8_t channel; /* 1 - 13 */ +}; + +struct ieee80211_hdr { + uint16_t frame_control; + uint16_t duration_id; + uint8_t addr1[ETH_ALEN]; + uint8_t addr2[ETH_ALEN]; + uint8_t addr3[ETH_ALEN]; + uint16_t seq_ctrl; + uint8_t addr4[ETH_ALEN]; +}; + +/* + * The radio capture header precedes the 802.11 header. + * + * Note well: all radiotap fields are little-endian. + */ +struct ieee80211_radiotap_header { + uint8_t it_version; /* Version 0. Only increases + * for drastic changes, + * introduction of compatible + * new fields does not count. + */ + uint8_t it_pad; + uint16_t it_len; /* length of the whole + * header in bytes, including + * it_version, it_pad, + * it_len, and data fields. + */ + uint32_t it_present; /* A bitmap telling which + * fields are present. Set bit 31 + * (0x80000000) to extend the + * bitmap by another 32 bits. + * Additional extensions are made + * by setting bit 31. + */ +}; + +/** + * struct ieee80211_ht_operation - HT operation IE + * + * This structure is the "HT operation element" as + * described in 802.11n-2009 7.3.2.57 + */ +struct ieee80211_ht_operation { + uint8_t primary_chan; + uint8_t ht_param; + uint16_t operation_mode; + uint16_t stbc_param; + uint8_t basic_set[16]; +}; + +struct ieee80211_vendor_ie { + uint8_t element_id; + uint8_t len; + uint8_t oui[3]; + uint8_t oui_type; +}; +/* + * i.e. alibaba ie + * @name @len @payload + * element_id 1 221 + * len 1 22 + * oui 3 0xD896E0 + * oui_type 1 1 -- alink router service advertisement + * version 1 1 + * challenge 16 non-zero-ascii code + * reserve 1 0 + */ + +struct ieee80211_mgmt { + uint16_t frame_control; + uint16_t duration; + uint8_t da[ETH_ALEN]; + uint8_t sa[ETH_ALEN]; + uint8_t bssid[ETH_ALEN]; + uint16_t seq_ctrl; + union { + struct { + /* __le64 timestamp; */ + uint16_t timestamp[4]; + uint16_t beacon_int; + uint16_t capab_info; + /* followed by some of SSID, Supported rates, + * FH Params, DS Params, CF Params, IBSS Params, TIM */ + uint8_t variable; + } beacon; + struct { + /* only variable items: SSID, Supported rates */ + uint8_t variable; + } probe_req; + struct { + /* __le64 timestamp; */ + uint16_t timestamp[4]; + uint16_t beacon_int; + uint16_t capab_info; + /* followed by some of SSID, Supported rates, + * FH Params, DS Params, CF Params, IBSS Params */ + uint8_t variable; + } probe_resp; + } u; +}; + +typedef int (*awss_protocol_process_func_type)(uint8_t *, int, int, struct parser_res *, signed char); +typedef int (*awss_protocol_finish_func_type)(struct parser_res *); + +struct awss_protocol_couple_type { + int type; + awss_protocol_process_func_type awss_protocol_process_func; + awss_protocol_finish_func_type awss_protocol_finish_func; +}; + +int ieee80211_data_extract(uint8_t *in, int len, int link_type, + struct parser_res *res, signed char rssi); + +struct ap_info *zconfig_get_apinfo(uint8_t *mac); +struct ap_info *zconfig_get_apinfo_by_ssid(uint8_t *ssid); +struct ap_info *zconfig_get_apinfo_by_ssid_prefix(uint8_t *ssid_prefix); +struct ap_info *zconfig_get_apinfo_by_ssid_suffix(uint8_t *ssid_suffix); + +/* add channel to scanning channel list */ +int zconfig_add_active_channel(int channel); +uint8_t zconfig_get_press_status(); + +int ieee80211_hdrlen(uint16_t fc); +int ieee80211_has_a4(uint16_t fc); +int ieee80211_is_ctl(uint16_t fc); +int ieee80211_is_mgmt(uint16_t fc); +int ieee80211_is_data(uint16_t fc); +int ieee80211_has_tods(uint16_t fc); +int ieee80211_has_frags(uint16_t fc); +int ieee80211_has_order(uint16_t fc); +int ieee80211_is_beacon(uint16_t fc); +int ieee80211_is_action(uint16_t fc); +int ieee80211_has_fromds(uint16_t fc); +int ieee80211_is_data_qos(uint16_t fc); +int ieee80211_is_probe_req(uint16_t fc); +int ieee80211_is_probe_resp(uint16_t fc); +int ieee80211_is_data_exact(uint16_t fc); +int ieee80211_has_protected(uint16_t fc); +int ieee80211_is_data_present(uint16_t fc); +int ieee80211_get_radiotap_len(uint8_t *data); +int ieee80211_get_bssid(uint8_t *in, uint8_t *mac); +int ieee80211_get_ssid(uint8_t *beacon_frame, uint16_t frame_len, uint8_t *ssid); +int ieee80211_data_extract(uint8_t *in, int len, int link_type, struct parser_res *res, signed char rssi); +int cfg80211_get_bss_channel(uint8_t *beacon_frame, uint16_t frame_len); +int cfg80211_get_cipher_info(uint8_t *beacon_frame, uint16_t frame_len, + uint8_t *auth_type, uint8_t *pairwise_cipher_type, uint8_t *group_cipher_type); +uint8_t *ieee80211_get_SA(struct ieee80211_hdr *hdr); +uint8_t *ieee80211_get_DA(struct ieee80211_hdr *hdr); +uint8_t *ieee80211_get_BSSID(struct ieee80211_hdr *hdr); +const uint8_t *cfg80211_find_ie(uint8_t eid, const uint8_t *ies, int len); +const uint8_t *cfg80211_find_vendor_ie(uint32_t oui, uint8_t oui_type, const uint8_t *ies, int len); +struct ap_info *zconfig_get_apinfo(uint8_t *mac); +struct ap_info *zconfig_get_apinfo_by_ssid(uint8_t *ssid); +struct ap_info *zconfig_get_apinfo_by_ssid_prefix(uint8_t *ssid_prefix); +struct ap_info *zconfig_get_apinfo_by_ssid_suffix(uint8_t *ssid_suffix); + + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif /* __IEEE80211_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/statics/awss_statis.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/statics/awss_statis.c new file mode 100644 index 00000000..f3e364b1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/statics/awss_statis.c @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#ifdef AWSS_SUPPORT_STATIS + +#define DROUTE_START g_awss_statis.droute.conn_router_start +#define DROUTE_END g_awss_statis.droute.conn_router_end +#define DROUTE_CNT g_awss_statis.droute.conn_router_cnt +#define DROUTE_SUC g_awss_statis.droute.conn_router_suc +#define DROUTE_TMIN g_awss_statis.droute.conn_router_time_min +#define DROUTE_TMAX g_awss_statis.droute.conn_router_time_max +#define DROUTE_TMEAN g_awss_statis.droute.conn_router_time_mean + +#ifdef AWSS_SUPPORT_SMARTCONFIG +#ifdef AWSS_SUPPORT_SMARTCONFIG_WPS +#define WPS_CNT g_awss_statis.wps.wps_parse_cnt +#define WPS_CRC_ERR g_awss_statis.wps.wps_parse_crc_err +#define WPS_PW_ERR g_awss_statis.wps.wps_parse_passwd_err +#define WPS_SUC g_awss_statis.wps.wps_parse_suc +#endif +#define SM_CNT g_awss_statis.sm.sm_parse_cnt +#define SM_CRC_ERR g_awss_statis.sm.sm_parse_crc_err +#define SM_PW_ERR g_awss_statis.sm.sm_parse_passwd_err +#define SM_SUC g_awss_statis.sm.sm_parse_suc +#define SM_START g_awss_statis.sm.sm_parse_start +#define SM_END g_awss_statis.sm.sm_parse_end +#define SM_TMIN g_awss_statis.sm.sm_time_min +#define SM_TMAX g_awss_statis.sm.sm_time_max +#define SM_TMEAN g_awss_statis.sm.sm_time_mean +#endif + +#ifdef AWSS_SUPPORT_AHA +#define PAP_CNT g_awss_statis.pap.aha_cnt +#define PAP_SUC g_awss_statis.pap.aha_suc +#define PAP_TMIN g_awss_statis.pap.aha_time_min +#define PAP_TMAX g_awss_statis.pap.aha_time_max +#define PAP_TMEAN g_awss_statis.pap.aha_time_mean +#define PAP_START g_awss_statis.pap.aha_start +#define PAP_END g_awss_statis.pap.aha_end +#define PAP_SSTART g_awss_statis.pap.aha_scan_start +#define PAP_SSTOP g_awss_statis.pap.aha_scan_end +#define PAP_SAP g_awss_statis.pap.aha_switch_ap +#define PAP_PW_ERR g_awss_statis.pap.aha_passwd_err +#endif + +#ifdef AWSS_SUPPORT_DEV_AP +#define DAP_CNT g_awss_statis.dap.dev_ap_cnt +#define DAP_SUC g_awss_statis.dap.dev_ap_suc +#define DAP_TMIN g_awss_statis.dap.dev_ap_time_min +#define DAP_TMAX g_awss_statis.dap.dev_ap_time_max +#define DAP_TMEAN g_awss_statis.dap.dev_ap_time_mean +#define DAP_START g_awss_statis.dap.dev_ap_start +#define DAP_END g_awss_statis.dap.dev_ap_end +#define DAP_PW_ERR g_awss_statis.dap.dev_ap_passwd_err +#endif + +#ifdef AWSS_SUPPORT_ADHA +#define ROUTE_CNT g_awss_statis.route.adha_cnt +#define ROUTE_SUC g_awss_statis.route.adha_suc +#define ROUTE_TMIN g_awss_statis.route.adha_time_min +#define ROUTE_TMAX g_awss_statis.route.adha_time_max +#define ROUTE_TMEAN g_awss_statis.route.adha_time_mean +#define ROUTE_START g_awss_statis.route.adha_start +#define ROUTE_END g_awss_statis.route.adha_end +#endif + +#ifndef AWSS_DISABLE_ENROLLEE +#define ZC_CNT g_awss_statis.zconfig.zc_cnt +#define ZC_SUC g_awss_statis.zconfig.zc_suc +#define ZC_PW_ERR g_awss_statis.zconfig.zc_passwd_err +#endif + +#define AWSS_STATIS_BUF_LEN (768) + +static void *awss_statis_mutex = NULL; +static uint32_t awss_statis_trace_id = 0; +static uint32_t awss_statis_report_id = 0; +static struct awss_statis_t g_awss_statis = {0}; + +int awss_report_statis(const char *module) +{ + const char *elem_fmt = "[%s max:%u min:%u mean:%u cnt:%u suc:%u crc-err:%u pw-err:%u],"; + int log_buf_len = AWSS_STATIS_BUF_LEN + strlen(AWSS_STATIS_FMT) + 21; + char statis_topic[TOPIC_LEN_MAX] = {0}; + char *log_content = NULL; + char id_str[21] = {0}; + char *log_buf = NULL; + int len = 0; + int ret; + + log_content = os_zalloc(AWSS_STATIS_BUF_LEN + 1); + if (log_content == NULL) + goto STATIS_ERR; + log_buf = os_zalloc(log_buf_len + 1); + if (log_buf == NULL) + goto STATIS_ERR; + + if (awss_build_topic(TOPIC_POST_STATIS, statis_topic, TOPIC_LEN_MAX) == NULL) { + awss_err("awss build statis topic fail\n"); + goto STATIS_ERR; + } + + if (awss_statis_mutex) + HAL_MutexLock(awss_statis_mutex); + + if (DROUTE_CNT > 0) { + len += HAL_Snprintf(log_buf + len, log_buf_len - len, elem_fmt, "ConnRouter", + DROUTE_TMAX, DROUTE_TMIN, DROUTE_TMEAN, DROUTE_CNT, DROUTE_SUC, 0, 0); + } + +#ifdef AWSS_SUPPORT_SMARTCONFIG + if (SM_CNT > 0) { + len += HAL_Snprintf(log_buf + len, log_buf_len - len, elem_fmt, "Smartconfig", + SM_TMAX, SM_TMIN, SM_TMEAN, SM_CNT, SM_SUC, SM_CRC_ERR, SM_PW_ERR); + } +#ifdef AWSS_SUPPORT_SMARTCONFIG_WPS + if (WPS_CNT > 0) { + len += HAL_Snprintf(log_buf + len, log_buf_len - len, elem_fmt, "Smartconfig-wps", + 0, 0, 0, WPS_CNT, WPS_SUC, WPS_CRC_ERR, WPS_PW_ERR); + } +#endif +#endif +#ifdef AWSS_SUPPORT_AHA + if (PAP_CNT > 0) { + len += HAL_Snprintf(log_buf + len, log_buf_len - len, elem_fmt, "Aha", + PAP_TMAX, PAP_TMIN, PAP_TMEAN, PAP_CNT, PAP_SUC, 0, PAP_PW_ERR); + } +#endif +#ifdef AWSS_SUPPORT_ADHA + if (ROUTE_CNT > 0) { + len += HAL_Snprintf(log_buf + len, log_buf_len - len, elem_fmt, "Adha", + ROUTE_TMAX, ROUTE_TMIN, ROUTE_TMEAN, ROUTE_CNT, ROUTE_SUC, 0, 0); + } +#endif +#ifndef AWSS_DISABLE_ENROLLEE + if (ZC_CNT > 0) { + len += HAL_Snprintf(log_buf + len, log_buf_len - len, elem_fmt, "Zconfig", + 0, 0, 0, ZC_CNT, ZC_SUC, 0, ZC_PW_ERR); + } +#endif +#ifdef AWSS_SUPPORT_DEV_AP + if (DAP_CNT > 0) { + len += HAL_Snprintf(log_buf + len, log_buf_len - len, elem_fmt, "Dev-ap", + DAP_TMAX, DAP_TMIN, DAP_TMEAN, DAP_CNT, DAP_SUC, 0, DAP_PW_ERR); + } +#endif + + do { + if (len == 0) /* no need to report log */ + break; + log_buf[len - 1] = '\0'; /* remove end of ',' */ + + HAL_Snprintf(log_content, AWSS_STATIS_BUF_LEN, AWSS_STATIS_FMT, (uint32_t)HAL_UptimeMs(), "AWSS_TRACE", + module == NULL ? "default" : module, awss_statis_trace_id, log_buf); + + HAL_Snprintf(id_str, sizeof(id_str), "%u", ++ awss_statis_report_id); + + awss_build_packet(AWSS_CMP_PKT_TYPE_REQ, id_str, ILOP_VER, METHOD_LOG_POST, log_content, 0, + log_buf, &log_buf_len); + + awss_debug("%s\n", log_buf); + + ret = awss_cmp_mqtt_send(statis_topic, log_buf, strlen(log_buf), 0); + + awss_info("awss report statis %s\n", ret == 0 ? "success" : "fail"); + } while (0); + + if (awss_statis_mutex) + HAL_MutexUnlock(awss_statis_mutex); + + HAL_Free(log_buf); + HAL_Free(log_content); + + return 0; + +STATIS_ERR: + if (log_content) HAL_Free(log_content); + if (log_buf) HAL_Free(log_buf); + return -1; +} + +void awss_disp_statis() +{ + if (awss_statis_mutex) + HAL_MutexLock(awss_statis_mutex); + + awss_debug("--------------------------------AWSS STATIS-----------------------------------"); + awss_debug("name\t\tmax\tmin\tmean\tcnt\tsuc\tcrc-err\tpasswd-err"); + awss_debug("ConnRouter \t%u\t%u\t%u\t%u\t%u\t%u\t%u\t", + DROUTE_TMAX, DROUTE_TMIN, DROUTE_TMEAN, DROUTE_CNT, DROUTE_SUC, 0, 0); +#ifdef AWSS_SUPPORT_SMARTCONFIG + awss_debug("Smartconfig \t%u\t%u\t%u\t%u\t%u\t%u\t%u\t", + SM_TMAX, SM_TMIN, SM_TMEAN, SM_CNT, SM_SUC, SM_CRC_ERR, SM_PW_ERR); +#ifdef AWSS_SUPPORT_SMARTCONFIG_WPS + awss_debug("Smartconfig-wps \t%u\t%u\t%u\t%u\t%u\t%u\t%u\t", + 0, 0, 0, WPS_CNT, WPS_SUC, WPS_CRC_ERR, WPS_PW_ERR); +#endif +#endif +#ifdef AWSS_SUPPORT_AHA + awss_debug("Aha \t%u\t%u\t%u\t%u\t%u\t%u\t%u\t", + PAP_TMAX, PAP_TMIN, PAP_TMEAN, PAP_CNT, PAP_SUC, 0, PAP_PW_ERR); +#endif +#ifdef AWSS_SUPPORT_ADHA + awss_debug("Adha \t%u\t%u\t%u\t%u\t%u\t%u\t%u\t", + ROUTE_TMAX, ROUTE_TMIN, ROUTE_TMEAN, ROUTE_CNT, ROUTE_SUC, 0, 0); +#endif +#ifndef AWSS_DISABLE_ENROLLEE + awss_debug("Zconfig \t%u\t%u\t%u\t%u\t%u\t%u\t%u\t", + 0, 0, 0, ZC_CNT, ZC_SUC, 0, ZC_PW_ERR); +#endif +#ifdef AWSS_SUPPORT_DEV_AP + awss_debug("Dev-ap \t%u\t%u\t%u\t%u\t%u\t%u\t%u\t", + DAP_TMAX, DAP_TMIN, DAP_TMEAN, DAP_CNT, DAP_SUC, 0, DAP_PW_ERR); +#endif + awss_debug("------------------------------------------------------------------------------"); + + if (awss_statis_mutex) + HAL_MutexUnlock(awss_statis_mutex); +} + +void awss_clear_statis() +{ + if (awss_statis_mutex) + HAL_MutexLock(awss_statis_mutex); + + memset(&g_awss_statis, 0, sizeof(g_awss_statis)); + + awss_statis_trace_id = 0; + awss_statis_report_id = 0; + + if (awss_statis_mutex) { + HAL_MutexUnlock(awss_statis_mutex); + HAL_MutexDestroy(awss_statis_mutex); + } + awss_statis_mutex = NULL; +} + +void awss_update_statis(int awss_statis_idx, int type) +{ + uint32_t time = HAL_UptimeMs(); + + if (awss_statis_mutex == NULL) { + awss_statis_mutex = HAL_MutexCreate(); + if (awss_statis_mutex == NULL) { + awss_debug("a-statis am fail\n"); + return; + } + } + + HAL_MutexLock(awss_statis_mutex); + + if (type == AWSS_STATIS_TYPE_TIME_START) + awss_statis_trace_id ++; + + switch (awss_statis_idx) { + case AWSS_STATIS_CONN_ROUTER_IDX: + switch (type) { + case AWSS_STATIS_TYPE_TIME_START: + DROUTE_CNT ++; + DROUTE_START = time; + break; + case AWSS_STATIS_TYPE_TIME_SUC: + DROUTE_SUC ++; + DROUTE_END = time; + time = (uint32_t)(DROUTE_END - DROUTE_START); + if (DROUTE_SUC > 0) { + DROUTE_TMEAN = (DROUTE_TMEAN + time) / (DROUTE_SUC); + } else { + DROUTE_TMEAN = time; + DROUTE_SUC = 1; + } + if (DROUTE_TMIN == 0 || DROUTE_TMIN > time) + DROUTE_TMIN = time; + if (DROUTE_TMAX == 0 || DROUTE_TMAX < time) + DROUTE_TMAX = time; + break; + default: + break; + } + break; +#ifdef AWSS_SUPPORT_SMARTCONFIG +#ifdef AWSS_SUPPORT_SMARTCONFIG_WPS + case AWSS_STATIS_WPS_IDX: + switch (type) { + case AWSS_STATIS_TYPE_TIME_START: + WPS_CNT ++; + break; + case AWSS_STATIS_TYPE_TIME_SUC: + WPS_SUC ++; + break; + case AWSS_STATIS_TYPE_PASSWD_ERR: + WPS_PW_ERR ++; + break; + case AWSS_STATIS_TYPE_CRC_ERR: + WPS_CRC_ERR ++; + break; + default: + break; + } + break; +#endif + case AWSS_STATIS_SM_IDX: + switch (type) { + case AWSS_STATIS_TYPE_TIME_START: + SM_CNT ++; + SM_START = time; + break; + case AWSS_STATIS_TYPE_TIME_SUC: + SM_SUC ++; + SM_END = time; + time = (uint32_t)(SM_END - SM_START); + if (SM_SUC > 0) { + SM_TMEAN = (SM_TMEAN + time) / (SM_SUC); + } else { + SM_TMEAN = time; + SM_SUC = 1; + } + + if (SM_TMIN == 0 || SM_TMIN > time) + SM_TMIN = time; + if (SM_TMAX == 0 || SM_TMAX < time) + SM_TMAX = time; + break; + case AWSS_STATIS_TYPE_PASSWD_ERR: + SM_PW_ERR ++; + break; + case AWSS_STATIS_TYPE_CRC_ERR: + SM_CRC_ERR ++; + break; + default: + break; + } + break; +#endif +#ifdef AWSS_SUPPORT_AHA + case AWSS_STATIS_PAP_IDX: + switch (type) { + case AWSS_STATIS_TYPE_TIME_START: + PAP_CNT ++; + PAP_START = time; + break; + case AWSS_STATIS_TYPE_TIME_SUC: + PAP_SUC ++; + PAP_END = time; + time = (uint32_t)(PAP_END - PAP_START); + if (PAP_SUC > 0) { + PAP_TMEAN = (PAP_TMEAN + time) / (PAP_SUC); + } else { + PAP_TMEAN = time; + PAP_SUC = 1; + } + if (PAP_TMIN == 0 || PAP_TMIN > time) + PAP_TMIN = time; + if (PAP_TMAX == 0 || PAP_TMAX < time) + PAP_TMAX = time; + break; + case AWSS_STATIS_TYPE_PASSWD_ERR: + PAP_PW_ERR ++; + break; + case AWSS_STATIS_TYPE_SCAN_START: + PAP_SSTART = time; + break; + case AWSS_STATIS_TYPE_SCAN_STOP: + PAP_SSTOP = time; + break; + case AWSS_STATIS_TYPE_SWITCHAP: + PAP_SAP ++; + break; + default: + break; + } + break; +#endif +#ifdef AWSS_SUPPORT_DEV_AP + case AWSS_STATIS_DAP_IDX: + switch (type) { + case AWSS_STATIS_TYPE_TIME_START: + DAP_CNT ++; + DAP_START = time; + break; + case AWSS_STATIS_TYPE_TIME_SUC: + DAP_SUC ++; + DAP_END = time; + time = (uint32_t)(DAP_END - DAP_START); + if (DAP_SUC > 0) { + DAP_TMEAN = (DAP_TMEAN + time) / (DAP_SUC); + } else { + DAP_TMEAN = time; + DAP_SUC = 1; + } + if (DAP_TMIN == 0 || DAP_TMIN > time) + DAP_TMIN = time; + if (DAP_TMAX == 0 || DAP_TMAX < time) + DAP_TMAX = time; + break; + case AWSS_STATIS_TYPE_PASSWD_ERR: + DAP_PW_ERR ++; + break; + default: + break; + } + break; +#endif +#ifdef AWSS_SUPPORT_ADHA + case AWSS_STATIS_ROUTE_IDX: + switch (type) { + case AWSS_STATIS_TYPE_TIME_START: + ROUTE_CNT ++; + ROUTE_START = time; + break; + case AWSS_STATIS_TYPE_TIME_SUC: + ROUTE_SUC ++; + ROUTE_END = time; + time = (uint32_t)(ROUTE_END - ROUTE_START); + if (ROUTE_SUC > 0) { + ROUTE_TMEAN = (ROUTE_TMEAN + time) / (ROUTE_SUC); + } else { + ROUTE_TMEAN = time; + ROUTE_SUC = 1; + } + + if (ROUTE_TMIN == 0 || ROUTE_TMIN > time) + ROUTE_TMIN = time; + if (ROUTE_TMAX == 0 || ROUTE_TMAX < time) + ROUTE_TMAX = time; + break; + default: + break; + } + break; +#endif +#ifndef AWSS_DISABLE_ENROLLEE + case AWSS_STATIS_ZCONFIG_IDX: + switch (type) { + case AWSS_STATIS_TYPE_TIME_START: + ZC_CNT ++; + break; + case AWSS_STATIS_TYPE_TIME_SUC: + ZC_SUC ++; + break; + case AWSS_STATIS_TYPE_PASSWD_ERR: + ZC_PW_ERR ++; + break; + default: + break; + } + break; +#endif + default: + break; + } + HAL_MutexUnlock(awss_statis_mutex); +} + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/statics/awss_statis.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/statics/awss_statis.h new file mode 100644 index 00000000..19afd4dd --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/statics/awss_statis.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_STATIS_H__ +#define __AWSS_STATIS_H__ + +#include +#ifdef AWSS_SUPPORT_DEV_AP +#include "awss_dev_ap.h" +#endif + +enum { + AWSS_STATIS_CONN_ROUTER_IDX = 0, /* Statistic for connection with router */ + AWSS_STATIS_SM_IDX, /* Statistic for smartconfig with bcast */ + AWSS_STATIS_WPS_IDX, /* Statistic for smartconfig with wps */ + AWSS_STATIS_PAP_IDX, /* Statistic for phone as AP */ + AWSS_STATIS_DAP_IDX, /* Statistic for device AP */ + AWSS_STATIS_ROUTE_IDX, /* Statistic for route solution */ + AWSS_STATIS_ZCONFIG_IDX, /* Statistic for zero config */ +}; + +enum { + AWSS_STATIS_TYPE_TIME_START = 0, /* Begining of operation */ + AWSS_STATIS_TYPE_TIME_SUC, /* Success of operation */ + AWSS_STATIS_TYPE_PASSWD_ERR, /* Failure of parsing PASSWD of router*/ + AWSS_STATIS_TYPE_CRC_ERR, /* Failure of CRC check */ + AWSS_STATIS_TYPE_SCAN_START, /* Start of scan operation */ + AWSS_STATIS_TYPE_SCAN_STOP, /* Stop of scan operation */ + AWSS_STATIS_TYPE_SWITCHAP /* Increase count of switch ap */ +}; + +#ifndef AWSS_SUPPORT_STATIS +#define AWSS_SUPPORT_STATIS +#endif + +#ifdef AWSS_SUPPORT_STATIS + +struct awss_statis_conn_router_t { + uint32_t conn_router_cnt; /* the count of connect router */ + uint32_t conn_router_suc; /* the success count of connect router */ + uint32_t conn_router_time_mean; /* the mean time of success connection with router */ + uint32_t conn_router_time_max; /* the max time of success connection with router */ + uint32_t conn_router_time_min; /* the min time of success connection with router */ + uint32_t conn_router_start; /* the start time to connect router */ + uint32_t conn_router_end; /* the end time of connect router */ +}; /* statistics for connection with router */ + +struct awss_statis_sm_t { + uint32_t sm_parse_cnt; /* the count of smartconfig */ + uint32_t sm_parse_crc_err; /* the count of crc error */ + uint32_t sm_parse_passwd_err; /* the count of passwd error */ + uint32_t sm_parse_suc; /* the count of smartconfig success */ + uint32_t sm_parse_start; /* the start time to smartconfig */ + uint32_t sm_parse_end; /* the ene time of smartconfig */ + uint32_t sm_time_mean; /* the mean time of smartconfig */ + uint32_t sm_time_max; /* the max time of smartconfig */ + uint32_t sm_time_min; /* the min time of smartconfig */ +}; /* smartconfig-bcast statistic */ + +struct awss_statis_wps_t { + uint32_t wps_parse_cnt; /* the count of smartconfig-wps */ + uint32_t wps_parse_crc_err; /* the count of crc error */ + uint32_t wps_parse_passwd_err; /* the count of passwd error */ + uint32_t wps_parse_suc; /* the count of smartconfig-wps success */ +}; /* smartconfig-wps statistic */ + +struct awss_statis_phone_ap_t { + uint32_t aha_cnt; + uint32_t aha_suc; + uint32_t aha_time_mean; /* mean time of phone as AP solution */ + uint32_t aha_time_max; /* max time of phone as AP solution */ + uint32_t aha_time_min; /* min time of phone as AP solution */ + uint32_t aha_start; + uint32_t aha_end; + uint32_t aha_scan_start; + uint32_t aha_scan_end; + uint32_t aha_switch_ap; + uint32_t aha_passwd_err; +}; /* Phone as AP */ + +struct awss_statis_dev_ap_t { + uint32_t dev_ap_cnt; + uint32_t dev_ap_suc; + uint32_t dev_ap_time_mean; /* mean time of device AP solution */ + uint32_t dev_ap_time_max; /* max time of device AP solution */ + uint32_t dev_ap_time_min; /* min time of device AP solution */ + uint32_t dev_ap_start; + uint32_t dev_ap_end; + uint32_t dev_ap_passwd_err; +}; /* device work as AP */ + +struct awss_statis_route_t { + uint32_t adha_cnt; + uint32_t adha_suc; + uint32_t adha_time_mean; /* mean time of discovery of route solution */ + uint32_t adha_time_max; /* min time of discovery of route solution */ + uint32_t adha_time_min; /* max time of discovery of route solution */ + uint32_t adha_start; + uint32_t adha_end; +}; /* discovery of route solution */ + +struct awss_statis_zconfig_t { + uint32_t zc_cnt; + uint32_t zc_suc; + uint32_t zc_passwd_err; +}; /* zero configure solution */ + +struct awss_statis_t { + struct awss_statis_conn_router_t droute; +#ifdef AWSS_SUPPORT_SMARTCONFIG + struct awss_statis_sm_t sm; +#ifdef AWSS_SUPPORT_SMARTCONFIG_WPS + struct awss_statis_wps_t wps; +#endif +#endif +#ifdef AWSS_SUPPORT_AHA + struct awss_statis_phone_ap_t pap; +#endif +#ifdef AWSS_SUPPORT_DEV_AP + struct awss_statis_dev_ap_t dap; +#endif +#ifdef AWSS_SUPPORT_ADHA + struct awss_statis_route_t route; +#endif +#ifndef AWSS_DISABLE_ENROLLEE + struct awss_statis_zconfig_t zconfig; +#endif +}; + +int awss_report_statis(const char *module); +void awss_update_statis(int awss_statis_idx, int type); +void awss_clear_statis(); +void awss_disp_statis(); + +#define AWSS_UPDATE_STATIS(idx, type) awss_update_statis(idx, type) +#define AWSS_CLEAR_STATIS() awss_clear_statis() +#define AWSS_DISP_STATIS() awss_disp_statis() +#define AWSS_REPORT_STATIS(m) awss_disp_statis(m) +#else +#define AWSS_UPDATE_STATIS(idx, type) +#define AWSS_CLEAR_STATIS() +#define AWSS_DISP_STATIS() +#define AWSS_REPORT_STATIS(m) +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/utils/awss_crypt.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/utils/awss_crypt.c new file mode 100644 index 00000000..48b72ab0 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/utils/awss_crypt.c @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +static const char *cal_passwd(void *key, void *random, void *passwd) +{ + uint16_t key_len; + uint8_t digest[SHA256_DIGEST_SIZE + 1] = {0}; + uint8_t passwd_src[KEY_MAX_LEN + RANDOM_MAX_LEN + 2] = {0}; + + if (!passwd || !key || !random) + return NULL; + + /* combine key and random, with split of comma */ + key_len = strlen(key); + if (key_len > KEY_MAX_LEN) + key_len = KEY_MAX_LEN; + memcpy(passwd_src, key, key_len); + passwd_src[key_len ++] = ','; + memcpy(passwd_src + key_len, random, RANDOM_MAX_LEN); + key_len += RANDOM_MAX_LEN; + + SHA256_hash(passwd_src, key_len, digest); + #if 0 + TODO + /* produce digest using combination of key and random */ + utils_sha256_hash(passwd_src, key_len, digest); +#endif + + /* use the first 128bits as AES-Key */ + memcpy(passwd, digest, AES128_KEY_LEN); + + return passwd; +} + +int aes_decrypt_string(char *cipher, char *plain, int len, int cipher_hex, int sec_lvl, char cbc, const char *rand) +{ + char res = 0; + char decrypt = 1; + uint8_t iv[AES128_KEY_LEN] = {0}; + uint8_t key[AES128_KEY_LEN] = {0}; + uint8_t random[RANDOM_MAX_LEN] = {0}; + + uint8_t *decoded = (uint8_t *)os_zalloc(len + 1); + if (decoded == NULL) + return -1; + + if (cipher_hex == 0) { + /* + * mobile-ap, router, dev-ap + */ + utils_str_to_hex(cipher, len, decoded, len); + } else { /* for smartconfig/wps, zconfig, */ + /* + * smartconfig/wps, zconfig + */ + memcpy(decoded, cipher, len); + } + + if (rand) { + /* + * smartconfig/wps uses zero + * zconfig/dev-ap/mobile-ap/router uses random + */ + memcpy(random, rand, sizeof(random)); + } + + awss_debug("security level: %d", sec_lvl); + + switch (sec_lvl) { + case SEC_LVL_AES128_PRODUCT: + { + char product_sec[OS_PRODUCT_SECRET_LEN + 1] = {0}; + HAL_GetProductSecret(product_sec); + cal_passwd(product_sec, random, key); + memcpy(iv, random, sizeof(random)); + break; + } + case SEC_LVL_AES128_DEVICE: + { + char dev_sec[OS_DEVICE_SECRET_LEN + 1] = {0}; + HAL_GetDeviceSecret(dev_sec); + cal_passwd(dev_sec, random, key); + memcpy(iv, random, sizeof(random)); + break; + } + default: + { + decrypt = 0; + awss_debug("wrong security level: %d\n", sec_lvl); + res = -2; + break; + } + } + + plain[0] = '\0'; + + if (decrypt) { + p_aes128_t aes = HAL_Aes128_Init(key, iv, PLATFORM_AES_DECRYPTION); + if (cbc) { /* AP */ + /* + * mobile-ap, dev-ap, router + */ + res = HAL_Aes128_Cbc_Decrypt(aes, decoded, len / AES128_KEY_LEN / 2, plain); + } else { /* smartconfig */ + /* + * smartconfig/wps, zconfig + */ + res = HAL_Aes128_Cfb_Decrypt(aes, decoded, len, plain); + } + HAL_Aes128_Destroy(aes); + } + + HAL_Free(decoded); + + return res; +} + + + +/** + * @brief 获取配网服务的安全等级 + * + * @param None. + * @return The security level: + @verbatim + 0: open (no encrypt) + 1: aes256cfb with default aes-key and aes-iv + 2: aes128cfb with default aes-key and aes-iv + 3: aes128cfb with aes-key per product and aes-iv = 0 + 4: aes128cfb with aes-key per device and aes-iv = 0 + 5: aes128cfb with aes-key per manufacture and aes-iv = 0 + others: invalid + @endverbatim + * @see None. + */ + +int awss_get_encrypt_type() +{ + return 3; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/utils/awss_crypt.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/utils/awss_crypt.h new file mode 100644 index 00000000..8b80c27e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/utils/awss_crypt.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_CRYPT_H__ +#define __AWSS_CRYPT_H__ + +enum { + SEC_LVL_OPEN = 0, /* open */ + SEC_LVL_AES256, /* AES256 */ + SEC_LVL_AES128_DEFAULT, /* AES128 with default key */ + SEC_LVL_AES128_PRODUCT, /* AES128 with key from product_sec */ + SEC_LVL_AES128_DEVICE, /* AES128 with key from device_sec */ + SEC_LVL_AES128_MANU, /* AES128 with key from manufacturer_sec */ +}; + +int aes_decrypt_string(char *cipher, char *plain, int len, int cipher_hex, int sec_lvl, char cbc, const char *rand); + +int awss_get_encrypt_type(); +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/utils/zconfig_utils.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/utils/zconfig_utils.c new file mode 100644 index 00000000..54b2ac64 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/utils/zconfig_utils.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +void dump_hex(uint8_t *data, int len, int tab_num) +{ + int i; + for (i = 0; i < len; i++) { + HAL_Printf("%02x ", data[i]); + + if (!((i + 1) % tab_num)) + HAL_Printf("\r\n"); + } + + HAL_Printf("\r\n"); +} +#if 0 +void dump_ascii(uint8_t *data, int len, int tab_num) +{ + int i; + for (i = 0; i < len; i++) { + HAL_Printf("%-2c ", data[i]); + + if (!((i + 1) % tab_num)) + HAL_Printf(" "); + } + + HAL_Printf("\r\n"); +} + +void dump_mac(uint8_t *src, uint8_t *dst) +{ + uint8_t *mac; + + mac = src; + HAL_Printf("%02x:%02x:%02x:%02x:%02x:%02x > ", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + mac = dst; + HAL_Printf("%02x:%02x:%02x:%02x:%02x:%02x\r\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + /* elimite compiler warning */ + mac = mac; +} +#endif +/* for smartconfig with encrypt */ +uint16_t zconfig_checksum_v3(uint8_t *data, uint8_t len) +{ + uint8_t i; + uint16_t sum = 0, res; + + for (i = 0; i < len; i++) + sum += data[i]; + + res = sum & (0x3F << 0); + res |= (sum & (0x3F << 6)) << 2; + + if (!(res & 0x00FF)) + res |= 0x0001; + if (!(res & 0xFF00)) + res |= 0x0100; + + return res; +} + +char is_utf8(const char *ansi_str, int length) +{ + int i = 0; + char utf8 = 1; + while (i < length) { + if ((0x80 & ansi_str[i]) == 0) { /* ASCII */ + i++; + continue; + } else if ((0xE0 & ansi_str[i]) == 0xC0) { /* 110xxxxx */ + if (ansi_str[i + 1] == '\0') { + utf8 = 0; + break; + } + if ((0xC0 & ansi_str[i + 1]) == 0x80) { /* 10xxxxxx */ + i += 2; + continue; + } else { + utf8 = 0; + break; + } + } else if ((0xF0 & ansi_str[i]) == 0xE0) { /* 1110xxxx */ + if (ansi_str[i + 1] == '\0') { + utf8 = 0; + break; + } + if (ansi_str[i + 2] == '\0') { + utf8 = 0; + break; + } + if (((0xC0 & ansi_str[i + 1]) == 0x80) && ((0xC0 & ansi_str[i + 2]) == 0x80)) { /* 10xxxxxx 10xxxxxx */ + i += 3; + continue; + } else { + utf8 = 0; + break; + } + } else { + utf8 = 0; + break; + } + } + return utf8; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/utils/zconfig_utils.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/utils/zconfig_utils.h new file mode 100644 index 00000000..d738bb7a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/utils/zconfig_utils.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __ZCONFIG_UTILS_H__ +#define __ZCONFIG_UTILS_H__ + +#include "os.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +void dump_mac(uint8_t *src, uint8_t *dst); +void dump_hex(uint8_t *data, int len, int tab_num); +void dump_ascii(uint8_t *data, int len, int tab_num); + +uint16_t zconfig_checksum_v3(uint8_t *data, uint8_t len); +char is_utf8(const char *ansi_str, int length); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/zconfig_lib.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/zconfig_lib.h new file mode 100644 index 00000000..32da0cfa --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/zconfig_lib.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __ZCONFIG_LIB_H__ +#define __ZCONFIG_LIB_H__ + +#include "os.h" + +#ifndef ETH_ALEN +#define ETH_ALEN (6) +#endif + +#define ZC_MAX_SSID_LEN (32 + 1)/* ssid: 32 octets at most, include the NULL-terminated */ +#define ZC_MAX_PASSWD_LEN (64 + 1)/* 8-63 ascii */ +#define MAX_APLIST_NUM (100) + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +enum _ZC_AUTH_TYPE_ { + ZC_AUTH_TYPE_OPEN, + ZC_AUTH_TYPE_SHARED, + ZC_AUTH_TYPE_WPAPSK, + ZC_AUTH_TYPE_WPA8021X, + ZC_AUTH_TYPE_WPA2PSK, + ZC_AUTH_TYPE_WPA28021X, + ZC_AUTH_TYPE_WPAPSKWPA2PSK, + ZC_AUTH_TYPE_MAX = ZC_AUTH_TYPE_WPAPSKWPA2PSK, + ZC_AUTH_TYPE_INVALID = 0xff, +}; + +enum _ZC_ENC_TYPE_ { + ZC_ENC_TYPE_NONE, + ZC_ENC_TYPE_WEP, + ZC_ENC_TYPE_TKIP, + ZC_ENC_TYPE_AES, + ZC_ENC_TYPE_TKIPAES, + ZC_ENC_TYPE_MAX = ZC_ENC_TYPE_TKIPAES, + ZC_ENC_TYPE_INVALID = 0xff, +}; + +enum _ZC_PKG_TYPE_ { + PKG_INVALID, /* invalid pkg, --无效包 */ + PKG_BC_FRAME, /* broadcast frame, --信道扫描阶段,收到收到该返回值建议延长在当前信道停留时间,可以延长T1 */ + PKG_START_FRAME, /* start frame, --信道扫描阶段,收到该返回值用于锁定信道 */ + PKG_DATA_FRAME, /* data frame, --数据包,锁定信道后长时间T2收不到数据包,需重新进入扫描阶段 */ + PKG_ALINK_ROUTER, /* alink router */ + PKG_GROUP_FRAME, /* group frame */ + PKG_END /* --配网结束事件,已拿到ssid和passwd,通过回调函数去获取ssid和passwd */ + /* + * 参考值: + * T1: 400ms >= T2 >= 100ms + * T2: 3s + */ +}; + +/*进入monitor模式前后调用该函数 */ +void zconfig_init(); +/* 配网成功后,调用该函数,释放内存资源 */ +void zconfig_destroy(void); +/* + 进入monitor/sniffer模式后,将收到的包传给该函数进行处理 + 若进入monitor时进行包过滤配置,以下几种包不能过滤: + 1) 数据包,目的地址为广播地址 + 2) 长度>40的管理帧 + 厂家需要自行切换信道,切信道时间按照自身平台需要进行调整,建议取值范围[100ms - 300ms] + 其中,6号信道需作为固定信道放在信道列表里!!! + input: + pkt_data: 80211 wireless raw package, include data frame & management frame + pkt_length: radio_hdr + 80211 hdr + payload, without fcs(4B) + return: + 见enum _PKG_TYPE_结构体说明 +*/ +int zconfig_recv_callback(void *pkt_data, uint32_t pkt_length, uint8_t channel, + int link_type, int with_fcs, signed char rssi); + +/* + * save apinfo + * 0 -- success, otherwise, failed. + */ +int zconfig_set_apinfo(uint8_t *ssid, uint8_t* bssid, uint8_t channel, uint8_t auth, + uint8_t pairwise_cipher, uint8_t group_cipher, signed char rssi); + +uint8_t zconfig_get_lock_chn(void); + +/* add channel to global scanning channel list */ +int zconfig_add_active_channel(int channel); +/* channel locked callback */ +void zconfig_channel_locked_callback(uint8_t primary_channel, + uint8_t secondary_channel, uint8_t *bssid); +/* got ssid&passwd callback */ +void zconfig_got_ssid_passwd_callback(uint8_t *ssid, uint8_t *passwd, uint8_t *bssid, + uint8_t auth, uint8_t encry, uint8_t channel); +void zconfig_force_rescan(void); +void aws_set_dst_chan(int channel); +void aws_switch_channel(void); +void aws_release_mutex(void); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/zconfig_protocol.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/zconfig_protocol.c new file mode 100644 index 00000000..4128a60c --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/zconfig_protocol.c @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +/* broadcast mac address */ +uint8_t br_mac[ETH_ALEN]; +/* all zero mac address */ +uint8_t zero_mac[ETH_ALEN]; + +/* which channel lock at */ +uint8_t zconfig_channel_locked = INVALID_CHANNEL;/* locked channel */ +/* + * avoid zconfig_callback_over() was called twice, + * once from tods, once from fromds + */ +uint8_t zconfig_finished; + +/* global data structure, which hold all broadcast data */ +struct zconfig_data *zconfig_data; + +/* + * 8bit -> x bit + * + * serialize chinese char from 8bit to x bit + */ +void encode_chinese(uint8_t *in, uint8_t in_len, + uint8_t *out, uint8_t *out_len, uint8_t bits) +{ + if (bits == 0 || bits > 7) { + return; + } + + do { + uint8_t i, j; + uint8_t bit[ZC_MAX_SSID_LEN * 8] = {0}; + uint8_t output_len = ((in_len * 8) + bits - 1) / bits; + + /* char to bit stream */ + for (i = 0; i < in_len; i ++) { + for (j = 0; j < 8; j ++) { + bit[i * 8 + j] = (in[i] >> j) & 0x01; + } + } + + out[output_len] = '\0'; /* NULL-terminated */ + for (i = 0; i < output_len; i ++) { + for (j = 0, out[i] = 0; j < bits; j ++) { + out[i] |= bit[i * bits + j] << j; + } + } + + if (out_len) { + *out_len = output_len; + } + } while (0); +} + +/* x bit -> 8bit */ +void decode_chinese(uint8_t *in, uint8_t in_len, + uint8_t *out, uint8_t *out_len, uint8_t bits) +{ + if (bits == 0 || bits > 7 || in_len == 0) { + return; + } + + do { + uint8_t i, j; + uint8_t output_len = (in_len * bits) / 8; + uint8_t *bit = (uint8_t *)os_zalloc(in_len * bits); + + if (bit == NULL) { + awss_crit("decode malloc failed!\r\n"); + return; + } + + /* char to bit stream */ + for (i = 0; i < in_len; i ++) { + for (j = 0; j < bits; j ++) { + bit[i * bits + j] = (in[i] >> j) & 0x01; + } + } + + out[output_len] = '\0'; /* NULL-terminated */ + for (i = 0; i < output_len; i++) { + for (j = 0, out[i] = 0; j < 8; j ++) { + out[i] |= bit[i * 8 + j] << j; + } + } + + HAL_Free(bit); + if (out_len) { + *out_len = output_len; + } + } while (0); +} + +/* + * 1/locked, 0/not locked + */ +uint8_t is_channel_locked(void) +{ + return zconfig_channel_locked != INVALID_CHANNEL; +} + +/* + * Note: this notification will be kept called, in case of + * user clear the channel locked state to re-scanning + * channel because of waiting timeout. + */ +uint8_t zconfig_callback_channel_locked(uint8_t channel) +{ + if (channel != zconfig_channel_locked) { + awss_info("channel lock @ %d\r\n", channel); + zconfig_channel_locked = channel; + } + + /* + * if recv timeout, vendor may re-scanning channel, + * so keep calling channel locked notification here. + */ + zconfig_channel_locked_callback(channel, 0, zc_bssid); + + return 0; +} + +uint8_t zconfig_callback_over(uint8_t *ssid, uint8_t *passwd, uint8_t *bssid) +{ + uint8_t auth = ZC_AUTH_TYPE_INVALID, encry = ZC_ENC_TYPE_INVALID, channel = 0; + + awss_info("zconfig done. ssid:%s, mac:%02x%02x%02x%02x%02x%02x\r\n", + ssid, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); + + if (zconfig_finished) { + return 0; + } + +#ifdef AWSS_SUPPORT_APLIST + awss_get_auth_info(ssid, bssid, &auth, &encry, &channel); +#endif + + zconfig_got_ssid_passwd_callback(ssid, passwd, bssid, auth, encry, channel); + + zconfig_finished = 1; + + HAL_Awss_Close_Monitor(); + + return 0; +} + +void zconfig_set_state(uint8_t state, uint8_t tods, uint8_t channel) +{ + /* state change callback */ + switch (state) { + case STATE_CHN_SCANNING: + break; + case STATE_CHN_LOCKED_BY_P2P: + /* locked state used by action/wps frame */ + zconfig_callback_channel_locked(channel); + break; + case STATE_CHN_LOCKED_BY_BR: + /* locked state used by br frame */ + zconfig_callback_channel_locked(zc_channel ? zc_channel : channel); + break; + case STATE_RCV_DONE: + /* prevent main_thread_func to free zconfig_data until curent task is finished. */ + HAL_MutexLock(zc_mutex); + /* + * in case of p2p/router, direct into RCV_DONE state, + * skiped the chn lock state, so better to call channel lock here + */ + if (!is_channel_locked()) { + zconfig_callback_channel_locked(channel); + } + zconfig_callback_over(zc_ssid, zc_passwd, zc_bssid); + break; + default: + break; + } + + /* + * state machine loop: + * scanning -> p2p lock -> rcv_done + * scanning -> (p2p) rcv_done + * scanning -> br lock -> (br) rcv_done + * scanning -> br lock -> (p2p) recv_done + * scanning -> p2p lock -> br lock -> (br) recv_done + * + * watch out zc_state rolling back. + * zconfig_set_state(CHN_LOCKED) will be called more than once, + */ + if (zc_state < state) { + zc_state = state; + } + if (state == STATE_RCV_DONE) { + HAL_MutexUnlock(zc_mutex); + } +} + +/* + pkt_data & pkt_length: + radio_hdr + 80211 hdr + payload, without fcs(4B) + return: + PKG_INVALID -- invalid pkt, + PKG_START_FRAME -- start frame, + PKG_DATA_FRAME -- data frame, + PKG_ALINK_ROUTER -- alink router, + PKG_GROUP_FRAME -- group frame, + PKG_BC_FRAME -- broadcast frame +*/ +int is_invalid_pkg(void *pkt_data, uint32_t pkt_length) +{ +#define MIN_PKG (33) +#define MAX_PKG (1480 + 56 + 200) + if (pkt_length < MIN_PKG || pkt_length > MAX_PKG) { + return 1; + } + return 0; +} + +/* + * zconfig_recv_callback() + * + * ieee80211 package parser + * + * @Return: + * zconfig state + */ +int zconfig_recv_callback(void *pkt_data, uint32_t pkt_length, uint8_t channel, + int link_type, int with_fcs, signed char rssi) +{ + int pkt_type = PKG_INVALID; + struct parser_res res; + memset(&res, 0, sizeof(res)); + + /* remove FCS filed */ + if (with_fcs) { + pkt_length -= 4; + } + + /* useless, will be removed */ + if (is_invalid_pkg(pkt_data, pkt_length)) { + return PKG_INVALID; + } + + res.channel = channel; + + pkt_type = ieee80211_data_extract(pkt_data, pkt_length, link_type, &res, rssi); + + return pkt_type; +} + +/* init mem & timer */ +void zconfig_init() +{ + awss_info("%s\r\n", __func__); + + zconfig_channel_locked = INVALID_CHANNEL; + zconfig_finished = 0; + + memset(br_mac, 0xff, ETH_ALEN); + memset(zero_mac, 0x00, ETH_ALEN); + + zconfig_data = (struct zconfig_data *)os_zalloc(sizeof(struct zconfig_data)); + if (zconfig_data == NULL) { + goto ZCONFIG_INIT_FAIL; + } + zc_mutex = HAL_MutexCreate(); + if (zc_mutex == NULL) { + goto ZCONFIG_INIT_FAIL; + } + +#ifdef AWSS_SUPPORT_APLIST + if (awss_init_ieee80211_aplist()) { + goto ZCONFIG_INIT_FAIL; + } +#endif +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + if (awss_init_adha_aplist()) { + goto ZCONFIG_INIT_FAIL; + } +#endif + +#ifdef AWSS_SUPPORT_HT40 + ht40_init(); +#endif + return; + +ZCONFIG_INIT_FAIL: + awss_crit("malloc failed!\r\n"); + zconfig_destroy(); + +#ifdef AWSS_SUPPORT_APLIST + awss_deinit_ieee80211_aplist(); +#endif +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + awss_deinit_adha_aplist(); +#endif + return; +} + +void zconfig_destroy(void) +{ + if (zconfig_data) { + if (zc_mutex) { + HAL_MutexDestroy(zc_mutex); + } + HAL_Free((void *)zconfig_data); + zconfig_data = NULL; + } +} + +void zconfig_force_destroy(void) +{ + zconfig_destroy(); + +#ifdef AWSS_SUPPORT_APLIST + awss_deinit_ieee80211_aplist(); + awss_close_aplist_monitor(); +#endif + +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + awss_deinit_adha_aplist(); +#endif +} + +int zconfig_is_valid_channel(int channel) +{ + return (ZC_MIN_CHANNEL <= channel && channel <= ZC_MAX_CHANNEL); +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/zconfig_protocol.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/zconfig_protocol.h new file mode 100644 index 00000000..57024637 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/zconfig_protocol.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __ZCONFIG_PROTOCOL_H__ +#define __ZCONFIG_PROTOCOL_H__ + +#include +#include "zconfig_utils.h" +#include "zconfig_ieee80211.h" +#include "zconfig_lib.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +enum state_machine { + STATE_CHN_SCANNING, + STATE_CHN_LOCKED_BY_P2P, /* wps/action used for enrollee */ + STATE_CHN_LOCKED_BY_BR, /* broadcast used for smartconfig */ + STATE_GOT_BEACON, + STATE_RCV_IN_PROGRESS, + STATE_RCV_COMPLETE, + STATE_RCV_DONE +}; + +enum _GOT_RESULT_ { + GOT_NOTHING = 0, + GOT_CHN_LOCK = 1, + GOT_SSID_PASSWD = 2, +}; + +#define PASSWD_ENCRYPT_BIT_OFFSET (1) +#define PASSWD_ENCRYPT_MASK (0x06) +#define SSID_EXIST_BIT (0) +#define SSID_EXIST_MASK (1 << SSID_EXIST_BIT) +#define SSID_ENCODE_BIT (5) +#define SSID_ENCODE_MASK (1 << SSID_ENCODE_BIT) + +enum passwd_encpyt_type { + PASSWD_ENCRYPT_OPEN = 0, + PASSWD_ENCRYPT_CIPHER, + PASSWD_ENCRYPT_AESCFB, + PASSWD_ENCRYPT_AESOFB, +}; + +#define flag_tods(tods) ((tods) ? 'T' : 'F') + +#define ZC_MAX_CHANNEL (14) +#define ZC_MIN_CHANNEL (1) +int zconfig_is_valid_channel(int channel); + +#define P2P_ENCODE_TYPE_OFFSET (0x05) +#define P2P_SSID_LEN_MASK ((1 << P2P_ENCODE_TYPE_OFFSET) - 1) +#define P2P_ENCRYPT_BIT_MASK ((uint8_t)(~P2P_SSID_LEN_MASK)) +enum p2p_encode_type { + P2P_ENCODE_TYPE_DICT = 0x00, + P2P_ENCODE_TYPE_ENCRYPT, +}; + +/* global data */ +/* max: 48(ssid gbk encode) + 64 (passwd) + 6 (1(tlen) + 1(flag) + 1(ssid_len) + 1(passwd_len) + 2(crc)) */ +#define MAX_PKG_NUMS (128) + +/* zconfig protocol */ +#define START_FRAME (0x4E0) /* 0x4E0 is group 0 */ +#define GROUP_FRAME (0x3E0) /* exclusive, 0x401 is group 1, 0x400 is not used */ +#define GROUP_FRAME_END (GROUP_FRAME + MAX_PKG_NUMS / GROUP_NUMBER) /* exclusive */ +#define GROUP_NUMBER (8) +#define ZC_GRP_PKT_IDX_START (2) +#define ZC_GRP_PKT_IDX_END (ZC_GRP_PKT_IDX_START + GROUP_NUMBER - 1) + +struct package { + uint16_t len; + char score; +}; + +struct zconfig_data { + struct { + uint8_t state_machine; /* state for tods/fromds */ + uint8_t frame_offset; /* frame fixed offset */ + uint8_t group_pos; /* latest group pkg pos */ + uint8_t cur_pos; /* data abs. position */ + uint8_t max_pos; /* data max len */ + uint8_t last_index; + uint8_t replace; /* whether pkg has been replaced recently */ + uint8_t score_uplimit; +#define score_max (100) +#define score_high (98) +#define score_mid (50) +#define score_low (1) +#define score_min (0) + + uint8_t pos_unsync; + uint16_t group_sn; /* latest group pkg sn */ + uint16_t prev_sn; /* last sn */ + uint16_t last_len; /* len pkg len */ + uint32_t timestamp; /* last timestamp */ +#define time_interval (300) /* ms */ + } data[2]; + + /* package store */ + struct package pkg[2][MAX_PKG_NUMS]; + struct package tmp_pkg[2][GROUP_NUMBER + 1]; + uint8_t src_mac[ETH_ALEN]; + uint8_t channel; /* from 1 -- 13 */ + + /* result, final result */ + uint8_t ssid[ZC_MAX_SSID_LEN]; + uint8_t passwd[ZC_MAX_PASSWD_LEN]; + uint8_t bssid[ETH_ALEN]; + uint8_t ssid_is_gbk; + uint8_t ssid_auto_complete_disable; + + /* used by v2 android p2p protocol, for gbk ssid correctness */ + uint8_t android_pre_ssid[ZC_MAX_SSID_LEN]; + uint8_t android_ssid[ZC_MAX_SSID_LEN]; + uint8_t android_bssid[ETH_ALEN]; + uint8_t android_src[ETH_ALEN]; + void *mutex; +}; + +#define zc_state zconfig_data->data[tods].state_machine +#define zc_frame_offset zconfig_data->data[tods].frame_offset +#define zc_group_pos zconfig_data->data[tods].group_pos +#define zc_group_sn zconfig_data->data[tods].group_sn +#define zc_prev_sn zconfig_data->data[tods].prev_sn +#define zc_cur_pos zconfig_data->data[tods].cur_pos +#define zc_max_pos zconfig_data->data[tods].max_pos +#define zc_last_index zconfig_data->data[tods].last_index +#define zc_last_len zconfig_data->data[tods].last_len +#define zc_replace zconfig_data->data[tods].replace +#define zc_score_uplimit zconfig_data->data[tods].score_uplimit +#define zc_timestamp zconfig_data->data[tods].timestamp +#define zc_pos_unsync zconfig_data->data[tods].pos_unsync + +#define zc_src_mac &zconfig_data->src_mac[0] + +#define zc_channel zconfig_data->channel + +#define zc_ssid (&zconfig_data->ssid[0]) +#define zc_passwd (&zconfig_data->passwd[0]) +#define zc_bssid (&zconfig_data->bssid[0]) +#define zc_ssid_is_gbk (zconfig_data->ssid_is_gbk) +#define zc_ssid_auto_complete_disable (zconfig_data->ssid_auto_complete_disable) + +#define pkg_score(n) zconfig_data->pkg[tods][n].score +#define pkg_len(n) zconfig_data->pkg[tods][n].len +#define pkg(n) &zconfig_data->pkg[tods][n] + +#define tmp_score(n) zconfig_data->tmp_pkg[tods][n].score +#define tmp_len(n) zconfig_data->tmp_pkg[tods][n].len +#define tmp(n) &zconfig_data->tmp_pkg[tods][n] + +#define zc_pre_ssid (&zconfig_data->android_pre_ssid[0]) +#define zc_android_ssid (&zconfig_data->android_ssid[0]) +#define zc_android_bssid (&zconfig_data->android_bssid[0]) +#define zc_android_src (&zconfig_data->android_src[0]) +#define zc_mutex zconfig_data->mutex + +void zconfig_force_destroy(void); +void encode_chinese(uint8_t *in, uint8_t in_len, uint8_t *out, uint8_t *out_len, uint8_t bits); +void decode_chinese(uint8_t *in, uint8_t in_len, uint8_t *out, uint8_t *out_len, uint8_t bits); +void zconfig_set_state(uint8_t state, uint8_t tods, uint8_t channel); +int is_ascii_string(uint8_t *str); + +/* + * [IN] ssid or bssid + * [OUT] auth, encry, channel + */ +uint8_t zconfig_get_auth_info(uint8_t *ssid, uint8_t *bssid, uint8_t *auth, uint8_t *encry, uint8_t *channel); +uint8_t zconfig_callback_over(uint8_t *ssid, uint8_t *passwd, uint8_t *bssid); + +#define MAC_FORMAT "%02x%02x%02x%02x%02x%02x" +#define MAC_VALUE(mac) mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + +extern const char *zc_default_ssid; +extern const char *zc_default_passwd; +extern struct zconfig_data *zconfig_data; +extern uint8_t zconfig_finished; +/* broadcast mac address */ +extern uint8_t br_mac[ETH_ALEN]; +/* all zero mac address */ +extern uint8_t zero_mac[ETH_ALEN]; + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif /* __IEEE80211_123_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/zconfig_vendor_common.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/zconfig_vendor_common.c new file mode 100644 index 00000000..43e8eaf4 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/frameworks/zconfig_vendor_common.c @@ -0,0 +1,568 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif +/* aws state machine */ +enum { + /* used by aws_state */ + AWS_SCANNING, + AWS_CHN_LOCKED, + AWS_SUCCESS, + AWS_TIMEOUT, + + /* used by aws_stop */ + AWS_STOPPING, + AWS_STOPPED +}; + +struct aws_info { + uint8_t state; + + uint8_t cur_chn; /* current working channel */ + uint8_t chn_index; + + uint8_t locked_chn; + +#define AWS_MAX_CHN_NUMS (2 * 13 + 5) /* +5 for safety gap */ + uint8_t chn_list[AWS_MAX_CHN_NUMS]; + uint8_t stop; + + uint32_t chn_timestamp;/* channel start time */ + uint32_t start_timestamp;/* aws start time */ +} *aws_info; + +#define aws_state (aws_info->state) +#define aws_locked_chn (aws_info->locked_chn) +#define aws_cur_chn (aws_info->cur_chn) +#define aws_chn_index (aws_info->chn_index) +#define aws_chn_list (aws_info->chn_list) +#define aws_chn_timestamp (aws_info->chn_timestamp) +#define aws_start_timestamp (aws_info->start_timestamp) +#define aws_stop (aws_info->stop) + +#define aws_channel_lock_timeout_ms (8 * 1000) + +static const uint8_t aws_fixed_scanning_channels[] = { + 1, 6, 11, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 +}; + +static void *rescan_timer = NULL; + +static void rescan_monitor(void); + +#define RESCAN_MONITOR_TIMEOUT_MS (5 * 60 * 1000) +static uint8_t rescan_available = 0; + +/* + * sniffer result/storage + * use global variable/buffer to keep it usable after zconfig_destroy + */ +uint8_t aws_result_ssid[ZC_MAX_SSID_LEN + 1]; +uint8_t aws_result_passwd[ZC_MAX_PASSWD_LEN + 1]; +uint8_t aws_result_bssid[ETH_ALEN];/* mac addr */ +uint8_t aws_result_channel = 0; +uint8_t aws_result_encry; +uint8_t aws_result_auth; + +int aws_80211_frame_handler(char *, int, enum AWSS_LINK_TYPE, int, signed char); + +uint8_t zconfig_get_lock_chn(void) +{ + return aws_locked_chn; +} + +void zconfig_force_rescan(void) +{ + if (aws_info) { + aws_state = AWS_SCANNING; + } +} + +void zconfig_channel_locked_callback(uint8_t primary_channel, + uint8_t secondary_channel, uint8_t *bssid) +{ + aws_locked_chn = primary_channel; + + if (aws_state == AWS_SCANNING) { + aws_state = AWS_CHN_LOCKED; + } + + awss_event_post(IOTX_AWSS_LOCK_CHAN); +} + +void zconfig_got_ssid_passwd_callback(uint8_t *ssid, uint8_t *passwd, + uint8_t *bssid, uint8_t auth, uint8_t encry, uint8_t channel) +{ + if (bssid) { + awss_debug("ssid:%s, bssid:%02x%02x%02x%02x%02x%02x, %d\r\n", + ssid, bssid[0], bssid[1], bssid[2], + bssid[3], bssid[4], bssid[5], channel); + } else { + awss_debug("ssid:%s, bssid:--, %d\r\n", + ssid, channel); + } + + memset(aws_result_ssid, 0, sizeof(aws_result_ssid)); + memset(aws_result_passwd, 0, sizeof(aws_result_passwd)); + strncpy((char *)aws_result_ssid, (const char *)ssid, ZC_MAX_SSID_LEN - 1); + strncpy((char *)aws_result_passwd, (const char *)passwd, ZC_MAX_PASSWD_LEN - 1); + + if (bssid) { + memcpy(aws_result_bssid, bssid, ETH_ALEN); + } + aws_result_auth = auth; + aws_result_encry = encry; + aws_result_channel = channel; + + aws_state = AWS_SUCCESS; + + awss_event_post(IOTX_AWSS_GOT_SSID_PASSWD); +} + +uint8_t aws_next_channel(void) +{ + /* aws_chn_index start from -1 */ + while (1) { + aws_chn_index ++; + if (aws_chn_index >= AWS_MAX_CHN_NUMS) { + aws_chn_index = 0; /* rollback to start */ + } + + if (aws_chn_list[aws_chn_index]) { /* valid channel */ + break; + } + } + + aws_cur_chn = aws_chn_list[aws_chn_index]; + + return aws_cur_chn; +} + +static void aws_switch_dst_chan(int channel); +static int aws_amend_dst_chan = 0; +void aws_switch_channel(void) +{ + HAL_MutexLock(zc_mutex); + if (aws_amend_dst_chan != 0) { + aws_switch_dst_chan(aws_amend_dst_chan); + aws_amend_dst_chan = 0; + HAL_MutexUnlock(zc_mutex); + return; + } + + if (aws_state == AWS_CHN_LOCKED) { + HAL_MutexUnlock(zc_mutex); + return; + } + + do { + int channel = aws_next_channel(); + aws_chn_timestamp = os_get_time_ms(); + HAL_Awss_Switch_Channel(channel, 0, NULL); + awss_trace("chan %d\r\n", channel); + } while (0); + HAL_MutexUnlock(zc_mutex); +} + +void aws_set_dst_chan(int channel) +{ + HAL_MutexLock(zc_mutex); + aws_amend_dst_chan = channel; + HAL_MutexUnlock(zc_mutex); +} + +static void aws_switch_dst_chan(int channel) +{ + int i = aws_chn_index; + for (; i < AWS_MAX_CHN_NUMS; i ++) { + if (aws_chn_list[i] == 0) { + continue; + } + if (aws_chn_list[i] == channel) { + break; + } + } + + if (i >= AWS_MAX_CHN_NUMS) { + for (i = 0; i < aws_chn_index; i ++) { + if (aws_chn_list[i] == 0) { + continue; + } + if (aws_chn_list[i] == channel) { + break; + } + } + } + + if (i == aws_chn_index) { /* no need to switch channel. */ + return; + } + + aws_chn_index = i; + aws_locked_chn = channel; + aws_cur_chn = channel; + aws_chn_timestamp = os_get_time_ms(); + if (aws_state == AWS_SCANNING) { + aws_state = AWS_CHN_LOCKED; + } + HAL_Awss_Switch_Channel(channel, 0, NULL); + + awss_trace("adjust chan %d\r\n", channel); +} + +enum { + CHNSCAN_ONGOING, /* no timeout, continue */ + CHNSCAN_NEXT_CHN, /* should swith to next channel */ + CHNSCAN_TIMEOUT /* aws timeout */ +}; + +int aws_is_chnscan_timeout(void) +{ + if (aws_stop == AWS_STOPPING) { + awss_debug("aws will stop...\r\n"); + return CHNSCAN_TIMEOUT; + } + + if (time_elapsed_ms_since(aws_chn_timestamp) > HAL_Awss_Get_Channelscan_Interval_Ms()) { + if ((0 != HAL_Awss_Get_Timeout_Interval_Ms()) && + (time_elapsed_ms_since(aws_start_timestamp) > HAL_Awss_Get_Timeout_Interval_Ms())) { + return CHNSCAN_TIMEOUT; + } else { + return CHNSCAN_NEXT_CHN; + } + } + + return CHNSCAN_ONGOING; +} + +int zconfig_add_active_channel(int channel) +{ + int fixed_channel_nums = sizeof(aws_fixed_scanning_channels); + + if (!zconfig_is_valid_channel(channel)) { + return -1; + } + + aws_chn_list[fixed_channel_nums + channel] = channel; + return 0; +} + +/* + * channel scanning/re-scanning control + * Note: 修改该函数时,需考虑到各平台差异 + * 庆科平台: + * --aws_switch_channel() 为空 + * --zconfig_destroy()会被调用两次,一次被aws_main_thread_fun(),一次被庆科驱动 + * linux/rtos平台差异 + * --vendor_recv_80211_frame()有实现,rtos平台该函数通常为空,通过注册callback方式收包 + */ +void aws_main_thread_func(void) +{ + int interval = 0; + aws_start_timestamp = os_get_time_ms(); + + /* channel switch init */ + aws_switch_channel(); + +rescanning: + /* start scaning channel */ + memset(zc_bssid, 0, ETH_ALEN); + while (aws_amend_dst_chan != 0 || aws_state == AWS_SCANNING) { + switch (aws_is_chnscan_timeout()) { + case CHNSCAN_ONGOING: + break; + case CHNSCAN_NEXT_CHN: + aws_switch_channel(); + break; + case CHNSCAN_TIMEOUT: + goto timeout_scanning; + default: + break; + } + + if (aws_stop == AWS_STOPPING) { /* interrupt by user */ + goto timeout_scanning; + } + + if (aws_state != AWS_SCANNING) { /* channel is locked, don't need to tx probe req */ + break; + } + + interval = (HAL_Awss_Get_Channelscan_Interval_Ms() + 2) / 3; + if (interval < 1) { + interval = 1; + } + + /* 80211 frame handled by callback */ + HAL_SleepMs(interval); +#ifndef AWSS_DISABLE_ENROLLEE + awss_broadcast_enrollee_info(); +#endif + HAL_SleepMs(interval); +#ifdef AWSS_SUPPORT_ADHA + aws_send_adha_probe_req(); +#endif + HAL_SleepMs(interval); +#ifdef AWSS_SUPPORT_AHA + aws_send_aha_probe_req(); +#endif + } + + /* channel lock */ + awss_debug("[channel scanning] %d ms\r\n", + time_elapsed_ms_since(aws_start_timestamp)); + + /* + * make sure switch to locked channel, + * in case of inconsistent with aws_cur_chn + */ +#ifdef AWSS_SUPPORT_APLIST + aws_try_adjust_chan(); +#endif + awss_debug("final channel %d\r\n", aws_locked_chn); + + while (aws_state != AWS_SUCCESS) { + /* 80211 frame handled by callback */ + HAL_SleepMs(300); + + if (aws_stop == AWS_STOPPING) { + goto timeout_recving; + } +#ifdef AWSS_SUPPORT_APLIST + aws_try_adjust_chan(); +#endif + if (aws_is_chnscan_timeout() == CHNSCAN_TIMEOUT) { + goto timeout_recving; + } + + if (aws_state == AWS_SCANNING) { + awss_debug("channel rescanning...\n"); + goto rescanning; + } + } + + awss_debug("[channel recving] %d ms\r\n", + time_elapsed_ms_since(aws_start_timestamp)); + + goto success; + +timeout_scanning: + awss_debug("aws timeout scanning!\r\n"); +timeout_recving: + awss_debug("aws timeout recving!\r\n"); + do { + if (aws_stop == AWS_STOPPING) { + break; + } + if (rescan_timer == NULL) { + rescan_timer = HAL_Timer_Create("rescan", (void(*)(void *))rescan_monitor, NULL); + } + HAL_Timer_Stop(rescan_timer); + HAL_Timer_Start(rescan_timer, RESCAN_MONITOR_TIMEOUT_MS); + HAL_Awss_Close_Monitor(); + while (rescan_available == 0) { + if (awss_get_config_press() || + aws_stop == AWS_STOPPING) { /* user interrupt sleep */ + HAL_Timer_Stop(rescan_timer); + break; + } + HAL_SleepMs(200); + } + rescan_available = 0; + } while (0); + + if (aws_stop == AWS_STOPPING) { /* interrupt by user */ + aws_stop = AWS_STOPPED; + goto success; + } + + aws_state = AWS_SCANNING; +#ifdef AWSS_SUPPORT_APLIST + if (awss_is_ready_clr_aplist()) { + awss_clear_aplist(); + } +#endif + + aws_start_timestamp = os_get_time_ms(); + HAL_Awss_Open_Monitor(aws_80211_frame_handler); + goto rescanning; + +success: + awss_stop_timer(rescan_timer); + rescan_timer = NULL; + /* don't destroy zconfig_data until monitor_cb is finished. */ + HAL_MutexLock(zc_mutex); + HAL_MutexUnlock(zc_mutex); + /* + * zconfig_destroy() after os_awss_monitor_close() beacause + * zconfig_destroy will release mem/buffer that + * zconfig_recv_callback will use + * + * Note: hiflying will reboot after calling this func, so + * aws_get_ssid_passwd() was called in os_awss_monitor_close() + */ + if (aws_stop == AWS_STOPPED) { + zconfig_force_destroy(); + } +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + else if (strcmp((const char *)aws_result_ssid, (const char *)zc_adha_ssid) == 0 || + strcmp((const char *)aws_result_ssid, (const char *)zc_default_ssid) == 0) { + zconfig_destroy(); + } +#endif + else { + zconfig_force_destroy(); + } +} + +static void rescan_monitor(void) +{ + rescan_available = 1; +} + +int aws_80211_frame_handler(char *buf, int length, enum AWSS_LINK_TYPE link_type, int with_fcs, signed char rssi) +{ + static uint32_t lock_start; + + int ret = zconfig_recv_callback(buf, length, aws_cur_chn, link_type, with_fcs, rssi); + + if (aws_state == AWS_CHN_LOCKED) { + switch (ret) { + case PKG_START_FRAME: + case PKG_DATA_FRAME: + case PKG_GROUP_FRAME: + lock_start = os_get_time_ms(); + break; + default: + /* set to rescanning */ + if (time_elapsed_ms_since(lock_start) > aws_channel_lock_timeout_ms) { + aws_state = AWS_SCANNING; + } + break; + } + } + + return ret; +} + +void aws_start(char *pk, char *dn, char *ds, char *ps) +{ + aws_info = os_zalloc(sizeof(struct aws_info)); + if (!aws_info) { + return; + } + + aws_state = AWS_SCANNING; + + /* start from -1 */ + aws_chn_index = 0xff; + memcpy(aws_chn_list, aws_fixed_scanning_channels, + sizeof(aws_fixed_scanning_channels)); + + memset(aws_result_ssid, 0, sizeof(aws_result_ssid)); + memset(aws_result_passwd, 0, sizeof(aws_result_passwd)); + memset(aws_result_bssid, 0, sizeof(aws_result_bssid)); + aws_result_auth = ZC_AUTH_TYPE_INVALID; + aws_result_encry = ZC_ENC_TYPE_INVALID; + aws_result_channel = 0; + + zconfig_init(); +#ifdef AWSS_SUPPORT_APLIST + awss_open_aplist_monitor(); +#endif + + HAL_Awss_Open_Monitor(aws_80211_frame_handler); + +#ifndef AWSS_DISABLE_ENROLLEE + awss_init_enrollee_info(); +#endif + + aws_main_thread_func(); +} + +static void *aws_mutex = NULL; + +void aws_destroy(void) +{ + if (aws_mutex == NULL) { + aws_mutex = HAL_MutexCreate(); + } + if (aws_mutex) { + HAL_MutexLock(aws_mutex); + } + + if (aws_info == NULL) { + return; + } + + if (aws_stop == AWS_STOPPED) { + return; + } + + aws_stop = AWS_STOPPING; + + HAL_Awss_Close_Monitor(); + + while (aws_stop != AWS_STOPPED) { + if (aws_state == AWS_SUCCESS) { + break; + } + HAL_MutexUnlock(aws_mutex); + HAL_SleepMs(100); + HAL_MutexLock(aws_mutex); + } + if (NULL != aws_info) { + HAL_Free(aws_info); + } + aws_info = NULL; + +#ifndef AWSS_DISABLE_ENROLLEE + awss_destroy_enrollee_info(); +#endif + if (aws_mutex) { + HAL_MutexUnlock(aws_mutex); + } +} + +void aws_release_mutex() +{ + if (aws_mutex) { + HAL_MutexDestroy(aws_mutex); + aws_mutex = NULL; + } +} + +int aws_get_ssid_passwd(char *ssid, char *passwd, uint8_t *bssid, + char *auth, char *encry, uint8_t *channel) +{ + if (aws_state != AWS_SUCCESS) { + return 0; + } + if (ssid) { + strncpy((char *)ssid, (const char *)aws_result_ssid, ZC_MAX_SSID_LEN - 1); + } + if (passwd) { + strncpy((char *)passwd, (const char *)aws_result_passwd, ZC_MAX_PASSWD_LEN - 1); + } + if (bssid) { + memcpy(bssid, aws_result_bssid, ETH_ALEN); + } + if (auth) { + *auth = aws_result_auth; + } + if (encry) { + *encry = aws_result_encry; + } + if (channel) { + *channel = aws_result_channel; + } + return 1; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/p2p/awss_wps.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/p2p/awss_wps.c new file mode 100644 index 00000000..2242160e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/p2p/awss_wps.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#ifdef AWSS_SUPPORT_SMARTCONFIG_WPS + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +int is_ascii_string(uint8_t *str) +{ + int i = 0; + while (str[i] != '\0') { + if (str[i] < 128) { + i ++; + } else { + return 0; + } + } + return 1; +} + +/** + * extract device name attribute from wps ie struct + * + * @wps_ie: [IN] wps ie struct + * @len: [OUT] len of dev name attr if exist + * + * Return: + * %NULL if dev name attr could not be found, otherwise return a + * pointer to dev name attr + */ +static uint8_t *get_device_name_attr_from_wps(uint8_t *wps_ie, uint8_t *len) +{ + /* 6 = 1(Element ID) + 1(Length) + 4(WPS OUI) */ + uint8_t *attr_ptr = wps_ie + 6; /* goto first attr */ + uint8_t wps_ielen = wps_ie[1]; + +#define device_name_id (0x1011) + while (attr_ptr - wps_ie < wps_ielen) { + /* 4 = 2(Attribute ID) + 2(Length) */ + uint16_t attr_id = os_get_unaligned_be16(attr_ptr); + uint16_t attr_data_len = os_get_unaligned_be16(attr_ptr + 2); + uint16_t attr_len = attr_data_len + 4; + + if (attr_id == device_name_id) { + *len = attr_len; + return attr_ptr; + } else { + attr_ptr += attr_len; /* goto next */ + } + } + return NULL; +} + +/* + * passwd_check_utf8() + * + * @Note: see andriod smartconfig with p2p + * if the byte in passwd is zero, jave will change 0x00 with 0xc080 + * the function will restore 0xc080 to 0x00 + */ +void passwd_check_utf8(uint8_t *passwd, int *passwd_len) +{ + int i, len; + + if (!passwd || !passwd_len) { + return; + } + + len = *passwd_len; + for (i = 0; i < len; i ++) { + if (passwd[i] < 0x80) { /* [0x01 ~ 0x7F] */ + continue; + } + passwd[i] = 0; /* resetore to 0x00 */ + if (i + 2 < len) { /* move the rest to overwrite useless content. */ + memmove(passwd + i + 1, passwd + i + 2, len - i - 2); + } + len --; + } + *passwd_len = len; +} + +/* + * get_ssid_passwd_from_wps() + * + * @Note: see andriod zconfig protocol + * android sdk limit sizeof(passwd) <= 23 + * + * @Return: _GOT_RESULT_ + * + * use src mac to do ssid completion + */ +static int get_ssid_passwd_from_w(uint8_t *in, int total_len, uint8_t *src, uint8_t *bssid) +{ + uint8_t tmp_ssid[ZC_MAX_SSID_LEN + 1] = {0}, tmp_passwd[ZC_MAX_PASSWD_LEN + 1] = {0}; + int ssid_len, passwd_len, ssid_truncated = 0; + uint16_t crc, cal_crc; + char encrypt = 0; + /* used by prepare frame */ + char *magic_p_w_d = "zl&ws";/* FIXME: Maybe it will be dangerous when opening source. */ + static uint32_t start_time = 0; + +#define W_LEN (32) /* total_len */ +#define EXTRA_LEN (3) /* ssid_len(1B) + checksum(2B) */ + if (!in || total_len <= 4 + EXTRA_LEN) { + return GOT_NOTHING; + } + + /* attr_id(2) + attr_len(2) = 4 */ + in += 4; + total_len -= 4; + + if (total_len > W_LEN) { + awss_warn("ssid len > 32\r\n"); + } + + /* total_len: ssid_len(1B), ssid, passwd, crc(2B) */ + ssid_len = in[0]; + if (ssid_len & P2P_ENCRYPT_BIT_MASK) { + encrypt = (ssid_len & P2P_ENCRYPT_BIT_MASK) >> P2P_ENCODE_TYPE_OFFSET; + ssid_len &= P2P_SSID_LEN_MASK; + } + if (encrypt > P2P_ENCODE_TYPE_ENCRYPT) { + return GOT_NOTHING; + } + + passwd_len = total_len - ssid_len - EXTRA_LEN; /* ssid_len(1B), crc(2B) */ + if (ssid_len > W_LEN - EXTRA_LEN || passwd_len < 0) { + return GOT_NOTHING; + } + + AWSS_UPDATE_STATIS(AWSS_STATIS_WPS_IDX, AWSS_STATIS_TYPE_TIME_START); + /* ssid_len(1B), ssid, passwd, crc(2B) */ + crc = os_get_unaligned_be16(in + 1 + ssid_len + passwd_len); + /* restore 0xc080 to 0x00 */ + passwd_check_utf8(in + 1 + ssid_len, &passwd_len); + cal_crc = zconfig_checksum_v3(in, 1 + ssid_len + passwd_len); + if (crc != cal_crc) { + memset(zc_android_src, 0, sizeof(zconfig_data->android_src)); + memset(zc_pre_ssid, 0, sizeof(zconfig_data->android_pre_ssid)); + memset(zc_android_ssid, 0, sizeof(zconfig_data->android_ssid)); + memset(zc_android_bssid, 0, sizeof(zconfig_data->android_bssid)); + awss_debug("rx illegal p2p (0x%x != 0x%x)\r\n", crc, cal_crc); + awss_event_post(IOTX_AWSS_CS_ERR); + AWSS_UPDATE_STATIS(AWSS_STATIS_WPS_IDX, AWSS_STATIS_TYPE_CRC_ERR); + /* + * use zconfig_checksum_v3() because + * java modified UTF-8, U+C080 equal U+00, + * ssid len & ssid & crc is not be 0, + * the content of passwd encrypted may be 0 + */ + return GOT_NOTHING; + } + + if (start_time == 0) { + start_time = os_get_time_ms(); + } + +#define MAC_LOCAL_ADMINISTERED_BIT (0x02) + memcpy(zc_android_src, src, ETH_ALEN); + if (zc_android_src[0] & MAC_LOCAL_ADMINISTERED_BIT) { + zc_android_src[0] &= ~MAC_LOCAL_ADMINISTERED_BIT; + /*awss_debug("android src: %02x%02x%02x\r\n", zc_android_src[0], src[1], src[2]); */ + } else { + awss_warn("local administered bit not set: %02x%02x%02x\r\n", + src[0], src[1], src[2]); + } + + in += 1;/* eating ssid_len(1B) */ + + memset(tmp_ssid, 0, ZC_MAX_SSID_LEN); + memset(tmp_passwd, 0, ZC_MAX_PASSWD_LEN); + + memcpy(tmp_ssid, in, ssid_len); + in += ssid_len; + if (passwd_len) { + memcpy(tmp_passwd, in, passwd_len); + } + + awss_dict_crypt(SSID_DECODE_TABLE, tmp_ssid, ssid_len); + + switch (encrypt) { + case P2P_ENCODE_TYPE_ENCRYPT: { + /* decypt passwd using aes128-cfb */ + uint8_t passwd_cipher_len = 0; + uint8_t *passwd_cipher = os_zalloc(128); + if (passwd_cipher == NULL) { + return GOT_NOTHING; + } + + decode_chinese(tmp_passwd, passwd_len, passwd_cipher, &passwd_cipher_len, 7); + passwd_len = passwd_cipher_len; + memset(tmp_passwd, 0, ZC_MAX_PASSWD_LEN); + aes_decrypt_string((char *)passwd_cipher, (char *)tmp_passwd, passwd_len, + 1, awss_get_encrypt_type(), 0, NULL); + HAL_Free(passwd_cipher); + if (is_utf8((const char *)tmp_passwd, passwd_len) == 0) { + /* memset(zconfig_data, 0, sizeof(*zconfig_data)); */ + memset(zc_android_src, 0, sizeof(zconfig_data->android_src)); + memset(zc_pre_ssid, 0, sizeof(zconfig_data->android_pre_ssid)); + memset(zc_android_ssid, 0, sizeof(zconfig_data->android_ssid)); + memset(zc_android_bssid, 0, sizeof(zconfig_data->android_bssid)); + + awss_warn("p2p decrypt passwd content err\r\n"); + awss_event_post(IOTX_AWSS_PASSWD_ERR); + AWSS_UPDATE_STATIS(AWSS_STATIS_WPS_IDX, AWSS_STATIS_TYPE_PASSWD_ERR); + return GOT_NOTHING; + } + break; + } + default: + awss_warn("p2p encypt:%d not support\r\n", encrypt); + memset(zconfig_data, 0, sizeof(*zconfig_data)); + return GOT_NOTHING; + } + + awss_debug("ssid:%s, tlen:%d\r\n", tmp_ssid, total_len); + if (passwd_len && !memcmp(tmp_passwd, magic_p_w_d, passwd_len)) { + /* Note: when v2 rollback to v1, zc_preapre_ssid will useless */ + strncpy((char *)zc_pre_ssid, (char const *)tmp_ssid, ZC_MAX_SSID_LEN - 1); + return GOT_CHN_LOCK; + } + /* + // for ascii ssid, max length is 29(32 - 1 - 2). + // for utf-8 ssid, max length is 29 - 2 or 29 - 3 + // gbk ssid also encoded as utf-8 + // SAMSUNG S4 max name length = 22 + */ + if (!is_ascii_string((uint8_t *)tmp_ssid)) { /* chinese ssid */ + ssid_truncated = 1; /* in case of gbk chinese */ + } else if (total_len >= W_LEN - EXTRA_LEN) { + ssid_truncated = 1; + } + + if (ssid_truncated) { + uint8_t *best_ssid; + int cur_ssid_len = strlen((const char *)tmp_ssid); /* current_ssid */ + int pre_ssid_len = strlen((const char *)zc_pre_ssid); /* prepare_ssid */ + if (pre_ssid_len && pre_ssid_len < cur_ssid_len) { + /* should not happen */ + awss_warn("pre:%s < cur:%s\r\n", zc_pre_ssid, tmp_ssid); + best_ssid = tmp_ssid; /* current ssid */ + } else if (pre_ssid_len) { + best_ssid = zc_pre_ssid; /* prepare ssid */ + } else { + best_ssid = tmp_ssid; /* default use current ssid */ + } + + /* awss_debug("ssid truncated, best ssid: %s\r\n", best_ssid); */ + + do { +#ifdef AWSS_SUPPORT_APLIST + struct ap_info *ap_info; + ap_info = zconfig_get_apinfo_by_ssid_suffix(best_ssid); + if (ap_info) { + awss_debug("ssid truncated, got ssid from aplist:%s\r\n", best_ssid); + strncpy((char *)zc_ssid, (const char *)ap_info->ssid, ZC_MAX_SSID_LEN - 1); + memcpy(zc_bssid, ap_info->mac, ETH_ALEN); + } else +#endif + { + if (memcmp(bssid, zero_mac, ETH_ALEN) && memcmp(bssid, br_mac, ETH_ALEN)) { + memcpy(zc_android_bssid, bssid, ETH_ALEN); + } +#ifdef AWSS_SUPPORT_APLIST + ap_info = zconfig_get_apinfo(zc_android_bssid); + if (ap_info) { + if (ap_info->ssid[0] == '\0') { /* hide ssid, MUST not truncate */ + strncpy((char *)zc_android_ssid, (const char *)best_ssid, ZC_MAX_SSID_LEN - 1); + } else { /* not hide ssid, amend ssid according to ap list */ + strncpy((char *)zc_android_ssid, (const char *)ap_info->ssid, ZC_MAX_SSID_LEN - 1); + } + } else +#endif + if (time_elapsed_ms_since(start_time) > HAL_Awss_Get_Channelscan_Interval_Ms() * (13 + 3) * 2) { + start_time = 0; + strncpy((char *)zc_android_ssid, (const char *)best_ssid, ZC_MAX_SSID_LEN - 1); + } + + if (zc_android_ssid[0] == '\0') { + return GOT_NOTHING; + } + strncpy((char *)zc_ssid, (const char *)zc_android_ssid, ZC_MAX_SSID_LEN - 1); + memcpy(zc_bssid, zc_android_bssid, ETH_ALEN); + } + } while (0); + } else { + strncpy((char *)zc_ssid, (char const *)tmp_ssid, ZC_MAX_SSID_LEN - 1); + if (memcmp(bssid, zero_mac, ETH_ALEN) && memcmp(bssid, br_mac, ETH_ALEN)) { + memcpy(zc_bssid, bssid, ETH_ALEN); + } + } + + strncpy((char *)zc_passwd, (char const *)tmp_passwd, ZC_MAX_PASSWD_LEN - 1); + start_time = 0; + + return GOT_SSID_PASSWD; +} + + +int awss_recv_callback_wps(struct parser_res *res) +{ + uint8_t *data = res->u.wps.data; + uint16_t len = res->u.wps.data_len; + + uint8_t tods = res->tods; + uint8_t channel = res->channel; + + int ret = get_ssid_passwd_from_w(data, len, res->src, res->bssid); + if (ret == GOT_CHN_LOCK) { + awss_debug("callback for v2:%02x%02x%02x\r\n", + res->src[0], res->src[1], res->src[2]); + goto chn_locked; + } else if (ret == GOT_SSID_PASSWD) { + goto rcv_done; + } else if (ret == GOT_NOTHING) { + return PKG_INVALID; + } else { + return PKG_INVALID; + } + +chn_locked: + zconfig_set_state(STATE_CHN_LOCKED_BY_P2P, tods, channel); + return PKG_START_FRAME; +rcv_done: + AWSS_UPDATE_STATIS(AWSS_STATIS_WPS_IDX, AWSS_STATIS_TYPE_TIME_SUC); + zconfig_set_state(STATE_RCV_DONE, tods, channel); + return PKG_END; +} + +int awss_ieee80211_wps_process(uint8_t *mgmt_header, int len, int link_type, struct parser_res *res, signed char rssi) +{ + const uint8_t *wps_ie = NULL; + struct ieee80211_hdr *hdr; + uint8_t attr_len = 0; + uint16_t ieoffset; + int fc; + + /* + * when device try to connect current router (include adha and aha) + * skip the wps packet. + */ + if (mgmt_header == NULL || zconfig_finished) { + return ALINK_INVALID; + } + + /* + * we don't process wps until user press configure button + */ + if (awss_get_config_press() == 0) { + return ALINK_INVALID; + } + + hdr = (struct ieee80211_hdr *)mgmt_header; + fc = hdr->frame_control; + + if (!ieee80211_is_probe_req(fc)) { + return ALINK_INVALID; + } + + ieoffset = offsetof(struct ieee80211_mgmt, u.probe_req.variable); + if (ieoffset > len) { + return ALINK_INVALID; + } + /* get wps ie */ + wps_ie = (const uint8_t *)cfg80211_find_vendor_ie(WLAN_OUI_WPS, WLAN_OUI_TYPE_WPS, + mgmt_header + ieoffset, len - ieoffset); + if (wps_ie == NULL) { + return ALINK_INVALID; + } + /* get wps name in wps ie */ + wps_ie = (const uint8_t *)get_device_name_attr_from_wps((uint8_t *)wps_ie, &attr_len); + if (wps_ie == NULL) { + return ALINK_INVALID; + } + res->u.wps.data_len = attr_len; + res->u.wps.data = (uint8_t *)wps_ie; + return ALINK_WPS; +} +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/p2p/awss_wps.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/p2p/awss_wps.h new file mode 100644 index 00000000..0cb7feec --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/p2p/awss_wps.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_WPS_H__ +#define __AWSS_WPS_H__ + +#ifdef AWSS_SUPPORT_SMARTCONFIG_WPS + +#include +#include "os.h" +#include "zconfig_ieee80211.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +#define WLAN_OUI_MICROSOFT (0x0050F2) +#define WLAN_OUI_WPS (0x0050F2) +#define WLAN_OUI_TYPE_MICROSOFT_WPA (1) +#define WLAN_OUI_TYPE_WPS (4) + +int awss_recv_callback_wps(struct parser_res *res); +int awss_ieee80211_wps_process(uint8_t *mgmt_header, int len, int link_type, + struct parser_res *res, signed char rssi); + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif +#endif /* end AWSS_SUPPORT_SMARTCONFIG_WPS */ +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/p2p/p2p_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/p2p/p2p_wrapper.h new file mode 100644 index 00000000..8c994140 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/p2p/p2p_wrapper.h @@ -0,0 +1,57 @@ +#include "infra_types.h" +#include "infra_defs.h" +#include "wrappers_defs.h" +/*************************************** common hals ***************************************/ +int HAL_Timer_Stop(void *timer); +int HAL_Timer_Delete(void *timer); +void *HAL_Timer_Create(const char *name, void (*func)(void *), void *user_data); +int HAL_Timer_Start(void *timer, int ms); +void HAL_SleepMs(uint32_t ms); +void *HAL_Malloc(uint32_t size); +void HAL_MutexLock(void *mutex); +void HAL_MutexUnlock(void *mutex); +uint64_t HAL_UptimeMs(void); +void HAL_Free(void *ptr); +void *HAL_MutexCreate(void); +void HAL_MutexDestroy(void *mutex); + +/*************************************** wifi provision frameworks hals ***************************************/ +/* frameworks/awss.c*/ +int HAL_Awss_Get_Timeout_Interval_Ms(void); +int HAL_Sys_Net_Is_Ready(); +int HAL_Wifi_Get_Ap_Info(char ssid[HAL_MAX_SSID_LEN],char passwd[HAL_MAX_PASSWD_LEN],uint8_t bssid[ETH_ALEN]); +/* awss_crypt.c */ +int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN]); +int HAL_GetProductSecret(char *product_secret); +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN]); +int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN]); +/* zconfig_vendor_common.c */ +void HAL_Awss_Close_Monitor(void); +void HAL_Awss_Open_Monitor(_IN_ awss_recv_80211_frame_cb_t cb); +void HAL_Awss_Switch_Channel(char primary_channel, char secondary_channel, uint8_t bssid[ETH_ALEN]); +int HAL_Awss_Get_Channelscan_Interval_Ms(void); +DLL_HAL_API p_HAL_Aes128_t HAL_Aes128_Init( + _IN_ const uint8_t *key, + _IN_ const uint8_t *iv, + _IN_ AES_DIR_t dir); +DLL_HAL_API int HAL_Aes128_Destroy(_IN_ p_HAL_Aes128_t aes); +DLL_HAL_API int HAL_Aes128_Cbc_Decrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t blockNum, + _OU_ void *dst); +DLL_HAL_API int HAL_Aes128_Cfb_Decrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t length, + _OU_ void *dst); +char *HAL_Wifi_Get_Mac(_OU_ char mac_str[HAL_MAC_LEN]); +int HAL_Awss_Connect_Ap( + _IN_ uint32_t connection_timeout_ms, + _IN_ char ssid[HAL_MAX_SSID_LEN], + _IN_ char passwd[HAL_MAX_PASSWD_LEN], + _IN_OPT_ enum AWSS_AUTH_TYPE auth, + _IN_OPT_ enum AWSS_ENC_TYPE encry, + _IN_OPT_ uint8_t bssid[ETH_ALEN], + _IN_OPT_ uint8_t channel); + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/aha_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/aha_wrapper.h new file mode 100644 index 00000000..ab430a58 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/aha_wrapper.h @@ -0,0 +1,62 @@ +#include "infra_types.h" +#include "infra_defs.h" +#include "wrappers_defs.h" + +/*************************************** common hals ***************************************/ +int HAL_Timer_Stop(void *timer); +int HAL_Timer_Delete(void *timer); +void *HAL_Timer_Create(const char *name, void (*func)(void *), void *user_data); +int HAL_Timer_Start(void *timer, int ms); +void HAL_SleepMs(uint32_t ms); +void *HAL_Malloc(uint32_t size); +void HAL_MutexLock(void *mutex); +void HAL_MutexUnlock(void *mutex); +uint64_t HAL_UptimeMs(void); +void HAL_Free(void *ptr); +void *HAL_MutexCreate(void); +void HAL_MutexDestroy(void *mutex); + +/*************************************** wifi provision frameworks hals ***************************************/ +/* frameworks/awss.c*/ +int HAL_Awss_Get_Timeout_Interval_Ms(void); +int HAL_Sys_Net_Is_Ready(); +int HAL_Wifi_Get_Ap_Info(char ssid[HAL_MAX_SSID_LEN],char passwd[HAL_MAX_PASSWD_LEN],uint8_t bssid[ETH_ALEN]); +/* awss_crypt.c */ +int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN]); +int HAL_GetProductSecret(char *product_secret); +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN]); +int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN]); +void HAL_Awss_Close_Monitor(void); +void HAL_Awss_Switch_Channel(char primary_channel, char secondary_channel, uint8_t bssid[ETH_ALEN]); +void HAL_Awss_Open_Monitor(_IN_ awss_recv_80211_frame_cb_t cb); +int HAL_Awss_Get_Channelscan_Interval_Ms(void); +/* zconfig_vendor_common.c */ +DLL_HAL_API p_HAL_Aes128_t HAL_Aes128_Init( + _IN_ const uint8_t *key, + _IN_ const uint8_t *iv, + _IN_ AES_DIR_t dir); +DLL_HAL_API int HAL_Aes128_Destroy(_IN_ p_HAL_Aes128_t aes); +DLL_HAL_API int HAL_Aes128_Cbc_Decrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t blockNum, + _OU_ void *dst); +DLL_HAL_API int HAL_Aes128_Cfb_Decrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t length, + _OU_ void *dst); +char *HAL_Wifi_Get_Mac(_OU_ char mac_str[HAL_MAC_LEN]); +int HAL_Awss_Connect_Ap( + _IN_ uint32_t connection_timeout_ms, + _IN_ char ssid[HAL_MAX_SSID_LEN], + _IN_ char passwd[HAL_MAX_PASSWD_LEN], + _IN_OPT_ enum AWSS_AUTH_TYPE auth, + _IN_OPT_ enum AWSS_ENC_TYPE encry, + _IN_OPT_ uint8_t bssid[ETH_ALEN], + _IN_OPT_ uint8_t channel); + +/*************************************** phone ap specially required hals ***************************************/ +int HAL_Wifi_Send_80211_Raw_Frame(_IN_ enum HAL_Awss_Frame_Type type, + _IN_ uint8_t *buffer, _IN_ int len); +DLL_HAL_API int HAL_Wifi_Scan(awss_wifi_scan_result_cb_t cb); diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/awss_aha.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/awss_aha.c new file mode 100644 index 00000000..44bacaf9 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/awss_aha.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#ifdef AWSS_SUPPORT_AHA + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +#define AHA_SA_OFFSET (10) +#define AHA_PROBE_PKT_LEN (49) +#define AHA_MONITOR_TIMEOUT_MS (1 * 60 * 1000) + +const char *zc_default_ssid = "aha"; +const char *zc_default_passwd = "12345678"; + +static const uint8_t aha_probe_req_frame[AHA_PROBE_PKT_LEN] = { + 0x40, 0x00, /* mgnt type, frame control */ + 0x00, 0x00, /* duration */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* DA */ + 0x28, 0xC2, 0xDD, 0x61, 0x68, 0x83, /* SA, to be replaced with wifi mac */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* BSSID */ + 0xC0, 0x79, /* seq */ + 0x00, 0x03, 0x61, 0x68, 0x61, /* ssid, aha */ + 0x01, 0x08, 0x82, 0x84, 0x8B, 0x96, 0x8C, 0x92, 0x98, 0xA4, /* supported rates */ + 0x32, 0x04, 0xB0, 0x48, 0x60, 0x6C, /* extended supported rates */ + 0x3F, 0x84, 0x10, 0x9E /* FCS */ +}; + +static void *aha_timer = NULL; +static volatile char aha_timeout = 0; + +static void aha_monitor(void); + +static void aha_monitor(void) +{ + aha_timeout = 1; +} + +int awss_aha_monitor_is_timeout(void) +{ + return aha_timeout > 0; +} + +int awss_open_aha_monitor(void) +{ + aha_timeout = 0; + if (aha_timer == NULL) + aha_timer = (void *)HAL_Timer_Create("aha", (void (*)(void *))aha_monitor, NULL); + if (aha_timer == NULL) + return -1; + + HAL_Timer_Stop(aha_timer); + HAL_Timer_Start(aha_timer, AHA_MONITOR_TIMEOUT_MS); + return 0; +} + +int awss_close_aha_monitor(void) +{ + awss_stop_timer(aha_timer); + aha_timer = NULL; + aha_timeout = 0; + return 0; +} + +int awss_recv_callback_aha_ssid(struct parser_res *res) +{ + uint8_t tods = res->tods; + uint8_t channel = res->channel; + + awss_debug("found default ssid: %s\r\n", zc_default_ssid); + AWSS_UPDATE_STATIS(AWSS_STATIS_PAP_IDX, AWSS_STATIS_TYPE_TIME_START); + + strncpy((char *)zc_ssid, zc_default_ssid, ZC_MAX_SSID_LEN - 1); + strncpy((char *)zc_passwd, zc_default_passwd, ZC_MAX_PASSWD_LEN - 1); + + zconfig_set_state(STATE_RCV_DONE, tods, channel); + return PKG_END; +} + +int aws_send_aha_probe_req(void) +{ + uint8_t probe[AHA_PROBE_PKT_LEN]; + memcpy(probe, aha_probe_req_frame, sizeof(probe)); + os_wifi_get_mac(&probe[AHA_SA_OFFSET]); + HAL_Wifi_Send_80211_Raw_Frame(FRAME_PROBE_REQ, probe, sizeof(probe)); + return 0; +} + +int awss_ieee80211_aha_process(uint8_t *mgmt_header, int len, int link_type, struct parser_res *res, signed char rssi) +{ + uint8_t ssid[ZC_MAX_SSID_LEN] = {0}, bssid[ETH_ALEN] = {0}; + uint8_t auth, pairwise_cipher, group_cipher; + struct ieee80211_hdr *hdr; + int fc, ret, channel; + + /* + * when device try to connect current router (include adha and aha) + * skip the new aha and process the new aha in the next scope. + */ + if (mgmt_header == NULL || zconfig_finished) + return ALINK_INVALID; + + /* + * we don't process aha until user press configure button + */ + if (awss_get_config_press() == 0) + return ALINK_INVALID; + + hdr = (struct ieee80211_hdr *)mgmt_header; + fc = hdr->frame_control; + + if (!ieee80211_is_beacon(fc) && !ieee80211_is_probe_resp(fc)) + return ALINK_INVALID; + ret = ieee80211_get_bssid(mgmt_header, bssid); + if (ret < 0) + return ALINK_INVALID; + + ret = ieee80211_get_ssid(mgmt_header, len, ssid); + if (ret < 0) + return ALINK_INVALID; + + /* + * skip ap which is not aha + */ + if (strcmp((const char *)ssid, zc_default_ssid)) + return ALINK_INVALID; + + channel = cfg80211_get_bss_channel(mgmt_header, len); + rssi = rssi > 0 ? rssi - 256 : rssi; + + cfg80211_get_cipher_info(mgmt_header, len, &auth, + &pairwise_cipher, &group_cipher); + awss_save_apinfo(ssid, bssid, channel, auth, + pairwise_cipher, group_cipher, rssi); + /* + * If user press the configure button, + * device just process aha, and skip all the adha. + */ + if (adha_aplist->cnt > adha_aplist->try_idx) { + uint8_t ap_idx = adha_aplist->aplist[adha_aplist->try_idx ++]; +#ifdef AWSS_SUPPORT_APLIST + memcpy(zc_bssid, zconfig_aplist[ap_idx].mac, ETH_ALEN); +#endif + awss_set_config_press(0); + return ALINK_DEFAULT_SSID; + } + return ALINK_INVALID; +} +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/awss_aha.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/awss_aha.h new file mode 100644 index 00000000..3d92cf70 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/awss_aha.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_AHA_H__ +#define __AWSS_AHA_H__ + +#include +#include "os.h" +#include "zconfig_ieee80211.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +int awss_open_aha_monitor(void); +int awss_close_aha_monitor(void); +int awss_aha_monitor_is_timeout(void); +int aws_send_aha_probe_req(void); +int awss_recv_callback_aha_ssid(struct parser_res *res); +int awss_ieee80211_aha_process(uint8_t *mgmt_header, int len, int link_type, struct parser_res *res, signed char rssi); + +extern const char *zc_default_ssid; +extern const char *zc_default_passwd; + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/awss_wifimgr.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/awss_wifimgr.c new file mode 100644 index 00000000..b241f321 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/awss_wifimgr.c @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) +#define WIFI_APINFO_LIST_LEN (512) +#define DEV_SIMPLE_ACK_LEN (64) + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +static char g_req_msg_id[MSG_REQ_ID_LEN]; +static platform_netaddr_t g_wifimgr_req_sa; + +static void *scan_req_timer = NULL; +static void *scan_tx_wifilist_timer = NULL; +static void wifimgr_scan_request(); +static void wifimgr_scan_tx_wifilist(); + +static char wifi_scan_runninng = 0; +static void *g_scan_mutex; + +typedef struct scan_list { + list_head_t entry; + void *data; +} scan_list_t; + +static ALIYUN_LIST_HEAD(g_scan_list); + +int wifimgr_scan_init(void) +{ + if (wifi_scan_runninng) + return 0; + + g_scan_mutex = HAL_MutexCreate(); + INIT_LIST_HEAD(&g_scan_list); + wifi_scan_runninng = 1; + return 0; +} + +static void wifimgr_scan_tx_wifilist() +{ + scan_list_t *item = NULL, *next = NULL; + + char topic[TOPIC_LEN_MAX] = {0}; + awss_build_topic((const char *)TOPIC_AWSS_WIFILIST, topic, TOPIC_LEN_MAX); + + HAL_MutexLock(g_scan_mutex); + list_for_each_entry_safe(item, next, &g_scan_list, entry, scan_list_t) { + if (item && item->data) { + if (0 != awss_cmp_coap_ob_send(item->data, strlen((char *)item->data), + &g_wifimgr_req_sa, topic, NULL)) { + awss_debug("sending failed."); + } + HAL_Free(item->data); + } + list_del(&item->entry); + HAL_Free(item); + item= NULL; + } + HAL_MutexUnlock(g_scan_mutex); +} + +static int awss_scan_cb(const char ssid[PLATFORM_MAX_SSID_LEN], + const uint8_t bssid[ETH_ALEN], + enum AWSS_AUTH_TYPE auth, + enum AWSS_ENC_TYPE encry, + uint8_t channel, signed char rssi, + int last_ap) +{ +#define ONE_AP_INFO_LEN_MAX (141) + static char *aplist = NULL; + static int msg_len = 0; + + if (aplist == NULL) { + aplist = os_zalloc(WIFI_APINFO_LIST_LEN); + if (aplist == NULL) + return SHUB_ERR; + + msg_len = 0; + msg_len += HAL_Snprintf(aplist + msg_len, WIFI_APINFO_LIST_LEN - msg_len - 1, "{\"awssVer\":%s, \"wifiList\":[", AWSS_VER); + } + if ((ssid != NULL) && (ssid[0] != '\0')) { + uint8_t bssid_connected[ETH_ALEN] = {0}; + char *other_apinfo = os_zalloc(64); + char *encode_ssid = os_zalloc(OS_MAX_SSID_LEN * 2 + 1); + int ssid_len = strlen(ssid); + ssid_len = ssid_len > OS_MAX_SSID_LEN - 1 ? OS_MAX_SSID_LEN - 1 : ssid_len; + + HAL_Wifi_Get_Ap_Info(NULL, NULL, bssid_connected); + + if (other_apinfo && encode_ssid) { + if (memcmp(bssid_connected, bssid, ETH_ALEN) == 0) { + HAL_Snprintf(other_apinfo, 64 - 1, "\"auth\":\"%d\",\"connected\":\"1\"", auth); + } else { + HAL_Snprintf(other_apinfo, 64 - 1, "\"auth\":\"%d\"", auth); + } + if (is_utf8(ssid, ssid_len)) { + strncpy(encode_ssid, (const char *)ssid, ssid_len); + msg_len += HAL_Snprintf(aplist + msg_len, WIFI_APINFO_LIST_LEN - msg_len - 1, + "{\"ssid\":\"%s\",\"bssid\":\"%02X:%02X:%02X:%02X:%02X:%02X\",\"rssi\":\"%d\",%s},", + encode_ssid, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], + rssi > 0 ? rssi - 256 : rssi, other_apinfo); + } else { + utils_hex_to_str((uint8_t *)ssid, ssid_len, encode_ssid, OS_MAX_SSID_LEN * 2); + msg_len += HAL_Snprintf(aplist + msg_len, WIFI_APINFO_LIST_LEN - msg_len - 1, + "{\"xssid\":\"%s\",\"bssid\":\"%02X:%02X:%02X:%02X:%02X:%02X\",\"rssi\":\"%d\",%s},", + encode_ssid, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], + rssi > 0 ? rssi - 256 : rssi, other_apinfo); + } + } + + if (other_apinfo) HAL_Free(other_apinfo); + if (encode_ssid) HAL_Free(encode_ssid); + } + awss_debug("last_ap:%u\r\n", last_ap); + + if (last_ap || WIFI_APINFO_LIST_LEN < msg_len + ONE_AP_INFO_LEN_MAX + strlen(AWSS_ACK_FMT)) { + uint32_t tlen; + char *msg_aplist = NULL; + scan_list_t *list = NULL; + if (last_ap) + AWSS_UPDATE_STATIS(AWSS_STATIS_PAP_IDX, AWSS_STATIS_TYPE_SCAN_STOP); + if (aplist[msg_len - 1] == ',') + msg_len--; /* eating the last ',' */ + msg_len += HAL_Snprintf(aplist + msg_len, WIFI_APINFO_LIST_LEN - msg_len - 1, "]}"); + + tlen = DEV_SIMPLE_ACK_LEN + msg_len; + msg_len = 0; + msg_aplist = os_zalloc(tlen + 1); + if (!msg_aplist) { + HAL_Free(aplist); + aplist = NULL; + return SHUB_ERR; + } + + HAL_Snprintf(msg_aplist, tlen, AWSS_ACK_FMT, g_req_msg_id, 200, aplist); + HAL_Free(aplist); + aplist = NULL; + + list = (scan_list_t *)os_zalloc(sizeof(scan_list_t)); + if (!list) { + awss_debug("scan list fail\n"); + HAL_Free(msg_aplist); + return SHUB_ERR; + } + list->data = msg_aplist; + HAL_MutexLock(g_scan_mutex); + list_add(&list->entry, &g_scan_list); + HAL_MutexUnlock(g_scan_mutex); + + if (last_ap) { + if (scan_tx_wifilist_timer == NULL) + scan_tx_wifilist_timer = HAL_Timer_Create("wifilist", (void (*)(void *))wifimgr_scan_tx_wifilist, NULL); + HAL_Timer_Stop(scan_tx_wifilist_timer); + HAL_Timer_Start(scan_tx_wifilist_timer, 1); + } + awss_debug("sending message to app: %s\n", msg_aplist); + } + + return 0; +} + +static void wifimgr_scan_request() +{ + wifimgr_scan_init(); + + AWSS_UPDATE_STATIS(AWSS_STATIS_PAP_IDX, AWSS_STATIS_TYPE_SCAN_START); + HAL_Wifi_Scan(&awss_scan_cb); +} + +/* + * @desc: ????getWifiList??Ϣ + * + */ +int wifimgr_process_get_wifilist_request(void *ctx, void *resource, void *remote, void *request) +{ + char buf[DEV_SIMPLE_ACK_LEN] = {0}; + char *msg = NULL, *id = NULL; + int len = 0, id_len = 0; + char topic[TOPIC_LEN_MAX] = {0}; + + msg = awss_cmp_get_coap_payload(request, &len); + if (msg == NULL || len == 0) + return -1; + + if (scan_req_timer == NULL) + scan_req_timer = HAL_Timer_Create("scan_req", (void (*)(void *))wifimgr_scan_request, NULL); + HAL_Timer_Stop(scan_req_timer); + + id = json_get_value_by_name(msg, len, "id", &id_len, 0); + memset(g_req_msg_id, 0, sizeof(g_req_msg_id)); + if (id && id_len < sizeof(g_req_msg_id) - 1) + memcpy(g_req_msg_id, id, id_len); + + HAL_Snprintf(buf, DEV_SIMPLE_ACK_LEN - 1, AWSS_ACK_FMT, g_req_msg_id, 200, "\"success\""); + + awss_debug("sending message to app: %s\n", buf); + awss_build_topic((const char *)TOPIC_AWSS_WIFILIST, topic, TOPIC_LEN_MAX); + memcpy(&g_wifimgr_req_sa, remote, sizeof(g_wifimgr_req_sa)); + if (0 != awss_cmp_coap_send_resp(buf, strlen(buf), &g_wifimgr_req_sa, topic, request, NULL, NULL, 0)) + awss_debug("sending failed."); + + HAL_Timer_Start(scan_req_timer, 1); + + return SHUB_OK; +} + +int wifimgr_process_mcast_get_device_info(void *ctx, void *resource, void *remote, void *request) +{ + return process_get_device_info(ctx, resource, remote, request, 1, AWSS_NOTIFY_DEV_RAND_SIGN); +} + +int wifimgr_process_ucast_get_device_info(void *ctx, void *resource, void *remote, void *request) +{ + return process_get_device_info(ctx, resource, remote, request, 0, AWSS_NOTIFY_DEV_RAND_SIGN); +} +#define WLAN_CONNECTION_TIMEOUT (30 * 1000) /* 30 seconds */ +int switch_ap_done = 0; + +void zconfig_force_destroy(void); +int wifimgr_process_switch_ap_request(void *ctx, void *resource, void *remote, void *request) +{ + char ssid[PLATFORM_MAX_SSID_LEN * 2 + 1] = {0}, passwd[PLATFORM_MAX_PASSWD_LEN + 1] = {0}; + int str_len = 0, success = 1, i = 0, len = 0, enc_lvl = SEC_LVL_OPEN; + char req_msg_id[MSG_REQ_ID_LEN] = {0}; + char *str = NULL, *buf = NULL; + char bssid[ETH_ALEN] = {0}; + char msg[128] = {0}; + char ssid_found = 0; + char topic[TOPIC_LEN_MAX] = {0}; + + static char switch_ap_parsed = 0; + if (switch_ap_parsed != 0) + return SHUB_ERR; + + switch_ap_parsed = 1; + + buf = awss_cmp_get_coap_payload(request, &len); + str = json_get_value_by_name(buf, len, "id", &str_len, 0); + memcpy(req_msg_id, str, str_len > MSG_REQ_ID_LEN - 1 ? MSG_REQ_ID_LEN - 1 : str_len); + awss_debug("switch ap, len:%u, %s\r\n", len, buf); + buf = json_get_value_by_name(buf, len, "params", &len, 0); + + do { + HAL_Snprintf(msg, sizeof(msg) - 1, AWSS_ACK_FMT, req_msg_id, 200, "\"success\""); + + str_len = 0; + str = json_get_value_by_name(buf, len, "ssid", &str_len, 0); + awss_debug("ssid, len:%u, %s\r\n", str_len, str != NULL ? str : "NULL"); + if (str && (str_len < PLATFORM_MAX_SSID_LEN)) { + memcpy(ssid, str, str_len); + ssid_found = 1; + } + + if (!ssid_found) { + str_len = 0; + str = json_get_value_by_name(buf, len, "xssid", &str_len, 0); + if (str && (str_len < PLATFORM_MAX_SSID_LEN * 2 - 1)) { + uint8_t decoded[OS_MAX_SSID_LEN] = {0}; + int len = str_len / 2; + memcpy(ssid, str, str_len); + utils_str_to_hex(ssid, str_len, decoded, OS_MAX_SSID_LEN); + memcpy(ssid, (const char *)decoded, len); + ssid[len] = '\0'; + } else { + HAL_Snprintf(msg, sizeof(msg) - 1, AWSS_ACK_FMT, req_msg_id, -1, "\"ssid error\""); + success = 0; + break; + } + } + + str_len = 0; + str = json_get_value_by_name(buf, len, "bssid", &str_len, 0); + if (str) os_wifi_str2mac(str, bssid); + + str_len = 0; + str = json_get_value_by_name(buf, len, "cipherType", &str_len, 0); + if (!str) { + success = 0; + HAL_Snprintf(msg, sizeof(msg) - 1, AWSS_ACK_FMT, req_msg_id, -4, "\"no security level error\""); + break; + } + + enc_lvl = atoi(str); + if (enc_lvl != awss_get_encrypt_type()) { + success = 0; + HAL_Snprintf(msg, sizeof(msg) - 1, AWSS_ACK_FMT, req_msg_id, -4, "\"security level error\""); + break; + } + + str_len = 0; + str = json_get_value_by_name(buf, len, "passwd", &str_len, 0); + /* TODO: empty passwd is allow? json parse "passwd":"" result is NULL? */ + switch (enc_lvl) { + case SEC_LVL_AES256: + HAL_Snprintf(msg, sizeof(msg) - 1, AWSS_ACK_FMT, req_msg_id, -4, "\"aes256 not support\""); + success = 0; + break; + default: + break; + } + + if (success == 0) + break; + + if (0 == enc_lvl) { + if (str_len < PLATFORM_MAX_PASSWD_LEN) { + memcpy(passwd, str, str_len); + } else { + HAL_Snprintf(msg, sizeof(msg) - 1, AWSS_ACK_FMT, req_msg_id, -2, "\"passwd len error\""); + success = 0; + } + } else { + if (str_len < (PLATFORM_MAX_PASSWD_LEN * 2) - 1) { + char encoded[PLATFORM_MAX_PASSWD_LEN * 2 + 1] = {0}; + memcpy(encoded, str, str_len); + aes_decrypt_string(encoded, passwd, str_len, + 0, awss_get_encrypt_type(), 1, (const char *)aes_random); + } else { + HAL_Snprintf(msg, sizeof(msg) - 1, AWSS_ACK_FMT, req_msg_id, -3, "\"passwd len error\""); + AWSS_UPDATE_STATIS(AWSS_STATIS_PAP_IDX, AWSS_STATIS_TYPE_PASSWD_ERR); + success = 0; + } + } + + if (success && is_utf8(passwd, strlen(passwd)) == 0) { + HAL_Snprintf(msg, sizeof(msg) - 1, AWSS_ACK_FMT, req_msg_id, + enc_lvl == SEC_LVL_OPEN ? -2 : -3 , "\"passwd content error\""); + AWSS_UPDATE_STATIS(AWSS_STATIS_PAP_IDX, AWSS_STATIS_TYPE_PASSWD_ERR); + success = 0; + } + } while (0); + + awss_devinfo_notify_stop(); + awss_dev_bind_notify_stop(); + + awss_debug("Sending message to app: %s", msg); + awss_debug("switch to ap: '%s'", ssid); + awss_build_topic((const char *)TOPIC_AWSS_SWITCHAP, topic, TOPIC_LEN_MAX); + for (i = 0; i < 5; i ++) { + if (0 != awss_cmp_coap_send_resp(msg, strlen(msg), remote, topic, request, NULL, NULL, 0)) { + awss_debug("sending failed."); + } else { + awss_debug("sending succeeded."); + } + } + + HAL_SleepMs(1000); + + if (!success) + goto SWITCH_AP_END; +#ifdef AWSS_SUPPORT_APLIST + do { + struct ap_info * aplist = NULL; + aplist = zconfig_get_apinfo_by_ssid((uint8_t *)ssid); + awss_debug("connect '%s'", ssid); + if (aplist) { + memcpy(bssid, aplist->mac, ETH_ALEN); + awss_debug("bssid: %02x:%02x:%02x:%02x:%02x:%02x", \ + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); + } + } while (0); +#endif + AWSS_UPDATE_STATIS(AWSS_STATIS_CONN_ROUTER_IDX, AWSS_STATIS_TYPE_TIME_START); + if (0 != HAL_Awss_Connect_Ap(WLAN_CONNECTION_TIMEOUT, + ssid, passwd, + AWSS_AUTH_TYPE_INVALID, + AWSS_ENC_TYPE_INVALID, + (uint8_t *)bssid, 0)) { + } else { + AWSS_UPDATE_STATIS(AWSS_STATIS_CONN_ROUTER_IDX, AWSS_STATIS_TYPE_TIME_SUC); + AWSS_UPDATE_STATIS(AWSS_STATIS_PAP_IDX, AWSS_STATIS_TYPE_TIME_SUC); + switch_ap_done = 1; + awss_close_aha_monitor(); + HAL_MutexDestroy(g_scan_mutex); + g_scan_mutex = NULL; + wifi_scan_runninng = 0; + awss_stop_timer(scan_req_timer); + scan_req_timer = NULL; + awss_stop_timer(scan_tx_wifilist_timer); + scan_tx_wifilist_timer = NULL; + + zconfig_force_destroy(); + + produce_random(aes_random, sizeof(aes_random)); + } + awss_debug("connect '%s' %s\r\n", ssid, switch_ap_done == 1 ? "success" : "fail"); + +SWITCH_AP_END: + switch_ap_parsed = 0; + return SHUB_OK; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/awss_wifimgr.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/awss_wifimgr.h new file mode 100644 index 00000000..19d41967 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/phone_ap/awss_wifimgr.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_WIFIMGR_H__ +#define __AWSS_WIFIMGR_H__ + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + +enum { + SHUB_ERR, + SHUB_OK +}; + +int wifimgr_process_get_wifilist_request(void *ctx, void *resource, void *remote, void *request); +int wifimgr_process_mcast_get_device_info(void *ctx, void *resource, void *remote, void *request); +int wifimgr_process_ucast_get_device_info(void *ctx, void *resource, void *remote, void *request); +int wifimgr_process_switch_ap_request(void *ctx, void *resource, void *remote, void *request); + +#endif + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/router_ap/awss_adha.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/router_ap/awss_adha.c new file mode 100644 index 00000000..ae637f46 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/router_ap/awss_adha.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +struct adha_info *adha_aplist = NULL; + +const char *zc_adha_ssid = "adha"; +const char *zc_adha_passwd = "08d9f22c60157fd01f57645d791a0b610fe0a558c104d6a1f9d9c0a9913c"; + +#ifdef AWSS_SUPPORT_ADHA + +#define ADHA_WORK_CYCLE (5 * 1000) +#define ADHA_PROBE_PKT_LEN (50) +#define ADHA_SA_OFFSET (10) + +static const uint8_t adha_probe_req_frame[ADHA_PROBE_PKT_LEN] = { + 0x40, 0x00, /* mgnt type, frame control */ + 0x00, 0x00, /* duration */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* DA */ + 0x28, 0xC2, 0xDD, 0x61, 0x68, 0x83, /* SA, to be replaced with wifi mac */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* BSSID */ + 0xC0, 0x79, /* seq */ + 0x00, 0x04, 0x61, 0x64, 0x68, 0x61, /* ssid, adha */ + 0x01, 0x08, 0x82, 0x84, 0x8B, 0x96, 0x8C, 0x92, 0x98, 0xA4, /*supported rates */ + 0x32, 0x04, 0xB0, 0x48, 0x60, 0x6C, /* extended supported rates */ + 0x3F, 0x84, 0x10, 0x9E /* FCS */ +}; + +static void *adha_timer = NULL; +static volatile char adha_switch = 0; + +static void adha_monitor(void); + +static void adha_monitor(void) +{ + adha_switch = 1; +} + +int awss_is_ready_switch_next_adha(void) +{ + return adha_switch > 0; +} + +int awss_open_adha_monitor(void) +{ + adha_switch = 0; + if (adha_timer == NULL) + adha_timer = (void *)HAL_Timer_Create("adha", (void (*)(void *))adha_monitor, NULL); + if (adha_timer == NULL) + return -1; + + HAL_Timer_Stop(adha_timer); + HAL_Timer_Start(adha_timer, ADHA_WORK_CYCLE); + return 0; +} + +int awss_close_adha_monitor(void) +{ + awss_stop_timer(adha_timer); + adha_timer = NULL; + adha_switch = 0; + return 0; +} + +int awss_recv_callback_adha_ssid(struct parser_res *res) +{ + uint8_t tods = res->tods; + uint8_t channel = res->channel; + + AWSS_UPDATE_STATIS(AWSS_STATIS_ROUTE_IDX, AWSS_STATIS_TYPE_TIME_START); + awss_debug("found adha ssid: %s\r\n", zc_adha_ssid); + + strncpy((char *)zc_ssid, zc_adha_ssid, ZC_MAX_SSID_LEN - 1); + strncpy((char *)zc_passwd, zc_adha_passwd, ZC_MAX_PASSWD_LEN - 1); + + zconfig_set_state(STATE_RCV_DONE, tods, channel); + return PKG_END; +} + +int aws_send_adha_probe_req(void) +{ + uint8_t probe[ADHA_PROBE_PKT_LEN]; + memcpy(probe, adha_probe_req_frame, sizeof(probe)); + os_wifi_get_mac(&probe[ADHA_SA_OFFSET]); + HAL_Wifi_Send_80211_Raw_Frame(FRAME_PROBE_REQ, probe, sizeof(probe)); + return 0; +} + +int awss_ieee80211_adha_process(uint8_t *mgmt_header, int len, int link_type, struct parser_res *res, signed char rssi) +{ + uint8_t ssid[ZC_MAX_SSID_LEN] = {0}, bssid[ETH_ALEN] = {0}; + uint8_t auth, pairwise_cipher, group_cipher; + struct ieee80211_hdr *hdr; + int fc, ret, channel; + + /* + * when device try to connect current router (include adha and aha) + * skip the new aha and process the new aha in the next scope. + */ + if (mgmt_header == NULL || zconfig_finished) + return ALINK_INVALID; + + /* + * if user press configure button, drop all adha + */ + if (awss_get_config_press()) + return ALINK_INVALID; + + hdr = (struct ieee80211_hdr *)mgmt_header; + fc = hdr->frame_control; + + if (!ieee80211_is_beacon(fc) && !ieee80211_is_probe_resp(fc)) + return ALINK_INVALID; + ret = ieee80211_get_bssid(mgmt_header, bssid); + if (ret < 0) + return ALINK_INVALID; + + ret = ieee80211_get_ssid(mgmt_header, len, ssid); + if (ret < 0) + return ALINK_INVALID; + /* + * skip ap which is not adha + */ + if (strcmp((const char *)ssid, zc_adha_ssid)) + return ALINK_INVALID; + + channel = cfg80211_get_bss_channel(mgmt_header, len); + rssi = rssi > 0 ? rssi - 256 : rssi; + + cfg80211_get_cipher_info(mgmt_header, len, &auth, + &pairwise_cipher, &group_cipher); +#ifdef AWSS_SUPPORT_APLIST + awss_save_apinfo(ssid, bssid, channel, auth, + pairwise_cipher, group_cipher, rssi); +#endif + /* + * If user press the configure button, + * skip all the adha. + */ + if (adha_aplist->cnt > adha_aplist->try_idx) { + uint8_t ap_idx = adha_aplist->aplist[adha_aplist->try_idx ++]; +#ifdef AWSS_SUPPORT_APLIST + memcpy(zc_bssid, zconfig_aplist[ap_idx].mac, ETH_ALEN); +#endif + return ALINK_ADHA_SSID; + } + return ALINK_INVALID; +} + +#endif + +int awss_init_adha_aplist(void) +{ + if (adha_aplist) + return 0; + adha_aplist = (struct adha_info *)os_zalloc(sizeof(struct adha_info)); + if (adha_aplist == NULL) + return -1; + return 0; +} + +int awss_deinit_adha_aplist(void) +{ + if (adha_aplist == NULL) + return 0; + + HAL_Free(adha_aplist); + adha_aplist = NULL; + return 0; +} +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/router_ap/awss_adha.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/router_ap/awss_adha.h new file mode 100644 index 00000000..68730518 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/router_ap/awss_adha.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_ADHA_H__ +#define __AWSS_ADHA_H__ + +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + +#include "zconfig_lib.h" +#include "zconfig_protocol.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +struct adha_info { + uint8_t try_idx; + uint8_t cnt; + uint8_t aplist[MAX_APLIST_NUM]; +}; + +int awss_init_adha_aplist(void); +int awss_deinit_adha_aplist(void); +extern struct adha_info *adha_aplist; +extern const char *zc_adha_passwd; +extern const char *zc_adha_ssid; + +#ifdef AWSS_SUPPORT_ADHA +int awss_open_adha_monitor(void); +int awss_close_adha_monitor(void); +int aws_send_adha_probe_req(void); + +int awss_is_ready_switch_next_adha(void); +int awss_recv_callback_adha_ssid(struct parser_res *res); +int awss_ieee80211_adha_process(uint8_t *mgmt_header, int len, int link_type, + struct parser_res *res, signed char rssi); +#endif + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif +#endif /* end AWSS_SUPPORT_ADHA || AWSS_SUPPORT_AHA */ +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/smartconfig/awss_smartconfig.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/smartconfig/awss_smartconfig.c new file mode 100644 index 00000000..90f3b87d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/smartconfig/awss_smartconfig.c @@ -0,0 +1,1206 @@ +#include "wifi_provision_internal.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +/* following is broadcast protocol related code */ +uint8_t is_start_frame(uint16_t len) +{ + return (len == START_FRAME); +} + +uint8_t is_group_frame(uint16_t len) +{ + /* is group frame? */ + return (len > GROUP_FRAME && len <= GROUP_FRAME_END); +} + +uint8_t is_data_frame(uint16_t len) +{ + uint8_t group_frame, index; + /* is start frame */ + if (is_start_frame(len)) { + return 0; + } + + /* is group frame? */ + group_frame = is_group_frame(len); + if (group_frame) { + return 0; + } + + index = (len >> PAYLOAD_BITS_CNT) & 0xF; + return (index >= ZC_GRP_PKT_IDX_START && index <= ZC_GRP_PKT_IDX_END); +} + +uint8_t get_group_index(uint16_t len) +{ + if (is_start_frame(len)) { + return 0; + } + + return (len - GROUP_FRAME) * GROUP_NUMBER; +} + +uint8_t get_data_index(uint16_t len) +{ + uint8_t index = (len >> PAYLOAD_BITS_CNT) & 0xF; /* from 2 to 9 */ + return index - (ZC_GRP_PKT_IDX_START - 1); /* adjust, from 1 to 8 */ +} + +#define sn_minus(a,b) (((a) - (b)) & 0xfff) + +/* a, b must be serial seq number */ +static int sn_compare(uint16_t a, uint16_t b) +{ + /* + case1: sn = 3, sn_prev = 5; a < b + case2: sn = 0, sn_prev = 0xfff; a > b + case3: sn = 4, sn_prev = 3; a > b + */ + uint16_t res = sn_minus(a, b); + + return res < 1000 ? res : -1; +} + +/* + * zconfig_get_data_len() + * here we guess the total_len of protocl message, + * base on the score of tods and fromds side. + */ +int zconfig_get_data_len(void) +{ + uint8_t len; /* total len, include len(1B) & crc(2B) */ + uint8_t score; + + /* tods > fromds */ + if (zconfig_data->pkg[1][1].score > zconfig_data->pkg[0][1].score) { + len = zconfig_data->pkg[1][1].len & PAYLOAD_BITS_MASK; + score = zconfig_data->pkg[1][1].score; + } else { + len = zconfig_data->pkg[0][1].len & PAYLOAD_BITS_MASK; + score = zconfig_data->pkg[0][1].score; + } + + if (len && score > score_mid) { + /* awss_debug("zconfig_get_data_len = %d\r\n", len); */ + goto out; + } + + if (zconfig_data->data[1].max_pos > zconfig_data->data[0].max_pos) { + len = zconfig_data->data[1].max_pos; + } else { + len = zconfig_data->data[0].max_pos; + } +out: + if (len < GROUP_NUMBER) { + return GROUP_NUMBER; + } else { + return len >= MAX_PKG_NUMS ? (MAX_PKG_NUMS - GROUP_NUMBER - 1) : len; + } +} + +/* check recv completed or not */ +int zconfig_recv_completed(uint8_t tods) +{ + int i; + uint8_t len, flag, ssid_len, passwd_len; + /* + byte: 0 1 2 3 4 5 6 + name: total_len flag ssid_len passwd_len ssid ... + index: 0x100 0x180 0x200 0x280 0x300 0x380 + */ + len = pkg_len(1) & PAYLOAD_BITS_MASK;/* total len, include len(1B) & crc(2B) */ + flag = pkg_len(2) & PAYLOAD_BITS_MASK; + if (flag & SSID_EXIST_MASK) {/* ssid exist */ + ssid_len = pkg_len(3) & PAYLOAD_BITS_MASK; + passwd_len = pkg_len(4) & PAYLOAD_BITS_MASK; + } else { + ssid_len = 0; + passwd_len = pkg_len(3) & PAYLOAD_BITS_MASK; + } + + if (!len || pkg_score(1) <= score_min) { + /* awss_trace("len=%d, pkg_score(1)=%d\r\n", len, pkg_score(1));*/ + return 0; + } + +#ifndef DISABLE_SSID_AUTO_COMPLETE +#define SSID_AUTO_COMPLETE_SCORE (score_max + 1) + /* ssid atuo-completion */ + if (zc_ssid[0] != '\0' && (flag & SSID_EXIST_MASK) + && pkg_score(2) < SSID_AUTO_COMPLETE_SCORE + && pkg_score(3) > score_mid + && !zc_ssid_auto_complete_disable) { + + /* over-written ssid_len here */ + ssid_len = strlen((char const *)zc_ssid); + if (ssid_len > ZC_MAX_SSID_LEN - 1) { + ssid_len = ZC_MAX_SSID_LEN - 1; + } + + if (!(flag & SSID_ENCODE_MASK)) {/* ASCLL ssid */ + if ((ssid_len | 0x200) != pkg_len(3)) { + awss_warn("ssid len not match! ssid:%s != %d\r\n", + zc_ssid, (pkg_len(3) & ~0x200)); + zc_ssid_auto_complete_disable = 1; + goto skip_ssid_auto_complete; + } + + awss_trace("ssid auto-complete: %s\r\n", zc_ssid); + pkg_score(2) = SSID_AUTO_COMPLETE_SCORE; + + pkg_len(3) = ssid_len | 0x200; /* 0x200 is the index 3 */ + pkg_score(3) = SSID_AUTO_COMPLETE_SCORE; + + for (i = 5; i < ssid_len + 5; i ++) { + pkg_len(i) = (zc_ssid[i - 5] - 32) | (0x100 + 0x80 * ((i - 1) % GROUP_NUMBER)); + pkg_score(i) = SSID_AUTO_COMPLETE_SCORE; + } + } else if ((flag & SSID_ENCODE_MASK)) { /* include chinese ssid */ + uint8_t *buf, buf_len = 0; + + uint8_t ssid_encode_len = (ssid_len * 8 + 5) / 6; + + /* + * for GBK encoded chinese, ssid auto-completion lead to crc error. + * because Android APP may send utf8 encoded ssid. + */ + if ((ssid_encode_len | 0x200) != pkg_len(3)) { + zc_ssid_is_gbk = 1; + zc_ssid_auto_complete_disable = 1; + goto skip_ssid_auto_complete; + } else { + zc_ssid_is_gbk = 0; + } + + buf = os_zalloc(ssid_encode_len + 1); + if (buf == NULL) { + awss_crit("malloc failed!\r\n"); + return 0; + } + + awss_trace("chinese ssid auto-complete: %s\r\n", zc_ssid); + encode_chinese(zc_ssid, ssid_len, buf, &buf_len, 6); + + pkg_score(2) = SSID_AUTO_COMPLETE_SCORE; + + pkg_len(3) = buf_len | 0x200; /* 0x200 is the index 3 */ + pkg_score(3) = SSID_AUTO_COMPLETE_SCORE; + + for (i = 5; i < buf_len + 5; i ++) { + pkg_len(i) = buf[i - 5] | (0x100 + 0x80 * ((i - 1) % GROUP_NUMBER)); + pkg_score(i) = SSID_AUTO_COMPLETE_SCORE; + } + HAL_Free(buf); + } + } +#endif + +skip_ssid_auto_complete: + /* awss_debug("expect len = %d, max len = %d\r\n", len, zc_max_pos); */ + if (zc_max_pos < len) { + return 0; /* receive all the packets */ + } + + for (i = 1; i <= len; i ++) { /* check score for all the packets */ + if (pkg_score(i) <= score_min) { + return 0; + } + } + + /* 4 for total_len, flag, ssid_len, passwd_len, 2 for crc */ + if (flag & SSID_EXIST_MASK) { /* ssid exist */ + if (len != ssid_len + passwd_len + 4 + 2) { + return 0; + } + } else if (len != passwd_len + 3 + 2) { + return 0; + } + + return 1; +} + +int zconfig_get_ssid_passwd(uint8_t tods) +{ + int i, ssid_len, package_num, passwd_len, ret; + uint8_t *buf, *pbuf, *tmp, flag, passwd_encrypt, passwd_cipher_len = 0; + uint16_t crc, cal_crc; + uint8_t data, score; + uint8_t tods_tmp; + + if (!zconfig_recv_completed(tods)) { + return -1; + } + + buf = os_zalloc(256); + if (NULL == buf) { + awss_crit("malloc failed!\r\n"); + return -1; + } + tmp = os_zalloc(128); + if (NULL == tmp) { + HAL_Free(buf); + awss_crit("malloc failed!\r\n"); + return -1; + } + + /* package num */ + package_num = pkg_len(1) & PAYLOAD_BITS_MASK;/* total len, include len(1B) & crc(2B) */ + + awss_trace("\r\n"); + for (i = 1; i <= package_num; i ++) { + data = pkg_len(i); + score = pkg_score(i); + buf[i - 1] = data & PAYLOAD_BITS_MASK; + tmp[i - 1] = score; + } + + dump_hex(&tmp[0], package_num, GROUP_NUMBER); + awss_trace("\r\n"); + dump_hex(&buf[0], package_num, GROUP_NUMBER); + awss_trace("\r\n"); + + crc = os_get_unaligned_be16(&buf[package_num - 2]); + + pbuf = &buf[0]; /* len @ [0] */ + + flag = pbuf[1]; /* flag @ [1] */ + pbuf += 2; /* 2B for total_len, flag */ + + passwd_encrypt = (flag & PASSWD_ENCRYPT_MASK) >> PASSWD_ENCRYPT_BIT_OFFSET; + + if (passwd_encrypt == PASSWD_ENCRYPT_CIPHER || passwd_encrypt == PASSWD_ENCRYPT_OPEN) { + awss_trace("!aes128-cfb is not support: flag 0x%x\r\n", flag); + ret = -1; + goto exit; + } else { + cal_crc = zconfig_checksum_v3(buf, package_num - 2); + } + + if (crc != cal_crc) { + awss_trace("crc error: recv 0x%x != 0x%x\r\n", crc, cal_crc); + /* memset(zconfig_data, 0, sizeof(*zconfig_data)); */ + tods_tmp = tods; + for (tods = 0; tods < 2; tods ++) { + for (i = 1; i <= package_num; i ++) { + score = pkg_score(i); + if (score > 0x60) { + pkg_score(i) = 0x60; + } else { + pkg_score(i) = score >> 1; + } + } + } + tods = tods_tmp; + ret = -1; + awss_event_post(IOTX_AWSS_CS_ERR); + AWSS_UPDATE_STATIS(AWSS_STATIS_SM_IDX, AWSS_STATIS_TYPE_CRC_ERR); + goto exit; + } + + if (flag & SSID_EXIST_MASK) {/* ssid exist */ + ssid_len = pbuf[0]; + passwd_len = pbuf[1]; + pbuf += 2; /* 2B for ssid_len, passwd_len */ + + if (!(flag & SSID_ENCODE_MASK)) { /* ascii */ + /* CAN'T use snprintf here, because of SPACE char */ + memcpy((char *)tmp, pbuf, ssid_len); + tmp[ssid_len] = '\0'; + for (i = 0; i < ssid_len; i ++) { + tmp[i] += 32; + } + } else {/* chinese format */ + decode_chinese(pbuf, ssid_len, tmp, NULL, 6); + /* make sure 'tmp' is null-terminated */ + } + pbuf += ssid_len; /* ssid */ + + if (zc_ssid[0] == '\0' || zc_ssid_auto_complete_disable) { + strncpy((char *)zc_ssid, (const char *)tmp, ZC_MAX_SSID_LEN - 1); + awss_trace("SSID0: [%s]\r\n", zc_ssid); + } else { + if (!strncmp((const char *)tmp, (char *)zc_ssid, ZC_MAX_SSID_LEN - 1)) { + awss_trace("SSID1: [%s]\r\n", zc_ssid); + } else { + awss_trace("gbk%s SSID:[%s]\r\n", zc_ssid_is_gbk ? "" : "?", zc_ssid); + } + } +#ifdef AWSS_SUPPORT_APLIST + do { /* amend SSID automatically */ + struct ap_info *ap = NULL; + ap = zconfig_get_apinfo(zc_bssid); + if (ap == NULL || ap->ssid[0] == '\0') { + break; + } +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + if (strncmp(ap->ssid, zc_adha_ssid, ZC_MAX_SSID_LEN) == 0 || + strncmp(ap->ssid, zc_default_ssid, ZC_MAX_SSID_LEN) == 0) { + memset(zc_bssid, 0, ETH_ALEN); + break; + } +#endif + strncpy((char *)zc_ssid, (const char *)ap->ssid, ZC_MAX_SSID_LEN - 1); + } while (0); +#endif + } else { + passwd_len = pbuf[0]; + pbuf += 1; /* 1B for passwd_len */ + } + + /* CAN'T use snprintf here, because of SPACE char */ + if (passwd_encrypt > PASSWD_ENCRYPT_CIPHER) { + /* decypt passwd using aes128-cfb */ + decode_chinese(pbuf, passwd_len, tmp, &passwd_cipher_len, 6); + passwd_len = passwd_cipher_len; + memset(zc_passwd, 0, ZC_MAX_PASSWD_LEN); + aes_decrypt_string((char *)tmp, (char *)zc_passwd, passwd_len, + 1, awss_get_encrypt_type(), 0, NULL); + if (is_utf8((const char *)zc_passwd, passwd_len) == 0) { + awss_trace("passwd err\r\n"); + memset(zconfig_data, 0, sizeof(*zconfig_data)); + awss_event_post(IOTX_AWSS_PASSWD_ERR); + AWSS_UPDATE_STATIS(AWSS_STATIS_SM_IDX, AWSS_STATIS_TYPE_PASSWD_ERR); + ret = -1; + goto exit; + } + } else { + memcpy((void *)tmp, (const void *)pbuf, passwd_len); + tmp[passwd_len] = '\0'; + for (i = 0; i < passwd_len; i ++) { + tmp[i] += 32; + } + strncpy((char *)zc_passwd, (const char *)tmp, ZC_MAX_PASSWD_LEN - 1); + + awss_trace("encrypt:%d not support\r\n", passwd_encrypt); + memset(zconfig_data, 0, sizeof(*zconfig_data)); + ret = -1; + goto exit; + } + + + /* awss_debug("PASSWD: [%s]\r\n", zc_passwd); */ + pbuf += passwd_len; /* passwd */ + ret = 0; +exit: + HAL_Free(buf); + HAL_Free(tmp); + + return ret; +} + +int package_cmp(uint8_t *package, uint8_t *src, uint8_t *dst, uint8_t tods, uint16_t len) +{ + struct package *pkg = (struct package *)package; + + if (pkg->len != len) { + return 1; + } + return 0; +} + +int package_save(uint8_t *package, uint8_t *src, uint8_t *dst, uint8_t tods, uint16_t len) +{ + struct package *pkg = (struct package *)package; + + pkg->len = len; + return 0; +} + +/* len -= (rth->it_len + hdrlen); see ieee80211.c */ +const uint8_t zconfig_fixed_offset[ZC_ENC_TYPE_MAX + 1][2] = { + { /* open, none, ip(20) + udp(8) + 8(LLC) */ + 36, 36 + }, + { /* wep, + iv(4) + data + ICV(4) */ + 44, 44 /* feixun, wep64(10byte), wep128(26byte) */ + }, + { /* tkip, + iv/keyID(4) + Ext IV(4) + data + MIC(8) + ICV(4) */ + 56, 56 /* tkip(10byte, 20byte), wpa2+tkip(20byte) */ + }, + { /* aes, + ccmp header(8) + data + MIC(8) + ICV(4) */ + 52, 52 + }, + { /* tkip-aes */ + 56, 52 /* fromDs==tkip,toDs==aes */ + } +}; + +const uint16_t zconfig_hint_frame[] = {/* GROUP_FRAME is not used, gourp 0 - 7 */ + START_FRAME, GROUP_FRAME + 1, GROUP_FRAME + 2, GROUP_FRAME + 3, GROUP_FRAME + 4, + GROUP_FRAME + 5, GROUP_FRAME + 6, GROUP_FRAME + 7, + 0 /* NULL terminated */ +}; + +/* + * is_hint_frame() + * + * start frame or group frame can be used as a hint frame + * + * @Return: + * 1/is start or group frame, otherwise return 0. + */ +int is_hint_frame(uint8_t encry, int len, uint8_t *bssid, uint8_t *src, + uint8_t channel, uint8_t tods, uint16_t sn) +{ + int i; + + if (encry > ZC_ENC_TYPE_MAX) { + return 0; + } + + len -= zconfig_fixed_offset[encry][0]; /* dont't care about tkip-aes */ + + for (i = 0; zconfig_hint_frame[i]; i++) { + if (zconfig_hint_frame[i] == len) { + goto found_match; + } + } + + return 0; + +found_match: + /* tods/fromds already locked? */ + if (!memcmp(zc_bssid, zero_mac, ETH_ALEN)) { + /* zero mac means not locked */ + memcpy(zc_bssid, bssid, ETH_ALEN); + memcpy(zc_src_mac, src, ETH_ALEN); + } else { + /* + * 1) src not equal, bssid equal, interference + * 2) src not equal, bssid not equal, interference + * 3) src equal, bssid equal, good, go on + * 4) src equal, bssid not equal + * if tods is true, replace old ssid in case of WDS + * if fromds is true, APP change the AP?? or WDS?? + * in this situation, zc_bssid is set by tods, + * in WDS case, zc_bssid should be unchanged + */ + + if (memcmp(zc_src_mac, src, ETH_ALEN)) {/* case 1,2 */ + /* someone must be working in aws at the same time */ + awss_warn("%c interference src:"MAC_FORMAT", bssid:"MAC_FORMAT"\r\n", + flag_tods(tods), MAC_VALUE(src), MAC_VALUE(bssid)); + return 0; + } else { + if (memcmp(zc_bssid, bssid, ETH_ALEN)) {/* case 4 */ + if (tods) { + memcpy(zc_bssid, bssid, ETH_ALEN); + memcpy(zc_src_mac, src, ETH_ALEN); + /* TODO: clear previous buffer, channel lock state? */ + if (zconfig_data->data[0].state_machine == STATE_CHN_LOCKED_BY_BR) { + zconfig_data->data[0].state_machine = STATE_CHN_SCANNING; + } + awss_warn("%c WDS! bssid:"MAC_FORMAT" -> bssid:"MAC_FORMAT"\r\n", + flag_tods(tods), MAC_VALUE(zc_bssid), + MAC_VALUE(bssid)); + } else { + awss_trace("%c WDS? src:"MAC_FORMAT" -> bssid:"MAC_FORMAT"\r\n", + flag_tods(tods), MAC_VALUE(src), + MAC_VALUE(bssid)); + return 0; + } + } /* else case */ + } + } + + zc_frame_offset = zconfig_fixed_offset[encry][0];/* delta, len(80211) - len(8023) */ + zc_group_pos = i * GROUP_NUMBER; + zc_cur_pos = zc_group_pos; + zc_group_sn = sn; + zc_prev_sn = sn; + zc_score_uplimit = score_max; + + memset(zc_ssid, 0, ZC_MAX_SSID_LEN); +#ifdef AWSS_SUPPORT_APLIST + /* fix channel with apinfo if exist, otherwise return anyway. */ + do { + struct ap_info *ap_info = zconfig_get_apinfo(bssid); + extern void aws_set_dst_chan(int channel); + if (ap_info && ap_info->encry[tods] > ZC_ENC_TYPE_MAX) { + awss_warn("invalid apinfo ssid:%s\r\n", ap_info->ssid); + } + + if (ap_info && ap_info->encry[tods] == encry && ap_info->channel) { + if (channel != ap_info->channel) { + awss_info("fix channel from %d to %d\r\n", channel, ap_info->channel); + zc_channel = ap_info->channel; /* fix by ap_info channel */ + aws_set_dst_chan(zc_channel); + } + } else { + /* warning: channel may eq 0! */ + }; + + if (ap_info) { /* save ssid */ + strncpy((char *)zc_ssid, (const char *)ap_info->ssid, ZC_MAX_SSID_LEN - 1); + } + } while (0); +#endif + + return 1; +} + +/* + * get_data_score() + * + * calc package score + * + * @Return: + * score between [0, 100] + */ +uint8_t get_data_score(uint16_t group_sn, uint16_t sn_now, uint16_t sn_last, + uint8_t index_now, uint8_t index_last, uint8_t tods) +{ + /* + example: 1 + 8+3 250 0 d0e cc:fa:00:c8:cf:d2 > ff:ff:ff:ff:ff:ff + 8+4 2bf 0 d15 cc:fa:00:c8:cf:d2 > ff:ff:ff:ff:ff:ff //两个包index_delta=1, sn_delta=7 + + example: 2 + 8+0, 3e1, 9a5 + 8+1, 13f, 9a7 + group_sn=9a7, sn=9ab-9a7, pos=e-9, len=3ce //here, index_delta=5, sn_delta=4 + group_sn=9a7, sn=9ac-9ab, pos=f-9, len=454 + group_sn=9a7, sn=9ad-9ac, pos=10-9, len=4d2 + example: 3 + 8+3, 225, a32 + 8+6, 3c7, a39 //此处应该是16+6, index_delta=3, sn_delta=7 + example: 4 + 0+0, 4e0, da5 + 0+7, 441, dab //此处应该是8+7, index_delta=7, sn_delta=6 + 0+0, 4e0, d89 + 0+8, 4c2, d8f //此处应该是8+8, index_delta=8, sn_delta=6 + + //example: 4 + 0+0 [100] 294 0 4e0 + 0+1 [60] 2a2 0 11a + 0+2 [40] 2aa 0 181 + group_sn:2aa, sn:2b8-2aa=14, pos:3-2, len:20a + group_sn:2aa, sn:2bc-2b8=18, pos:4-2, len:28a + group_sn:2aa, sn:2c0-2bc=22, pos:5-2, len:310 + group_sn:2aa, sn:2c4-2c0=26, pos:6-2, len:391 + group_sn:2aa, sn:2c8-2c4=30, pos:7-2, len:412 + group_sn:2aa, sn:2cc-2c8=34, pos:8-2, len:493 + */ + static const uint16_t score_level[][2] = { + {0, 0}, + {1, 2}, /* include, example 1, 3 */ + {4, 8}, + {8, 16},/* example 1 */ + {15, 30}, + {40, 40}, + {0xFFFF, score_max} /* the end missing seq, example 2 */ + }; + + uint16_t sn_delta = sn_minus(sn_now, group_sn) - 1; + uint16_t index_delta = (index_now - index_last) - 1; + uint16_t delta = sn_delta + index_delta; + + uint8_t i = 0; + uint8_t res; + + /* suppose: sn > zc_prev_sn, pos > zc_cur_pos */ + if (sn_compare(sn_now, group_sn) <= 0 || sn_compare(sn_now, zc_prev_sn) <= 0) { + return score_min; + } else if (index_now <= index_last) { + return score_min; + } + + while (delta > score_level[i][0]) { /* include */ + i ++; + } + + res = score_level[i][1]; + + if (zc_score_uplimit > res) { + return zc_score_uplimit - res; + } else { + return score_low; + } +} + +/* + 遍历所有分组,找到最多匹配的分组: 分组号,匹配的起止位置,匹配的最小score + 遍历分两步:遍历相等的数量 和 遍历空位置的数量 + guess_pos: 根据前后位置确定的pos + match_pos: 根据匹配计算的pos + + 1) 如果guess_pos && match_pos存在,且相等,则score += 5, pos = match_pos + 2) 不相等,则score -= 5, pos = match_pos + 3) 只有guess_pos存在,则score = 2 + 4) 只有match_pos存在,则score不变 +*/ +int try_to_sync_pos(uint8_t tods, uint16_t last_sn, uint8_t sn, + int last_group_pos, int group_pos) +{ + int ret = -1, empty_match = 0, reason = 0; + int guess_pos = -1, final_pos = -1; + + int max_match = 0, match_group = -1, match_end = GROUP_NUMBER, match_score = 0; + int match, i, j, score; /* loop variable */ + +retry: + for (i = 0; i <= zconfig_get_data_len(); i += GROUP_NUMBER) { + for (match = 0, score = score_max, j = 1; j <= GROUP_NUMBER; j ++) { + if (!tmp_score(j)) { + continue; + } + + if (empty_match) { + if (pkg_score(i + j) <= 1) { + match++; + score = 1; + } + } else { + if (!pkg_len(i + j)) { + continue; + } + if (pkg_len(i + j) == tmp_len(j)) { + match ++; + score = (score > pkg_score(i + j)) ? pkg_score(i + j) : score; + } else {/* encounter first unmatch */ + awss_trace("[%d]=%x, [%d]=%x\r\n", i + j, pkg_len(i + j), j, tmp_len(j)); + break; + } + } + } + if (match > max_match) { + max_match = match; + match_group = i; + match_end = j - 1; + match_score = score; + awss_trace("match=%d, match_group=%d, match_end=%d\r\n", + match, match_group, match_end); + } + } + + if (!max_match && !empty_match) {/* retry empty place match */ + empty_match = 1; + goto retry; + } + + if (group_pos != -1) {/* 根据后位置确定 */ + guess_pos = group_pos - GROUP_NUMBER;/* 前一组 */ + if (guess_pos < 0) { + guess_pos = (zconfig_get_data_len() / GROUP_NUMBER) * GROUP_NUMBER; + } + + if (!max_match || empty_match) {/* case 3 */ + match_score = 2; + final_pos = guess_pos; + reason = 3; + goto replace; + /* can not del goto, cause guess_pos has higher priority than empty match */ + } + } + /* 前位置 有效性难以判断,忽略 */ + + if (max_match > 0) { + if (max_match == 1) { + match_score = match_score > 10 ? 10 : match_score; + } else if (max_match == 2) { + match_score = match_score > 20 ? 20 : match_score; + } else if (max_match <= GROUP_NUMBER) { + match_score = match_score > 30 ? 30 : match_score; + } else { + goto clear; + } + + if (guess_pos != -1) { + if (guess_pos == match_group) {/* case 1 */ + match_end = GROUP_NUMBER; + match_score += 2;/*bonus */ + final_pos = match_group; + reason = 1; + } else {/*case 2*/ + match_score -= 0;/*bonus*/ + if (max_match >= 2 && !empty_match) { + final_pos = match_group; + } else { + final_pos = guess_pos; + } + reason = 2; + } + } else {/*case 4: 只有match_pos存在*/ + final_pos = match_group; + + reason = 4; + } + } else { + goto clear; + } + +replace: + if (final_pos != -1) { + reason = reason; + awss_trace("\tX = %d, score=%d, match=%d, reason=%d\r\n", final_pos, match_score, max_match, reason); + if (match_end != GROUP_NUMBER) { + awss_trace("\t match from [1-%d]\r\n", match_end); + } + for (i = final_pos + 1, j = 1; i <= final_pos + match_end; i++, j++) { + if (j > GROUP_NUMBER || i >= MAX_PKG_NUMS) { + break; + } + if (pkg_score(i) < match_score && tmp_score(j)) { + pkg_len(i) = tmp_len(j); + pkg_score(i) = (match_score > tmp_score(j) - 1) ? + (match_score - (tmp_score(j) - 1)) : match_score;/*TODO*/ + awss_trace("\t%d+%d [%d] %c %-3x\r\n", final_pos, j, pkg_score(i), flag_tods(tods), tmp_len(j)); + + zc_replace = 1; + if (zc_max_pos < i) { + zc_max_pos = i; + } + + ret = 0; + } + } + } + +clear: + zc_pos_unsync = 0; + memset((uint8_t *)tmp(0), 0, sizeof(zconfig_data->tmp_pkg[0])); + return ret; +} + +/* + 判断同一个位置是否应发生替换 + 调用该函数的前提: 同一个位置pos, 相同的得分score, 不同的数据 + 替换条件: 在各分组相同位置下,旧的数据有重复,新的数据无重复 +*/ +int try_to_replace_same_pos(int tods, int pos, int new_len) +{ + int replace = 0, i, old_match = 0, new_match = 0; + + for (i = pos % GROUP_NUMBER; i <= zconfig_get_data_len(); + i += GROUP_NUMBER) { + if (i != pos && pkg_len(i) == pkg_len(pos)) { + old_match = 1; + } + + if (pkg_len(i) == new_len) { + new_match = 1; + } + } + + if ((old_match && !new_match) || tods == 0) { + replace = 1; + pkg_len(pos) = new_len; + } + + return replace; +} + +int awss_ieee80211_smartconfig_process(uint8_t *ieee80211, int len, int link_type, struct parser_res *res, + signed char rssi) +{ + int hdrlen, fc, seq_ctrl; + struct ieee80211_hdr *hdr; + uint8_t *data, *bssid_mac, *dst_mac; + uint8_t encry = ZC_ENC_TYPE_INVALID; + uint8_t tods; + + /* + * when device try to connect current router (include adha and aha) + * skip the new packet. + */ + if (ieee80211 == NULL || zconfig_finished) { + return ALINK_INVALID; + } + + /* + * we don't process smartconfig until user press configure button + */ + if (awss_get_config_press() == 0) { + return ALINK_INVALID; + } + + hdr = (struct ieee80211_hdr *)ieee80211; + fc = hdr->frame_control; + seq_ctrl = hdr->seq_ctrl; + + /* + * for smartconfig with bcast of data + */ + if (!ieee80211_is_data_exact(fc)) { + return ALINK_INVALID; + } + + /* tods = 1, fromds = 0 || tods = 0, fromds = 1 */ + if (ieee80211_has_tods(fc) == ieee80211_has_fromds(fc)) { + return ALINK_INVALID; + } + /* drop frag, more, order*/ + if (ieee80211_has_frags(fc)) { + return ALINK_INVALID; + } + + dst_mac = (uint8_t *)ieee80211_get_DA(hdr); + if (memcmp(dst_mac, br_mac, ETH_ALEN)) { + return ALINK_INVALID; /* only handle br frame */ + } + + bssid_mac = (uint8_t *)ieee80211_get_BSSID(hdr); + + /* + * payload len = frame.len - (radio_header + wlan_hdr) + */ + hdrlen = ieee80211_hdrlen(fc); + if (hdrlen > len) { + return ALINK_INVALID; + } + +#ifdef _PLATFORM_QCOM_ + /* Note: http://stackoverflow.com/questions/17688710/802-11-qos-data-frames */ + hdrlen = (hdrlen + 3) & 0xFC;/* align header to 32bit boundary */ +#endif + + res->u.br.data_len = len - hdrlen; /* eating the hdr */ + res->u.br.sn = IEEE80211_SEQ_TO_SN(os_le16toh(seq_ctrl)); + + data = ieee80211 + hdrlen; /* eating the hdr */ + tods = ieee80211_has_tods(fc); + + do { +#ifdef AWSS_SUPPORT_APLIST + struct ap_info *ap_info; + ap_info = zconfig_get_apinfo(bssid_mac); + if (ap_info && ZC_ENC_TYPE_INVALID != ap_info->encry[tods]) { + encry = ap_info->encry[tods]; + } else +#endif + { + if (!ieee80211_has_protected(fc)) { + encry = ZC_ENC_TYPE_NONE; + } else { + /* Note: avoid empty null data */ + if (len < 8) { /* IV + ICV + DATA >= 8 */ + return ALINK_INVALID; + } + if (!(data[3] & 0x3F)) { + encry = ZC_ENC_TYPE_WEP; + } else if (data[3] & (1 << 5)) {/* Extended IV */ + if (data[1] == ((data[0] | 0x20) & 0x7F)) { /* tkip, WEPSeed = (TSC1 | 0x20 ) & 0x7F */ + encry = ZC_ENC_TYPE_TKIP; + } + if (data[2] == 0 && (!(data[3] & 0x0F))) { + encry = ZC_ENC_TYPE_AES; + } + + /* + * Note: above code use if(tkip) and if(ase) + * instead of if(tkip) else if(aes) + * beacause two condition may bother match. + */ + } + } + } + } while (0); + + if (encry == ZC_ENC_TYPE_INVALID) { + awss_warn("invalid encry type!\r\n"); + } + res->u.br.encry_type = encry; + + /* convert IEEE 802.11 header + possible LLC headers into Ethernet header + * IEEE 802.11 address fields: + * ToDS FromDS Addr1 Addr2 Addr3 Addr4 + * 0 0 DA SA BSSID n/a + * 0 1 DA BSSID SA n/a + * 1 0 BSSID SA DA n/a + * 1 1 RA TA DA SA + */ + res->src = ieee80211_get_SA(hdr); + res->dst = ieee80211_get_DA(hdr); + res->bssid = ieee80211_get_BSSID(hdr); + res->tods = ieee80211_has_tods(fc); + + return ALINK_BROADCAST; +} + +int awss_recv_callback_smartconfig(struct parser_res *res) +{ + static char statis = 0; + uint32_t timestamp = os_get_time_ms(); + + uint8_t *src = res->src; + uint8_t *dst = res->dst; + uint8_t *bssid = res->bssid; + uint8_t tods = res->tods; + uint8_t channel = res->channel; + + uint16_t sn = res->u.br.sn; + uint16_t len = res->u.br.data_len; + uint8_t encry_type = res->u.br.encry_type; + + int ret, pkg_type = PKG_INVALID; + uint8_t score = 0, timeout = 0, equal = 0; + + uint16_t pos = 0, index = 0; + + awss_flow("len=%d, %c, sn=%d, enc=%d, chn=%d, src=%02x%02x%02x%02x%02x%02x\r\n", + len, flag_tods(tods), sn, encry_type, channel, + src[0], src[1], src[2], src[3], src[4], src[5]); + /* + * STATE_CHN_LOCKED_BY_P2P is set by v2 wps/action frame, which means + * APP is sending v2, but if v2 is fail, APP will rollback to v1, + * so still need to parse br frame here + * even zc_state == STATE_CHN_LOCKED_BY_P2P. + */ + if (zc_state == STATE_CHN_LOCKED_BY_P2P || + zc_state == STATE_CHN_SCANNING) { + if (is_hint_frame(encry_type, len, bssid, src, channel, tods, sn)) { + if (statis == 0) { + statis = 1; + AWSS_UPDATE_STATIS(AWSS_STATIS_SM_IDX, AWSS_STATIS_TYPE_TIME_START); + } + awss_trace("hint frame: offset:%d, %c, sn:%x\r\n", + zc_frame_offset, flag_tods(tods), sn); + + awss_trace("src:%02x%02x%02x%02x%02x%02x, bssid:%02x%02x%02x%02x%02x%02x\r\n", + src[0], src[1], src[2], src[3], src[4], src[5], + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); + + pkg_type = PKG_START_FRAME; + zconfig_set_state(STATE_CHN_LOCKED_BY_BR, tods, channel); + + goto update_sn; + } else if (!memcmp(zc_android_src, src, ETH_ALEN)) { +#ifdef AWSS_SUPPORT_APLIST + struct ap_info *ap_info = zconfig_get_apinfo(bssid); + if (ap_info) { + if (ap_info->ssid[0] != 0x00 && ap_info->ssid[0] != 0xFF) { + strncpy((char *)zc_android_ssid, (const char *)ap_info->ssid, ZC_MAX_SSID_LEN - 1); + } + memcpy(zc_android_bssid, bssid, ETH_ALEN); + awss_trace("src %02x%02x%02x match %02x%02x%02x\r\n", + zc_android_src[0], zc_android_src[1], zc_android_src[2], + zc_android_bssid[0], zc_android_bssid[1], zc_android_bssid[2]); + } +#endif + } + } else if (zc_state == STATE_CHN_LOCKED_BY_BR) { + /* same src mac & br & bssid */ + if (memcmp(&src[0], zc_src_mac, ETH_ALEN) || + memcmp(&dst[0], br_mac, sizeof(br_mac)) || + memcmp(bssid, zc_bssid, ETH_ALEN)) { /* in case of WDS */ + goto drop; + } + + if (timestamp - zc_timestamp > time_interval) { + awss_debug("\t\t\t\t\ttimestamp = %d\r\n", timestamp - zc_timestamp); + timeout = 1; + } + + ret = sn_compare(sn, zc_prev_sn); + if (ret <= 0) { /* retry packet, update timestamp */ + zc_timestamp = timestamp; + } + if (ret == 0) { + awss_debug("drop: %3x == %3x\r\n", sn, zc_prev_sn);/* log level, too many retry pkg */ + goto drop; + } else if (ret < 0 && !timeout) {/* if timeout, goto pos_unsync */ + awss_debug("drop: %3x < %3x\r\n", sn, zc_prev_sn);/* TODO: better not drop */ + goto update_sn;/* FIXME: update sn??? */ + } + + /* assert(sn > zc_prev_sn && !timeout); */ + + if (len <= zc_frame_offset) { /* length invalid */ + goto drop; + } + + len -= zc_frame_offset; + + if (is_data_frame(len)) { + pkg_type = PKG_DATA_FRAME; + index = get_data_index(len); + pos = zc_group_pos + index; + + if (index > GROUP_NUMBER || pos >= MAX_PKG_NUMS) { + goto drop; + } + /* + * pos_unsync: 进入条件,任一条 + * case1: index rollback + * case2: index equal but len not equal + * case3: data frame & timeout + * 退出条件: + * case1: 进入条件同时也是退出条件 + * case2: 收到同步帧 + */ + if (index < zc_last_index || + (index == zc_last_index && len != zc_last_len) || timeout) { + if (zc_pos_unsync) {/* already in pos_unsync state */ + awss_trace("\texit try_to_sync_pos: re-enter!\r\n"); + try_to_sync_pos(tods, zc_prev_sn, sn, zc_group_pos, -1); + } + zc_pos_unsync = 1;/* also a new start */ + if (index < zc_last_index) { + awss_trace("\tenter try_to_sync_pos: rollback \r\n"); + } else if (timeout) { + awss_trace("\tenter try_to_sync_pos: timeout \r\n"); + } else { + awss_trace("\tenter try_to_sync_pos: != \r\n"); + } + } +pos_unsync: + if (zc_pos_unsync) {/* tmp save */ + package_save((uint8_t *)tmp(index), src, dst, tods, len); + if (zc_pos_unsync == 1) { + tmp_score(index) = 1; + } else { + tmp_score(index) = (sn - zc_prev_sn); /* TODO: index? last_tmp_score */ + } + zc_pos_unsync ++; /* unsync pkg counter */ + awss_trace("\tX+%d [%d] %-3x %c %-3x\r\n", index, tmp_score(index), sn, flag_tods(tods), len); + goto update_sn;/* FIXME: update prev_sn or not? */ + } + + /* assert(sn > zc_prev_sn && pos > zc_cur_pos) */ + score = get_data_score(zc_group_sn, sn, zc_prev_sn, pos, zc_cur_pos, tods); + if (score == score_min) {/* better not drop any pkg here */ + awss_trace("\t drop: group_sn:%x, sn:%x-%x=%x, pos:%d-%d, len:%x\r\n", + zc_group_sn, sn, zc_prev_sn, sn_minus(sn, zc_group_sn), pos, zc_cur_pos, len); + goto update_sn; + } else { + if (zc_score_uplimit > score) { + zc_score_uplimit = score; /* inherit last limit */ + } + + zc_group_sn = sn;/* TODO */ + awss_trace("%d+%d [%d] %-3x %c %-3x\r\n", zc_group_pos, index, score, sn, flag_tods(tods), len); + } + } else { + if (is_start_frame(len) || is_group_frame(len)) { + uint8_t group = get_group_index(len); + + if (zc_pos_unsync) { + awss_trace("\texit try_to_sync_pos: group frame\r\n"); + try_to_sync_pos(tods, zc_prev_sn, sn, zc_group_pos, group); + } + + zc_cur_pos = group; + zc_group_pos = group; + zc_group_sn = sn; + zc_score_uplimit = score_max; + + awss_trace("%d+%d [%d] %-3x %c %-3x\r\n", group, 0, zc_score_uplimit, sn, flag_tods(tods), len); + + /* ignore PKG_GROUP_FRAME here */ + pkg_type = PKG_START_FRAME; + + /* + * keep calling zconfig_set_state(), see Note about + * zconfig_callback_channel_locked() + */ + zconfig_set_state(STATE_CHN_LOCKED_BY_BR, tods, channel); + + /* zc_replace may happen in try_to_sync_pos(), so goto is_recv_completed */ + goto is_recv_completed; + } else { + awss_trace("\t invalid len = %d\r\n", len + zc_frame_offset); + goto drop; + } + } + + /* start from pkg(1), leave pkg(0) for start frame */ + if (pos >= MAX_PKG_NUMS || pos <= 0) { + awss_warn("msg index(%d) out of range!\r\n", pos); + goto drop; + } + + zc_cur_pos = pos; + + /* + score now > last: + 1) data equal: pkg_score = now + 2) not equal: pkg_score = now, data replace + score now == last: + 1) data equal: pkg_score++ and ??? + 2) not equal: pkg_score cut down & give warning & try_to_replace + score now < last: + 1) data equal: score_uplimit up??? + 2) not equal: goto pos_unsync + */ + for (tods = 0; tods < 2; tods ++) { + equal = !package_cmp((uint8_t *)pkg(pos), src, dst, tods, len); + + if (score > pkg_score(pos)) { + pkg_score(pos) = score; /* update score first */ + if (equal) { + continue; + } + /* not equal */ + zc_replace = 1; + package_save((uint8_t *)pkg(pos), src, dst, tods, len); + } else if (score == pkg_score(pos)) {/* range check ? */ + int replace; + if (equal) { + pkg_score(pos) ++; + continue; + } + /* not equal */ + replace = try_to_replace_same_pos(tods, pos, len); + if (replace) { + awss_trace("\t replace @ %d, len=%x\r\n", pos, len); + continue; + } + pkg_score(pos) /= 2; + if (score >= score_mid) /* better not happen */ + awss_warn("xxxxxxxx warn: pos=%d, score=[%d], %x != %x\r\n", + pos, score, pkg_len(pos), len); + + } else if (tods == res->tods) {/* pkg_score(pos) > score */ + if (!equal) {/* data not equal */ + if (zc_pos_unsync) { + continue; + } + zc_pos_unsync = 1; + awss_trace("\tenter try_to_sync_pos: data mismatch\r\n"); + tods = res->tods; + goto pos_unsync; + } else if (zc_score_uplimit >= score_mid && pkg_score(pos) - score < 10) { /* data equal */ + uint8_t uplimit = (zc_score_uplimit + pkg_score(pos)) / 2; + if (zc_score_uplimit != uplimit) { + awss_trace("\t\t\t uplimit [%d] -> [%d]\r\n", zc_score_uplimit, uplimit); + } + zc_score_uplimit = uplimit; + } + } + } + tods = res->tods; + +is_recv_completed: + zc_max_pos = (zc_max_pos < zc_cur_pos) ? zc_cur_pos : zc_max_pos; + if (zc_replace && zconfig_recv_completed(tods)) { + zc_replace = 0; + memcpy(zc_bssid, res->bssid, ETH_ALEN); + if (!zconfig_get_ssid_passwd(tods)) { + /* we got it! */ + AWSS_UPDATE_STATIS(AWSS_STATIS_SM_IDX, AWSS_STATIS_TYPE_TIME_SUC); + statis = 0; + zconfig_set_state(STATE_RCV_DONE, tods, channel); + return PKG_END; + } + } + } + +update_sn: + zc_prev_sn = sn; + + zc_timestamp = timestamp; + zc_last_index = index; + zc_last_len = len; + + return pkg_type; + +drop: + return PKG_INVALID; +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/smartconfig/smartconfig_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/smartconfig/smartconfig_wrapper.h new file mode 100644 index 00000000..8c994140 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/smartconfig/smartconfig_wrapper.h @@ -0,0 +1,57 @@ +#include "infra_types.h" +#include "infra_defs.h" +#include "wrappers_defs.h" +/*************************************** common hals ***************************************/ +int HAL_Timer_Stop(void *timer); +int HAL_Timer_Delete(void *timer); +void *HAL_Timer_Create(const char *name, void (*func)(void *), void *user_data); +int HAL_Timer_Start(void *timer, int ms); +void HAL_SleepMs(uint32_t ms); +void *HAL_Malloc(uint32_t size); +void HAL_MutexLock(void *mutex); +void HAL_MutexUnlock(void *mutex); +uint64_t HAL_UptimeMs(void); +void HAL_Free(void *ptr); +void *HAL_MutexCreate(void); +void HAL_MutexDestroy(void *mutex); + +/*************************************** wifi provision frameworks hals ***************************************/ +/* frameworks/awss.c*/ +int HAL_Awss_Get_Timeout_Interval_Ms(void); +int HAL_Sys_Net_Is_Ready(); +int HAL_Wifi_Get_Ap_Info(char ssid[HAL_MAX_SSID_LEN],char passwd[HAL_MAX_PASSWD_LEN],uint8_t bssid[ETH_ALEN]); +/* awss_crypt.c */ +int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN]); +int HAL_GetProductSecret(char *product_secret); +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN]); +int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN]); +/* zconfig_vendor_common.c */ +void HAL_Awss_Close_Monitor(void); +void HAL_Awss_Open_Monitor(_IN_ awss_recv_80211_frame_cb_t cb); +void HAL_Awss_Switch_Channel(char primary_channel, char secondary_channel, uint8_t bssid[ETH_ALEN]); +int HAL_Awss_Get_Channelscan_Interval_Ms(void); +DLL_HAL_API p_HAL_Aes128_t HAL_Aes128_Init( + _IN_ const uint8_t *key, + _IN_ const uint8_t *iv, + _IN_ AES_DIR_t dir); +DLL_HAL_API int HAL_Aes128_Destroy(_IN_ p_HAL_Aes128_t aes); +DLL_HAL_API int HAL_Aes128_Cbc_Decrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t blockNum, + _OU_ void *dst); +DLL_HAL_API int HAL_Aes128_Cfb_Decrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t length, + _OU_ void *dst); +char *HAL_Wifi_Get_Mac(_OU_ char mac_str[HAL_MAC_LEN]); +int HAL_Awss_Connect_Ap( + _IN_ uint32_t connection_timeout_ms, + _IN_ char ssid[HAL_MAX_SSID_LEN], + _IN_ char passwd[HAL_MAX_PASSWD_LEN], + _IN_OPT_ enum AWSS_AUTH_TYPE auth, + _IN_OPT_ enum AWSS_ENC_TYPE encry, + _IN_OPT_ uint8_t bssid[ETH_ALEN], + _IN_OPT_ uint8_t channel); + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/wifi_provision_api.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/wifi_provision_api.h new file mode 100644 index 00000000..d6038c65 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/wifi_provision_api.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_H__ +#define __AWSS_H__ + +#include +#include "infra_defs.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +#ifndef _IN_ + #define _IN_ +#endif + +DLL_IOT_API int awss_start(void); + +/** + * @brief stop wifi setup service + * + * @retval -1 : failure + * @retval 0 : sucess + * @note + * if awss_stop is called before exit of awss_start, awss and notify will stop. + */ +DLL_IOT_API int awss_stop(void); + +/** + * @brief make sure user touches device belong to themselves + * + * @retval -1 : failure + * @retval 0 : sucess + * @note: AWSS doesn't parse awss packet until user touches deivce use this api. + */ +DLL_IOT_API int awss_config_press(void); + +/** + * @brief get the awss config press status in realtime. + * + * @retval 1 : user has touched device + * @retval 0 : user don't touch device + */ +DLL_IOT_API uint8_t awss_get_config_press(void); +DLL_IOT_API void awss_set_config_press(uint8_t press); + +/** + * @brief check reset flag in perisistent storage. + * + * @retval -1 : failure + * @retval 0 : sucess + * @note + * check reset flag in perisistent storage, if device failed to report reset message last time, retry it. + */ +DLL_IOT_API int awss_check_reset(void); + +/** + * @brief report reset to cloud. + * + * @retval -1 : failure + * @retval 0 : sucess + * @note + * device will save reset flag if device dosen't connect cloud, device will fails to send reset to cloud. + * when connection between device and cloud is ready, device will retry to report reset to cloud. + */ +DLL_IOT_API int awss_report_reset(void); + +/** + * @brief stop to report reset to cloud. + * + * @retval -1 : failure + * @retval 0 : sucess + * @note + * just stop report reset to cloud without any touch reset flag in flash. + */ +DLL_IOT_API int awss_stop_report_reset(void); + +/** + * @brief start awss dev softap mode. + * + * @retval -1 : failure + * @retval 0 : sucess + * @note + * Start softap mode to get wifi ssid and password. + */ +DLL_IOT_API int awss_dev_ap_start(void); + +/** + * @brief stop awss dev softap mode. + * + * @retval -1 : failure + * @retval 0 : sucess + * @note + * Stop softap mode. + */ +DLL_IOT_API int awss_dev_ap_stop(void); +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/wifi_provision_internal.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/wifi_provision_internal.h new file mode 100644 index 00000000..c5163713 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/wifi_provision_internal.h @@ -0,0 +1,84 @@ +#include "infra_config.h" +#include +#include +#include "aws_lib.h" +#include "awss_aplist.h" +#include "zconfig_lib.h" +#include "zconfig_utils.h" +#include "zconfig_protocol.h" +#include "zconfig_ieee80211.h" +#include "awss_event.h" +#include "awss_timer.h" +#include "awss_main.h" +#include "iot_import_awss.h" +#include "os.h" +#include "infra_compat.h" +#include "awss_smartconfig.h" +#include "infra_sha1.h" +#include "passwd.h" +#include "awss_utils.h" +#include "awss_statis.h" +#include "awss_packet.h" +#include "awss_notify.h" +#include "awss_cmp.h" +#include "wifi_provision_api.h" +#include "awss_cmp.h" +#include "awss_crypt.h" +#include "sha256.h" +#include +#include "infra_json_parser.h" +#include "mqtt_api.h" +#include "awss_dev_reset_internal.h" +#include "awss_info.h" + +#include "awss_bind_statis.h" +#include "dev_bind_wrapper.h" +#include "awss_aplist.h" + +#ifdef AWSS_SUPPORT_SMARTCONFIG_WPS +#include "awss_wps.h" +#endif + +#ifdef AWSS_SUPPORT_HT40 +#include "awss_ht40.h" +#endif + +#if defined(AWSS_SUPPORT_AHA) || defined(AWSS_SUPPORT_ADHA) +#include "awss_wifimgr.h" +#endif + +#ifndef AWSS_DISABLE_ENROLLEE + #include "awss_enrollee.h" +#endif + +#if defined(AWSS_SUPPORT_AHA) + #include "awss_aha.h" +#endif +#if defined(AWSS_SUPPORT_ADHA) + #include "awss_adha.h" +#endif + +#if defined(WIFI_PROVISION_ENABLED) || defined(DEV_BIND_ENABLED) + #include "coap_api.h" + #include "iotx_coap.h" +#endif + +#ifdef AWSS_SUPPORT_SMARTCONFIG_WPS +#include "p2p_wrapper.h" +#endif + +#ifdef AWSS_SUPPORT_SMARTCONFIG +#include "smartconfig_wrapper.h" +#endif + +#ifdef AWSS_SUPPORT_ZEROCONFIG +#include "zeroconfig_wrapper.h" +#endif + +#ifdef AWSS_SUPPORT_AHA +#include "aha_wrapper.h" +#endif + +#ifdef AWSS_SUPPORT_DEV_AP +#include "dev_ap_wrapper.h" +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/zero_config/awss_enrollee.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/zero_config/awss_enrollee.c new file mode 100644 index 00000000..2cbb0e2d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/zero_config/awss_enrollee.c @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#ifndef AWSS_DISABLE_ENROLLEE + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +const uint8_t probe_req_frame[ZC_PROBE_LEN] = { + 0x40, 0x00, /* mgnt type, frame control */ + 0x00, 0x00, /* duration */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* DA */ + 0x28, 0xC2, 0xDD, 0x61, 0x68, 0x83, /* SA, to be replaced with wifi mac */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* BSSID */ + 0xC0, 0x79, /* seq */ + 0x00, 0x00, /* hide ssid, */ + 0x01, 0x08, 0x82, 0x84, 0x8B, 0x96, 0x8C, 0x92, 0x98, 0xA4, /* supported rates */ + 0x32, 0x04, 0xB0, 0x48, 0x60, 0x6C, /* extended supported rates */ + 0x3F, 0x84, 0x10, 0x9E /* FCS */ +}; + +static uint8_t *g_dev_sign; /* pointer to dev_name_len start pos */ +static uint8_t *g_product_key; /* pointer to model_len start pos */ +static uint8_t *enrollee_frame; +static uint16_t enrollee_frame_len; + +static int decrypt_ssid_passwd(uint8_t *ie, uint8_t ie_len, + uint8_t out_ssid[OS_MAX_SSID_LEN], + uint8_t out_passwd[OS_MAX_PASSWD_LEN], + uint8_t out_bssid[ETH_ALEN]); + +void awss_init_enrollee_info(void) /* void enrollee_raw_frame_init(void) */ +{ + char *pk = NULL, *dev_name = NULL, *text = NULL; + uint8_t sign[ENROLLEE_SIGN_SIZE + 1] = {0}; + char key[OS_DEVICE_SECRET_LEN + 1] = {0}; + int dev_name_len, pk_len; + int len, ie_len; + + if (enrollee_frame_len) + return; + + dev_name = os_zalloc(OS_DEVICE_NAME_LEN + 1); + if (NULL == dev_name) { + return; + } + pk = os_zalloc(OS_PRODUCT_KEY_LEN + 1); + if (NULL == pk) { + HAL_Free(dev_name); + return; + } + + HAL_GetProductKey(pk); + pk_len = strlen(pk); + + HAL_GetDeviceName(dev_name); + dev_name_len = strlen(dev_name); + + len = RANDOM_MAX_LEN + dev_name_len + pk_len; + text = os_zalloc(len + 1); /* +1 for string print */ + + awss_build_sign_src(text, &len); + + if (awss_get_encrypt_type() == 3) { /* aes-key per product */ + HAL_GetProductSecret(key); + } else { /* aes-key per device */ + HAL_GetDeviceSecret(key); + } + produce_signature(sign, (uint8_t *)text, len, key); + + HAL_Free(text); + + ie_len = pk_len + dev_name_len + ENROLLEE_IE_FIX_LEN; + enrollee_frame_len = sizeof(probe_req_frame) + ie_len; + + enrollee_frame = os_zalloc(enrollee_frame_len); + + /* construct the enrollee frame right now */ + len = sizeof(probe_req_frame) - FCS_SIZE; + memcpy(enrollee_frame, probe_req_frame, len); + + enrollee_frame[len ++] = 221; /* vendor ie */ + enrollee_frame[len ++] = ie_len - 2; /* exclude 221 & len */ + enrollee_frame[len ++] = 0xD8; + enrollee_frame[len ++] = 0x96; + enrollee_frame[len ++] = 0xE0; + enrollee_frame[len ++] = 0xAA;/* OUI type */ + enrollee_frame[len ++] = DEVICE_TYPE_VERSION;/* version & dev type */ + + enrollee_frame[len ++] = dev_name_len;/* dev name len*/ + memcpy(&enrollee_frame[len], dev_name, dev_name_len); + len += dev_name_len; + + enrollee_frame[len ++] = ENROLLEE_FRAME_TYPE;/* frame type */ + + g_product_key = &enrollee_frame[len]; /* pointer to pk len, see decrypt func */ + enrollee_frame[len ++] = pk_len; + memcpy(&enrollee_frame[len], pk, pk_len); + len += pk_len; + + enrollee_frame[len ++] = RANDOM_MAX_LEN; + memcpy(&enrollee_frame[len], aes_random, RANDOM_MAX_LEN); + len += RANDOM_MAX_LEN; + + enrollee_frame[len ++] = awss_get_encrypt_type(); /*encrypt type */ + enrollee_frame[len ++] = 0; /* signature method, 0: hmacsha1, 1: hmacsha256 */ + enrollee_frame[len ++] = ENROLLEE_SIGN_SIZE; /* signature length */ + g_dev_sign = &enrollee_frame[len]; + memcpy(&enrollee_frame[len], sign, ENROLLEE_SIGN_SIZE); + len += ENROLLEE_SIGN_SIZE; + + memcpy(&enrollee_frame[len], + &probe_req_frame[sizeof(probe_req_frame) - FCS_SIZE], FCS_SIZE); + + /* update probe request frame src mac */ + os_wifi_get_mac(enrollee_frame + SA_POS); + + HAL_Free(pk); + HAL_Free(dev_name); +} + +void awss_destroy_enrollee_info(void) +{ + if (enrollee_frame_len) { + if (NULL != enrollee_frame) { + HAL_Free(enrollee_frame); + } + enrollee_frame_len = 0; + enrollee_frame = NULL; + g_dev_sign = NULL; + g_product_key = NULL; + } +} + +void awss_broadcast_enrollee_info(void) +{ + if (enrollee_frame_len == 0 || enrollee_frame == NULL) + return; + + HAL_Wifi_Send_80211_Raw_Frame(FRAME_PROBE_REQ, enrollee_frame, + enrollee_frame_len); +} + +/* return 0 for success, -1 dev_name not match, otherwise return -2 */ +static int decrypt_ssid_passwd( + uint8_t *ie, uint8_t ie_len, + uint8_t out_ssid[OS_MAX_SSID_LEN], + uint8_t out_passwd[OS_MAX_PASSWD_LEN], + uint8_t out_bssid[ETH_ALEN]) +{ + uint8_t tmp_ssid[OS_MAX_SSID_LEN + 1] = {0}, tmp_passwd[OS_MAX_PASSWD_LEN + 1] = {0}; + uint8_t *p_dev_name_sign = NULL, *p_ssid = NULL, *p_passwd = NULL, *p_bssid = NULL; + + /* ignore ie hdr: 221, len, oui[3], type(0xAB) */ +#define REGISTRAR_IE_HDR (6) + ie += REGISTRAR_IE_HDR; + if (ie[0] != DEVICE_TYPE_VERSION) { + awss_debug("registrar(devtype/ver=%d not supported!", ie[0]); + return -1; + } + + ie ++; /* skip version */ + p_dev_name_sign = ie; + + if (!g_dev_sign || memcmp(g_dev_sign, p_dev_name_sign + 1, p_dev_name_sign[0])) { + p_dev_name_sign[p_dev_name_sign[0]] = '\0'; + awss_debug("dev_name not match, expect:"); + if (g_dev_sign) dump_hex(g_dev_sign, p_dev_name_sign[0], 16); + awss_debug("\r\nbut recv:"); + dump_hex(p_dev_name_sign + 1, p_dev_name_sign[0], 16); + return -2; + } + ie += ie[0] + 1; /* eating device name sign length & device name sign[n] */ + + if (ie[0] != REGISTRAR_FRAME_TYPE) { + awss_debug("registrar(frametype=%d not supported!", ie[0]); + return -1; + } + + ie ++; /* eating frame type */ + p_ssid = ie; + if (ie[0] >= OS_MAX_SSID_LEN) { + awss_debug("registrar(ssidlen=%d invalid!", ie[0]); + return -1; + } + memcpy(tmp_ssid, &p_ssid[1], p_ssid[0]); + awss_debug("Registrar ssid:%s", tmp_ssid); + + ie += ie[0] + 1; /* eating ssid_len & ssid[n] */ + + p_passwd = ie; + if (p_passwd[0] >= OS_MAX_PASSWD_LEN) { + awss_debug("registrar(passwdlen=%d invalid!", p_passwd[0]); + return -1; + } + + ie += ie[0] + 1; /* eating passwd_len & passwd */ + + p_bssid = ie; + ie += ETH_ALEN; /* eating bssid len */ + + AWSS_UPDATE_STATIS(AWSS_STATIS_ZCONFIG_IDX, AWSS_STATIS_TYPE_TIME_START); + + aes_decrypt_string((char *)p_passwd + 1, (char *)tmp_passwd, p_passwd[0], + 1, awss_get_encrypt_type(), 0, (const char *)aes_random); /* aes128 cfb */ + if (is_utf8((const char *)tmp_passwd, p_passwd[0]) != 1) { + awss_debug("registrar(passwd invalid!"); + AWSS_UPDATE_STATIS(AWSS_STATIS_ZCONFIG_IDX, AWSS_STATIS_TYPE_PASSWD_ERR); + return -1; + } + awss_debug("ssid:%s\r\n", tmp_ssid); + + strncpy((char *)out_passwd, (const char *)tmp_passwd, OS_MAX_PASSWD_LEN - 1); + strncpy((char *)out_ssid, (const char *)tmp_ssid, OS_MAX_SSID_LEN - 1); + memcpy((char *)out_bssid, (char *)p_bssid, ETH_ALEN); + + return 0;/* success */ +} + +int awss_ieee80211_zconfig_process(uint8_t *mgmt_header, int len, int link_type, struct parser_res *res, signed char rssi) +{ + const uint8_t *registrar_ie = NULL; + struct ieee80211_hdr *hdr; + uint16_t ieoffset; + int fc; + + /* + * when device try to connect current router (include adha and aha) + * skip the new aha and process the new aha in the next scope. + */ + if (mgmt_header == NULL || zconfig_finished) + return ALINK_INVALID; + /* + * we don't process zconfig used by enrollee until user press configure button + */ + if (awss_get_config_press() == 0) + return ALINK_INVALID; + + hdr = (struct ieee80211_hdr *)mgmt_header; + fc = hdr->frame_control; + + if (!ieee80211_is_probe_req(fc) && !ieee80211_is_probe_resp(fc)) + return ALINK_INVALID; + + ieoffset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + if (ieoffset > len) + return ALINK_INVALID; + + registrar_ie = (const uint8_t *)cfg80211_find_vendor_ie(WLAN_OUI_ALIBABA, + WLAN_OUI_TYPE_REGISTRAR, mgmt_header + ieoffset, len - ieoffset); + if (registrar_ie == NULL) + return ALINK_INVALID; + + res->u.ie.alink_ie_len = len - (registrar_ie - mgmt_header); + res->u.ie.alink_ie = (uint8_t *)registrar_ie; + + return ALINK_ZERO_CONFIG; +} + +int awss_recv_callback_zconfig(struct parser_res *res) +{ + uint8_t tods = res->tods; + uint8_t channel = res->channel; + + uint8_t *ie = res->u.ie.alink_ie; + uint8_t ie_len = ie[1]; + int ret; + + if (res->u.ie.alink_ie_len < ie_len) + return PKG_INVALID; + + ret = decrypt_ssid_passwd(ie, ie_len, zc_ssid, zc_passwd, zc_bssid); + if (ret) + return PKG_INVALID; + + zconfig_set_state(STATE_RCV_DONE, tods, channel); + + AWSS_UPDATE_STATIS(AWSS_STATIS_ROUTE_IDX, AWSS_STATIS_TYPE_TIME_SUC); + + return PKG_END; +} +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/zero_config/awss_enrollee.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/zero_config/awss_enrollee.h new file mode 100644 index 00000000..884da241 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/zero_config/awss_enrollee.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#ifndef __AWSS_ENROLLEE_H__ +#define __AWSS_ENROLLEE_H__ + +#include +#include "infra_sha1.h" +#include "infra_sha256.h" +#include "passwd.h" +#include "os.h" +#include "zconfig_ieee80211.h" + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" +{ +#endif + +/* enrollee/registrar doc see following + * http://docs.alibaba-inc.com/pages/viewpage.action?pageId=450855381 + */ +/* ie oui def. */ +#define WLAN_OUI_ALIBABA (0xD896E0) +#define WLAN_OUI_TYPE_ENROLLEE (0xAA) +#define WLAN_OUI_TYPE_REGISTRAR (0xAB) + +#define DEVICE_TYPE_VERSION (1) +#define ENROLLEE_FRAME_TYPE (0) +#define REGISTRAR_FRAME_TYPE (1) +#define REGISTRAR_IDLE_DUTY (1) + +struct ieee80211_enrollee_alibaba_ie { + uint8_t element_id; /* 221 */ + uint8_t len; /* len of this struct, exclude element id & len field */ + uint8_t oui[3]; /* D896E0 */ + uint8_t oui_type; /* 0xAA, device request */ + + uint8_t version:4; /* bit7 - bit4 */ + uint8_t dev_type:4; /* bit3 - bit0; alink=0, alink_cloud=1, yoc=8 */ + uint8_t dn_len; /* device name length*/ +#ifdef __GNUC__ + uint8_t dev_name[0]; /* device name, unique name for device */ +#endif + uint8_t frame_type; /* frame_type = 0 */ + + uint8_t pk_len; /* product key length */ +#ifdef __GNUC__ + uint8_t pk[0]; /* product key */ +#endif + uint8_t rand_len; /* random length */ +#ifdef __GNUC__ + uint8_t random[0]; /* random salt */ +#endif + uint8_t security; /* securation type, per product(3) or device(4) or manufacture(5) */ + uint8_t sign_method; /* 0: hmacsha1, 1:hmacsha256 */ + uint8_t sign_len; /* signature length */ +#ifdef __GNUC__ + uint8_t sign[0]; /* sign = hmacsha1(secret, random+dev_name+product_key) */ +#endif +}; + +/* len = 17 + sign[n] + ssid[n] + passwd[n] */ +struct ieee80211_registrar_alibaba_ie { + uint8_t element_id; /* 221 */ + uint8_t len; /* len of this struct, exclude element id & len field */ + uint8_t oui[3]; /* D896E0 */ + uint8_t oui_type; /* 0xAB, device response */ + + uint8_t version:4; /* bit7 - bit4 */ + uint8_t dev_type:4; /* bit3 - bit0; alink=0, alink_cloud=1, yoc=8 */ + uint8_t sign_len; /* signature length */ +#ifdef __GNUC__ + uint8_t sign[0]; /* sign = hmacsha1(secret, random+dev_name+product_key)*/ +#endif + uint8_t frame_type; /* frame_type = 0 */ + + uint8_t ssid_len; /* AP's SSID length */ +#ifdef __GNUC__ + uint8_t ssid[0]; /* SSID of AP */ +#endif + uint8_t passwd_len; /* AP's PASSWORD length */ +#ifdef __GNUC__ + uint8_t passwd[0]; /* PASSWORD of AP */ +#endif + uint8_t bssid[6]; /* BSSID of AP */ +}; + +#define MAX_DEV_NAME_LEN (64) +#define MAX_PK_LEN (20) +#define MAX_KEY_LEN (32) +#define MAX_TOKEN_LEN (32) +#define ZC_PROBE_LEN (46) +#define ENROLLEE_SIGN_SIZE (SHA1_DIGEST_SIZE) +#define ENROLLEE_IE_FIX_LEN (sizeof(struct ieee80211_enrollee_alibaba_ie) + RANDOM_MAX_LEN + ENROLLEE_SIGN_SIZE) +#define REGISTRAR_IE_FIX_LEN (sizeof(struct ieee80211_registrar_alibaba_ie)) +#define ENROLLEE_INFO_HDR_SIZE (ENROLLEE_IE_FIX_LEN - 6 + MAX_DEV_NAME_LEN + 1 + MAX_PK_LEN + 1) + +#ifndef AWSS_DISABLE_REGISTRAR +struct enrollee_info { + uint8_t dev_type_ver; + uint8_t dev_name_len; + uint8_t dev_name[MAX_DEV_NAME_LEN + 1]; + uint8_t frame_type; + + uint8_t pk_len; + uint8_t pk[MAX_PK_LEN + 1]; + uint8_t rand_len; + uint8_t random[RANDOM_MAX_LEN]; + uint8_t security; /* encryption per product(3) or device(4) or manufacture(5) */ + uint8_t sign_method; /* 0:hmacsha1, 1:hmacsha256 */ + uint8_t sign_len; + uint8_t sign[ENROLLEE_SIGN_SIZE]; + + signed char rssi; + + uint8_t key[MAX_KEY_LEN + 1]; /* aes key */ + + uint8_t state; /* free or not */ + uint8_t checkin_priority; /* smaller means high pri */ + uint32_t checkin_timestamp; + uint32_t report_timestamp; + uint32_t interval; /* report timeout */ + uint32_t checkin_timeout; +}; +#endif +/* registrar configuration */ +#define MAX_ENROLLEE_NUM (5) /* Note: max enrollee num supported */ + +/* + * ENR_FREE --producer--> ENR_IN_QUEUE + * ENR_IN_QUEUE --cloud-----> ENR_CHECKIN_ENABLE + * ENR_CHECKIN_ENABLE --consumer--> ENR_CHECKIN_ONGOING --> ENR_CHECKIN_END/ENR_FREE + * *any state* --consumer--> ENR_FREE + */ +enum enrollee_state { + ENR_FREE = 0, + ENR_IN_QUEUE, + ENR_FOUND, + ENR_CHECKIN_ENABLE, + ENR_CHECKIN_CIPHER, + ENR_CHECKIN_ONGOING, + ENR_CHECKIN_END, + /* ENR_OUTOFDATE = 0 */ +}; + +#define AES_KEY_LEN (16) +/* return 0 for success, -1 dev_name not match, otherwise return -2 */ +extern const uint8_t probe_req_frame[ZC_PROBE_LEN]; +#define SA_POS (10) /* source mac pos */ +#define FCS_SIZE (4) + +/* enrollee API */ +#ifdef AWSS_DISABLE_ENROLLEE +#if 0 +static inline void awss_init_enrollee_info(void) { } +static inline void awss_broadcast_enrollee_info(void) { } +static inline void awss_destroy_enrollee_info(void) { } +#endif +#else +void awss_init_enrollee_info(void); +void awss_broadcast_enrollee_info(void); +void awss_destroy_enrollee_info(void); +int awss_recv_callback_zconfig(struct parser_res *res); +int awss_ieee80211_zconfig_process(uint8_t *mgmt_header, int len, int link_type, + struct parser_res *res, signed char rssi); +#endif + +/* registrar API */ +#ifdef AWSS_DISABLE_REGISTRAR +#if 0 +static inline void awss_registrar_deinit(void) { } +static inline void awss_registrar_init(void) { } +#endif +#else +void awss_registrar_init(void); +void awss_registrar_deinit(void); +#endif + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/zero_config/awss_registrar.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/zero_config/awss_registrar.c new file mode 100644 index 00000000..7e11dc91 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/zero_config/awss_registrar.c @@ -0,0 +1,1092 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ +#include "wifi_provision_internal.h" + +#ifndef AWSS_DISABLE_REGISTRAR + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#define AWSS_JSON_DEV_NAME "deviceName" +#define AWSS_JSON_PK "productKey" +#define AWSS_JSON_DEV_LIST "data" +#define AWSS_JSON_PERIOD "timeout" +#define AWSS_JSON_CIPHER "secret" +#define AWSS_REPORT_PKT_LEN (512) +#define AWSS_REPORT_PARAM_FMT "{\"awssVer\":%s,\"type\":0,\"ssid\":\"%s\",\"bssid\":\"%s\",\"rssi\":%d,\"payload\":[\"%s\"]}" + +static void awss_wifi_mgnt_frame_callback(uint8_t *buffer, int length, signed char rssi, int buffer_type); +static void registrar_raw_frame_init(struct enrollee_info *enr); +static void registrar_raw_frame_send(void); +static void registrar_raw_frame_destroy(void); +static void enrollee_report(void); +static int enrollee_checkin(void); +static int enrollee_enable_somebody_checkin(char *key, char *dev_name, int timeout); +static int awss_enrollee_get_dev_info(char *payload, int payload_len, char *product_key, + char *dev_name, char *cipher, int *timeout); + +/* registrar send pkt interval in ms */ +#define REGISTRAR_TIMEOUT (60) +#define REGISTRAR_WORK_TIME (16 * 400) + +static struct enrollee_info enrollee_info[MAX_ENROLLEE_NUM]; +static char registrar_sched_cnt = 0; +static char registrar_inited = 0; +static char registrar_id = 0; + +static void *checkin_timer = NULL; +static void *enrollee_report_timer = NULL; +static void *registrar_sched_timer = NULL; + +#define ALIBABA_OUI {0xD8, 0x96, 0xE0} +#ifdef REGISTRAR_IDLE_DUTY +#if REGISTRAR_IDLE_DUTY > 0 +void registrar_schedule(void *param) +{ + uint8_t alibaba_oui[3] = ALIBABA_OUI; + char last_open = registrar_sched_cnt & 0x01; + unsigned int idle_duty = REGISTRAR_IDLE_DUTY; + + HAL_Timer_Stop(registrar_sched_timer); + registrar_sched_cnt ++; + + if (last_open) { /* need to close */ + HAL_Wifi_Enable_Mgmt_Frame_Filter(FRAME_BEACON_MASK | FRAME_PROBE_REQ_MASK, + (uint8_t *)alibaba_oui, NULL); + HAL_Timer_Start(registrar_sched_timer, REGISTRAR_WORK_TIME * idle_duty); + } else { + HAL_Wifi_Enable_Mgmt_Frame_Filter(FRAME_BEACON_MASK | FRAME_PROBE_REQ_MASK, + (uint8_t *)alibaba_oui, awss_wifi_mgnt_frame_callback); + HAL_Timer_Start(registrar_sched_timer, REGISTRAR_WORK_TIME); + } +} +#endif +#endif + +void awss_registrar_init(void) +{ + uint8_t alibaba_oui[3] = ALIBABA_OUI; + if (registrar_inited) { + return; + } + + memset(enrollee_info, 0, sizeof(enrollee_info)); + registrar_inited = 1; + + + /* + * if idle duty is zero, don't need to care about power consumption + */ +#ifdef REGISTRAR_IDLE_DUTY +#if REGISTRAR_IDLE_DUTY > 0 + if (registrar_sched_timer == NULL) { + registrar_sched_timer = HAL_Timer_Create("sched", (void (*)(void *))registrar_schedule, NULL); + } + if (registrar_sched_timer) { + registrar_sched_cnt ++; + HAL_Timer_Stop(registrar_sched_timer); + HAL_Timer_Start(registrar_sched_timer, REGISTRAR_WORK_TIME); + } +#endif +#endif + + HAL_Wifi_Enable_Mgmt_Frame_Filter(FRAME_BEACON_MASK | FRAME_PROBE_REQ_MASK, + (uint8_t *)alibaba_oui, awss_wifi_mgnt_frame_callback); +} + +void awss_registrar_deinit(void) +{ + uint8_t alibaba_oui[3] = ALIBABA_OUI; + HAL_Wifi_Enable_Mgmt_Frame_Filter(FRAME_BEACON_MASK | FRAME_PROBE_REQ_MASK, + (uint8_t *)alibaba_oui, NULL); + + registrar_inited = 0; + registrar_sched_cnt = 0; + awss_stop_timer(checkin_timer); + checkin_timer = NULL; + awss_stop_timer(enrollee_report_timer); + enrollee_report_timer = NULL; + awss_stop_timer(registrar_sched_timer); + registrar_sched_timer = NULL; +} + +int online_dev_bind_monitor(void *ctx, void *resource, void *remote, void *request) +{ + uint8_t i; + char *payload = NULL; + int payload_len = 0, dev_info_len = 0; + char *key = NULL, *dev_name = NULL, *dev_info = NULL; + + payload = awss_cmp_get_coap_payload(request, &payload_len); + if (payload == NULL || payload_len == 0) { + goto CONNECTAP_MONITOR_END; + } + + dev_info = json_get_value_by_name(payload, payload_len, AWSS_JSON_PARAM, &dev_info_len, NULL); + if (dev_info == NULL || dev_info_len == 0) { + goto CONNECTAP_MONITOR_END; + } + + dev_name = os_zalloc(MAX_DEV_NAME_LEN + 1); + key = os_zalloc(MAX_PK_LEN + 1); + + if (!dev_name || !key) { + goto CONNECTAP_MONITOR_END; + } + + if (awss_enrollee_get_dev_info(dev_info, dev_info_len, key, dev_name, NULL, NULL) < 0) { + goto CONNECTAP_MONITOR_END; + } + + for (i = 0; i < MAX_ENROLLEE_NUM; i++) { + if (enrollee_info[i].state != ENR_CHECKIN_ONGOING) { + continue; + } + + if (strlen(dev_name) == enrollee_info[i].dev_name_len && + 0 == memcmp(dev_name, enrollee_info[i].dev_name, enrollee_info[i].dev_name_len) && + strlen(key) == enrollee_info[i].pk_len && + 0 == memcmp(key, enrollee_info[i].pk, enrollee_info[i].pk_len)) { + enrollee_info[i].state = ENR_FREE; + } + } + +CONNECTAP_MONITOR_END: + if (dev_name) { + HAL_Free(dev_name); + } + if (key) { + HAL_Free(key); + } + return 0; +} + +void awss_enrollee_checkin(void *pcontext, void *pclient, void *msg) +{ +#define CHECK_IN_RSP_LEN (64) + char *packet = NULL; + int len = 0, timeout = 0; + int packet_len = CHECK_IN_RSP_LEN, dev_info_len = 0; + char *key = NULL, *dev_name = NULL, *dev_info = NULL; + uint32_t payload_len; + char *payload; + int ret; + char reply[TOPIC_LEN_MAX] = {0}; + + ret = awss_cmp_mqtt_get_payload(msg, &payload, &payload_len); + + if (ret != 0) { + goto CHECKIN_FAIL; + } + + if (payload == NULL || payload_len == 0) { + goto CHECKIN_FAIL; + } + + dev_name = os_zalloc(MAX_DEV_NAME_LEN + 1); + packet = os_zalloc(CHECK_IN_RSP_LEN + 1); + key = os_zalloc(MAX_PK_LEN + 1); + + if (!dev_name || !key || !packet) { + goto CHECKIN_FAIL; + } + + awss_debug("checkin len:%u, payload:%s\r\n", payload_len, payload); + + dev_info = json_get_value_by_name(payload, payload_len, AWSS_JSON_PARAM, &dev_info_len, NULL); + if (dev_info == NULL || dev_info_len == 0) { + goto CHECKIN_FAIL; + } + + if (awss_enrollee_get_dev_info(dev_info, dev_info_len, key, dev_name, NULL, &timeout) < 0) { + goto CHECKIN_FAIL; + } + + enrollee_enable_somebody_checkin(key, dev_name, timeout); + + { + char *id = NULL; + char id_str[MSG_REQ_ID_LEN] = {0}; + id = json_get_value_by_name(payload, payload_len, AWSS_JSON_ID, &len, NULL); + memcpy(id_str, id, len > MSG_REQ_ID_LEN - 1 ? MSG_REQ_ID_LEN - 1 : len); + awss_build_packet(AWSS_CMP_PKT_TYPE_RSP, id_str, ILOP_VER, METHOD_EVENT_ZC_CHECKIN, "{}", 200, packet, &packet_len); + } + + awss_build_topic(TOPIC_ZC_CHECKIN_REPLY, reply, TOPIC_LEN_MAX); + awss_cmp_mqtt_send(reply, packet, packet_len, 1); + + HAL_Free(dev_name); + HAL_Free(packet); + HAL_Free(key); + return; + +CHECKIN_FAIL: + if (dev_name) { + HAL_Free(dev_name); + } + if (packet) { + HAL_Free(packet); + } + if (key) { + HAL_Free(key); + } + + awss_warn("alink checkin failed"); + return; +} + +static int enrollee_enable_somebody_cipher(char *key, char *dev_name, char *cipher) +{ + int i; + + awss_debug("key:%s, dev_name:%s, cipher:%s\r\n", key, dev_name, cipher); + + if (strlen(key) > MAX_PK_LEN || + strlen(dev_name) > MAX_DEV_NAME_LEN) { + goto out; + } + + for (i = 0; i < MAX_ENROLLEE_NUM; i++) { + awss_debug("enrollee[%d] state %d", i, enrollee_info[i].state); + if (enrollee_info[i].state != ENR_CHECKIN_ENABLE) { + continue; + } + if (strlen(dev_name) == enrollee_info[i].dev_name_len && + 0 == memcmp(dev_name, enrollee_info[i].dev_name, enrollee_info[i].dev_name_len) && + strlen(key) == enrollee_info[i].pk_len && + 0 == memcmp(key, enrollee_info[i].pk, enrollee_info[i].pk_len)) { + + uint8_t *key_byte = os_zalloc(MAX_KEY_LEN + 1); + if (NULL == key_byte) { + goto out; + } + + utils_str_to_hex(cipher, strlen(cipher), key_byte, MAX_KEY_LEN); + + memcpy((char *)&enrollee_info[i].key[0], key_byte, AES_KEY_LEN); + + HAL_Free(key_byte); + + awss_debug("enrollee[%d] state %d->%d", i, enrollee_info[i].state, + ENR_CHECKIN_CIPHER); + enrollee_info[i].state = ENR_CHECKIN_CIPHER; + + HAL_Timer_Stop(checkin_timer); + HAL_Timer_Start(checkin_timer, 1); + return 1;/* match */ + } + } + +out: + return 0;/* mismatch */ +} + +static int enrollee_enable_somebody_checkin(char *key, char *dev_name, int timeout) +{ + int i; + + awss_debug("key:%s, dev_name:%s, timeout:%u\r\n", key, dev_name, timeout); + if (strlen(key) > MAX_PK_LEN || + strlen(dev_name) > MAX_DEV_NAME_LEN) { + goto out; + } + + for (i = 0; i < MAX_ENROLLEE_NUM; i++) { + awss_debug("len:%u---%lu, name:%s---%s\r\n", + enrollee_info[i].dev_name_len, strlen(dev_name), + enrollee_info[i].dev_name, dev_name); + awss_debug("enrollee[%d] state %d", i, enrollee_info[i].state); + if (enrollee_info[i].state != ENR_FOUND) { + continue; + } + + if (strlen(dev_name) == enrollee_info[i].dev_name_len && + 0 == memcmp(dev_name, enrollee_info[i].dev_name, enrollee_info[i].dev_name_len) && + strlen(key) == enrollee_info[i].pk_len && + 0 == memcmp(key, enrollee_info[i].pk, enrollee_info[i].pk_len)) { + + enrollee_info[i].state = ENR_CHECKIN_ENABLE; + enrollee_info[i].checkin_priority = 1; /* TODO: not implement yet */ + enrollee_info[i].checkin_timeout = timeout <= 0 ? REGISTRAR_TIMEOUT : timeout; + enrollee_info[i].checkin_timestamp = os_get_time_ms(); + + HAL_Timer_Stop(checkin_timer); + HAL_Timer_Start(checkin_timer, 1); + return 1;/* match */ + } + } + +out: + return 0;/* mismatch */ +} + +static int awss_request_cipher_key(int i) +{ + int packet_len = AWSS_REPORT_PKT_LEN - 1; + char topic[TOPIC_LEN_MAX] = {0}; + char *param = NULL; + char *packet = NULL; + if (i < 0) { + return -1; + } +#define AWSS_DEV_CIPHER_FMT "{\"awssVer\":%s,\"productKey\":\"%s\",\"deviceName\":\"%s\",\"cipherType\":%d, \"random\":\"%s\"}" + + param = os_zalloc(AWSS_REPORT_PKT_LEN); + packet = os_zalloc(AWSS_REPORT_PKT_LEN); + if (param == NULL || packet == NULL) { + goto REQ_CIPHER_ERR; + } + + { + char id[MSG_REQ_ID_LEN] = {0}; + char rand_str[(RANDOM_MAX_LEN << 1) + 1] = {0}; + + utils_hex_to_str(enrollee_info[i].random, RANDOM_MAX_LEN, rand_str, sizeof(rand_str)); + HAL_Snprintf(id, MSG_REQ_ID_LEN - 1, "\"%u\"", registrar_id ++); + HAL_Snprintf(param, AWSS_REPORT_PKT_LEN - 1, AWSS_DEV_CIPHER_FMT, + AWSS_VER, enrollee_info[i].pk, enrollee_info[i].dev_name, enrollee_info[i].security, rand_str); + awss_build_packet(AWSS_CMP_PKT_TYPE_REQ, id, ILOP_VER, METHOD_EVENT_ZC_CIPHER, param, 0, packet, &packet_len); + HAL_Free(param); + } + + awss_build_topic(TOPIC_ZC_CIPHER, topic, TOPIC_LEN_MAX); + awss_cmp_mqtt_send(topic, packet, packet_len, 1); + + HAL_Free(packet); + + return 0; + +REQ_CIPHER_ERR: + if (param) { + HAL_Free(param); + } + if (packet) { + HAL_Free(packet); + } + + return -1; +} + +void awss_get_cipher_reply(void *pcontext, void *pclient, void *msg) +{ + int dev_info_len = 0; + char *key = NULL, *dev_name = NULL, *dev_info = NULL, *cipher = NULL; + uint32_t payload_len; + char *payload; + int ret; + + ret = awss_cmp_mqtt_get_payload(msg, &payload, &payload_len); + + if (ret != 0) { + goto CIPHER_ERR; + } + + if (payload == NULL || payload_len == 0) { + goto CIPHER_ERR; + } + + dev_name = os_zalloc(MAX_DEV_NAME_LEN + 1); + cipher = os_zalloc(RANDOM_MAX_LEN * 2 + 1); + key = os_zalloc(MAX_PK_LEN + 1); + + if (!dev_name || !key || !cipher) { + goto CIPHER_ERR; + } + + awss_debug("cipher len:%u, payload:%s\r\n", payload_len, payload); + + dev_info = json_get_value_by_name(payload, payload_len, AWSS_JSON_DEV_LIST, &dev_info_len, NULL); + if (dev_info == NULL || dev_info_len == 0) { + goto CIPHER_ERR; + } + + if (awss_enrollee_get_dev_info(dev_info, dev_info_len, key, dev_name, cipher, NULL) < 0) { + goto CIPHER_ERR; + } + + enrollee_enable_somebody_cipher(key, dev_name, cipher); + + HAL_Free(dev_name); + HAL_Free(cipher); + HAL_Free(key); + + return; +CIPHER_ERR: + if (dev_name) { + HAL_Free(dev_name); + } + if (cipher) { + HAL_Free(cipher); + } + if (key) { + HAL_Free(key); + } + return; +} + +/* 1 -- checkin onging, 0 -- idle */ +static int enrollee_checkin(void) +{ + int pri = 65536; + uint8_t i, check = 0; + uint8_t checkin_new = 0xff, get_cipher = 0xff; + + for (i = 0; i < MAX_ENROLLEE_NUM; i++) { + switch (enrollee_info[i].state) { + case ENR_CHECKIN_ENABLE: + if (pri > enrollee_info[i].checkin_priority) { + pri = enrollee_info[i].checkin_priority; + checkin_new = i; + check = 1; + } + break; + case ENR_CHECKIN_CIPHER: + get_cipher = i; + check = 1; + break; + case ENR_CHECKIN_ONGOING: + goto ongoing; + default: + break; + } + } + + awss_debug("cn:%d, ci:%d, c:%d\r\n", checkin_new, get_cipher, check); + /* no device need to setup */ + if (check == 0) { + return 0; + } + + if (get_cipher != 0xff) { + goto checkin_ongoing; + } + + /* request cipher */ + awss_request_cipher_key(checkin_new); + return 1; + + /* checkin_new: */ +checkin_ongoing: + awss_debug("enrollee[%d] state %d->%d", get_cipher, + enrollee_info[get_cipher].state, ENR_CHECKIN_ONGOING); + enrollee_info[get_cipher].state = ENR_CHECKIN_ONGOING; + enrollee_info[get_cipher].checkin_timestamp = os_get_time_ms(); + registrar_raw_frame_init(&enrollee_info[get_cipher]); + i = get_cipher; + + /* undergoing */ +ongoing: + registrar_raw_frame_send(); + awss_debug("registrar_raw_frame_send"); + if (time_elapsed_ms_since(enrollee_info[i].checkin_timestamp) > enrollee_info[i].checkin_timeout * 1000) { + memset(&enrollee_info[i], 0, sizeof(enrollee_info[0])); + awss_debug("enrollee[%d] state %d->%d", i, + enrollee_info[i].state, ENR_CHECKIN_END); + enrollee_info[i].state = ENR_CHECKIN_END;/* FIXME: remove this state? */ + awss_debug("enrollee[%d] state %d->%d", i, + enrollee_info[i].state, ENR_FREE); + enrollee_info[i].state = ENR_FREE; + registrar_raw_frame_destroy(); + } + + HAL_Timer_Stop(checkin_timer); + HAL_Timer_Start(checkin_timer, HAL_Awss_Get_Channelscan_Interval_Ms() * 15 / 16); + + return 1; +} + +int awss_report_set_interval(char *key, char *dev_name, int interval) +{ + int i; + + awss_debug("key:%s, dev_name:%s, interval:%u\r\n", key, dev_name, interval); + if (strlen(key) > MAX_PK_LEN || + strlen(dev_name) > MAX_DEV_NAME_LEN) { + return -1; + } + + for (i = 0; i < MAX_ENROLLEE_NUM; i++) { + if (enrollee_info[i].state != ENR_FOUND) { + continue; + } + + if (strlen(dev_name) == enrollee_info[i].dev_name_len && + 0 == memcmp(dev_name, enrollee_info[i].dev_name, enrollee_info[i].dev_name_len) && + strlen(key) == enrollee_info[i].pk_len && + 0 == memcmp(key, enrollee_info[i].pk, enrollee_info[i].pk_len)) { + + enrollee_info[i].interval = interval <= 0 ? REGISTRAR_TIMEOUT : interval; + if (checkin_timer == NULL) { + checkin_timer = HAL_Timer_Create("checkin", (void (*)(void *))enrollee_checkin, NULL); + } + HAL_Timer_Stop(checkin_timer); + HAL_Timer_Start(checkin_timer, 1); + return 0;/* match */ + } + } + + return -1; + +} + +static int awss_enrollee_get_dev_info(char *payload, int payload_len, + char *product_key, char *dev_name, + char *cipher, int *timeout) +{ + char *elem = NULL; + int len = 0; + if (product_key == NULL || dev_name == NULL) { + return -1; + } + + elem = json_get_value_by_name(payload, payload_len, AWSS_JSON_PK, &len, NULL); + if (len > MAX_PK_LEN || elem == NULL) { + return -1; + } + + memcpy(product_key, elem, len); + + len = 0; + elem = json_get_value_by_name(payload, payload_len, AWSS_JSON_DEV_NAME, &len, NULL); + if (len > MAX_DEV_NAME_LEN || elem == NULL) { + return -1; + } + + memcpy(dev_name, elem, len); + + len = 0; + elem = json_get_value_by_name(payload, payload_len, AWSS_JSON_PERIOD, &len, NULL); + if (elem && timeout) { + *timeout = atoi(elem); + } + + len = 0; + elem = json_get_value_by_name(payload, payload_len, AWSS_JSON_CIPHER, &len, NULL); + if (elem && cipher && len <= RANDOM_MAX_LEN * 2) { + memcpy(cipher, elem, len); + } + + return 0; +} + +void awss_report_enrollee_reply(void *pcontext, void *pclient, void *msg) +{ + int interval = 0; + int dev_list_len = 0; + char *dev_list = NULL; + char *key = NULL, *dev_name = NULL; + uint32_t payload_len; + char *payload; + int ret; + char *str_pos, *entry; + int entry_len, type; + + ret = awss_cmp_mqtt_get_payload(msg, &payload, &payload_len); + + if (ret != 0) { + goto REPORT_REPLY_FAIL; + } + + if (payload == NULL || payload_len == 0) { + goto REPORT_REPLY_FAIL; + } + + awss_debug("found reply:%s\r\n", payload); + dev_name = os_zalloc(MAX_DEV_NAME_LEN + 1); + key = os_zalloc(MAX_PK_LEN + 1); + + if (!dev_name || !key) { + goto REPORT_REPLY_FAIL; + } + + dev_list = json_get_value_by_name(payload, payload_len, AWSS_JSON_DEV_LIST, &dev_list_len, NULL); + if (dev_list == NULL) { + goto REPORT_REPLY_FAIL; + } + + json_array_for_each_entry(dev_list, dev_list_len, str_pos, entry, entry_len, type) { + memset(dev_name, 0, MAX_DEV_NAME_LEN + 1); + memset(key, 0, MAX_PK_LEN + 1); + if (awss_enrollee_get_dev_info(entry, entry_len, key, dev_name, NULL, &interval) < 0) { + continue; + } + + awss_report_set_interval(key, dev_name, interval); + } + + HAL_Free(dev_name); + HAL_Free(key); + return; + +REPORT_REPLY_FAIL: + if (dev_name) { + HAL_Free(dev_name); + } + if (key) { + HAL_Free(key); + } + + awss_warn("ilop report enrollee failed"); + return; +} + +int awss_report_enrollee(uint8_t *payload, int payload_len, signed char rssi) +{ + int i; + char *payload_str = NULL; + char *param = NULL, *packet = NULL; + int packet_len = AWSS_REPORT_PKT_LEN - 1; + char topic[TOPIC_LEN_MAX] = {0}; + + payload_str = os_zalloc(payload_len * 2 + 1); + param = os_zalloc(AWSS_REPORT_PKT_LEN); + packet = os_zalloc(AWSS_REPORT_PKT_LEN); + if (!payload_str || !param || !packet) { + goto REPORT_FAIL; + } + + { + char id[MSG_REQ_ID_LEN] = {0}; + uint8_t bssid[OS_ETH_ALEN] = {0}; + char ssid[OS_MAX_SSID_LEN + 1] = {0}; + char bssid_str[OS_ETH_ALEN * 2 + 6] = {0}; + + HAL_Wifi_Get_Ap_Info(ssid, NULL, bssid); + sprintf(bssid_str, "%02X:%02X:%02X:%02X:%02X:%02X", bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); + + for (i = 0; i < payload_len; i ++) { + sprintf(&payload_str[i * 2], "%02X", payload[i]); + } + + payload_str[payload_len * 2] = '\0'; /* sprintf not add '\0' in the end of string in qcom */ + + HAL_Snprintf(id, MSG_REQ_ID_LEN - 1, "\"%u\"", registrar_id ++); + + HAL_Snprintf(param, AWSS_REPORT_PKT_LEN - 1, AWSS_REPORT_PARAM_FMT, + AWSS_VER, ssid, bssid_str, rssi > 0 ? rssi - 256 : rssi, payload_str); + HAL_Free(payload_str); + awss_build_packet(AWSS_CMP_PKT_TYPE_REQ, id, ILOP_VER, METHOD_EVENT_ZC_ENROLLEE, param, 0, packet, &packet_len); + HAL_Free(param); + } + + awss_build_topic(TOPIC_ZC_ENROLLEE, topic, TOPIC_LEN_MAX); + awss_debug("topic:%s, packet:%s, method:%s\r\n", topic, packet, METHOD_EVENT_ZC_ENROLLEE); + + awss_cmp_mqtt_send(topic, packet, packet_len, 1); + + HAL_Free(packet); + return 0; + +REPORT_FAIL: + if (payload_str) { + HAL_Free(payload_str); + } + if (packet) { + HAL_Free(packet); + } + if (param) { + HAL_Free(param); + } + + return -1; +} + +/* consumer */ +static void enrollee_report(void) +{ + int i; +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + char ssid[OS_MAX_SSID_LEN + 1] = {0}; + HAL_Wifi_Get_Ap_Info(ssid, NULL, NULL); + if (!strcmp(ssid, DEFAULT_SSID) || !strcmp(ssid, ADHA_SSID)) { + return; /* ignore enrollee in 'aha' or 'adha' mode */ + } +#endif + + /* evict timeout enrollee */ + for (i = 0; i < MAX_ENROLLEE_NUM; i++) { + struct enrollee_info *enrollee = &enrollee_info[i]; + switch (enrollee->state) { + case ENR_FOUND: { + if (time_elapsed_ms_since(enrollee->report_timestamp) > enrollee->interval * 1000) { + memset(enrollee, 0, sizeof(enrollee_info[0])); + enrollee->state = ENR_FREE; + } + break; + } + case ENR_IN_QUEUE: { + uint16_t idx = 0; + int ret = -1; + uint16_t payload_len = 1 + enrollee->dev_name_len + 1 + enrollee->pk_len + + 1 + enrollee->rand_len + 3 + enrollee->sign_len; + uint8_t *payload = HAL_Malloc(payload_len + 1); + if (payload == NULL) { + break; + } + + payload[idx ++] = enrollee->dev_name_len; + memcpy(&payload[idx], enrollee->dev_name, enrollee->dev_name_len); + idx += enrollee->dev_name_len; + + payload[idx ++] = enrollee->pk_len; + memcpy(&payload[idx], enrollee->pk, enrollee->pk_len); + idx += enrollee->pk_len; + + payload[idx ++] = enrollee->rand_len; + memcpy(&payload[idx], &enrollee->random, enrollee->rand_len); + idx += enrollee->rand_len; + + payload[idx ++] = enrollee->security; + payload[idx ++] = enrollee->sign_method; + payload[idx ++] = enrollee->sign_len; + memcpy(&payload[idx], &enrollee->sign, enrollee->sign_len); + idx += enrollee->sign_len; + + ret = awss_report_enrollee(payload, idx, enrollee->rssi); + + enrollee->state = ENR_FOUND; + enrollee->report_timestamp = os_get_time_ms(); + + awss_trace("enrollee report result:%s, period:%dms\n", + ret == 0 ? "success" : "failed", + enrollee->interval * 1000); + + HAL_Free(payload); + break; + } + default: + break; + } + } +} + +int enrollee_put(struct enrollee_info *in); + +int process_enrollee_ie(const uint8_t *ie, signed char rssi) +{ + struct enrollee_info tmp_enrollee = {0}; + /* suppose enrollee_ie is complete */ +#define ENROLLEE_IE_HDR (6) + /* copy to tmp_enrollee */ + ie += ENROLLEE_IE_HDR; + + if (ie[0] != DEVICE_TYPE_VERSION) { + awss_warn("enrollee(devtype/ver=%d not supported!", ie[0]); + return -1; + } + tmp_enrollee.dev_type_ver = ie[0]; + ie ++;/* eating dev_type_ver */ + + if (ie[0] > MAX_DEV_NAME_LEN) { + awss_warn("enrollee(dev_name_len=%d out of range!\r\n", ie[0]); + return -1; + } + tmp_enrollee.dev_name_len = ie[0]; + memcpy(tmp_enrollee.dev_name, &ie[1], ie[0]); + ie += ie[0] + 1; /* eating dev_name[n], dev_name_len */ + + if (ie[0] != ENROLLEE_FRAME_TYPE) { + awss_warn("enrollee(frametype=%d invalid!\r\n", ie[0]); + return -1; + } + tmp_enrollee.frame_type = ie[0]; + ie ++;/* eating frame type */ + + if (ie[0] > MAX_PK_LEN) { + awss_warn("enrollee(pk_len=%d invalid!\r\n", ie[0]); + return -1; + } + tmp_enrollee.pk_len = ie[0]; + memcpy(tmp_enrollee.pk, &ie[1], ie[0]); + ie += ie[0] + 1; /* eating pk[n], pk_len */ + + if (ie[0] != RANDOM_MAX_LEN) { + awss_warn("enrollee(rand_len=%d invalid!\r\n", ie[0]); + return -1; + } + tmp_enrollee.rand_len = ie[0]; + memcpy(tmp_enrollee.random, &ie[1], RANDOM_MAX_LEN); + ie += ie[0] + 1; /* eating random[n], rand_len */ + + if (ie[0] > 5 || ie[0] < 3) { + awss_warn("enrollee(security=%d invalid!\r\n", ie[0]); + return -1; + } + if (ie[1] > 1) { + awss_warn("enrollee(sign_method=%d invalid!\r\n", ie[1]); + return -1; + } + if (ie[2] != ENROLLEE_SIGN_SIZE) { + awss_warn("enrollee(sign_len=%d invalid!\r\n", ie[2]); + return -1; + } + tmp_enrollee.security = ie[0]; + tmp_enrollee.sign_method = ie[1]; + tmp_enrollee.sign_len = ie[2]; + + memcpy(tmp_enrollee.sign, &ie[3], ie[2]); + ie += ie[2] + 3; /* eating signature[n], security, sign_method, sign_len */ + + tmp_enrollee.rssi = rssi; + + enrollee_put(&tmp_enrollee); + + return 0; +} + +/* producer */ +/* + * 1: already saved, update timestamp + * 0: new saved + * -1: no slot to save, drop + */ +int enrollee_put(struct enrollee_info *in) +{ + uint8_t i, empty_slot = MAX_ENROLLEE_NUM; + do { +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + char ssid[OS_MAX_SSID_LEN + 1] = {0}; +#endif + /* reduce stack used */ + if (in == NULL || !HAL_Sys_Net_Is_Ready()) { /* not ready to work as registerar */ + return -1; + } +#if defined(AWSS_SUPPORT_ADHA) || defined(AWSS_SUPPORT_AHA) + HAL_Wifi_Get_Ap_Info(ssid, NULL, NULL); + if (!strcmp(ssid, DEFAULT_SSID) || !strcmp(ssid, ADHA_SSID)) { + return -1; /* ignore enrollee in 'aha' or 'adha' mode */ + } +#endif + } while (0); + + for (i = 0; i < MAX_ENROLLEE_NUM; i++) { + if (enrollee_info[i].state) { + if (in->dev_name_len == enrollee_info[i].dev_name_len && + 0 == memcmp(in->dev_name, enrollee_info[i].dev_name, enrollee_info[i].dev_name_len) && + in->pk_len == enrollee_info[i].pk_len && + 0 == memcmp(in->pk, enrollee_info[i].pk, enrollee_info[i].pk_len)) { + if (enrollee_info[i].state == ENR_FOUND && + time_elapsed_ms_since(enrollee_info[i].report_timestamp) > enrollee_info[i].interval * 1000) { + if (enrollee_report_timer == NULL) { + enrollee_report_timer = HAL_Timer_Create("enrollee", (void (*)(void *))enrollee_report, NULL); + } + HAL_Timer_Stop(enrollee_report_timer); + HAL_Timer_Start(enrollee_report_timer, 1); + } + if (enrollee_info[i].state != ENR_IN_QUEUE) { /* already reported */ + return 1; + } + memcpy(&enrollee_info[i], in, ENROLLEE_INFO_HDR_SIZE); + enrollee_info[i].rssi = (2 * enrollee_info[i].rssi + in->rssi) / 3; + return 1;/* wait for report */ + } + } else if (enrollee_info[i].state == ENR_FREE && empty_slot >= MAX_ENROLLEE_NUM) { + empty_slot = i; + } + } + + if (empty_slot >= MAX_ENROLLEE_NUM) { + return -1; /* no slot to save */ + } + + /* new enrollee */ + memset(&enrollee_info[empty_slot], 0, sizeof(struct enrollee_info)); + memcpy(&enrollee_info[empty_slot], in, ENROLLEE_INFO_HDR_SIZE); + enrollee_info[empty_slot].rssi = in->rssi; + enrollee_info[empty_slot].state = ENR_IN_QUEUE; + enrollee_info[empty_slot].checkin_priority = 1; /* smaller means high pri */ + enrollee_info[empty_slot].interval = REGISTRAR_TIMEOUT; + enrollee_info[empty_slot].checkin_timeout = REGISTRAR_TIMEOUT; + awss_debug("new enrollee[%d] dev_name:%s time:%x", + empty_slot, in->dev_name, os_get_time_ms()); + + if (enrollee_report_timer == NULL) { + enrollee_report_timer = HAL_Timer_Create("enrollee", (void (*)(void *))enrollee_report, NULL); + } + HAL_Timer_Stop(enrollee_report_timer); + HAL_Timer_Start(enrollee_report_timer, 1); + + return 0; +} + +extern const uint8_t *cfg80211_find_vendor_ie( + uint32_t oui, uint8_t oui_type, + const uint8_t *ies, int len); +/** + * @brief management frame handler + * + * @param[in] buffer @n 80211 raw frame or ie(information element) buffer + * @param[in] len @n buffer length + * @param[in] buffer_type @n 0 when buffer is a 80211 frame, + * 1 when buffer only contain IE info + * @return None. + * @see None. + * @note None. + */ +void awss_wifi_mgnt_frame_callback(uint8_t *buffer, int length, signed char rssi, int buffer_type) +{ +#define MGMT_BEACON (0x80) +#define MGMT_PROBE_REQ (0x40) +#define MGMT_PROBE_RESP (0x50) + + /* fc(2) + dur(2) + da(6) + sa(6) + bssid(6) + seq(2) */ +#define MGMT_HDR_LEN (24) + + int type = buffer[0], len = 0, eid; + const uint8_t *ie; + + if (buffer_type) { + ie = buffer; + goto ie_handler; + } + + switch (type) { + case MGMT_BEACON: + /* awss_trace("beacon"); */ + buffer += MGMT_HDR_LEN + 12;/* hdr(24) + 12(timestamp, beacon_interval, cap) */ + length -= MGMT_HDR_LEN + 12; + + eid = buffer[0]; + len = buffer[1]; + if (eid != 0) { + /* awss_warn("error eid, should be 0!"); */ + return; + } + + /* skip ssid */ + buffer += 2; + buffer += len; + length -= len; + + goto find_ie; + break; + case MGMT_PROBE_REQ: + /* awss_trace("probe req\n"); */ + buffer += MGMT_HDR_LEN; + length -= MGMT_HDR_LEN; + +find_ie: + ie = cfg80211_find_vendor_ie((uint32_t)WLAN_OUI_ALIBABA, + (uint8_t)WLAN_OUI_TYPE_ENROLLEE, + (const uint8_t *)buffer, (int)length); + if (ie) { +ie_handler: + /* awss_trace("ie found to be processed\n"); */ + process_enrollee_ie(ie, rssi); + } + break; + case MGMT_PROBE_RESP: + /* awss_trace("probe resp"); */ + break; + default: + /* awss_trace("frame (%d): %02x \n", length, type); */ + break; + } +} + +static uint8_t *registrar_frame; +static int registrar_frame_len; + +static void registrar_raw_frame_init(struct enrollee_info *enr) +{ + int len, ie_len; + + char passwd[OS_MAX_PASSWD_LEN + 1] = {0}; + char ssid[OS_MAX_SSID_LEN + 1] = {0}; + uint8_t bssid[OS_ETH_ALEN] = {0}; + int ssid_len, passwd_len; + + HAL_Wifi_Get_Ap_Info(ssid, passwd, bssid); + ssid_len = strlen(ssid); + if (ssid_len > OS_MAX_SSID_LEN - 1) { + ssid_len = OS_MAX_SSID_LEN - 1; + } + + passwd_len = strlen(passwd); + if (passwd_len > OS_MAX_PASSWD_LEN - 1) { + passwd_len = OS_MAX_PASSWD_LEN - 1; + } + + ie_len = ENROLLEE_SIGN_SIZE + ssid_len + passwd_len + REGISTRAR_IE_FIX_LEN; + registrar_frame_len = sizeof(probe_req_frame) + ie_len; + + registrar_frame = HAL_Malloc(registrar_frame_len); + if (!registrar_frame) { + awss_err("error: malloc size %d faild\r\n", registrar_frame_len); + return; + } + + /* construct the registrar frame right now */ + len = sizeof(probe_req_frame) - FCS_SIZE; + memcpy(registrar_frame, probe_req_frame, len); + + registrar_frame[len ++] = 221; /* vendor ie */ + registrar_frame[len ++] = ie_len - 2; /* exclude 221 & len */ + registrar_frame[len ++] = 0xD8; + registrar_frame[len ++] = 0x96; + registrar_frame[len ++] = 0xE0; + registrar_frame[len ++] = 0xAB;/* OUI type */ + registrar_frame[len ++] = DEVICE_TYPE_VERSION;/* version & dev type */ + registrar_frame[len ++] = enr->sign_len;/* dev signature len*/ + memcpy(®istrar_frame[len], enr->sign, enr->sign_len); + len += enr->sign_len; + registrar_frame[len ++] = REGISTRAR_FRAME_TYPE;/* frame type */ + + registrar_frame[len ++] = ssid_len; + memcpy(®istrar_frame[len], ssid, ssid_len); + len += ssid_len; + + registrar_frame[len ++] = passwd_len; + + { + p_aes128_t aes = HAL_Aes128_Init(&enr->key[0], enr->random, PLATFORM_AES_ENCRYPTION); + HAL_Aes128_Cfb_Encrypt(aes, (uint8_t *)passwd, passwd_len, (uint8_t *)®istrar_frame[len]); + HAL_Aes128_Destroy(aes); + } + + len += passwd_len; + + memcpy(®istrar_frame[len], bssid, ETH_ALEN); + len += ETH_ALEN; + + memcpy(®istrar_frame[len], + &probe_req_frame[sizeof(probe_req_frame) - FCS_SIZE], FCS_SIZE); + + /* update probe request frame src mac */ + os_wifi_get_mac(registrar_frame + SA_POS); + + { + /* dump registrar info */ + awss_debug("dump registrar info:"); + dump_hex(registrar_frame, registrar_frame_len, 16); + } +} + +static void registrar_raw_frame_destroy(void) +{ + if (registrar_frame_len) { + HAL_Free(registrar_frame); + registrar_frame = NULL; + registrar_frame_len = 0; + } +} + +static void registrar_raw_frame_send(void) +{ + /* suppose registrar_frame was ready + * @see enrollee_checkin() + */ + int ret = HAL_Wifi_Send_80211_Raw_Frame(FRAME_PROBE_REQ, registrar_frame, + registrar_frame_len); + if (ret) { + awss_warn("send failed"); + } +} + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/zero_config/zeroconfig_wrapper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/zero_config/zeroconfig_wrapper.h new file mode 100644 index 00000000..31d295ff --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/iotkit-embedded/wifi_provision/zero_config/zeroconfig_wrapper.h @@ -0,0 +1,77 @@ +#include "infra_types.h" +#include "infra_defs.h" +#include "wrappers_defs.h" +/*************************************** common hals ***************************************/ +int HAL_Timer_Stop(void *timer); +int HAL_Timer_Delete(void *timer); +void *HAL_Timer_Create(const char *name, void (*func)(void *), void *user_data); +int HAL_Timer_Start(void *timer, int ms); +void HAL_SleepMs(uint32_t ms); +void *HAL_Malloc(uint32_t size); +void HAL_MutexLock(void *mutex); +void HAL_MutexUnlock(void *mutex); +uint64_t HAL_UptimeMs(void); +void HAL_Free(void *ptr); +void *HAL_MutexCreate(void); +void HAL_MutexDestroy(void *mutex); + +/*************************************** wifi provision frameworks hals ***************************************/ +/* frameworks/awss.c*/ +int HAL_Awss_Get_Timeout_Interval_Ms(void); +int HAL_Sys_Net_Is_Ready(); +int HAL_Wifi_Get_Ap_Info(char ssid[HAL_MAX_SSID_LEN],char passwd[HAL_MAX_PASSWD_LEN],uint8_t bssid[ETH_ALEN]); +/* awss_crypt.c */ +int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN]); +int HAL_GetProductSecret(char *product_secret); +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN]); +int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN]); + +/* zconfig_vendor_common.c */ +void HAL_Awss_Close_Monitor(void); +void HAL_Awss_Open_Monitor(_IN_ awss_recv_80211_frame_cb_t cb); +void HAL_Awss_Switch_Channel(char primary_channel, char secondary_channel, uint8_t bssid[ETH_ALEN]); +int HAL_Awss_Get_Channelscan_Interval_Ms(void); +DLL_HAL_API p_HAL_Aes128_t HAL_Aes128_Init( + _IN_ const uint8_t *key, + _IN_ const uint8_t *iv, + _IN_ AES_DIR_t dir); + +DLL_HAL_API int HAL_Aes128_Destroy(_IN_ p_HAL_Aes128_t aes); +DLL_HAL_API int HAL_Aes128_Cbc_Decrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t blockNum, + _OU_ void *dst); +DLL_HAL_API int HAL_Aes128_Cfb_Decrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t length, + _OU_ void *dst); +DLL_HAL_API int HAL_Aes128_Cbc_Encrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t blockNum, + _OU_ void *dst); +DLL_HAL_API int HAL_Aes128_Cfb_Encrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t length, + _OU_ void *dst); +char *HAL_Wifi_Get_Mac(_OU_ char mac_str[HAL_MAC_LEN]); +int HAL_Awss_Connect_Ap( + _IN_ uint32_t connection_timeout_ms, + _IN_ char ssid[HAL_MAX_SSID_LEN], + _IN_ char passwd[HAL_MAX_PASSWD_LEN], + _IN_OPT_ enum AWSS_AUTH_TYPE auth, + _IN_OPT_ enum AWSS_ENC_TYPE encry, + _IN_OPT_ uint8_t bssid[ETH_ALEN], + _IN_OPT_ uint8_t channel); + +/*************************************** zero-config special hals ***************************************/ +int HAL_Wifi_Enable_Mgmt_Frame_Filter( + _IN_ uint32_t filter_mask, + _IN_OPT_ uint8_t vendor_oui[3], + _IN_ awss_wifi_mgmt_frame_cb_t callback); +int HAL_Wifi_Send_80211_Raw_Frame(_IN_ enum HAL_Awss_Frame_Type type, + _IN_ uint8_t *buffer, _IN_ int len); + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/cJSON.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/cJSON.c new file mode 100644 index 00000000..47fb5c32 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/cJSON.c @@ -0,0 +1,2283 @@ +/* +Copyright (c) 2009-2017 Dave Gamble and cJSON contributors +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +#ifdef __GNUC__ + #pragma GCC visibility push(default) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __GNUC__ + #pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#define true ((cJSON_bool)1) +#define false ((cJSON_bool)0) + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char *)(global_error.json + global_error.position); +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 3) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char *) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) { + return 1; + } + + if (string1 == string2) { + return 0; + } + + for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++) { + if (*string1 == '\0') { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks { + void *(*allocate)(uint32_t size); + void(*deallocate)(void *pointer); + void *(*reallocate)(void *pointer, size_t size); +} internal_hooks; + +extern void *HAL_Malloc(uint32_t size); +extern void HAL_Free(void *ptr); +static internal_hooks global_hooks = { HAL_Malloc, HAL_Free, realloc }; + +static unsigned char *cJSON_strdup(const unsigned char *string, const internal_hooks *const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) { + return NULL; + } + + length = strlen((const char *)string) + sizeof(""); + if (!(copy = (unsigned char *)hooks->allocate(length))) { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks *const hooks) +{ + cJSON *node = (cJSON *)hooks->allocate(sizeof(cJSON)); + if (node) { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ + struct lconv *lconv = localeconv(); + return (unsigned char)lconv->decimal_point[0]; +} + +typedef struct { + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +#define cannot_read(buffer, size) (!can_read(buffer, size)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) { + switch (buffer_at_offset(input_buffer)[i]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char *)number_c_string, (char **)&after_end); + if (number_c_string == after_end) { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) { + item->valueint = INT_MAX; + } else if (number <= INT_MIN) { + item->valueint = INT_MIN; + } else { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) { + object->valueint = INT_MAX; + } else if (number <= INT_MIN) { + object->valueint = INT_MIN; + } else { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +typedef struct { + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char *ensure(printbuffer *const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) { + newsize = INT_MAX; + } else { + return NULL; + } + } else { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) { + /* reallocate with realloc if available */ + newbuffer = (unsigned char *)p->hooks.reallocate(p->buffer, newsize); + } else { + /* otherwise reallocate manually */ + newbuffer = (unsigned char *)p->hooks.allocate(newsize); + if (!newbuffer) { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) { + memcpy(newbuffer, p->buffer, p->offset + 1); + } + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer *const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char *)buffer_pointer); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON *const item, printbuffer *const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test; + + if (output_buffer == NULL) { + return false; + } + + /* This checks for NaN and Infinity */ + if ((d * 0) != 0) { + length = sprintf((char *)number_buffer, "null"); + } else { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char *)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char *)number_buffer, "%lg", &test) != 1) || ((double)test != d)) { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char *)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occured */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length); + if (output_pointer == NULL) { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) { + if (number_buffer[i] == decimal_point) { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char *const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) { + h += (unsigned int)input[i] - '0'; + } else if ((input[i] >= 'A') && (input[i] <= 'F')) { + h += (unsigned int)10 + input[i] - 'A'; + } else if ((input[i] >= 'a') && (input[i] <= 'f')) { + h += (unsigned int)10 + input[i] - 'a'; + } else { /* invalid */ + return 0; + } + + if (i < 3) { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 +* A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char *const input_pointer, + const unsigned char *const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } else { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } else if (codepoint < 0x800) { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } else if (codepoint < 0x10000) { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } else if (codepoint <= 0x10FFFF) { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } else { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } else { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON *const item, parse_buffer *const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) { + /* is escape sequence */ + if (input_end[0] == '\\') { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char *)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) { + if (*input_pointer != '\\') { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) { + goto fail; + } + + switch (input_pointer[1]) { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char *)output; + + input_buffer->offset = (size_t)(input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) { + return false; + } + + /* empty string */ + if (input == NULL) { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) { + return false; + } + strcpy((char *)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) { + switch (*input_pointer) { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) { + /* normal character, copy */ + *output_pointer = *input_pointer; + } else { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char *)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON *const item, printbuffer *const p) +{ + return print_string_ptr((unsigned char *)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer); +static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer); +static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer); +static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer); +static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer); +static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) { + return NULL; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) { + buffer->offset++; + } + + if (buffer->offset == buffer->length) { + buffer->offset--; + } + + return buffer; +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, + cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL) { + goto fail; + } + + buffer.content = (const unsigned char *)value; + buffer.length = strlen((const char *)value) + sizeof(""); + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) { /* memory fail */ + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(&buffer))) { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') { + goto fail; + } + } + if (return_parse_end) { + *return_parse_end = (const char *)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) { + cJSON_Delete(item); + } + + if (value != NULL) { + error local_error; + local_error.json = (const unsigned char *)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) { + local_error.position = buffer.offset; + } else if (buffer.length > 0) { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) { + *return_parse_end = (const char *)local_error.json + local_error.position; + } else { + global_error = local_error; + } + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +#define cjson_min(a, b) ((a < b) ? a : b) + +static unsigned char *print(const cJSON *const item, cJSON_bool format, const internal_hooks *const hooks) +{ + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char *)hooks->allocate(256); + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) { + printed = (unsigned char *)hooks->reallocate(buffer->buffer, buffer->length); + buffer->buffer = NULL; + if (printed == NULL) { + goto fail; + } + } else { /* otherwise copy the JSON over to a new buffer */ + printed = (unsigned char *)hooks->allocate(buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) { + hooks->deallocate(buffer->buffer); + } + +#if 0 + if (printed != NULL) { + hooks->deallocate(printed); + } +#endif + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char *)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char *)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) { + return NULL; + } + + p.buffer = (unsigned char *)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) { + return NULL; + } + + return (char *)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (len < 0) { + return false; + } + + p.buffer = (unsigned char *)buf; + p.length = (size_t)len; + p.offset = 0; + p.noalloc = true; + p.format = fmt; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)) { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)) { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)) { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') + || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) { + return parse_object(item, input_buffer); + } + + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) { + return false; + } + + switch ((item->type) & 0xFF) { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) { + return false; + } + strcpy((char *)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) { + return false; + } + strcpy((char *)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) { + return false; + } + strcpy((char *)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: { + size_t raw_length = 0; + if (item->valuestring == NULL) { + if (!output_buffer->noalloc) { + output_buffer->hooks.deallocate(output_buffer->buffer); + } + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) { + /* start the linked list */ + current_item = head = new_item; + } else { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) { + if (!print_value(current_element, output_buffer)) { + return false; + } + update_offset(output_buffer); + if (current_element->next) { + length = (size_t)(output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) { + return false; + } + *output_pointer++ = ','; + if (output_buffer->format) { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) { + /* start the linked list */ + current_item = head = new_item; + } else { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) { + goto fail; /* faile to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) { + return false; + } + + /* Compose the output: */ + length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) { + if (output_buffer->format) { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) { + return false; + } + for (i = 0; i < output_buffer->depth; i++) { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char *)current_item->string, output_buffer)) { + return false; + } + update_offset(output_buffer); + + length = (size_t)(output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = (size_t)((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) { + return false; + } + if (current_item->next) { + *output_pointer++ = ','; + } + + if (output_buffer->format) { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) { + return false; + } + if (output_buffer->format) { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *c = array->child; + size_t i = 0; + while (c) { + i++; + c = c->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)i; +} + +static cJSON *get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON *const object, const char *const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) { + return NULL; + } + + current_element = object->child; + if (case_sensitive) { + while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) { + current_element = current_element->next; + } + } else { + while ((current_element != NULL) + && (case_insensitive_strcmp((const unsigned char *)name, (const unsigned char *)(current_element->string)) != 0)) { + current_element = current_element->next; + } + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *const object, const char *const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON *const object, const char *const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks *const hooks) +{ + cJSON *ref = cJSON_New_Item(hooks); + if (!ref) { + return NULL; + } + memcpy(ref, item, sizeof(cJSON)); + ref->string = NULL; + ref->type |= cJSON_IsReference; + ref->next = ref->prev = NULL; + return ref; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL)) { + return; + } + + child = array->child; + + if (child == NULL) { + /* list is empty, start new one */ + array->child = item; + } else { + /* append to the end */ + while (child->next) { + child = child->next; + } + suffix_object(child, item); + } +} + +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + /* call cJSON_AddItemToObjectCS for code reuse */ + cJSON_AddItemToObjectCS(object, (char *)cJSON_strdup((const unsigned char *)string, &global_hooks), item); + /* remove cJSON_StringIsConst flag */ + item->type &= ~cJSON_StringIsConst; +} + +#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ + #pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + if (!item) { + return; + } + if (!(item->type & cJSON_StringIsConst) && item->string) { + global_hooks.deallocate(item->string); + } + item->string = (char *)string; + item->type |= cJSON_StringIsConst; + cJSON_AddItemToArray(object, item); +} +#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + cJSON_AddItemToArray(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item) +{ + if ((parent == NULL) || (item == NULL)) { + return NULL; + } + + if (item->prev != NULL) { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) { + /* first element */ + parent->child = item->next; + } + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) { + return; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) { + cJSON_AddItemToArray(array, newitem); + return; + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) { + array->child = newitem; + } else { + newitem->prev->next = newitem; + } +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item, cJSON *replacement) +{ + if ((parent == NULL) || (replacement == NULL)) { + return false; + } + + if (replacement == item) { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) { + replacement->next->prev = replacement; + } + if (replacement->prev != NULL) { + replacement->prev->next = replacement; + } + if (parent->child == item) { + parent->child = replacement; + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *obj = NULL; + + if (which < 0) { + return; + } + + obj = get_array_item(array, (size_t)which); + if (obj == NULL) { + return; + } + + cJSON_ReplaceItemViaPointer(array, obj, newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, + cJSON_bool case_sensitive) +{ + cJSON *obj = NULL; + + if (replacement == NULL) { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) { + cJSON_free(replacement->string); + } + replacement->string = (char *)cJSON_strdup((const unsigned char *)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + obj = get_object_item(object, string, case_sensitive); + if (obj == NULL) { + return false; + } + + cJSON_ReplaceItemViaPointer(object, obj, replacement); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = b ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) { + item->valueint = INT_MAX; + } else if (num <= INT_MIN) { + item->valueint = INT_MIN; + } else { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_String; + item->valuestring = (char *)cJSON_strdup((const unsigned char *)string, &global_hooks); + if (!item->valuestring) { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_Raw; + item->valuestring = (char *)cJSON_strdup((const unsigned char *)raw, &global_hooks); + if (!item->valuestring) { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if (count < 0) { + return NULL; + } + + a = cJSON_CreateArray(); + for (i = 0; a && (i < (size_t)count); i++) { + n = cJSON_CreateNumber(numbers[i]); + if (!n) { + cJSON_Delete(a); + return NULL; + } + if (!i) { + a->child = n; + } else { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if (count < 0) { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) { + n = cJSON_CreateNumber((double)numbers[i]); + if (!n) { + cJSON_Delete(a); + return NULL; + } + if (!i) { + a->child = n; + } else { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if (count < 0) { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) { + n = cJSON_CreateNumber(numbers[i]); + if (!n) { + cJSON_Delete(a); + return NULL; + } + if (!i) { + a->child = n; + } else { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if (count < 0) { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) { + n = cJSON_CreateString(strings[i]); + if (!n) { + cJSON_Delete(a); + return NULL; + } + if (!i) { + a->child = n; + } else { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) { + newitem->valuestring = (char *)cJSON_strdup((unsigned char *)item->valuestring, &global_hooks); + if (!newitem->valuestring) { + goto fail; + } + } + if (item->string) { + newitem->string = (item->type & cJSON_StringIsConst) ? item->string : (char *)cJSON_strdup(( + unsigned char *)item->string, &global_hooks); + if (!newitem->string) { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) { + goto fail; + } + if (next != NULL) { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } else { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + + return newitem; + +fail: + if (newitem != NULL) { + cJSON_Delete(newitem); + } + + return NULL; +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + unsigned char *into = (unsigned char *)json; + while (*json) { + if (*json == ' ') { + json++; + } else if (*json == '\t') { + /* Whitespace characters. */ + json++; + } else if (*json == '\r') { + json++; + } else if (*json == '\n') { + json++; + } else if ((*json == '/') && (json[1] == '/')) { + /* double-slash comments, to end of line. */ + while (*json && (*json != '\n')) { + json++; + } + } else if ((*json == '/') && (json[1] == '*')) { + /* multiline comments. */ + while (*json && !((*json == '*') && (json[1] == '/'))) { + json++; + } + json += 2; + } else if (*json == '\"') { + /* string literals, which are \" sensitive. */ + *into++ = (unsigned char) * json++; + while (*json && (*json != '\"')) { + if (*json == '\\') { + *into++ = (unsigned char) * json++; + } + *into++ = (unsigned char) * json++; + } + *into++ = (unsigned char) * json++; + } else { + /* All other characters. */ + *into++ = (unsigned char) * json++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON *const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON *const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON *const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON *const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON *const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON *const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON *const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON *const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON *const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON *const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON *const a, const cJSON *const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) { + return true; + } + + switch (a->type & 0xFF) { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (a->valuedouble == b->valuedouble) { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) { + return true; + } + + return false; + + case cJSON_Array: { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + return true; + } + + case cJSON_Object: { + cJSON *a_element = NULL; + cJSON_ArrayForEach(a_element, a) { + /* TODO This has O(n^2) runtime, which is horrible! */ + cJSON *b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/cJSON.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/cJSON.h new file mode 100644 index 00000000..2e3715a6 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/cJSON.h @@ -0,0 +1,247 @@ +/* +Copyright (c) 2009-2017 Dave Gamble and cJSON contributors +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 5 +#define CJSON_VERSION_PATCH 3 + +#include +#include + + /* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + + /* The cJSON structure: */ + typedef struct cJSON + { + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; + } cJSON; + + typedef int cJSON_bool; + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif +#ifdef __WINDOWS__ + + /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: + CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols + CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) + CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + For *nix builds that support visibility attribute, you can define similar behavior by + setting default visibility to hidden by adding + -fvisibility=hidden (for gcc) + or + -xldscope=hidden (for sun cc) + to CFLAGS + then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + */ + + /* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type __stdcall +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall +#endif +#else /* !WIN32 */ +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + + /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + + /* returns the version of cJSON as a string */ + CJSON_PUBLIC(const char*) cJSON_Version(void); + + /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ + /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ + CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); + /* Render a cJSON entity to text for transfer/storage. */ + CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); + /* Render a cJSON entity to text for transfer/storage without any formatting. */ + CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); + /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ + CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); + /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ + /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ + CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); + /* Delete a cJSON entity and all subentities. */ + CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); + + /* Returns the number of items in an array (or object). */ + CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); + /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ + CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); + /* Get item "string" from object. Case insensitive. */ + CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); + CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); + CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); + /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ + CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + + /* These functions check the type of an item */ + CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + + /* These calls create a cJSON item of the appropriate type. */ + CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); + CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); + CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); + CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); + CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); + CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); + /* raw json */ + CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); + CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); + CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + + /* These utilities create an Array of count items. */ + CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); + CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); + CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); + CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); + + /* Append item to the specified array/object. */ + CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); + CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); + /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ + CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); + /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ + CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); + CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + + /* Remove/Detatch items from Arrays/Objects. */ + CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); + CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); + CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); + CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); + CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); + CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); + CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + + /* Update array items. */ + CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ + CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); + CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); + CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem); + CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem); + + /* Duplicate a cJSON item */ + CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); + /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + need to be released. With recurse!=0, it will duplicate any children connected to the item. + The item->next and ->prev pointers are always zero on return from Duplicate. */ + /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ + CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + + + /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ + /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */ + CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); + + CJSON_PUBLIC(void) cJSON_Minify(char *json); + + /* Macros for creating things quickly. */ +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) +#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) +#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s)) + + /* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) + /* helper for the cJSON_SetNumberValue macro */ + CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) + + /* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + + /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ + CJSON_PUBLIC(void *) cJSON_malloc(size_t size); + CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2.h new file mode 100644 index 00000000..8b96d25d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2.h @@ -0,0 +1,5363 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_H +#define NGHTTP2_H + + +#ifdef IOTX_HTTP2_DEBUG +#define DEBUGBUILD +#endif +/* Define WIN32 when build target is Win32 API (borrowed from + libcurl) */ +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +#define WIN32 +#define ssize_t unsigned int +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#if defined(_MSC_VER) && (_MSC_VER < 1800) +/* MSVC < 2013 does not have inttypes.h because it is not C99 + compliant. See compiler macros and version number in + https://sourceforge.net/p/predef/wiki/Compilers/ */ +#include +#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +#include +#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +#include +#include + +#include + +#ifdef NGHTTP2_STATICLIB +#define NGHTTP2_EXTERN +#elif defined(WIN32__) +#ifdef BUILDING_NGHTTP2 +#define NGHTTP2_EXTERN __declspec(dllexport) +#else /* !BUILDING_NGHTTP2 */ +#define NGHTTP2_EXTERN __declspec(dllimport) +#endif /* !BUILDING_NGHTTP2 */ +#else /* !defined(WIN32) */ +#ifdef BUILDING_NGHTTP2 +#define NGHTTP2_EXTERN __attribute__((visibility("default"))) +#else /* !BUILDING_NGHTTP2 */ +#define NGHTTP2_EXTERN +#endif /* !BUILDING_NGHTTP2 */ +#endif /* !defined(WIN32) */ + +/** + * @macro + * + * The protocol version identification string of this library + * supports. This identifier is used if HTTP/2 is used over TLS. + */ +#define NGHTTP2_PROTO_VERSION_ID "h2" +/** + * @macro + * + * The length of :macro:`NGHTTP2_PROTO_VERSION_ID`. + */ +#define NGHTTP2_PROTO_VERSION_ID_LEN 2 + +/** + * @macro + * + * The serialized form of ALPN protocol identifier this library + * supports. Notice that first byte is the length of following + * protocol identifier. This is the same wire format of `TLS ALPN + * extension `_. This is useful + * to process incoming ALPN tokens in wire format. + */ +#define NGHTTP2_PROTO_ALPN "\x2h2" + +/** + * @macro + * + * The length of :macro:`NGHTTP2_PROTO_ALPN`. + */ +#define NGHTTP2_PROTO_ALPN_LEN (sizeof(NGHTTP2_PROTO_ALPN) - 1) + +/** + * @macro + * + * The protocol version identification string of this library + * supports. This identifier is used if HTTP/2 is used over cleartext + * TCP. + */ +#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "h2c" + +/** + * @macro + * + * The length of :macro:`NGHTTP2_CLEARTEXT_PROTO_VERSION_ID`. + */ +#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN 3 + +struct nghttp2_session; +/** + * @struct + * + * The primary structure to hold the resources needed for a HTTP/2 + * session. The details of this structure are intentionally hidden + * from the public API. + */ +typedef struct nghttp2_session nghttp2_session; + +/** + * @macro + * + * The age of :type:`nghttp2_info` + */ +#define NGHTTP2_VERSION_AGE 1 + +#ifndef HTTP2_RECV_BUFFER_LENGHT +#define HTTP2_RECV_BUFFER_LENGHT 16384 +#endif +/** + * @struct + * + * This struct is what `nghttp2_version()` returns. It holds + * information about the particular nghttp2 version. + */ +typedef struct { + /** + * Age of this struct. This instance of nghttp2 sets it to + * :macro:`NGHTTP2_VERSION_AGE` but a future version may bump it and + * add more struct fields at the bottom + */ + int age; + /** + * the :macro:`NGHTTP2_VERSION_NUM` number (since age ==1) + */ + int version_num; + /** + * points to the :macro:`NGHTTP2_VERSION` string (since age ==1) + */ + const char *version_str; + /** + * points to the :macro:`NGHTTP2_PROTO_VERSION_ID` string this + * instance implements (since age ==1) + */ + const char *proto_str; + /* -------- the above fields all exist when age == 1 */ +} nghttp2_info; + +/** + * @macro + * + * The default weight of stream dependency. + */ +#define NGHTTP2_DEFAULT_WEIGHT 16 + +/** + * @macro + * + * The maximum weight of stream dependency. + */ +#define NGHTTP2_MAX_WEIGHT 256 + +/** + * @macro + * + * The minimum weight of stream dependency. + */ +#define NGHTTP2_MIN_WEIGHT 1 + +/** + * @macro + * + * The maximum window size + */ +#define NGHTTP2_MAX_WINDOW_SIZE ((int32_t)((1U << 31) - 1)) + +/** + * @macro + * + * The initial window size for stream level flow control. + */ +#define NGHTTP2_INITIAL_WINDOW_SIZE ((1 << 24) - 1) +/** + * @macro + * + * The initial window size for connection level flow control. + */ +#define NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE ((1 << 24) - 1) + +/** + * @macro + * + * The default header table size. + */ +#define NGHTTP2_DEFAULT_HEADER_TABLE_SIZE (1 << 12) + +/** + * @macro + * + * The client magic string, which is the first 24 bytes byte string of + * client connection preface. + */ +#define NGHTTP2_CLIENT_MAGIC "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" + +/** + * @macro + * + * The length of :macro:`NGHTTP2_CLIENT_MAGIC`. + */ +#define NGHTTP2_CLIENT_MAGIC_LEN 24 + +/** + * @enum + * + * Error codes used in this library. The code range is [-999, -500], + * inclusive. The following values are defined: + */ +typedef enum { + /** + * Invalid argument passed. + */ + NGHTTP2_ERR_INVALID_ARGUMENT = -501, + /** + * Out of buffer space. + */ + NGHTTP2_ERR_BUFFER_ERROR = -502, + /** + * The specified protocol version is not supported. + */ + NGHTTP2_ERR_UNSUPPORTED_VERSION = -503, + /** + * Used as a return value from :type:`nghttp2_send_callback`, + * :type:`nghttp2_recv_callback` and + * :type:`nghttp2_send_data_callback` to indicate that the operation + * would block. + */ + NGHTTP2_ERR_WOULDBLOCK = -504, + /** + * General protocol error + */ + NGHTTP2_ERR_PROTO = -505, + /** + * The frame is invalid. + */ + NGHTTP2_ERR_INVALID_FRAME = -506, + /** + * The peer performed a shutdown on the connection. + */ + NGHTTP2_ERR_EOF = -507, + /** + * Used as a return value from + * :func:`nghttp2_data_source_read_callback` to indicate that data + * transfer is postponed. See + * :func:`nghttp2_data_source_read_callback` for details. + */ + NGHTTP2_ERR_DEFERRED = -508, + /** + * Stream ID has reached the maximum value. Therefore no stream ID + * is available. + */ + NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE = -509, + /** + * The stream is already closed; or the stream ID is invalid. + */ + NGHTTP2_ERR_STREAM_CLOSED = -510, + /** + * RST_STREAM has been added to the outbound queue. The stream is + * in closing state. + */ + NGHTTP2_ERR_STREAM_CLOSING = -511, + /** + * The transmission is not allowed for this stream (e.g., a frame + * with END_STREAM flag set has already sent). + */ + NGHTTP2_ERR_STREAM_SHUT_WR = -512, + /** + * The stream ID is invalid. + */ + NGHTTP2_ERR_INVALID_STREAM_ID = -513, + /** + * The state of the stream is not valid (e.g., DATA cannot be sent + * to the stream if response HEADERS has not been sent). + */ + NGHTTP2_ERR_INVALID_STREAM_STATE = -514, + /** + * Another DATA frame has already been deferred. + */ + NGHTTP2_ERR_DEFERRED_DATA_EXIST = -515, + /** + * Starting new stream is not allowed (e.g., GOAWAY has been sent + * and/or received). + */ + NGHTTP2_ERR_START_STREAM_NOT_ALLOWED = -516, + /** + * GOAWAY has already been sent. + */ + NGHTTP2_ERR_GOAWAY_ALREADY_SENT = -517, + /** + * The received frame contains the invalid header block (e.g., There + * are duplicate header names; or the header names are not encoded + * in US-ASCII character set and not lower cased; or the header name + * is zero-length string; or the header value contains multiple + * in-sequence NUL bytes). + */ + NGHTTP2_ERR_INVALID_HEADER_BLOCK = -518, + /** + * Indicates that the context is not suitable to perform the + * requested operation. + */ + NGHTTP2_ERR_INVALID_STATE = -519, + /** + * The user callback function failed due to the temporal error. + */ + NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE = -521, + /** + * The length of the frame is invalid, either too large or too small. + */ + NGHTTP2_ERR_FRAME_SIZE_ERROR = -522, + /** + * Header block inflate/deflate error. + */ + NGHTTP2_ERR_HEADER_COMP = -523, + /** + * Flow control error + */ + NGHTTP2_ERR_FLOW_CONTROL = -524, + /** + * Insufficient buffer size given to function. + */ + NGHTTP2_ERR_INSUFF_BUFSIZE = -525, + /** + * Callback was paused by the application + */ + NGHTTP2_ERR_PAUSE = -526, + /** + * There are too many in-flight SETTING frame and no more + * transmission of SETTINGS is allowed. + */ + NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS = -527, + /** + * The server push is disabled. + */ + NGHTTP2_ERR_PUSH_DISABLED = -528, + /** + * DATA or HEADERS frame for a given stream has been already + * submitted and has not been fully processed yet. Application + * should wait for the transmission of the previously submitted + * frame before submitting another. + */ + NGHTTP2_ERR_DATA_EXIST = -529, + /** + * The current session is closing due to a connection error or + * `nghttp2_session_terminate_session()` is called. + */ + NGHTTP2_ERR_SESSION_CLOSING = -530, + /** + * Invalid HTTP header field was received and stream is going to be + * closed. + */ + NGHTTP2_ERR_HTTP_HEADER = -531, + /** + * Violation in HTTP messaging rule. + */ + NGHTTP2_ERR_HTTP_MESSAGING = -532, + /** + * Stream was refused. + */ + NGHTTP2_ERR_REFUSED_STREAM = -533, + /** + * Unexpected internal error, but recovered. + */ + NGHTTP2_ERR_INTERNAL = -534, + /** + * Indicates that a processing was canceled. + */ + NGHTTP2_ERR_CANCEL = -535, + /** + * When a local endpoint expects to receive SETTINGS frame, it + * receives an other type of frame. + */ + NGHTTP2_ERR_SETTINGS_EXPECTED = -536, + /** + * The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is + * under unexpected condition and processing was terminated (e.g., + * out of memory). If application receives this error code, it must + * stop using that :type:`nghttp2_session` object and only allowed + * operation for that object is deallocate it using + * `nghttp2_session_del()`. + */ + NGHTTP2_ERR_FATAL = -900, + /** + * Out of memory. This is a fatal error. + */ + NGHTTP2_ERR_NOMEM = -901, + /** + * The user callback function failed. This is a fatal error. + */ + NGHTTP2_ERR_CALLBACK_FAILURE = -902, + /** + * Invalid client magic (see :macro:`NGHTTP2_CLIENT_MAGIC`) was + * received and further processing is not possible. + */ + NGHTTP2_ERR_BAD_CLIENT_MAGIC = -903, + /** + * Possible flooding by peer was detected in this HTTP/2 session. + * Flooding is measured by how many PING and SETTINGS frames with + * ACK flag set are queued for transmission. These frames are + * response for the peer initiated frames, and peer can cause memory + * exhaustion on server side to send these frames forever and does + * not read network. + */ + NGHTTP2_ERR_FLOODED = -904 +} nghttp2_error; + +/** + * @struct + * + * The object representing single contiguous buffer. + */ +typedef struct { + /** + * The pointer to the buffer. + */ + uint8_t *base; + /** + * The length of the buffer. + */ + size_t len; +} nghttp2_vec; + +struct nghttp2_rcbuf; + +/** + * @struct + * + * The object representing reference counted buffer. The details of + * this structure are intentionally hidden from the public API. + */ +typedef struct nghttp2_rcbuf nghttp2_rcbuf; + +/** + * @function + * + * Increments the reference count of |rcbuf| by 1. + */ +NGHTTP2_EXTERN void nghttp2_rcbuf_incref(nghttp2_rcbuf *rcbuf); + +/** + * @function + * + * Decrements the reference count of |rcbuf| by 1. If the reference + * count becomes zero, the object pointed by |rcbuf| will be freed. + * In this case, application must not use |rcbuf| again. + */ +NGHTTP2_EXTERN void nghttp2_rcbuf_decref(nghttp2_rcbuf *rcbuf); + +/** + * @function + * + * Returns the underlying buffer managed by |rcbuf|. + */ +NGHTTP2_EXTERN nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf); + +/** + * @function + * + * Returns nonzero if the underlying buffer is statically allocated, + * and 0 otherwise. This can be useful for language bindings that wish + * to avoid creating duplicate strings for these buffers. + */ +NGHTTP2_EXTERN int nghttp2_rcbuf_is_static(const nghttp2_rcbuf *rcbuf); + +/** + * @enum + * + * The flags for header field name/value pair. + */ +typedef enum { + /** + * No flag set. + */ + NGHTTP2_NV_FLAG_NONE = 0, + /** + * Indicates that this name/value pair must not be indexed ("Literal + * Header Field never Indexed" representation must be used in HPACK + * encoding). Other implementation calls this bit as "sensitive". + */ + NGHTTP2_NV_FLAG_NO_INDEX = 0x01, + /** + * This flag is set solely by application. If this flag is set, the + * library does not make a copy of header field name. This could + * improve performance. + */ + NGHTTP2_NV_FLAG_NO_COPY_NAME = 0x02, + /** + * This flag is set solely by application. If this flag is set, the + * library does not make a copy of header field value. This could + * improve performance. + */ + NGHTTP2_NV_FLAG_NO_COPY_VALUE = 0x04 +} nghttp2_nv_flag; + +/** + * @struct + * + * The name/value pair, which mainly used to represent header fields. + */ +typedef struct { + /** + * The |name| byte string. If this struct is presented from library + * (e.g., :type:`nghttp2_on_frame_recv_callback`), |name| is + * guaranteed to be NULL-terminated. For some callbacks + * (:type:`nghttp2_before_frame_send_callback`, + * :type:`nghttp2_on_frame_send_callback`, and + * :type:`nghttp2_on_frame_not_send_callback`), it may not be + * NULL-terminated if header field is passed from application with + * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`). When application + * is constructing this struct, |name| is not required to be + * NULL-terminated. + */ + uint8_t *name; + /** + * The |value| byte string. If this struct is presented from + * library (e.g., :type:`nghttp2_on_frame_recv_callback`), |value| + * is guaranteed to be NULL-terminated. For some callbacks + * (:type:`nghttp2_before_frame_send_callback`, + * :type:`nghttp2_on_frame_send_callback`, and + * :type:`nghttp2_on_frame_not_send_callback`), it may not be + * NULL-terminated if header field is passed from application with + * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE`). When + * application is constructing this struct, |value| is not required + * to be NULL-terminated. + */ + uint8_t *value; + /** + * The length of the |name|, excluding terminating NULL. + */ + size_t namelen; + /** + * The length of the |value|, excluding terminating NULL. + */ + size_t valuelen; + /** + * Bitwise OR of one or more of :type:`nghttp2_nv_flag`. + */ + uint8_t flags; +} nghttp2_nv; + +/** + * @enum + * + * The frame types in HTTP/2 specification. + */ +typedef enum { + /** + * The DATA frame. + */ + NGHTTP2_DATA = 0, + /** + * The HEADERS frame. + */ + NGHTTP2_HEADERS = 0x01, + /** + * The PRIORITY frame. + */ + NGHTTP2_PRIORITY = 0x02, + /** + * The RST_STREAM frame. + */ + NGHTTP2_RST_STREAM = 0x03, + /** + * The SETTINGS frame. + */ + NGHTTP2_SETTINGS = 0x04, + /** + * The PUSH_PROMISE frame. + */ + NGHTTP2_PUSH_PROMISE = 0x05, + /** + * The PING frame. + */ + NGHTTP2_PING = 0x06, + /** + * The GOAWAY frame. + */ + NGHTTP2_GOAWAY = 0x07, + /** + * The WINDOW_UPDATE frame. + */ + NGHTTP2_WINDOW_UPDATE = 0x08, + /** + * The CONTINUATION frame. This frame type won't be passed to any + * callbacks because the library processes this frame type and its + * preceding HEADERS/PUSH_PROMISE as a single frame. + */ + NGHTTP2_CONTINUATION = 0x09, + /** + * The ALTSVC frame, which is defined in `RFC 7383 + * `_. + */ + NGHTTP2_ALTSVC = 0x0a +} nghttp2_frame_type; + +/** + * @enum + * + * The flags for HTTP/2 frames. This enum defines all flags for all + * frames. + */ +typedef enum { + /** + * No flag set. + */ + NGHTTP2_FLAG_NONE = 0, + /** + * The END_STREAM flag. + */ + NGHTTP2_FLAG_END_STREAM = 0x01, + /** + * The END_HEADERS flag. + */ + NGHTTP2_FLAG_END_HEADERS = 0x04, + /** + * The ACK flag. + */ + NGHTTP2_FLAG_ACK = 0x01, + /** + * The PADDED flag. + */ + NGHTTP2_FLAG_PADDED = 0x08, + /** + * The PRIORITY flag. + */ + NGHTTP2_FLAG_PRIORITY = 0x20 +} nghttp2_flag; + +/** + * @enum + * The SETTINGS ID. + */ +typedef enum { + /** + * SETTINGS_HEADER_TABLE_SIZE + */ + NGHTTP2_SETTINGS_HEADER_TABLE_SIZE = 0x01, + /** + * SETTINGS_ENABLE_PUSH + */ + NGHTTP2_SETTINGS_ENABLE_PUSH = 0x02, + /** + * SETTINGS_MAX_CONCURRENT_STREAMS + */ + NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 0x03, + /** + * SETTINGS_INITIAL_WINDOW_SIZE + */ + NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 0x04, + /** + * SETTINGS_MAX_FRAME_SIZE + */ + NGHTTP2_SETTINGS_MAX_FRAME_SIZE = 0x05, + /** + * SETTINGS_MAX_HEADER_LIST_SIZE + */ + NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 0x06 +} nghttp2_settings_id; +/* Note: If we add SETTINGS, update the capacity of + NGHTTP2_INBOUND_NUM_IV as well */ + +/** + * @macro + * + * .. warning:: + * + * Deprecated. The initial max concurrent streams is 0xffffffffu. + * + * Default maximum number of incoming concurrent streams. Use + * `nghttp2_submit_settings()` with + * :enum:`NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS` to change the + * maximum number of incoming concurrent streams. + * + * .. note:: + * + * The maximum number of outgoing concurrent streams is 100 by + * default. + */ +#define NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1) + +/** + * @enum + * The status codes for the RST_STREAM and GOAWAY frames. + */ +typedef enum { + /** + * No errors. + */ + NGHTTP2_NO_ERROR = 0x00, + /** + * PROTOCOL_ERROR + */ + NGHTTP2_PROTOCOL_ERROR = 0x01, + /** + * INTERNAL_ERROR + */ + NGHTTP2_INTERNAL_ERROR = 0x02, + /** + * FLOW_CONTROL_ERROR + */ + NGHTTP2_FLOW_CONTROL_ERROR = 0x03, + /** + * SETTINGS_TIMEOUT + */ + NGHTTP2_SETTINGS_TIMEOUT = 0x04, + /** + * STREAM_CLOSED + */ + NGHTTP2_STREAM_CLOSED = 0x05, + /** + * FRAME_SIZE_ERROR + */ + NGHTTP2_FRAME_SIZE_ERROR = 0x06, + /** + * REFUSED_STREAM + */ + NGHTTP2_REFUSED_STREAM = 0x07, + /** + * CANCEL + */ + NGHTTP2_CANCEL = 0x08, + /** + * COMPRESSION_ERROR + */ + NGHTTP2_COMPRESSION_ERROR = 0x09, + /** + * CONNECT_ERROR + */ + NGHTTP2_CONNECT_ERROR = 0x0a, + /** + * ENHANCE_YOUR_CALM + */ + NGHTTP2_ENHANCE_YOUR_CALM = 0x0b, + /** + * INADEQUATE_SECURITY + */ + NGHTTP2_INADEQUATE_SECURITY = 0x0c, + /** + * HTTP_1_1_REQUIRED + */ + NGHTTP2_HTTP_1_1_REQUIRED = 0x0d +} nghttp2_error_code; + +/** + * @struct + * The frame header. + */ +typedef struct { + /** + * The length field of this frame, excluding frame header. + */ + size_t length; + /** + * The stream identifier (aka, stream ID) + */ + int32_t stream_id; + /** + * The type of this frame. See `nghttp2_frame_type`. + */ + uint8_t type; + /** + * The flags. + */ + uint8_t flags; + /** + * Reserved bit in frame header. Currently, this is always set to 0 + * and application should not expect something useful in here. + */ + uint8_t reserved; +} nghttp2_frame_hd; + +/** + * @union + * + * This union represents the some kind of data source passed to + * :type:`nghttp2_data_source_read_callback`. + */ +typedef struct { + /** + * The integer field, suitable for a file descriptor. + */ + int fd; + /** + * data length. + */ + int len; + /** + * The pointer to an arbitrary object. + */ + void *ptr; +} nghttp2_data_source; + +/** + * @enum + * + * The flags used to set in |data_flags| output parameter in + * :type:`nghttp2_data_source_read_callback`. + */ +typedef enum { + /** + * No flag set. + */ + NGHTTP2_DATA_FLAG_NONE = 0, + /** + * Indicates EOF was sensed. + */ + NGHTTP2_DATA_FLAG_EOF = 0x01, + /** + * Indicates that END_STREAM flag must not be set even if + * NGHTTP2_DATA_FLAG_EOF is set. Usually this flag is used to send + * trailer fields with `nghttp2_submit_request()` or + * `nghttp2_submit_response()`. + */ + NGHTTP2_DATA_FLAG_NO_END_STREAM = 0x02, + /** + * Indicates that application will send complete DATA frame in + * :type:`nghttp2_send_data_callback`. + */ + NGHTTP2_DATA_FLAG_NO_COPY = 0x04 +} nghttp2_data_flag; + +/** + * @functypedef + * + * Callback function invoked when the library wants to read data from + * the |source|. The read data is sent in the stream |stream_id|. + * The implementation of this function must read at most |length| + * bytes of data from |source| (or possibly other places) and store + * them in |buf| and return number of data stored in |buf|. If EOF is + * reached, set :enum:`NGHTTP2_DATA_FLAG_EOF` flag in |*data_flags|. + * + * Sometime it is desirable to avoid copying data into |buf| and let + * application to send data directly. To achieve this, set + * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` to |*data_flags| (and possibly + * other flags, just like when we do copy), and return the number of + * bytes to send without copying data into |buf|. The library, seeing + * :enum:`NGHTTP2_DATA_FLAG_NO_COPY`, will invoke + * :type:`nghttp2_send_data_callback`. The application must send + * complete DATA frame in that callback. + * + * If this callback is set by `nghttp2_submit_request()`, + * `nghttp2_submit_response()` or `nghttp2_submit_headers()` and + * `nghttp2_submit_data()` with flag parameter + * :enum:`NGHTTP2_FLAG_END_STREAM` set, and + * :enum:`NGHTTP2_DATA_FLAG_EOF` flag is set to |*data_flags|, DATA + * frame will have END_STREAM flag set. Usually, this is expected + * behaviour and all are fine. One exception is send trailer fields. + * You cannot send trailer fields after sending frame with END_STREAM + * set. To avoid this problem, one can set + * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM` along with + * :enum:`NGHTTP2_DATA_FLAG_EOF` to signal the library not to set + * END_STREAM in DATA frame. Then application can use + * `nghttp2_submit_trailer()` to send trailer fields. + * `nghttp2_submit_trailer()` can be called inside this callback. + * + * If the application wants to postpone DATA frames (e.g., + * asynchronous I/O, or reading data blocks for long time), it is + * achieved by returning :enum:`NGHTTP2_ERR_DEFERRED` without reading + * any data in this invocation. The library removes DATA frame from + * the outgoing queue temporarily. To move back deferred DATA frame + * to outgoing queue, call `nghttp2_session_resume_data()`. + * + * By default, |length| is limited to 16KiB at maximum. If peer + * allows larger frames, application can enlarge transmission buffer + * size. See :type:`nghttp2_data_source_read_length_callback` for + * more details. + * + * If the application just wants to return from + * `nghttp2_session_send()` or `nghttp2_session_mem_send()` without + * sending anything, return :enum:`NGHTTP2_ERR_PAUSE`. + * + * In case of error, there are 2 choices. Returning + * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close the stream + * by issuing RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. If a + * different error code is desirable, use + * `nghttp2_submit_rst_stream()` with a desired error code and then + * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Returning + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session + * failure. + */ +typedef ssize_t (*nghttp2_data_source_read_callback)( + nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length, + uint32_t *data_flags, nghttp2_data_source *source, void *user_data); + +/** + * @struct + * + * This struct represents the data source and the way to read a chunk + * of data from it. + */ +typedef struct { + /** + * The data source. + */ + nghttp2_data_source source; + /** + * The callback function to read a chunk of data from the |source|. + */ + nghttp2_data_source_read_callback read_callback; +} nghttp2_data_provider; + +/** + * @struct + * + * The DATA frame. The received data is delivered via + * :type:`nghttp2_on_data_chunk_recv_callback`. + */ +typedef struct { + nghttp2_frame_hd hd; + /** + * The length of the padding in this frame. This includes PAD_HIGH + * and PAD_LOW. + */ + size_t padlen; +} nghttp2_data; + +/** + * @enum + * + * The category of HEADERS, which indicates the role of the frame. In + * HTTP/2 spec, request, response, push response and other arbitrary + * headers (e.g., trailer fields) are all called just HEADERS. To + * give the application the role of incoming HEADERS frame, we define + * several categories. + */ +typedef enum { + /** + * The HEADERS frame is opening new stream, which is analogous to + * SYN_STREAM in SPDY. + */ + NGHTTP2_HCAT_REQUEST = 0, + /** + * The HEADERS frame is the first response headers, which is + * analogous to SYN_REPLY in SPDY. + */ + NGHTTP2_HCAT_RESPONSE = 1, + /** + * The HEADERS frame is the first headers sent against reserved + * stream. + */ + NGHTTP2_HCAT_PUSH_RESPONSE = 2, + /** + * The HEADERS frame which does not apply for the above categories, + * which is analogous to HEADERS in SPDY. If non-final response + * (e.g., status 1xx) is used, final response HEADERS frame will be + * categorized here. + */ + NGHTTP2_HCAT_HEADERS = 3 +} nghttp2_headers_category; + +/** + * @struct + * + * The structure to specify stream dependency. + */ +typedef struct { + /** + * The stream ID of the stream to depend on. Specifying 0 makes + * stream not depend any other stream. + */ + int32_t stream_id; + /** + * The weight of this dependency. + */ + int32_t weight; + /** + * nonzero means exclusive dependency + */ + uint8_t exclusive; +} nghttp2_priority_spec; + +/** + * @struct + * + * The HEADERS frame. It has the following members: + */ +typedef struct { + /** + * The frame header. + */ + nghttp2_frame_hd hd; + /** + * The length of the padding in this frame. This includes PAD_HIGH + * and PAD_LOW. + */ + size_t padlen; + /** + * The priority specification + */ + nghttp2_priority_spec pri_spec; + /** + * The name/value pairs. + */ + nghttp2_nv *nva; + /** + * The number of name/value pairs in |nva|. + */ + size_t nvlen; + /** + * The category of this HEADERS frame. + */ + nghttp2_headers_category cat; +} nghttp2_headers; + +/** + * @struct + * + * The PRIORITY frame. It has the following members: + */ +typedef struct { + /** + * The frame header. + */ + nghttp2_frame_hd hd; + /** + * The priority specification. + */ + nghttp2_priority_spec pri_spec; +} nghttp2_priority; + +/** + * @struct + * + * The RST_STREAM frame. It has the following members: + */ +typedef struct { + /** + * The frame header. + */ + nghttp2_frame_hd hd; + /** + * The error code. See :type:`nghttp2_error_code`. + */ + uint32_t error_code; +} nghttp2_rst_stream; + +/** + * @struct + * + * The SETTINGS ID/Value pair. It has the following members: + */ +typedef struct { + /** + * The SETTINGS ID. See :type:`nghttp2_settings_id`. + */ + int32_t settings_id; + /** + * The value of this entry. + */ + uint32_t value; +} nghttp2_settings_entry; + +/** + * @struct + * + * The SETTINGS frame. It has the following members: + */ +typedef struct { + /** + * The frame header. + */ + nghttp2_frame_hd hd; + /** + * The number of SETTINGS ID/Value pairs in |iv|. + */ + size_t niv; + /** + * The pointer to the array of SETTINGS ID/Value pair. + */ + nghttp2_settings_entry *iv; +} nghttp2_settings; + +/** + * @struct + * + * The PUSH_PROMISE frame. It has the following members: + */ +typedef struct { + /** + * The frame header. + */ + nghttp2_frame_hd hd; + /** + * The length of the padding in this frame. This includes PAD_HIGH + * and PAD_LOW. + */ + size_t padlen; + /** + * The name/value pairs. + */ + nghttp2_nv *nva; + /** + * The number of name/value pairs in |nva|. + */ + size_t nvlen; + /** + * The promised stream ID + */ + int32_t promised_stream_id; + /** + * Reserved bit. Currently this is always set to 0 and application + * should not expect something useful in here. + */ + uint8_t reserved; +} nghttp2_push_promise; + +/** + * @struct + * + * The PING frame. It has the following members: + */ +typedef struct { + /** + * The frame header. + */ + nghttp2_frame_hd hd; + /** + * The opaque data + */ + uint8_t opaque_data[8]; +} nghttp2_ping; + +/** + * @struct + * + * The GOAWAY frame. It has the following members: + */ +typedef struct { + /** + * The frame header. + */ + nghttp2_frame_hd hd; + /** + * The last stream stream ID. + */ + int32_t last_stream_id; + /** + * The error code. See :type:`nghttp2_error_code`. + */ + uint32_t error_code; + /** + * The additional debug data + */ + uint8_t *opaque_data; + /** + * The length of |opaque_data| member. + */ + size_t opaque_data_len; + /** + * Reserved bit. Currently this is always set to 0 and application + * should not expect something useful in here. + */ + uint8_t reserved; +} nghttp2_goaway; + +/** + * @struct + * + * The WINDOW_UPDATE frame. It has the following members: + */ +typedef struct { + /** + * The frame header. + */ + nghttp2_frame_hd hd; + /** + * The window size increment. + */ + int32_t window_size_increment; + /** + * Reserved bit. Currently this is always set to 0 and application + * should not expect something useful in here. + */ + uint8_t reserved; +} nghttp2_window_update; + +/** + * @struct + * + * The extension frame. It has following members: + */ +typedef struct { + /** + * The frame header. + */ + nghttp2_frame_hd hd; + /** + * The pointer to extension payload. The exact pointer type is + * determined by hd.type. + * + * Currently, no extension is supported. This is a place holder for + * the future extensions. + */ + void *payload; +} nghttp2_extension; + +/** + * @union + * + * This union includes all frames to pass them to various function + * calls as nghttp2_frame type. The CONTINUATION frame is omitted + * from here because the library deals with it internally. + */ +typedef union { + /** + * The frame header, which is convenient to inspect frame header. + */ + nghttp2_frame_hd hd; + /** + * The DATA frame. + */ + nghttp2_data data; + /** + * The HEADERS frame. + */ + nghttp2_headers headers; + /** + * The PRIORITY frame. + */ + nghttp2_priority priority; + /** + * The RST_STREAM frame. + */ + nghttp2_rst_stream rst_stream; + /** + * The SETTINGS frame. + */ + nghttp2_settings settings; + /** + * The PUSH_PROMISE frame. + */ + nghttp2_push_promise push_promise; + /** + * The PING frame. + */ + nghttp2_ping ping; + /** + * The GOAWAY frame. + */ + nghttp2_goaway goaway; + /** + * The WINDOW_UPDATE frame. + */ + nghttp2_window_update window_update; + /** + * The extension frame. + */ + nghttp2_extension ext; +} nghttp2_frame; + +/** + * @functypedef + * + * Callback function invoked when |session| wants to send data to the + * remote peer. The implementation of this function must send at most + * |length| bytes of data stored in |data|. The |flags| is currently + * not used and always 0. It must return the number of bytes sent if + * it succeeds. If it cannot send any single byte without blocking, + * it must return :enum:`NGHTTP2_ERR_WOULDBLOCK`. For other errors, + * it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. The + * |user_data| pointer is the third argument passed in to the call to + * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. + * + * This callback is required if the application uses + * `nghttp2_session_send()` to send data to the remote endpoint. If + * the application uses solely `nghttp2_session_mem_send()` instead, + * this callback function is unnecessary. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_send_callback()`. + * + * .. note:: + * + * The |length| may be very small. If that is the case, and + * application disables Nagle algorithm (``TCP_NODELAY``), then just + * writing |data| to the network stack leads to very small packet, + * and it is very inefficient. An application should be responsible + * to buffer up small chunks of data as necessary to avoid this + * situation. + */ +typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session, + const uint8_t *data, size_t length, + int flags, void *user_data); + +/** + * @functypedef + * + * Callback function invoked when :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is + * used in :type:`nghttp2_data_source_read_callback` to send complete + * DATA frame. + * + * The |frame| is a DATA frame to send. The |framehd| is the + * serialized frame header (9 bytes). The |length| is the length of + * application data to send (this does not include padding). The + * |source| is the same pointer passed to + * :type:`nghttp2_data_source_read_callback`. + * + * The application first must send frame header |framehd| of length 9 + * bytes. If ``frame->data.padlen > 0``, send 1 byte of value + * ``frame->data.padlen - 1``. Then send exactly |length| bytes of + * application data. Finally, if ``frame->data.padlen > 1``, send + * ``frame->data.padlen - 1`` bytes of zero as padding. + * + * The application has to send complete DATA frame in this callback. + * If all data were written successfully, return 0. + * + * If it cannot send any data at all, just return + * :enum:`NGHTTP2_ERR_WOULDBLOCK`; the library will call this callback + * with the same parameters later (It is recommended to send complete + * DATA frame at once in this function to deal with error; if partial + * frame data has already sent, it is impossible to send another data + * in that state, and all we can do is tear down connection). When + * data is fully processed, but application wants to make + * `nghttp2_session_mem_send()` or `nghttp2_session_send()` return + * immediately without processing next frames, return + * :enum:`NGHTTP2_ERR_PAUSE`. If application decided to reset this + * stream, return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then + * the library will send RST_STREAM with INTERNAL_ERROR as error code. + * The application can also return + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, which will result in + * connection closure. Returning any other value is treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. + */ +typedef int (*nghttp2_send_data_callback)(nghttp2_session *session, + nghttp2_frame *frame, + const uint8_t *framehd, size_t length, + nghttp2_data_source *source, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked when |session| wants to receive data from + * the remote peer. The implementation of this function must read at + * most |length| bytes of data and store it in |buf|. The |flags| is + * currently not used and always 0. It must return the number of + * bytes written in |buf| if it succeeds. If it cannot read any + * single byte without blocking, it must return + * :enum:`NGHTTP2_ERR_WOULDBLOCK`. If it gets EOF before it reads any + * single byte, it must return :enum:`NGHTTP2_ERR_EOF`. For other + * errors, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * Returning 0 is treated as :enum:`NGHTTP2_ERR_WOULDBLOCK`. The + * |user_data| pointer is the third argument passed in to the call to + * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. + * + * This callback is required if the application uses + * `nghttp2_session_recv()` to receive data from the remote endpoint. + * If the application uses solely `nghttp2_session_mem_recv()` + * instead, this callback function is unnecessary. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_recv_callback()`. + */ +typedef ssize_t (*nghttp2_recv_callback)(nghttp2_session *session, uint8_t *buf, + size_t length, int flags, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked by `nghttp2_session_recv()` and + * `nghttp2_session_mem_recv()` when a frame is received. The + * |user_data| pointer is the third argument passed in to the call to + * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. + * + * If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen`` + * member of their data structure are always ``NULL`` and 0 + * respectively. The header name/value pairs are emitted via + * :type:`nghttp2_on_header_callback`. + * + * For HEADERS, PUSH_PROMISE and DATA frames, this callback may be + * called after stream is closed (see + * :type:`nghttp2_on_stream_close_callback`). The application should + * check that stream is still alive using its own stream management or + * :func:`nghttp2_session_get_stream_user_data()`. + * + * Only HEADERS and DATA frame can signal the end of incoming data. + * If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` is nonzero, the + * |frame| is the last frame from the remote peer in this stream. + * + * This callback won't be called for CONTINUATION frames. + * HEADERS/PUSH_PROMISE + CONTINUATIONs are treated as single frame. + * + * The implementation of this function must return 0 if it succeeds. + * If nonzero value is returned, it is treated as fatal error and + * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions + * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_on_frame_recv_callback()`. + */ +typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session, + const nghttp2_frame *frame, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked by `nghttp2_session_recv()` and + * `nghttp2_session_mem_recv()` when an invalid non-DATA frame is + * received. The error is indicated by the |lib_error_code|, which is + * one of the values defined in :type:`nghttp2_error`. When this + * callback function is invoked, the library automatically submits + * either RST_STREAM or GOAWAY frame. The |user_data| pointer is the + * third argument passed in to the call to + * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. + * + * If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen`` + * member of their data structure are always ``NULL`` and 0 + * respectively. + * + * The implementation of this function must return 0 if it succeeds. + * If nonzero is returned, it is treated as fatal error and + * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions + * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_on_invalid_frame_recv_callback()`. + */ +typedef int (*nghttp2_on_invalid_frame_recv_callback)( + nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked when a chunk of data in DATA frame is + * received. The |stream_id| is the stream ID this DATA frame belongs + * to. The |flags| is the flags of DATA frame which this data chunk + * is contained. ``(flags & NGHTTP2_FLAG_END_STREAM) != 0`` does not + * necessarily mean this chunk of data is the last one in the stream. + * You should use :type:`nghttp2_on_frame_recv_callback` to know all + * data frames are received. The |user_data| pointer is the third + * argument passed in to the call to `nghttp2_session_client_new()` or + * `nghttp2_session_server_new()`. + * + * If the application uses `nghttp2_session_mem_recv()`, it can return + * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()` + * return without processing further input bytes. The memory by + * pointed by the |data| is retained until + * `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called. + * The application must retain the input bytes which was used to + * produce the |data| parameter, because it may refer to the memory + * region included in the input bytes. + * + * The implementation of this function must return 0 if it succeeds. + * If nonzero is returned, it is treated as fatal error, and + * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions + * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_on_data_chunk_recv_callback()`. + */ +typedef int (*nghttp2_on_data_chunk_recv_callback)(nghttp2_session *session, + uint8_t flags, + int32_t stream_id, + const uint8_t *data, + size_t len, void *user_data); + +/** + * @functypedef + * + * Callback function invoked just before the non-DATA frame |frame| is + * sent. The |user_data| pointer is the third argument passed in to + * the call to `nghttp2_session_client_new()` or + * `nghttp2_session_server_new()`. + * + * The implementation of this function must return 0 if it succeeds. + * It can also return :enum:`NGHTTP2_ERR_CANCEL` to cancel the + * transmission of the given frame. + * + * If there is a fatal error while executing this callback, the + * implementation should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, + * which makes `nghttp2_session_send()` and + * `nghttp2_session_mem_send()` functions immediately return + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * + * If the other value is returned, it is treated as if + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. But the + * implementation should not rely on this since the library may define + * new return value to extend its capability. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_before_frame_send_callback()`. + */ +typedef int (*nghttp2_before_frame_send_callback)(nghttp2_session *session, + const nghttp2_frame *frame, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked after the frame |frame| is sent. The + * |user_data| pointer is the third argument passed in to the call to + * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. + * + * The implementation of this function must return 0 if it succeeds. + * If nonzero is returned, it is treated as fatal error and + * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions + * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_on_frame_send_callback()`. + */ +typedef int (*nghttp2_on_frame_send_callback)(nghttp2_session *session, + const nghttp2_frame *frame, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked after the non-DATA frame |frame| is not + * sent because of the error. The error is indicated by the + * |lib_error_code|, which is one of the values defined in + * :type:`nghttp2_error`. The |user_data| pointer is the third + * argument passed in to the call to `nghttp2_session_client_new()` or + * `nghttp2_session_server_new()`. + * + * The implementation of this function must return 0 if it succeeds. + * If nonzero is returned, it is treated as fatal error and + * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions + * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * + * `nghttp2_session_get_stream_user_data()` can be used to get + * associated data. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_on_frame_not_send_callback()`. + */ +typedef int (*nghttp2_on_frame_not_send_callback)(nghttp2_session *session, + const nghttp2_frame *frame, + int lib_error_code, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked when the stream |stream_id| is closed. + * The reason of closure is indicated by the |error_code|. The + * |error_code| is usually one of :enum:`nghttp2_error_code`, but that + * is not guaranteed. The stream_user_data, which was specified in + * `nghttp2_submit_request()` or `nghttp2_submit_headers()`, is still + * available in this function. The |user_data| pointer is the third + * argument passed in to the call to `nghttp2_session_client_new()` or + * `nghttp2_session_server_new()`. + * + * This function is also called for a stream in reserved state. + * + * The implementation of this function must return 0 if it succeeds. + * If nonzero is returned, it is treated as fatal error and + * `nghttp2_session_recv()`, `nghttp2_session_mem_recv()`, + * `nghttp2_session_send()`, and `nghttp2_session_mem_send()` + * functions immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_on_stream_close_callback()`. + */ +typedef int (*nghttp2_on_stream_close_callback)(nghttp2_session *session, + int32_t stream_id, + uint32_t error_code, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked when the reception of header block in + * HEADERS or PUSH_PROMISE is started. Each header name/value pair + * will be emitted by :type:`nghttp2_on_header_callback`. + * + * The ``frame->hd.flags`` may not have + * :enum:`NGHTTP2_FLAG_END_HEADERS` flag set, which indicates that one + * or more CONTINUATION frames are involved. But the application does + * not need to care about that because the header name/value pairs are + * emitted transparently regardless of CONTINUATION frames. + * + * The server applications probably create an object to store + * information about new stream if ``frame->hd.type == + * NGHTTP2_HEADERS`` and ``frame->headers.cat == + * NGHTTP2_HCAT_REQUEST``. If |session| is configured as server side, + * ``frame->headers.cat`` is either ``NGHTTP2_HCAT_REQUEST`` + * containing request headers or ``NGHTTP2_HCAT_HEADERS`` containing + * trailer fields and never get PUSH_PROMISE in this callback. + * + * For the client applications, ``frame->hd.type`` is either + * ``NGHTTP2_HEADERS`` or ``NGHTTP2_PUSH_PROMISE``. In case of + * ``NGHTTP2_HEADERS``, ``frame->headers.cat == + * NGHTTP2_HCAT_RESPONSE`` means that it is the first response + * headers, but it may be non-final response which is indicated by 1xx + * status code. In this case, there may be zero or more HEADERS frame + * with ``frame->headers.cat == NGHTTP2_HCAT_HEADERS`` which has + * non-final response code and finally client gets exactly one HEADERS + * frame with ``frame->headers.cat == NGHTTP2_HCAT_HEADERS`` + * containing final response headers (non-1xx status code). The + * trailer fields also has ``frame->headers.cat == + * NGHTTP2_HCAT_HEADERS`` which does not contain any status code. + * + * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close + * the stream (promised stream if frame is PUSH_PROMISE) by issuing + * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. In this case, + * :type:`nghttp2_on_header_callback` and + * :type:`nghttp2_on_frame_recv_callback` will not be invoked. If a + * different error code is desirable, use + * `nghttp2_submit_rst_stream()` with a desired error code and then + * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Again, use + * ``frame->push_promise.promised_stream_id`` as stream_id parameter + * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE. + * + * The implementation of this function must return 0 if it succeeds. + * It can return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` to + * reset the stream (promised stream if frame is PUSH_PROMISE). For + * critical errors, it must return + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the other value is + * returned, it is treated as if :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` + * is returned. If :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned, + * `nghttp2_session_mem_recv()` function will immediately return + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_on_begin_headers_callback()`. + */ +typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session, + const nghttp2_frame *frame, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked when a header name/value pair is received + * for the |frame|. The |name| of length |namelen| is header name. + * The |value| of length |valuelen| is header value. The |flags| is + * bitwise OR of one or more of :type:`nghttp2_nv_flag`. + * + * If :enum:`NGHTTP2_NV_FLAG_NO_INDEX` is set in |flags|, the receiver + * must not index this name/value pair when forwarding it to the next + * hop. More specifically, "Literal Header Field never Indexed" + * representation must be used in HPACK encoding. + * + * When this callback is invoked, ``frame->hd.type`` is either + * :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`. After all + * header name/value pairs are processed with this callback, and no + * error has been detected, :type:`nghttp2_on_frame_recv_callback` + * will be invoked. If there is an error in decompression, + * :type:`nghttp2_on_frame_recv_callback` for the |frame| will not be + * invoked. + * + * Both |name| and |value| are guaranteed to be NULL-terminated. The + * |namelen| and |valuelen| do not include terminal NULL. If + * `nghttp2_option_set_no_http_messaging()` is used with nonzero + * value, NULL character may be included in |name| or |value| before + * terminating NULL. + * + * Please note that unless `nghttp2_option_set_no_http_messaging()` is + * used, nghttp2 library does perform validation against the |name| + * and the |value| using `nghttp2_check_header_name()` and + * `nghttp2_check_header_value()`. In addition to this, nghttp2 + * performs validation based on HTTP Messaging rule, which is briefly + * explained in :ref:`http-messaging` section. + * + * If the application uses `nghttp2_session_mem_recv()`, it can return + * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()` + * return without processing further input bytes. The memory pointed + * by |frame|, |name| and |value| parameters are retained until + * `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called. + * The application must retain the input bytes which was used to + * produce these parameters, because it may refer to the memory region + * included in the input bytes. + * + * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close + * the stream (promised stream if frame is PUSH_PROMISE) by issuing + * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. In this case, + * :type:`nghttp2_on_header_callback` and + * :type:`nghttp2_on_frame_recv_callback` will not be invoked. If a + * different error code is desirable, use + * `nghttp2_submit_rst_stream()` with a desired error code and then + * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Again, use + * ``frame->push_promise.promised_stream_id`` as stream_id parameter + * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE. + * + * The implementation of this function must return 0 if it succeeds. + * It may return :enum:`NGHTTP2_ERR_PAUSE` or + * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. For other critical + * failures, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If + * the other nonzero value is returned, it is treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned, + * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions + * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_on_header_callback()`. + * + * .. warning:: + * + * Application should properly limit the total buffer size to store + * incoming header fields. Without it, peer may send large number + * of header fields or large header fields to cause out of memory in + * local endpoint. Due to how HPACK works, peer can do this + * effectively without using much memory on their own. + */ +typedef int (*nghttp2_on_header_callback)(nghttp2_session *session, + const nghttp2_frame *frame, + const uint8_t *name, size_t namelen, + const uint8_t *value, size_t valuelen, + uint8_t flags, void *user_data); + +/** + * @functypedef + * + * Callback function invoked when a header name/value pair is received + * for the |frame|. The |name| is header name. The |value| is header + * value. The |flags| is bitwise OR of one or more of + * :type:`nghttp2_nv_flag`. + * + * This callback behaves like :type:`nghttp2_on_header_callback`, + * except that |name| and |value| are stored in reference counted + * buffer. If application wishes to keep these references without + * copying them, use `nghttp2_rcbuf_incref()` to increment their + * reference count. It is the application's responsibility to call + * `nghttp2_rcbuf_decref()` if they called `nghttp2_rcbuf_incref()` so + * as not to leak memory. If the |session| is created by + * `nghttp2_session_server_new3()` or `nghttp2_session_client_new3()`, + * the function to free memory is the one belongs to the mem + * parameter. As long as this free function alives, |name| and + * |value| can live after |session| was destroyed. + */ +typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session, + const nghttp2_frame *frame, + nghttp2_rcbuf *name, + nghttp2_rcbuf *value, uint8_t flags, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked when a invalid header name/value pair is + * received for the |frame|. + * + * The parameter and behaviour are similar to + * :type:`nghttp2_on_header_callback`. The difference is that this + * callback is only invoked when a invalid header name/value pair is + * received which is treated as stream error if this callback is not + * set. Only invalid regular header field are passed to this + * callback. In other words, invalid pseudo header field is not + * passed to this callback. Also header fields which includes upper + * cased latter are also treated as error without passing them to this + * callback. + * + * This callback is only considered if HTTP messaging validation is + * turned on (which is on by default, see + * `nghttp2_option_set_no_http_messaging()`). + * + * With this callback, application inspects the incoming invalid + * field, and it also can reset stream from this callback by returning + * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the + * error code is :enum:`NGHTTP2_PROTOCOL_ERROR`. To change the error + * code, call `nghttp2_submit_rst_stream()` with the error code of + * choice in addition to returning + * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. + * + * If 0 is returned, the header field is ignored, and the stream is + * not reset. + */ +typedef int (*nghttp2_on_invalid_header_callback)( + nghttp2_session *session, const nghttp2_frame *frame, const uint8_t *name, + size_t namelen, const uint8_t *value, size_t valuelen, uint8_t flags, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked when a invalid header name/value pair is + * received for the |frame|. + * + * The parameter and behaviour are similar to + * :type:`nghttp2_on_header_callback2`. The difference is that this + * callback is only invoked when a invalid header name/value pair is + * received which is silently ignored if this callback is not set. + * Only invalid regular header field are passed to this callback. In + * other words, invalid pseudo header field is not passed to this + * callback. Also header fields which includes upper cased latter are + * also treated as error without passing them to this callback. + * + * This callback is only considered if HTTP messaging validation is + * turned on (which is on by default, see + * `nghttp2_option_set_no_http_messaging()`). + * + * With this callback, application inspects the incoming invalid + * field, and it also can reset stream from this callback by returning + * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the + * error code is :enum:`NGHTTP2_INTERNAL_ERROR`. To change the error + * code, call `nghttp2_submit_rst_stream()` with the error code of + * choice in addition to returning + * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. + */ +typedef int (*nghttp2_on_invalid_header_callback2)( + nghttp2_session *session, const nghttp2_frame *frame, nghttp2_rcbuf *name, + nghttp2_rcbuf *value, uint8_t flags, void *user_data); + +/** + * @functypedef + * + * Callback function invoked when the library asks application how + * many padding bytes are required for the transmission of the + * |frame|. The application must choose the total length of payload + * including padded bytes in range [frame->hd.length, max_payloadlen], + * inclusive. Choosing number not in this range will be treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Returning + * ``frame->hd.length`` means no padding is added. Returning + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will make + * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions + * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_select_padding_callback()`. + */ +typedef ssize_t (*nghttp2_select_padding_callback)(nghttp2_session *session, + const nghttp2_frame *frame, + size_t max_payloadlen, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked when library wants to get max length of + * data to send data to the remote peer. The implementation of this + * function should return a value in the following range. [1, + * min(|session_remote_window_size|, |stream_remote_window_size|, + * |remote_max_frame_size|)]. If a value greater than this range is + * returned than the max allow value will be used. Returning a value + * smaller than this range is treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. The |frame_type| is provided + * for future extensibility and identifies the type of frame (see + * :type:`nghttp2_frame_type`) for which to get the length for. + * Currently supported frame types are: :enum:`NGHTTP2_DATA`. + * + * This callback can be used to control the length in bytes for which + * :type:`nghttp2_data_source_read_callback` is allowed to send to the + * remote endpoint. This callback is optional. Returning + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session + * failure. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_data_source_read_length_callback()`. + */ +typedef ssize_t (*nghttp2_data_source_read_length_callback)( + nghttp2_session *session, uint8_t frame_type, int32_t stream_id, + int32_t session_remote_window_size, int32_t stream_remote_window_size, + uint32_t remote_max_frame_size, void *user_data); + +/** + * @functypedef + * + * Callback function invoked when a frame header is received. The + * |hd| points to received frame header. + * + * Unlike :type:`nghttp2_on_frame_recv_callback`, this callback will + * also be called when frame header of CONTINUATION frame is received. + * + * If both :type:`nghttp2_on_begin_frame_callback` and + * :type:`nghttp2_on_begin_headers_callback` are set and HEADERS or + * PUSH_PROMISE is received, :type:`nghttp2_on_begin_frame_callback` + * will be called first. + * + * The implementation of this function must return 0 if it succeeds. + * If nonzero value is returned, it is treated as fatal error and + * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions + * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * + * To set this callback to :type:`nghttp2_session_callbacks`, use + * `nghttp2_session_callbacks_set_on_begin_frame_callback()`. + */ +typedef int (*nghttp2_on_begin_frame_callback)(nghttp2_session *session, + const nghttp2_frame_hd *hd, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked when chunk of extension frame payload is + * received. The |hd| points to frame header. The received + * chunk is |data| of length |len|. + * + * The implementation of this function must return 0 if it succeeds. + * + * To abort processing this extension frame, return + * :enum:`NGHTTP2_ERR_CANCEL`. + * + * If fatal error occurred, application should return + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, + * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions + * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the + * other values are returned, currently they are treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + */ +typedef int (*nghttp2_on_extension_chunk_recv_callback)( + nghttp2_session *session, const nghttp2_frame_hd *hd, const uint8_t *data, + size_t len, void *user_data); + +/** + * @functypedef + * + * Callback function invoked when library asks the application to + * unpack extension payload from its wire format. The extension + * payload has been passed to the application using + * :type:`nghttp2_on_extension_chunk_recv_callback`. The frame header + * is already unpacked by the library and provided as |hd|. + * + * To receive extension frames, the application must tell desired + * extension frame type to the library using + * `nghttp2_option_set_user_recv_extension_type()`. + * + * The implementation of this function may store the pointer to the + * created object as a result of unpacking in |*payload|, and returns + * 0. The pointer stored in |*payload| is opaque to the library, and + * the library does not own its pointer. |*payload| is initialized as + * ``NULL``. The |*payload| is available as ``frame->ext.payload`` in + * :type:`nghttp2_on_frame_recv_callback`. Therefore if application + * can free that memory inside :type:`nghttp2_on_frame_recv_callback` + * callback. Of course, application has a liberty not ot use + * |*payload|, and do its own mechanism to process extension frames. + * + * To abort processing this extension frame, return + * :enum:`NGHTTP2_ERR_CANCEL`. + * + * If fatal error occurred, application should return + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, + * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions + * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the + * other values are returned, currently they are treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + */ +typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session, + void **payload, + const nghttp2_frame_hd *hd, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked when library asks the application to pack + * extension payload in its wire format. The frame header will be + * packed by library. Application must pack payload only. + * ``frame->ext.payload`` is the object passed to + * `nghttp2_submit_extension()` as payload parameter. Application + * must pack extension payload to the |buf| of its capacity |len| + * bytes. The |len| is at least 16KiB. + * + * The implementation of this function should return the number of + * bytes written into |buf| when it succeeds. + * + * To abort processing this extension frame, return + * :enum:`NGHTTP2_ERR_CANCEL`, and + * :type:`nghttp2_on_frame_not_send_callback` will be invoked. + * + * If fatal error occurred, application should return + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, + * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions + * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the + * other values are returned, currently they are treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the return value is + * strictly larger than |len|, it is treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + */ +typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session, + uint8_t *buf, size_t len, + const nghttp2_frame *frame, + void *user_data); + +/** + * @functypedef + * + * Callback function invoked when library provides the error message + * intended for human consumption. This callback is solely for + * debugging purpose. The |msg| is typically NULL-terminated string + * of length |len|. |len| does not include the sentinel NULL + * character. + * + * This function is deprecated. The new application should use + * :type:`nghttp2_error_callback2`. + * + * The format of error message may change between nghttp2 library + * versions. The application should not depend on the particular + * format. + * + * Normally, application should return 0 from this callback. If fatal + * error occurred while doing something in this callback, application + * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, + * library will return immediately with return value + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value + * is returned from this callback, they are treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not + * rely on this details. + */ +typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg, + size_t len, void *user_data); + +/** + * @functypedef + * + * Callback function invoked when library provides the error code, and + * message. This callback is solely for debugging purpose. + * |lib_error_code| is one of error code defined in + * :enum:`nghttp2_error`. The |msg| is typically NULL-terminated + * string of length |len|, and intended for human consumption. |len| + * does not include the sentinel NULL character. + * + * The format of error message may change between nghttp2 library + * versions. The application should not depend on the particular + * format. + * + * Normally, application should return 0 from this callback. If fatal + * error occurred while doing something in this callback, application + * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, + * library will return immediately with return value + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value + * is returned from this callback, they are treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not + * rely on this details. + */ +typedef int (*nghttp2_error_callback2)(nghttp2_session *session, + int lib_error_code, const char *msg, + size_t len, void *user_data); + +struct nghttp2_session_callbacks; + +/** + * @struct + * + * Callback functions for :type:`nghttp2_session`. The details of + * this structure are intentionally hidden from the public API. + */ +typedef struct nghttp2_session_callbacks nghttp2_session_callbacks; + +/** + * @function + * + * Initializes |*callbacks_ptr| with NULL values. + * + * The initialized object can be used when initializing multiple + * :type:`nghttp2_session` objects. + * + * When the application finished using this object, it can use + * `nghttp2_session_callbacks_del()` to free its memory. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int +nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr); + +/** + * @function + * + * Frees any resources allocated for |callbacks|. If |callbacks| is + * ``NULL``, this function does nothing. + */ +NGHTTP2_EXTERN void +nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks); + +/** + * @function + * + * Sets callback function invoked when a session wants to send data to + * the remote peer. This callback is not necessary if the application + * uses solely `nghttp2_session_mem_send()` to serialize data to + * transmit. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_callback( + nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback); + +/** + * @function + * + * Sets callback function invoked when the a session wants to receive + * data from the remote peer. This callback is not necessary if the + * application uses solely `nghttp2_session_mem_recv()` to process + * received data. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_recv_callback( + nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback); + +/** + * @function + * + * Sets callback function invoked by `nghttp2_session_recv()` and + * `nghttp2_session_mem_recv()` when a frame is received. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_recv_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_frame_recv_callback on_frame_recv_callback); + +/** + * @function + * + * Sets callback function invoked by `nghttp2_session_recv()` and + * `nghttp2_session_mem_recv()` when an invalid non-DATA frame is + * received. + */ +NGHTTP2_EXTERN void +nghttp2_session_callbacks_set_on_invalid_frame_recv_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback); + +/** + * @function + * + * Sets callback function invoked when a chunk of data in DATA frame + * is received. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_data_chunk_recv_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback); + +/** + * @function + * + * Sets callback function invoked before a non-DATA frame is sent. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_before_frame_send_callback( + nghttp2_session_callbacks *cbs, + nghttp2_before_frame_send_callback before_frame_send_callback); + +/** + * @function + * + * Sets callback function invoked after a frame is sent. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_send_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_frame_send_callback on_frame_send_callback); + +/** + * @function + * + * Sets callback function invoked when a non-DATA frame is not sent + * because of an error. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_not_send_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_frame_not_send_callback on_frame_not_send_callback); + +/** + * @function + * + * Sets callback function invoked when the stream is closed. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_stream_close_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_stream_close_callback on_stream_close_callback); + +/** + * @function + * + * Sets callback function invoked when the reception of header block + * in HEADERS or PUSH_PROMISE is started. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_headers_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_begin_headers_callback on_begin_headers_callback); + +/** + * @function + * + * Sets callback function invoked when a header name/value pair is + * received. If both + * `nghttp2_session_callbacks_set_on_header_callback()` and + * `nghttp2_session_callbacks_set_on_header_callback2()` are used to + * set callbacks, the latter has the precedence. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_header_callback on_header_callback); + +/** + * @function + * + * Sets callback function invoked when a header name/value pair is + * received. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback2( + nghttp2_session_callbacks *cbs, + nghttp2_on_header_callback2 on_header_callback2); + +/** + * @function + * + * Sets callback function invoked when a invalid header name/value + * pair is received. If both + * `nghttp2_session_callbacks_set_on_invalid_header_callback()` and + * `nghttp2_session_callbacks_set_on_invalid_header_callback2()` are + * used to set callbacks, the latter takes the precedence. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_invalid_header_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_invalid_header_callback on_invalid_header_callback); + +/** + * @function + * + * Sets callback function invoked when a invalid header name/value + * pair is received. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_invalid_header_callback2( + nghttp2_session_callbacks *cbs, + nghttp2_on_invalid_header_callback2 on_invalid_header_callback2); + +/** + * @function + * + * Sets callback function invoked when the library asks application + * how many padding bytes are required for the transmission of the + * given frame. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_select_padding_callback( + nghttp2_session_callbacks *cbs, + nghttp2_select_padding_callback select_padding_callback); + +/** + * @function + * + * Sets callback function determine the length allowed in + * :type:`nghttp2_data_source_read_callback`. + */ +NGHTTP2_EXTERN void +nghttp2_session_callbacks_set_data_source_read_length_callback( + nghttp2_session_callbacks *cbs, + nghttp2_data_source_read_length_callback data_source_read_length_callback); + +/** + * @function + * + * Sets callback function invoked when a frame header is received. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_frame_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_begin_frame_callback on_begin_frame_callback); + +/** + * @function + * + * Sets callback function invoked when + * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is used in + * :type:`nghttp2_data_source_read_callback` to avoid data copy. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_data_callback( + nghttp2_session_callbacks *cbs, + nghttp2_send_data_callback send_data_callback); + +/** + * @function + * + * Sets callback function invoked when the library asks the + * application to pack extension frame payload in wire format. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_pack_extension_callback( + nghttp2_session_callbacks *cbs, + nghttp2_pack_extension_callback pack_extension_callback); + +/** + * @function + * + * Sets callback function invoked when the library asks the + * application to unpack extension frame payload from wire format. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_unpack_extension_callback( + nghttp2_session_callbacks *cbs, + nghttp2_unpack_extension_callback unpack_extension_callback); + +/** + * @function + * + * Sets callback function invoked when chunk of extension frame + * payload is received. + */ +NGHTTP2_EXTERN void +nghttp2_session_callbacks_set_on_extension_chunk_recv_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback); + +/** + * @function + * + * Sets callback function invoked when library tells error message to + * the application. + * + * This function is deprecated. The new application should use + * `nghttp2_session_callbacks_set_error_callback2()`. + * + * If both :type:`nghttp2_error_callback` and + * :type:`nghttp2_error_callback2` are set, the latter takes + * precedence. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback( + nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback); + +/** + * @function + * + * Sets callback function invoked when library tells error code, and + * message to the application. + * + * If both :type:`nghttp2_error_callback` and + * :type:`nghttp2_error_callback2` are set, the latter takes + * precedence. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback2( + nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2); + +/** + * @functypedef + * + * Custom memory allocator to replace malloc(). The |mem_user_data| + * is the mem_user_data member of :type:`nghttp2_mem` structure. + */ +typedef void *(*nghttp2_malloc)(size_t size, void *mem_user_data); + +/** + * @functypedef + * + * Custom memory allocator to replace free(). The |mem_user_data| is + * the mem_user_data member of :type:`nghttp2_mem` structure. + */ +typedef void (*nghttp2_free)(void *ptr, void *mem_user_data); + +/** + * @functypedef + * + * Custom memory allocator to replace calloc(). The |mem_user_data| + * is the mem_user_data member of :type:`nghttp2_mem` structure. + */ +typedef void *(*nghttp2_calloc)(size_t nmemb, size_t size, void *mem_user_data); + +/** + * @functypedef + * + * Custom memory allocator to replace realloc(). The |mem_user_data| + * is the mem_user_data member of :type:`nghttp2_mem` structure. + */ +typedef void *(*nghttp2_realloc)(void *ptr, size_t size, void *mem_user_data); + +/** + * @struct + * + * Custom memory allocator functions and user defined pointer. The + * |mem_user_data| member is passed to each allocator function. This + * can be used, for example, to achieve per-session memory pool. + * + * In the following example code, ``my_malloc``, ``my_free``, + * ``my_calloc`` and ``my_realloc`` are the replacement of the + * standard allocators ``malloc``, ``free``, ``calloc`` and + * ``realloc`` respectively:: + * + * void *my_malloc_cb(size_t size, void *mem_user_data) { + * return my_malloc(size); + * } + * + * void my_free_cb(void *ptr, void *mem_user_data) { my_free(ptr); } + * + * void *my_calloc_cb(size_t nmemb, size_t size, void *mem_user_data) { + * return my_calloc(nmemb, size); + * } + * + * void *my_realloc_cb(void *ptr, size_t size, void *mem_user_data) { + * return my_realloc(ptr, size); + * } + * + * void session_new() { + * nghttp2_session *session; + * nghttp2_session_callbacks *callbacks; + * nghttp2_mem mem = {NULL, my_malloc_cb, my_free_cb, my_calloc_cb, + * my_realloc_cb}; + * + * ... + * + * nghttp2_session_client_new3(&session, callbacks, NULL, NULL, &mem); + * + * ... + * } + */ +typedef struct { + /** + * An arbitrary user supplied data. This is passed to each + * allocator function. + */ + void *mem_user_data; + /** + * Custom allocator function to replace malloc(). + */ + nghttp2_malloc malloc; + /** + * Custom allocator function to replace free(). + */ + nghttp2_free free; + /** + * Custom allocator function to replace calloc(). + */ + nghttp2_calloc calloc; + /** + * Custom allocator function to replace realloc(). + */ + nghttp2_realloc realloc; +} nghttp2_mem; + +struct nghttp2_option; + +/** + * @struct + * + * Configuration options for :type:`nghttp2_session`. The details of + * this structure are intentionally hidden from the public API. + */ +typedef struct nghttp2_option nghttp2_option; + +/** + * @function + * + * Initializes |*option_ptr| with default values. + * + * When the application finished using this object, it can use + * `nghttp2_option_del()` to free its memory. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int nghttp2_option_new(nghttp2_option **option_ptr); + +/** + * @function + * + * Frees any resources allocated for |option|. If |option| is + * ``NULL``, this function does nothing. + */ +NGHTTP2_EXTERN void nghttp2_option_del(nghttp2_option *option); + +/** + * @function + * + * This option prevents the library from sending WINDOW_UPDATE for a + * connection automatically. If this option is set to nonzero, the + * library won't send WINDOW_UPDATE for DATA until application calls + * `nghttp2_session_consume()` to indicate the consumed amount of + * data. Don't use `nghttp2_submit_window_update()` for this purpose. + * By default, this option is set to zero. + */ +NGHTTP2_EXTERN void +nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val); + +/** + * @function + * + * This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of + * remote endpoint as if it is received in SETTINGS frame. Without + * specifying this option, before the local endpoint receives + * SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote + * endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. This may + * cause problem if local endpoint submits lots of requests initially + * and sending them at once to the remote peer may lead to the + * rejection of some requests. Specifying this option to the sensible + * value, say 100, may avoid this kind of issue. This value will be + * overwritten if the local endpoint receives + * SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint. + */ +NGHTTP2_EXTERN void +nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option, + uint32_t val); + +/** + * @function + * + * By default, nghttp2 library, if configured as server, requires + * first 24 bytes of client magic byte string (MAGIC). In most cases, + * this will simplify the implementation of server. But sometimes + * server may want to detect the application protocol based on first + * few bytes on clear text communication. + * + * If this option is used with nonzero |val|, nghttp2 library does not + * handle MAGIC. It still checks following SETTINGS frame. This + * means that applications should deal with MAGIC by themselves. + * + * If this option is not used or used with zero value, if MAGIC does + * not match :macro:`NGHTTP2_CLIENT_MAGIC`, `nghttp2_session_recv()` + * and `nghttp2_session_mem_recv()` will return error + * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal error. + */ +NGHTTP2_EXTERN void +nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val); + +/** + * @function + * + * By default, nghttp2 library enforces subset of HTTP Messaging rules + * described in `HTTP/2 specification, section 8 + * `_. See + * :ref:`http-messaging` section for details. For those applications + * who use nghttp2 library as non-HTTP use, give nonzero to |val| to + * disable this enforcement. Please note that disabling this feature + * does not change the fundamental client and server model of HTTP. + * That is, even if the validation is disabled, only client can send + * requests. + */ +NGHTTP2_EXTERN void nghttp2_option_set_no_http_messaging(nghttp2_option *option, + int val); + +/** + * @function + * + * RFC 7540 does not enforce any limit on the number of incoming + * reserved streams (in RFC 7540 terms, streams in reserved (remote) + * state). This only affects client side, since only server can push + * streams. Malicious server can push arbitrary number of streams, + * and make client's memory exhausted. This option can set the + * maximum number of such incoming streams to avoid possible memory + * exhaustion. If this option is set, and pushed streams are + * automatically closed on reception, without calling user provided + * callback, if they exceed the given limit. The default value is + * 200. If session is configured as server side, this option has no + * effect. Server can control the number of streams to push. + */ +NGHTTP2_EXTERN void +nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option, + uint32_t val); + +/** + * @function + * + * Sets extension frame type the application is willing to handle with + * user defined callbacks (see + * :type:`nghttp2_on_extension_chunk_recv_callback` and + * :type:`nghttp2_unpack_extension_callback`). The |type| is + * extension frame type, and must be strictly greater than 0x9. + * Otherwise, this function does nothing. The application can call + * this function multiple times to set more than one frame type to + * receive. The application does not have to call this function if it + * just sends extension frames. + */ +NGHTTP2_EXTERN void +nghttp2_option_set_user_recv_extension_type(nghttp2_option *option, + uint8_t type); + +/** + * @function + * + * Sets extension frame type the application is willing to receive + * using builtin handler. The |type| is the extension frame type to + * receive, and must be strictly greater than 0x9. Otherwise, this + * function does nothing. The application can call this function + * multiple times to set more than one frame type to receive. The + * application does not have to call this function if it just sends + * extension frames. + * + * If same frame type is passed to both + * `nghttp2_option_set_builtin_recv_extension_type()` and + * `nghttp2_option_set_user_recv_extension_type()`, the latter takes + * precedence. + */ +NGHTTP2_EXTERN void +nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option, + uint8_t type); + +/** + * @function + * + * This option prevents the library from sending PING frame with ACK + * flag set automatically when PING frame without ACK flag set is + * received. If this option is set to nonzero, the library won't send + * PING frame with ACK flag set in the response for incoming PING + * frame. The application can send PING frame with ACK flag set using + * `nghttp2_submit_ping()` with :enum:`NGHTTP2_FLAG_ACK` as flags + * parameter. + */ +NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option, + int val); + +/** + * @function + * + * This option sets the maximum length of header block (a set of + * header fields per one HEADERS frame) to send. The length of a + * given set of header fields is calculated using + * `nghttp2_hd_deflate_bound()`. The default value is 64KiB. If + * application attempts to send header fields larger than this limit, + * the transmission of the frame fails with error code + * :enum:`NGHTTP2_ERR_FRAME_SIZE_ERROR`. + */ +NGHTTP2_EXTERN void +nghttp2_option_set_max_send_header_block_length(nghttp2_option *option, + size_t val); + +/** + * @function + * + * This option sets the maximum dynamic table size for deflating + * header fields. The default value is 4KiB. In HTTP/2, receiver of + * deflated header block can specify maximum dynamic table size. The + * actual maximum size is the minimum of the size receiver specified + * and this option value. + */ +NGHTTP2_EXTERN void +nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option, + size_t val); + +/** + * @function + * + * This option prevents the library from retaining closed streams to + * maintain the priority tree. If this option is set to nonzero, + * applications can discard closed stream completely to save memory. + */ +NGHTTP2_EXTERN void nghttp2_option_set_no_closed_streams(nghttp2_option *option, + int val); + +/** + * @function + * + * Initializes |*session_ptr| for client use. The all members of + * |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr| + * does not store |callbacks|. The |user_data| is an arbitrary user + * supplied data, which will be passed to the callback functions. + * + * The :type:`nghttp2_send_callback` must be specified. If the + * application code uses `nghttp2_session_recv()`, the + * :type:`nghttp2_recv_callback` must be specified. The other members + * of |callbacks| can be ``NULL``. + * + * If this function fails, |*session_ptr| is left untouched. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int +nghttp2_session_client_new(nghttp2_session **session_ptr, + const nghttp2_session_callbacks *callbacks, + void *user_data); + +/** + * @function + * + * Initializes |*session_ptr| for server use. The all members of + * |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr| + * does not store |callbacks|. The |user_data| is an arbitrary user + * supplied data, which will be passed to the callback functions. + * + * The :type:`nghttp2_send_callback` must be specified. If the + * application code uses `nghttp2_session_recv()`, the + * :type:`nghttp2_recv_callback` must be specified. The other members + * of |callbacks| can be ``NULL``. + * + * If this function fails, |*session_ptr| is left untouched. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int +nghttp2_session_server_new(nghttp2_session **session_ptr, + const nghttp2_session_callbacks *callbacks, + void *user_data); + +/** + * @function + * + * Like `nghttp2_session_client_new()`, but with additional options + * specified in the |option|. + * + * The |option| can be ``NULL`` and the call is equivalent to + * `nghttp2_session_client_new()`. + * + * This function does not take ownership |option|. The application is + * responsible for freeing |option| if it finishes using the object. + * + * The library code does not refer to |option| after this function + * returns. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int +nghttp2_session_client_new2(nghttp2_session **session_ptr, + const nghttp2_session_callbacks *callbacks, + void *user_data, const nghttp2_option *option); + +/** + * @function + * + * Like `nghttp2_session_server_new()`, but with additional options + * specified in the |option|. + * + * The |option| can be ``NULL`` and the call is equivalent to + * `nghttp2_session_server_new()`. + * + * This function does not take ownership |option|. The application is + * responsible for freeing |option| if it finishes using the object. + * + * The library code does not refer to |option| after this function + * returns. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int +nghttp2_session_server_new2(nghttp2_session **session_ptr, + const nghttp2_session_callbacks *callbacks, + void *user_data, const nghttp2_option *option); + +/** + * @function + * + * Like `nghttp2_session_client_new2()`, but with additional custom + * memory allocator specified in the |mem|. + * + * The |mem| can be ``NULL`` and the call is equivalent to + * `nghttp2_session_client_new2()`. + * + * This function does not take ownership |mem|. The application is + * responsible for freeing |mem|. + * + * The library code does not refer to |mem| pointer after this + * function returns, so the application can safely free it. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int nghttp2_session_client_new3( + nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks, + void *user_data, const nghttp2_option *option, nghttp2_mem *mem); + +/** + * @function + * + * Like `nghttp2_session_server_new2()`, but with additional custom + * memory allocator specified in the |mem|. + * + * The |mem| can be ``NULL`` and the call is equivalent to + * `nghttp2_session_server_new2()`. + * + * This function does not take ownership |mem|. The application is + * responsible for freeing |mem|. + * + * The library code does not refer to |mem| pointer after this + * function returns, so the application can safely free it. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int nghttp2_session_server_new3( + nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks, + void *user_data, const nghttp2_option *option, nghttp2_mem *mem); + +/** + * @function + * + * Frees any resources allocated for |session|. If |session| is + * ``NULL``, this function does nothing. + */ +NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session); + +/** + * @function + * + * Sends pending frames to the remote peer. + * + * This function retrieves the highest prioritized frame from the + * outbound queue and sends it to the remote peer. It does this as + * many as possible until the user callback + * :type:`nghttp2_send_callback` returns + * :enum:`NGHTTP2_ERR_WOULDBLOCK` or the outbound queue becomes empty. + * This function calls several callback functions which are passed + * when initializing the |session|. Here is the simple time chart + * which tells when each callback is invoked: + * + * 1. Get the next frame to send from outbound queue. + * + * 2. Prepare transmission of the frame. + * + * 3. If the control frame cannot be sent because some preconditions + * are not met (e.g., request HEADERS cannot be sent after GOAWAY), + * :type:`nghttp2_on_frame_not_send_callback` is invoked. Abort + * the following steps. + * + * 4. If the frame is HEADERS, PUSH_PROMISE or DATA, + * :type:`nghttp2_select_padding_callback` is invoked. + * + * 5. If the frame is request HEADERS, the stream is opened here. + * + * 6. :type:`nghttp2_before_frame_send_callback` is invoked. + * + * 7. If :enum:`NGHTTP2_ERR_CANCEL` is returned from + * :type:`nghttp2_before_frame_send_callback`, the current frame + * transmission is canceled, and + * :type:`nghttp2_on_frame_not_send_callback` is invoked. Abort + * the following steps. + * + * 8. :type:`nghttp2_send_callback` is invoked one or more times to + * send the frame. + * + * 9. :type:`nghttp2_on_frame_send_callback` is invoked. + * + * 10. If the transmission of the frame triggers closure of the + * stream, the stream is closed and + * :type:`nghttp2_on_stream_close_callback` is invoked. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` + * The callback function failed. + */ +NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session); + +/** + * @function + * + * Returns the serialized data to send. + * + * This function behaves like `nghttp2_session_send()` except that it + * does not use :type:`nghttp2_send_callback` to transmit data. + * Instead, it assigns the pointer to the serialized data to the + * |*data_ptr| and returns its length. The other callbacks are called + * in the same way as they are in `nghttp2_session_send()`. + * + * If no data is available to send, this function returns 0. + * + * This function may not return all serialized data in one invocation. + * To get all data, call this function repeatedly until it returns 0 + * or one of negative error codes. + * + * The assigned |*data_ptr| is valid until the next call of + * `nghttp2_session_mem_send()` or `nghttp2_session_send()`. + * + * The caller must send all data before sending the next chunk of + * data. + * + * This function returns the length of the data pointed by the + * |*data_ptr| if it succeeds, or one of the following negative error + * codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * + * .. note:: + * + * This function may produce very small byte string. If that is the + * case, and application disables Nagle algorithm (``TCP_NODELAY``), + * then writing this small chunk leads to very small packet, and it + * is very inefficient. An application should be responsible to + * buffer up small chunks of data as necessary to avoid this + * situation. + */ +NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session, + const uint8_t **data_ptr); + +/** + * @function + * + * Receives frames from the remote peer. + * + * This function receives as many frames as possible until the user + * callback :type:`nghttp2_recv_callback` returns + * :enum:`NGHTTP2_ERR_WOULDBLOCK`. This function calls several + * callback functions which are passed when initializing the + * |session|. Here is the simple time chart which tells when each + * callback is invoked: + * + * 1. :type:`nghttp2_recv_callback` is invoked one or more times to + * receive frame header. + * + * 2. When frame header is received, + * :type:`nghttp2_on_begin_frame_callback` is invoked. + * + * 3. If the frame is DATA frame: + * + * 1. :type:`nghttp2_recv_callback` is invoked to receive DATA + * payload. For each chunk of data, + * :type:`nghttp2_on_data_chunk_recv_callback` is invoked. + * + * 2. If one DATA frame is completely received, + * :type:`nghttp2_on_frame_recv_callback` is invoked. If the + * reception of the frame triggers the closure of the stream, + * :type:`nghttp2_on_stream_close_callback` is invoked. + * + * 4. If the frame is the control frame: + * + * 1. :type:`nghttp2_recv_callback` is invoked one or more times to + * receive whole frame. + * + * 2. If the received frame is valid, then following actions are + * taken. If the frame is either HEADERS or PUSH_PROMISE, + * :type:`nghttp2_on_begin_headers_callback` is invoked. Then + * :type:`nghttp2_on_header_callback` is invoked for each header + * name/value pair. For invalid header field, + * :type:`nghttp2_on_invalid_header_callback` is called. After + * all name/value pairs are emitted successfully, + * :type:`nghttp2_on_frame_recv_callback` is invoked. For other + * frames, :type:`nghttp2_on_frame_recv_callback` is invoked. + * If the reception of the frame triggers the closure of the + * stream, :type:`nghttp2_on_stream_close_callback` is invoked. + * + * 3. If the received frame is unpacked but is interpreted as + * invalid, :type:`nghttp2_on_invalid_frame_recv_callback` is + * invoked. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_EOF` + * The remote peer did shutdown on the connection. + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` + * The callback function failed. + * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC` + * Invalid client magic was detected. This error only returns + * when |session| was configured as server and + * `nghttp2_option_set_no_recv_client_magic()` is not used with + * nonzero value. + * :enum:`NGHTTP2_ERR_FLOODED` + * Flooding was detected in this HTTP/2 session, and it must be + * closed. This is most likely caused by misbehaviour of peer. + */ +NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session); + +/** + * @function + * + * Processes data |in| as an input from the remote endpoint. The + * |inlen| indicates the number of bytes in the |in|. + * + * This function behaves like `nghttp2_session_recv()` except that it + * does not use :type:`nghttp2_recv_callback` to receive data; the + * |in| is the only data for the invocation of this function. If all + * bytes are processed, this function returns. The other callbacks + * are called in the same way as they are in `nghttp2_session_recv()`. + * + * In the current implementation, this function always tries to + * processes all input data unless either an error occurs or + * :enum:`NGHTTP2_ERR_PAUSE` is returned from + * :type:`nghttp2_on_header_callback` or + * :type:`nghttp2_on_data_chunk_recv_callback`. If + * :enum:`NGHTTP2_ERR_PAUSE` is used, the return value includes the + * number of bytes which was used to produce the data or frame for the + * callback. + * + * This function returns the number of processed bytes, or one of the + * following negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` + * The callback function failed. + * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC` + * Invalid client magic was detected. This error only returns + * when |session| was configured as server and + * `nghttp2_option_set_no_recv_client_magic()` is not used with + * nonzero value. + * :enum:`NGHTTP2_ERR_FLOODED` + * Flooding was detected in this HTTP/2 session, and it must be + * closed. This is most likely caused by misbehaviour of peer. + */ +NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session, + const uint8_t *in, + size_t inlen); + +/** + * @function + * + * Puts back previously deferred DATA frame in the stream |stream_id| + * to the outbound queue. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The stream does not exist; or no deferred data exist. + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int nghttp2_session_resume_data(nghttp2_session *session, + int32_t stream_id); + +/** + * @function + * + * Returns nonzero value if |session| wants to receive data from the + * remote peer. + * + * If both `nghttp2_session_want_read()` and + * `nghttp2_session_want_write()` return 0, the application should + * drop the connection. + */ +NGHTTP2_EXTERN int nghttp2_session_want_read(nghttp2_session *session); + +/** + * @function + * + * Returns nonzero value if |session| wants to send data to the remote + * peer. + * + * If both `nghttp2_session_want_read()` and + * `nghttp2_session_want_write()` return 0, the application should + * drop the connection. + */ +NGHTTP2_EXTERN int nghttp2_session_want_write(nghttp2_session *session); + +/** + * @function + * + * Returns stream_user_data for the stream |stream_id|. The + * stream_user_data is provided by `nghttp2_submit_request()`, + * `nghttp2_submit_headers()` or + * `nghttp2_session_set_stream_user_data()`. Unless it is set using + * `nghttp2_session_set_stream_user_data()`, if the stream is + * initiated by the remote endpoint, stream_user_data is always + * ``NULL``. If the stream does not exist, this function returns + * ``NULL``. + */ +NGHTTP2_EXTERN void * +nghttp2_session_get_stream_user_data(nghttp2_session *session, + int32_t stream_id); + +/** + * @function + * + * Sets the |stream_user_data| to the stream denoted by the + * |stream_id|. If a stream user data is already set to the stream, + * it is replaced with the |stream_user_data|. It is valid to specify + * ``NULL`` in the |stream_user_data|, which nullifies the associated + * data pointer. + * + * It is valid to set the |stream_user_data| to the stream reserved by + * PUSH_PROMISE frame. + * + * This function returns 0 if it succeeds, or one of following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The stream does not exist + */ +NGHTTP2_EXTERN int +nghttp2_session_set_stream_user_data(nghttp2_session *session, + int32_t stream_id, void *stream_user_data); + +/** + * @function + * + * Sets |user_data| to |session|, overwriting the existing user data + * specified in `nghttp2_session_client_new()`, or + * `nghttp2_session_server_new()`. + */ +NGHTTP2_EXTERN void nghttp2_session_set_user_data(nghttp2_session *session, + void *user_data); + +/** + * @function + * + * Returns the number of frames in the outbound queue. This does not + * include the deferred DATA frames. + */ +NGHTTP2_EXTERN size_t +nghttp2_session_get_outbound_queue_size(nghttp2_session *session); + +/** + * @function + * + * Returns the number of DATA payload in bytes received without + * WINDOW_UPDATE transmission for the stream |stream_id|. The local + * (receive) window size can be adjusted by + * `nghttp2_submit_window_update()`. This function takes into account + * that and returns effective data length. In particular, if the + * local window size is reduced by submitting negative + * window_size_increment with `nghttp2_submit_window_update()`, this + * function returns the number of bytes less than actually received. + * + * This function returns -1 if it fails. + */ +NGHTTP2_EXTERN int32_t nghttp2_session_get_stream_effective_recv_data_length( + nghttp2_session *session, int32_t stream_id); + +/** + * @function + * + * Returns the local (receive) window size for the stream |stream_id|. + * The local window size can be adjusted by + * `nghttp2_submit_window_update()`. This function takes into account + * that and returns effective window size. + * + * This function does not take into account the amount of received + * data from the remote endpoint. Use + * `nghttp2_session_get_stream_local_window_size()` to know the amount + * of data the remote endpoint can send without receiving stream level + * WINDOW_UPDATE frame. Note that each stream is still subject to the + * connection level flow control. + * + * This function returns -1 if it fails. + */ +NGHTTP2_EXTERN int32_t nghttp2_session_get_stream_effective_local_window_size( + nghttp2_session *session, int32_t stream_id); + +/** + * @function + * + * Returns the amount of flow-controlled payload (e.g., DATA) that the + * remote endpoint can send without receiving stream level + * WINDOW_UPDATE frame. It is also subject to the connection level + * flow control. So the actual amount of data to send is + * min(`nghttp2_session_get_stream_local_window_size()`, + * `nghttp2_session_get_local_window_size()`). + * + * This function returns -1 if it fails. + */ +NGHTTP2_EXTERN int32_t nghttp2_session_get_stream_local_window_size( + nghttp2_session *session, int32_t stream_id); + +/** + * @function + * + * Returns the number of DATA payload in bytes received without + * WINDOW_UPDATE transmission for a connection. The local (receive) + * window size can be adjusted by `nghttp2_submit_window_update()`. + * This function takes into account that and returns effective data + * length. In particular, if the local window size is reduced by + * submitting negative window_size_increment with + * `nghttp2_submit_window_update()`, this function returns the number + * of bytes less than actually received. + * + * This function returns -1 if it fails. + */ +NGHTTP2_EXTERN int32_t +nghttp2_session_get_effective_recv_data_length(nghttp2_session *session); + +/** + * @function + * + * Returns the local (receive) window size for a connection. The + * local window size can be adjusted by + * `nghttp2_submit_window_update()`. This function takes into account + * that and returns effective window size. + * + * This function does not take into account the amount of received + * data from the remote endpoint. Use + * `nghttp2_session_get_local_window_size()` to know the amount of + * data the remote endpoint can send without receiving + * connection-level WINDOW_UPDATE frame. Note that each stream is + * still subject to the stream level flow control. + * + * This function returns -1 if it fails. + */ +NGHTTP2_EXTERN int32_t +nghttp2_session_get_effective_local_window_size(nghttp2_session *session); + +/** + * @function + * + * Returns the amount of flow-controlled payload (e.g., DATA) that the + * remote endpoint can send without receiving connection level + * WINDOW_UPDATE frame. Note that each stream is still subject to the + * stream level flow control (see + * `nghttp2_session_get_stream_local_window_size()`). + * + * This function returns -1 if it fails. + */ +NGHTTP2_EXTERN int32_t +nghttp2_session_get_local_window_size(nghttp2_session *session); + +/** + * @function + * + * Returns the remote window size for a given stream |stream_id|. + * + * This is the amount of flow-controlled payload (e.g., DATA) that the + * local endpoint can send without stream level WINDOW_UPDATE. There + * is also connection level flow control, so the effective size of + * payload that the local endpoint can actually send is + * min(`nghttp2_session_get_stream_remote_window_size()`, + * `nghttp2_session_get_remote_window_size()`). + * + * This function returns -1 if it fails. + */ +NGHTTP2_EXTERN int32_t nghttp2_session_get_stream_remote_window_size( + nghttp2_session *session, int32_t stream_id); + +/** + * @function + * + * Returns the remote window size for a connection. + * + * This function always succeeds. + */ +NGHTTP2_EXTERN int32_t +nghttp2_session_get_remote_window_size(nghttp2_session *session); + +/** + * @function + * + * Returns 1 if local peer half closed the given stream |stream_id|. + * Returns 0 if it did not. Returns -1 if no such stream exists. + */ +NGHTTP2_EXTERN int +nghttp2_session_get_stream_local_close(nghttp2_session *session, + int32_t stream_id); + +/** + * @function + * + * Returns 1 if remote peer half closed the given stream |stream_id|. + * Returns 0 if it did not. Returns -1 if no such stream exists. + */ +NGHTTP2_EXTERN int +nghttp2_session_get_stream_remote_close(nghttp2_session *session, + int32_t stream_id); + +/** + * @function + * + * Returns the current dynamic table size of HPACK inflater, including + * the overhead 32 bytes per entry described in RFC 7541. + */ +NGHTTP2_EXTERN size_t +nghttp2_session_get_hd_inflate_dynamic_table_size(nghttp2_session *session); + +/** + * @function + * + * Returns the current dynamic table size of HPACK deflater including + * the overhead 32 bytes per entry described in RFC 7541. + */ +NGHTTP2_EXTERN size_t +nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session); + +/** + * @function + * + * Signals the session so that the connection should be terminated. + * + * The last stream ID is the minimum value between the stream ID of a + * stream for which :type:`nghttp2_on_frame_recv_callback` was called + * most recently and the last stream ID we have sent to the peer + * previously. + * + * The |error_code| is the error code of this GOAWAY frame. The + * pre-defined error code is one of :enum:`nghttp2_error_code`. + * + * After the transmission, both `nghttp2_session_want_read()` and + * `nghttp2_session_want_write()` return 0. + * + * This function should be called when the connection should be + * terminated after sending GOAWAY. If the remaining streams should + * be processed after GOAWAY, use `nghttp2_submit_goaway()` instead. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int nghttp2_session_terminate_session(nghttp2_session *session, + uint32_t error_code); + +/** + * @function + * + * Signals the session so that the connection should be terminated. + * + * This function behaves like `nghttp2_session_terminate_session()`, + * but the last stream ID can be specified by the application for fine + * grained control of stream. The HTTP/2 specification does not allow + * last_stream_id to be increased. So the actual value sent as + * last_stream_id is the minimum value between the given + * |last_stream_id| and the last_stream_id we have previously sent to + * the peer. + * + * The |last_stream_id| is peer's stream ID or 0. So if |session| is + * initialized as client, |last_stream_id| must be even or 0. If + * |session| is initialized as server, |last_stream_id| must be odd or + * 0. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |last_stream_id| is invalid. + */ +NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session, + int32_t last_stream_id, + uint32_t error_code); + +/** + * @function + * + * Signals to the client that the server started graceful shutdown + * procedure. + * + * This function is only usable for server. If this function is + * called with client side session, this function returns + * :enum:`NGHTTP2_ERR_INVALID_STATE`. + * + * To gracefully shutdown HTTP/2 session, server should call this + * function to send GOAWAY with last_stream_id (1u << 31) - 1. And + * after some delay (e.g., 1 RTT), send another GOAWAY with the stream + * ID that the server has some processing using + * `nghttp2_submit_goaway()`. See also + * `nghttp2_session_get_last_proc_stream_id()`. + * + * Unlike `nghttp2_submit_goaway()`, this function just sends GOAWAY + * and does nothing more. This is a mere indication to the client + * that session shutdown is imminent. The application should call + * `nghttp2_submit_goaway()` with appropriate last_stream_id after + * this call. + * + * If one or more GOAWAY frame have been already sent by either + * `nghttp2_submit_goaway()` or `nghttp2_session_terminate_session()`, + * this function has no effect. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_STATE` + * The |session| is initialized as client. + */ +NGHTTP2_EXTERN int nghttp2_submit_shutdown_notice(nghttp2_session *session); + +/** + * @function + * + * Returns the value of SETTINGS |id| notified by a remote endpoint. + * The |id| must be one of values defined in + * :enum:`nghttp2_settings_id`. + */ +NGHTTP2_EXTERN uint32_t nghttp2_session_get_remote_settings( + nghttp2_session *session, nghttp2_settings_id id); + +/** + * @function + * + * Returns the value of SETTINGS |id| of local endpoint acknowledged + * by the remote endpoint. The |id| must be one of the values defined + * in :enum:`nghttp2_settings_id`. + */ +NGHTTP2_EXTERN uint32_t nghttp2_session_get_local_settings( + nghttp2_session *session, nghttp2_settings_id id); + +/** + * @function + * + * Tells the |session| that next stream ID is |next_stream_id|. The + * |next_stream_id| must be equal or greater than the value returned + * by `nghttp2_session_get_next_stream_id()`. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |next_stream_id| is strictly less than the value + * `nghttp2_session_get_next_stream_id()` returns; or + * |next_stream_id| is invalid (e.g., even integer for client, or + * odd integer for server). + */ +NGHTTP2_EXTERN int nghttp2_session_set_next_stream_id(nghttp2_session *session, + int32_t next_stream_id); + +/** + * @function + * + * Returns the next outgoing stream ID. Notice that return type is + * uint32_t. If we run out of stream ID for this session, this + * function returns 1 << 31. + */ +NGHTTP2_EXTERN uint32_t +nghttp2_session_get_next_stream_id(nghttp2_session *session); + +/** + * @function + * + * Tells the |session| that |size| bytes for a stream denoted by + * |stream_id| were consumed by application and are ready to + * WINDOW_UPDATE. The consumed bytes are counted towards both + * connection and stream level WINDOW_UPDATE (see + * `nghttp2_session_consume_connection()` and + * `nghttp2_session_consume_stream()` to update consumption + * independently). This function is intended to be used without + * automatic window update (see + * `nghttp2_option_set_no_auto_window_update()`). + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |stream_id| is 0. + * :enum:`NGHTTP2_ERR_INVALID_STATE` + * Automatic WINDOW_UPDATE is not disabled. + */ +NGHTTP2_EXTERN int nghttp2_session_consume(nghttp2_session *session, + int32_t stream_id, size_t size); + +/** + * @function + * + * Like `nghttp2_session_consume()`, but this only tells library that + * |size| bytes were consumed only for connection level. Note that + * HTTP/2 maintains connection and stream level flow control windows + * independently. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_STATE` + * Automatic WINDOW_UPDATE is not disabled. + */ +NGHTTP2_EXTERN int nghttp2_session_consume_connection(nghttp2_session *session, + size_t size); + +/** + * @function + * + * Like `nghttp2_session_consume()`, but this only tells library that + * |size| bytes were consumed only for stream denoted by |stream_id|. + * Note that HTTP/2 maintains connection and stream level flow control + * windows independently. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |stream_id| is 0. + * :enum:`NGHTTP2_ERR_INVALID_STATE` + * Automatic WINDOW_UPDATE is not disabled. + */ +NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session, + int32_t stream_id, + size_t size); + +/** + * @function + * + * Changes priority of existing stream denoted by |stream_id|. The + * new priority specification is |pri_spec|. + * + * The priority is changed silently and instantly, and no PRIORITY + * frame will be sent to notify the peer of this change. This + * function may be useful for server to change the priority of pushed + * stream. + * + * If |session| is initialized as server, and ``pri_spec->stream_id`` + * points to the idle stream, the idle stream is created if it does + * not exist. The created idle stream will depend on root stream + * (stream 0) with weight 16. + * + * Otherwise, if stream denoted by ``pri_spec->stream_id`` is not + * found, we use default priority instead of given |pri_spec|. That + * is make stream depend on root stream with weight 16. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * Attempted to depend on itself; or no stream exist for the given + * |stream_id|; or |stream_id| is 0 + */ +NGHTTP2_EXTERN int +nghttp2_session_change_stream_priority(nghttp2_session *session, + int32_t stream_id, + const nghttp2_priority_spec *pri_spec); + +/** + * @function + * + * Creates idle stream with the given |stream_id|, and priority + * |pri_spec|. + * + * The stream creation is done without sending PRIORITY frame, which + * means that peer does not know about the existence of this idle + * stream in the local endpoint. + * + * RFC 7540 does not disallow the use of creation of idle stream with + * odd or even stream ID regardless of client or server. So this + * function can create odd or even stream ID regardless of client or + * server. But probably it is a bit safer to use the stream ID the + * local endpoint can initiate (in other words, use odd stream ID for + * client, and even stream ID for server), to avoid potential + * collision from peer's instruction. Also we can use + * `nghttp2_session_set_next_stream_id()` to avoid to open created + * idle streams accidentally if we follow this recommendation. + * + * If |session| is initialized as server, and ``pri_spec->stream_id`` + * points to the idle stream, the idle stream is created if it does + * not exist. The created idle stream will depend on root stream + * (stream 0) with weight 16. + * + * Otherwise, if stream denoted by ``pri_spec->stream_id`` is not + * found, we use default priority instead of given |pri_spec|. That + * is make stream depend on root stream with weight 16. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * Attempted to depend on itself; or stream denoted by |stream_id| + * already exists; or |stream_id| cannot be used to create idle + * stream (in other words, local endpoint has already opened + * stream ID greater than or equal to the given stream ID; or + * |stream_id| is 0 + */ +NGHTTP2_EXTERN int +nghttp2_session_create_idle_stream(nghttp2_session *session, int32_t stream_id, + const nghttp2_priority_spec *pri_spec); + +/** + * @function + * + * Performs post-process of HTTP Upgrade request. This function can + * be called from both client and server, but the behavior is very + * different in each other. + * + * .. warning:: + * + * This function is deprecated in favor of + * `nghttp2_session_upgrade2()`, because this function lacks the + * parameter to tell the library the request method used in the + * original HTTP request. This information is required for client + * to validate actual response body length against content-length + * header field (see `nghttp2_option_set_no_http_messaging()`). If + * HEAD is used in request, the length of response body must be 0 + * regardless of value included in content-length header field. + * + * If called from client side, the |settings_payload| must be the + * value sent in ``HTTP2-Settings`` header field and must be decoded + * by base64url decoder. The |settings_payloadlen| is the length of + * |settings_payload|. The |settings_payload| is unpacked and its + * setting values will be submitted using `nghttp2_submit_settings()`. + * This means that the client application code does not need to submit + * SETTINGS by itself. The stream with stream ID=1 is opened and the + * |stream_user_data| is used for its stream_user_data. The opened + * stream becomes half-closed (local) state. + * + * If called from server side, the |settings_payload| must be the + * value received in ``HTTP2-Settings`` header field and must be + * decoded by base64url decoder. The |settings_payloadlen| is the + * length of |settings_payload|. It is treated as if the SETTINGS + * frame with that payload is received. Thus, callback functions for + * the reception of SETTINGS frame will be invoked. The stream with + * stream ID=1 is opened. The |stream_user_data| is ignored. The + * opened stream becomes half-closed (remote). + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |settings_payload| is badly formed. + * :enum:`NGHTTP2_ERR_PROTO` + * The stream ID 1 is already used or closed; or is not available. + */ +NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session, + const uint8_t *settings_payload, + size_t settings_payloadlen, + void *stream_user_data); + +/** + * @function + * + * Performs post-process of HTTP Upgrade request. This function can + * be called from both client and server, but the behavior is very + * different in each other. + * + * If called from client side, the |settings_payload| must be the + * value sent in ``HTTP2-Settings`` header field and must be decoded + * by base64url decoder. The |settings_payloadlen| is the length of + * |settings_payload|. The |settings_payload| is unpacked and its + * setting values will be submitted using `nghttp2_submit_settings()`. + * This means that the client application code does not need to submit + * SETTINGS by itself. The stream with stream ID=1 is opened and the + * |stream_user_data| is used for its stream_user_data. The opened + * stream becomes half-closed (local) state. + * + * If called from server side, the |settings_payload| must be the + * value received in ``HTTP2-Settings`` header field and must be + * decoded by base64url decoder. The |settings_payloadlen| is the + * length of |settings_payload|. It is treated as if the SETTINGS + * frame with that payload is received. Thus, callback functions for + * the reception of SETTINGS frame will be invoked. The stream with + * stream ID=1 is opened. The |stream_user_data| is ignored. The + * opened stream becomes half-closed (remote). + * + * If the request method is HEAD, pass nonzero value to + * |head_request|. Otherwise, pass 0. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |settings_payload| is badly formed. + * :enum:`NGHTTP2_ERR_PROTO` + * The stream ID 1 is already used or closed; or is not available. + */ +NGHTTP2_EXTERN int nghttp2_session_upgrade2(nghttp2_session *session, + const uint8_t *settings_payload, + size_t settings_payloadlen, + int head_request, + void *stream_user_data); + +/** + * @function + * + * Serializes the SETTINGS values |iv| in the |buf|. The size of the + * |buf| is specified by |buflen|. The number of entries in the |iv| + * array is given by |niv|. The required space in |buf| for the |niv| + * entries is ``6*niv`` bytes and if the given buffer is too small, an + * error is returned. This function is used mainly for creating a + * SETTINGS payload to be sent with the ``HTTP2-Settings`` header + * field in an HTTP Upgrade request. The data written in |buf| is NOT + * base64url encoded and the application is responsible for encoding. + * + * This function returns the number of bytes written in |buf|, or one + * of the following negative error codes: + * + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |iv| contains duplicate settings ID or invalid value. + * + * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE` + * The provided |buflen| size is too small to hold the output. + */ +NGHTTP2_EXTERN ssize_t nghttp2_pack_settings_payload( + uint8_t *buf, size_t buflen, const nghttp2_settings_entry *iv, size_t niv); + +/** + * @function + * + * Returns string describing the |lib_error_code|. The + * |lib_error_code| must be one of the :enum:`nghttp2_error`. + */ +NGHTTP2_EXTERN const char *nghttp2_strerror(int lib_error_code); + +/** + * @function + * + * Returns string representation of HTTP/2 error code |error_code| + * (e.g., ``PROTOCOL_ERROR`` is returned if ``error_code == + * NGHTTP2_PROTOCOL_ERROR``). If string representation is unknown for + * given |error_code|, this function returns string ``unknown``. + */ +NGHTTP2_EXTERN const char *nghttp2_http2_strerror(uint32_t error_code); + +/** + * @function + * + * Initializes |pri_spec| with the |stream_id| of the stream to depend + * on with |weight| and its exclusive flag. If |exclusive| is + * nonzero, exclusive flag is set. + * + * The |weight| must be in [:enum:`NGHTTP2_MIN_WEIGHT`, + * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. + */ +NGHTTP2_EXTERN void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec, + int32_t stream_id, + int32_t weight, int exclusive); + +/** + * @function + * + * Initializes |pri_spec| with the default values. The default values + * are: stream_id = 0, weight = :macro:`NGHTTP2_DEFAULT_WEIGHT` and + * exclusive = 0. + */ +NGHTTP2_EXTERN void +nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec); + +/** + * @function + * + * Returns nonzero if the |pri_spec| is filled with default values. + */ +NGHTTP2_EXTERN int +nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); + +/** + * @function + * + * Submits HEADERS frame and optionally one or more DATA frames. + * + * The |pri_spec| is priority specification of this request. ``NULL`` + * means the default priority (see + * `nghttp2_priority_spec_default_init()`). To specify the priority, + * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, + * this function will copy its data members. + * + * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`, + * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is + * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes + * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than + * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. + * + * The |nva| is an array of name/value pair :type:`nghttp2_nv` with + * |nvlen| elements. The application is responsible to include + * required pseudo-header fields (header field whose name starts with + * ":") in |nva| and must place pseudo-headers before regular header + * fields. + * + * This function creates copies of all name/value pairs in |nva|. It + * also lower-cases all names in |nva|. The order of elements in + * |nva| is preserved. For header fields with + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + * and value are not copied respectively. With + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + * pass header field name in lowercase. The application should + * maintain the references to them until + * :type:`nghttp2_on_frame_send_callback` or + * :type:`nghttp2_on_frame_not_send_callback` is called. + * + * HTTP/2 specification has requirement about header fields in the + * request HEADERS. See the specification for more details. + * + * If |data_prd| is not ``NULL``, it provides data which will be sent + * in subsequent DATA frames. In this case, a method that allows + * request message bodies + * (https://tools.ietf.org/html/rfc7231#section-4) must be specified + * with ``:method`` key in |nva| (e.g. ``POST``). This function does + * not take ownership of the |data_prd|. The function copies the + * members of the |data_prd|. If |data_prd| is ``NULL``, HEADERS have + * END_STREAM set. The |stream_user_data| is data associated to the + * stream opened by this request and can be an arbitrary pointer, + * which can be retrieved later by + * `nghttp2_session_get_stream_user_data()`. + * + * This function returns assigned stream ID if it succeeds, or one of + * the following negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` + * No stream ID is available because maximum stream ID was + * reached. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * Trying to depend on itself (new stream ID equals + * ``pri_spec->stream_id``). + * :enum:`NGHTTP2_ERR_PROTO` + * The |session| is server session. + * + * .. warning:: + * + * This function returns assigned stream ID if it succeeds. But + * that stream is not opened yet. The application must not submit + * frame to that stream ID before + * :type:`nghttp2_before_frame_send_callback` is called for this + * frame. + * + */ +NGHTTP2_EXTERN int32_t nghttp2_submit_request( + nghttp2_session *session, const nghttp2_priority_spec *pri_spec, + const nghttp2_nv *nva, size_t nvlen, const nghttp2_data_provider *data_prd, + void *stream_user_data); + +/** + * @function + * + * Submits response HEADERS frame and optionally one or more DATA + * frames against the stream |stream_id|. + * + * The |nva| is an array of name/value pair :type:`nghttp2_nv` with + * |nvlen| elements. The application is responsible to include + * required pseudo-header fields (header field whose name starts with + * ":") in |nva| and must place pseudo-headers before regular header + * fields. + * + * This function creates copies of all name/value pairs in |nva|. It + * also lower-cases all names in |nva|. The order of elements in + * |nva| is preserved. For header fields with + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + * and value are not copied respectively. With + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + * pass header field name in lowercase. The application should + * maintain the references to them until + * :type:`nghttp2_on_frame_send_callback` or + * :type:`nghttp2_on_frame_not_send_callback` is called. + * + * HTTP/2 specification has requirement about header fields in the + * response HEADERS. See the specification for more details. + * + * If |data_prd| is not ``NULL``, it provides data which will be sent + * in subsequent DATA frames. This function does not take ownership + * of the |data_prd|. The function copies the members of the + * |data_prd|. If |data_prd| is ``NULL``, HEADERS will have + * END_STREAM flag set. + * + * This method can be used as normal HTTP response and push response. + * When pushing a resource using this function, the |session| must be + * configured using `nghttp2_session_server_new()` or its variants and + * the target stream denoted by the |stream_id| must be reserved using + * `nghttp2_submit_push_promise()`. + * + * To send non-final response headers (e.g., HTTP status 101), don't + * use this function because this function half-closes the outbound + * stream. Instead, use `nghttp2_submit_headers()` for this purpose. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |stream_id| is 0. + * :enum:`NGHTTP2_ERR_DATA_EXIST` + * DATA or HEADERS has been already submitted and not fully + * processed yet. Normally, this does not happen, but when + * application wrongly calls `nghttp2_submit_response()` twice, + * this may happen. + * :enum:`NGHTTP2_ERR_PROTO` + * The |session| is client session. + * + * .. warning:: + * + * Calling this function twice for the same stream ID may lead to + * program crash. It is generally considered to a programming error + * to commit response twice. + */ +NGHTTP2_EXTERN int +nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, + const nghttp2_nv *nva, size_t nvlen, + const nghttp2_data_provider *data_prd); + +/** + * @function + * + * Submits trailer fields HEADERS against the stream |stream_id|. + * + * The |nva| is an array of name/value pair :type:`nghttp2_nv` with + * |nvlen| elements. The application must not include pseudo-header + * fields (headers whose names starts with ":") in |nva|. + * + * This function creates copies of all name/value pairs in |nva|. It + * also lower-cases all names in |nva|. The order of elements in + * |nva| is preserved. For header fields with + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + * and value are not copied respectively. With + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + * pass header field name in lowercase. The application should + * maintain the references to them until + * :type:`nghttp2_on_frame_send_callback` or + * :type:`nghttp2_on_frame_not_send_callback` is called. + * + * For server, trailer fields must follow response HEADERS or response + * DATA without END_STREAM flat set. The library does not enforce + * this requirement, and applications should do this for themselves. + * If `nghttp2_submit_trailer()` is called before any response HEADERS + * submission (usually by `nghttp2_submit_response()`), the content of + * |nva| will be sent as response headers, which will result in error. + * + * This function has the same effect with `nghttp2_submit_headers()`, + * with flags = :enum:`NGHTTP2_FLAG_END_STREAM` and both pri_spec and + * stream_user_data to NULL. + * + * To submit trailer fields after `nghttp2_submit_response()` is + * called, the application has to specify + * :type:`nghttp2_data_provider` to `nghttp2_submit_response()`. + * Inside of :type:`nghttp2_data_source_read_callback`, when setting + * :enum:`NGHTTP2_DATA_FLAG_EOF`, also set + * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM`. After that, the + * application can send trailer fields using + * `nghttp2_submit_trailer()`. `nghttp2_submit_trailer()` can be used + * inside :type:`nghttp2_data_source_read_callback`. + * + * This function returns 0 if it succeeds and |stream_id| is -1. + * Otherwise, this function returns 0 if it succeeds, or one of the + * following negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |stream_id| is 0. + */ +NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, + int32_t stream_id, + const nghttp2_nv *nva, size_t nvlen); + +/** + * @function + * + * Submits HEADERS frame. The |flags| is bitwise OR of the + * following values: + * + * * :enum:`NGHTTP2_FLAG_END_STREAM` + * + * If |flags| includes :enum:`NGHTTP2_FLAG_END_STREAM`, this frame has + * END_STREAM flag set. + * + * The library handles the CONTINUATION frame internally and it + * correctly sets END_HEADERS to the last sequence of the PUSH_PROMISE + * or CONTINUATION frame. + * + * If the |stream_id| is -1, this frame is assumed as request (i.e., + * request HEADERS frame which opens new stream). In this case, the + * assigned stream ID will be returned. Otherwise, specify stream ID + * in |stream_id|. + * + * The |pri_spec| is priority specification of this request. ``NULL`` + * means the default priority (see + * `nghttp2_priority_spec_default_init()`). To specify the priority, + * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, + * this function will copy its data members. + * + * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`, + * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is + * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes + * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than + * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. + * + * The |nva| is an array of name/value pair :type:`nghttp2_nv` with + * |nvlen| elements. The application is responsible to include + * required pseudo-header fields (header field whose name starts with + * ":") in |nva| and must place pseudo-headers before regular header + * fields. + * + * This function creates copies of all name/value pairs in |nva|. It + * also lower-cases all names in |nva|. The order of elements in + * |nva| is preserved. For header fields with + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + * and value are not copied respectively. With + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + * pass header field name in lowercase. The application should + * maintain the references to them until + * :type:`nghttp2_on_frame_send_callback` or + * :type:`nghttp2_on_frame_not_send_callback` is called. + * + * The |stream_user_data| is a pointer to an arbitrary data which is + * associated to the stream this frame will open. Therefore it is + * only used if this frame opens streams, in other words, it changes + * stream state from idle or reserved to open. + * + * This function is low-level in a sense that the application code can + * specify flags directly. For usual HTTP request, + * `nghttp2_submit_request()` is useful. Likewise, for HTTP response, + * prefer `nghttp2_submit_response()`. + * + * This function returns newly assigned stream ID if it succeeds and + * |stream_id| is -1. Otherwise, this function returns 0 if it + * succeeds, or one of the following negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` + * No stream ID is available because maximum stream ID was + * reached. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |stream_id| is 0; or trying to depend on itself (stream ID + * equals ``pri_spec->stream_id``). + * :enum:`NGHTTP2_ERR_DATA_EXIST` + * DATA or HEADERS has been already submitted and not fully + * processed yet. This happens if stream denoted by |stream_id| + * is in reserved state. + * :enum:`NGHTTP2_ERR_PROTO` + * The |stream_id| is -1, and |session| is server session. + * + * .. warning:: + * + * This function returns assigned stream ID if it succeeds and + * |stream_id| is -1. But that stream is not opened yet. The + * application must not submit frame to that stream ID before + * :type:`nghttp2_before_frame_send_callback` is called for this + * frame. + * + */ +NGHTTP2_EXTERN int32_t nghttp2_submit_headers( + nghttp2_session *session, uint8_t flags, int32_t stream_id, + const nghttp2_priority_spec *pri_spec, const nghttp2_nv *nva, size_t nvlen, + void *stream_user_data); + +/** + * @function + * + * Submits one or more DATA frames to the stream |stream_id|. The + * data to be sent are provided by |data_prd|. If |flags| contains + * :enum:`NGHTTP2_FLAG_END_STREAM`, the last DATA frame has END_STREAM + * flag set. + * + * This function does not take ownership of the |data_prd|. The + * function copies the members of the |data_prd|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_DATA_EXIST` + * DATA or HEADERS has been already submitted and not fully + * processed yet. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |stream_id| is 0. + * :enum:`NGHTTP2_ERR_STREAM_CLOSED` + * The stream was already closed; or the |stream_id| is invalid. + * + * .. note:: + * + * Currently, only one DATA or HEADERS is allowed for a stream at a + * time. Submitting these frames more than once before first DATA + * or HEADERS is finished results in :enum:`NGHTTP2_ERR_DATA_EXIST` + * error code. The earliest callback which tells that previous + * frame is done is :type:`nghttp2_on_frame_send_callback`. In side + * that callback, new data can be submitted using + * `nghttp2_submit_data()`. Of course, all data except for last one + * must not have :enum:`NGHTTP2_FLAG_END_STREAM` flag set in + * |flags|. This sounds a bit complicated, and we recommend to use + * `nghttp2_submit_request()` and `nghttp2_submit_response()` to + * avoid this cascading issue. The experience shows that for HTTP + * use, these two functions are enough to implement both client and + * server. + */ +NGHTTP2_EXTERN int nghttp2_submit_data(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + const nghttp2_data_provider *data_prd); + +/** + * @function + * + * Submits PRIORITY frame to change the priority of stream |stream_id| + * to the priority specification |pri_spec|. + * + * The |flags| is currently ignored and should be + * :enum:`NGHTTP2_FLAG_NONE`. + * + * The |pri_spec| is priority specification of this request. ``NULL`` + * is not allowed for this function. To specify the priority, use + * `nghttp2_priority_spec_init()`. This function will copy its data + * members. + * + * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`, + * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is + * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes + * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than + * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |stream_id| is 0; or the |pri_spec| is NULL; or trying to + * depend on itself. + */ +NGHTTP2_EXTERN int +nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + const nghttp2_priority_spec *pri_spec); + +/** + * @function + * + * Submits RST_STREAM frame to cancel/reject the stream |stream_id| + * with the error code |error_code|. + * + * The pre-defined error code is one of :enum:`nghttp2_error_code`. + * + * The |flags| is currently ignored and should be + * :enum:`NGHTTP2_FLAG_NONE`. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |stream_id| is 0. + */ +NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session, + uint8_t flags, int32_t stream_id, + uint32_t error_code); + +/** + * @function + * + * Stores local settings and submits SETTINGS frame. The |iv| is the + * pointer to the array of :type:`nghttp2_settings_entry`. The |niv| + * indicates the number of :type:`nghttp2_settings_entry`. + * + * The |flags| is currently ignored and should be + * :enum:`NGHTTP2_FLAG_NONE`. + * + * This function does not take ownership of the |iv|. This function + * copies all the elements in the |iv|. + * + * While updating individual stream's local window size, if the window + * size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE, + * RST_STREAM is issued against such a stream. + * + * SETTINGS with :enum:`NGHTTP2_FLAG_ACK` is automatically submitted + * by the library and application could not send it at its will. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |iv| contains invalid value (e.g., initial window size + * strictly greater than (1 << 31) - 1. + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session, + uint8_t flags, + const nghttp2_settings_entry *iv, + size_t niv); + +/** + * @function + * + * Submits PUSH_PROMISE frame. + * + * The |flags| is currently ignored. The library handles the + * CONTINUATION frame internally and it correctly sets END_HEADERS to + * the last sequence of the PUSH_PROMISE or CONTINUATION frame. + * + * The |stream_id| must be client initiated stream ID. + * + * The |nva| is an array of name/value pair :type:`nghttp2_nv` with + * |nvlen| elements. The application is responsible to include + * required pseudo-header fields (header field whose name starts with + * ":") in |nva| and must place pseudo-headers before regular header + * fields. + * + * This function creates copies of all name/value pairs in |nva|. It + * also lower-cases all names in |nva|. The order of elements in + * |nva| is preserved. For header fields with + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + * and value are not copied respectively. With + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + * pass header field name in lowercase. The application should + * maintain the references to them until + * :type:`nghttp2_on_frame_send_callback` or + * :type:`nghttp2_on_frame_not_send_callback` is called. + * + * The |promised_stream_user_data| is a pointer to an arbitrary data + * which is associated to the promised stream this frame will open and + * make it in reserved state. It is available using + * `nghttp2_session_get_stream_user_data()`. The application can + * access it in :type:`nghttp2_before_frame_send_callback` and + * :type:`nghttp2_on_frame_send_callback` of this frame. + * + * The client side is not allowed to use this function. + * + * To submit response headers and data, use + * `nghttp2_submit_response()`. + * + * This function returns assigned promised stream ID if it succeeds, + * or one of the following negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_PROTO` + * This function was invoked when |session| is initialized as + * client. + * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` + * No stream ID is available because maximum stream ID was + * reached. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |stream_id| is 0; The |stream_id| does not designate stream + * that peer initiated. + * :enum:`NGHTTP2_ERR_STREAM_CLOSED` + * The stream was already closed; or the |stream_id| is invalid. + * + * .. warning:: + * + * This function returns assigned promised stream ID if it succeeds. + * As of 1.16.0, stream object for pushed resource is created when + * this function succeeds. In that case, the application can submit + * push response for the promised frame. + * + * In 1.15.0 or prior versions, pushed stream is not opened yet when + * this function succeeds. The application must not submit frame to + * that stream ID before :type:`nghttp2_before_frame_send_callback` + * is called for this frame. + * + */ +NGHTTP2_EXTERN int32_t nghttp2_submit_push_promise( + nghttp2_session *session, uint8_t flags, int32_t stream_id, + const nghttp2_nv *nva, size_t nvlen, void *promised_stream_user_data); + +/** + * @function + * + * Submits PING frame. You don't have to send PING back when you + * received PING frame. The library automatically submits PING frame + * in this case. + * + * The |flags| is bitwise OR of 0 or more of the following value. + * + * * :enum:`NGHTTP2_FLAG_ACK` + * + * Unless `nghttp2_option_set_no_auto_ping_ack()` is used, the |flags| + * should be :enum:`NGHTTP2_FLAG_NONE`. + * + * If the |opaque_data| is non ``NULL``, then it should point to the 8 + * bytes array of memory to specify opaque data to send with PING + * frame. If the |opaque_data| is ``NULL``, zero-cleared 8 bytes will + * be sent as opaque data. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags, + const uint8_t *opaque_data); + +/** + * @function + * + * Submits GOAWAY frame with the last stream ID |last_stream_id| and + * the error code |error_code|. + * + * The pre-defined error code is one of :enum:`nghttp2_error_code`. + * + * The |flags| is currently ignored and should be + * :enum:`NGHTTP2_FLAG_NONE`. + * + * The |last_stream_id| is peer's stream ID or 0. So if |session| is + * initialized as client, |last_stream_id| must be even or 0. If + * |session| is initialized as server, |last_stream_id| must be odd or + * 0. + * + * The HTTP/2 specification says last_stream_id must not be increased + * from the value previously sent. So the actual value sent as + * last_stream_id is the minimum value between the given + * |last_stream_id| and the last_stream_id previously sent to the + * peer. + * + * If the |opaque_data| is not ``NULL`` and |opaque_data_len| is not + * zero, those data will be sent as additional debug data. The + * library makes a copy of the memory region pointed by |opaque_data| + * with the length |opaque_data_len|, so the caller does not need to + * keep this memory after the return of this function. If the + * |opaque_data_len| is 0, the |opaque_data| could be ``NULL``. + * + * After successful transmission of GOAWAY, following things happen. + * All incoming streams having strictly more than |last_stream_id| are + * closed. All incoming HEADERS which starts new stream are simply + * ignored. After all active streams are handled, both + * `nghttp2_session_want_read()` and `nghttp2_session_want_write()` + * return 0 and the application can close session. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |opaque_data_len| is too large; the |last_stream_id| is + * invalid. + */ +NGHTTP2_EXTERN int nghttp2_submit_goaway(nghttp2_session *session, + uint8_t flags, int32_t last_stream_id, + uint32_t error_code, + const uint8_t *opaque_data, + size_t opaque_data_len); + +/** + * @function + * + * Returns the last stream ID of a stream for which + * :type:`nghttp2_on_frame_recv_callback` was invoked most recently. + * The returned value can be used as last_stream_id parameter for + * `nghttp2_submit_goaway()` and + * `nghttp2_session_terminate_session2()`. + * + * This function always succeeds. + */ +NGHTTP2_EXTERN int32_t +nghttp2_session_get_last_proc_stream_id(nghttp2_session *session); + +/** + * @function + * + * Returns nonzero if new request can be sent from local endpoint. + * + * This function return 0 if request is not allowed for this session. + * There are several reasons why request is not allowed. Some of the + * reasons are: session is server; stream ID has been spent; GOAWAY + * has been sent or received. + * + * The application can call `nghttp2_submit_request()` without + * consulting this function. In that case, `nghttp2_submit_request()` + * may return error. Or, request is failed to sent, and + * :type:`nghttp2_on_stream_close_callback` is called. + */ +NGHTTP2_EXTERN int +nghttp2_session_check_request_allowed(nghttp2_session *session); + +/** + * @function + * + * Returns nonzero if |session| is initialized as server side session. + */ +NGHTTP2_EXTERN int +nghttp2_session_check_server_session(nghttp2_session *session); + +/** + * @function + * + * Submits WINDOW_UPDATE frame. + * + * The |flags| is currently ignored and should be + * :enum:`NGHTTP2_FLAG_NONE`. + * + * The |stream_id| is the stream ID to send this WINDOW_UPDATE. To + * send connection level WINDOW_UPDATE, specify 0 to |stream_id|. + * + * If the |window_size_increment| is positive, the WINDOW_UPDATE with + * that value as window_size_increment is queued. If the + * |window_size_increment| is larger than the received bytes from the + * remote endpoint, the local window size is increased by that + * difference. If the sole purpose is to increase the local window + * size, consider to use `nghttp2_session_set_local_window_size()`. + * + * If the |window_size_increment| is negative, the local window size + * is decreased by -|window_size_increment|. If automatic + * WINDOW_UPDATE is enabled + * (`nghttp2_option_set_no_auto_window_update()`), and the library + * decided that the WINDOW_UPDATE should be submitted, then + * WINDOW_UPDATE is queued with the current received bytes count. If + * the sole purpose is to decrease the local window size, consider to + * use `nghttp2_session_set_local_window_size()`. + * + * If the |window_size_increment| is 0, the function does nothing and + * returns 0. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_FLOW_CONTROL` + * The local window size overflow or gets negative. + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session, + uint8_t flags, + int32_t stream_id, + int32_t window_size_increment); + +/** + * @function + * + * Set local window size (local endpoints's window size) to the given + * |window_size| for the given stream denoted by |stream_id|. To + * change connection level window size, specify 0 to |stream_id|. To + * increase window size, this function may submit WINDOW_UPDATE frame + * to transmission queue. + * + * The |flags| is currently ignored and should be + * :enum:`NGHTTP2_FLAG_NONE`. + * + * This sounds similar to `nghttp2_submit_window_update()`, but there + * are 2 differences. The first difference is that this function + * takes the absolute value of window size to set, rather than the + * delta. To change the window size, this may be easier to use since + * the application just declares the intended window size, rather than + * calculating delta. The second difference is that + * `nghttp2_submit_window_update()` affects the received bytes count + * which has not acked yet. By the specification of + * `nghttp2_submit_window_update()`, to strictly increase the local + * window size, we have to submit delta including all received bytes + * count, which might not be desirable in some cases. On the other + * hand, this function does not affect the received bytes count. It + * just sets the local window size to the given value. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |stream_id| is negative. + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int +nghttp2_session_set_local_window_size(nghttp2_session *session, uint8_t flags, + int32_t stream_id, int32_t window_size); + +/** + * @function + * + * Submits extension frame. + * + * Application can pass arbitrary frame flags and stream ID in |flags| + * and |stream_id| respectively. The |payload| is opaque pointer, and + * it can be accessible though ``frame->ext.payload`` in + * :type:`nghttp2_pack_extension_callback`. The library will not own + * passed |payload| pointer. + * + * The application must set :type:`nghttp2_pack_extension_callback` + * using `nghttp2_session_callbacks_set_pack_extension_callback()`. + * + * The application should retain the memory pointed by |payload| until + * the transmission of extension frame is done (which is indicated by + * :type:`nghttp2_on_frame_send_callback`), or transmission fails + * (which is indicated by :type:`nghttp2_on_frame_not_send_callback`). + * If application does not touch this memory region after packing it + * into a wire format, application can free it inside + * :type:`nghttp2_pack_extension_callback`. + * + * The standard HTTP/2 frame cannot be sent with this function, so + * |type| must be strictly grater than 0x9. Otherwise, this function + * will fail with error code :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_INVALID_STATE` + * If :type:`nghttp2_pack_extension_callback` is not set. + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * If |type| specifies standard HTTP/2 frame type. The frame + * types in the rage [0x0, 0x9], both inclusive, are standard + * HTTP/2 frame type, and cannot be sent using this function. + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory + */ +NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session, + uint8_t type, uint8_t flags, + int32_t stream_id, void *payload); + +/** + * @struct + * + * The payload of ALTSVC frame. ALTSVC frame is a non-critical + * extension to HTTP/2. If this frame is received, and + * `nghttp2_option_set_user_recv_extension_type()` is not set, and + * `nghttp2_option_set_builtin_recv_extension_type()` is set for + * :enum:`NGHTTP2_ALTSVC`, ``nghttp2_extension.payload`` will point to + * this struct. + * + * It has the following members: + */ +typedef struct { + /** + * The pointer to origin which this alternative service is + * associated with. This is not necessarily NULL-terminated. + */ + uint8_t *origin; + /** + * The length of the |origin|. + */ + size_t origin_len; + /** + * The pointer to Alt-Svc field value contained in ALTSVC frame. + * This is not necessarily NULL-terminated. + */ + uint8_t *field_value; + /** + * The length of the |field_value|. + */ + size_t field_value_len; +} nghttp2_ext_altsvc; + +/** + * @function + * + * Submits ALTSVC frame. + * + * ALTSVC frame is a non-critical extension to HTTP/2, and defined in + * is defined in `RFC 7383 + * `_. + * + * The |flags| is currently ignored and should be + * :enum:`NGHTTP2_FLAG_NONE`. + * + * The |origin| points to the origin this alternative service is + * associated with. The |origin_len| is the length of the origin. If + * |stream_id| is 0, the origin must be specified. If |stream_id| is + * not zero, the origin must be empty (in other words, |origin_len| + * must be 0). + * + * The ALTSVC frame is only usable from server side. If this function + * is invoked with client side session, this function returns + * :enum:`NGHTTP2_ERR_INVALID_STATE`. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory + * :enum:`NGHTTP2_ERR_INVALID_STATE` + * The function is called from client side session + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The sum of |origin_len| and |field_value_len| is larger than + * 16382; or |origin_len| is 0 while |stream_id| is 0; or + * |origin_len| is not 0 while |stream_id| is not 0. + */ +NGHTTP2_EXTERN int nghttp2_submit_altsvc(nghttp2_session *session, + uint8_t flags, int32_t stream_id, + const uint8_t *origin, + size_t origin_len, + const uint8_t *field_value, + size_t field_value_len); + +/** + * @function + * + * Compares ``lhs->name`` of length ``lhs->namelen`` bytes and + * ``rhs->name`` of length ``rhs->namelen`` bytes. Returns negative + * integer if ``lhs->name`` is found to be less than ``rhs->name``; or + * returns positive integer if ``lhs->name`` is found to be greater + * than ``rhs->name``; or returns 0 otherwise. + */ +NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs, + const nghttp2_nv *rhs); + +/** + * @function + * + * A helper function for dealing with NPN in client side or ALPN in + * server side. The |in| contains peer's protocol list in preferable + * order. The format of |in| is length-prefixed and not + * null-terminated. For example, ``h2`` and + * ``http/1.1`` stored in |in| like this:: + * + * in[0] = 2 + * in[1..2] = "h2" + * in[3] = 8 + * in[4..11] = "http/1.1" + * inlen = 12 + * + * The selection algorithm is as follows: + * + * 1. If peer's list contains HTTP/2 protocol the library supports, + * it is selected and returns 1. The following step is not taken. + * + * 2. If peer's list contains ``http/1.1``, this function selects + * ``http/1.1`` and returns 0. The following step is not taken. + * + * 3. This function selects nothing and returns -1 (So called + * non-overlap case). In this case, |out| and |outlen| are left + * untouched. + * + * Selecting ``h2`` means that ``h2`` is written into |*out| and its + * length (which is 2) is assigned to |*outlen|. + * + * For ALPN, refer to https://tools.ietf.org/html/rfc7301 + * + * See http://technotes.googlecode.com/git/nextprotoneg.html for more + * details about NPN. + * + * For NPN, to use this method you should do something like:: + * + * static int select_next_proto_cb(SSL* ssl, + * unsigned char **out, + * unsigned char *outlen, + * const unsigned char *in, + * unsigned int inlen, + * void *arg) + * { + * int rv; + * rv = nghttp2_select_next_protocol(out, outlen, in, inlen); + * if (rv == -1) { + * return SSL_TLSEXT_ERR_NOACK; + * } + * if (rv == 1) { + * ((MyType*)arg)->http2_selected = 1; + * } + * return SSL_TLSEXT_ERR_OK; + * } + * ... + * SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, my_obj); + * + */ +NGHTTP2_EXTERN int nghttp2_select_next_protocol(unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen); + +/** + * @function + * + * Returns a pointer to a nghttp2_info struct with version information + * about the run-time library in use. The |least_version| argument + * can be set to a 24 bit numerical value for the least accepted + * version number and if the condition is not met, this function will + * return a ``NULL``. Pass in 0 to skip the version checking. + */ +NGHTTP2_EXTERN nghttp2_info *nghttp2_version(int least_version); + +/** + * @function + * + * Returns nonzero if the :type:`nghttp2_error` library error code + * |lib_error| is fatal. + */ +NGHTTP2_EXTERN int nghttp2_is_fatal(int lib_error_code); + +/** + * @function + * + * Returns nonzero if HTTP header field name |name| of length |len| is + * valid according to http://tools.ietf.org/html/rfc7230#section-3.2 + * + * Because this is a header field name in HTTP2, the upper cased alphabet + * is treated as error. + */ +NGHTTP2_EXTERN int nghttp2_check_header_name(const uint8_t *name, size_t len); + +/** + * @function + * + * Returns nonzero if HTTP header field value |value| of length |len| + * is valid according to + * http://tools.ietf.org/html/rfc7230#section-3.2 + */ +NGHTTP2_EXTERN int nghttp2_check_header_value(const uint8_t *value, size_t len); + +/* HPACK API */ + +struct nghttp2_hd_deflater; + +/** + * @struct + * + * HPACK deflater object. + */ +typedef struct nghttp2_hd_deflater nghttp2_hd_deflater; + +/** + * @function + * + * Initializes |*deflater_ptr| for deflating name/values pairs. + * + * The |max_deflate_dynamic_table_size| is the upper bound of header + * table size the deflater will use. + * + * If this function fails, |*deflater_ptr| is left untouched. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int +nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr, + size_t max_deflate_dynamic_table_size); + +/** + * @function + * + * Like `nghttp2_hd_deflate_new()`, but with additional custom memory + * allocator specified in the |mem|. + * + * The |mem| can be ``NULL`` and the call is equivalent to + * `nghttp2_hd_deflate_new()`. + * + * This function does not take ownership |mem|. The application is + * responsible for freeing |mem|. + * + * The library code does not refer to |mem| pointer after this + * function returns, so the application can safely free it. + */ +NGHTTP2_EXTERN int +nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr, + size_t max_deflate_dynamic_table_size, + nghttp2_mem *mem); + +/** + * @function + * + * Deallocates any resources allocated for |deflater|. + */ +NGHTTP2_EXTERN void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater); + +/** + * @function + * + * Changes header table size of the |deflater| to + * |settings_max_dynamic_table_size| bytes. This may trigger eviction + * in the dynamic table. + * + * The |settings_max_dynamic_table_size| should be the value received + * in SETTINGS_HEADER_TABLE_SIZE. + * + * The deflater never uses more memory than + * ``max_deflate_dynamic_table_size`` bytes specified in + * `nghttp2_hd_deflate_new()`. Therefore, if + * |settings_max_dynamic_table_size| > + * ``max_deflate_dynamic_table_size``, resulting maximum table size + * becomes ``max_deflate_dynamic_table_size``. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int +nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, + size_t settings_max_dynamic_table_size); + +/** + * @function + * + * Deflates the |nva|, which has the |nvlen| name/value pairs, into + * the |buf| of length |buflen|. + * + * If |buf| is not large enough to store the deflated header block, + * this function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The + * caller should use `nghttp2_hd_deflate_bound()` to know the upper + * bound of buffer size required to deflate given header name/value + * pairs. + * + * Once this function fails, subsequent call of this function always + * returns :enum:`NGHTTP2_ERR_HEADER_COMP`. + * + * After this function returns, it is safe to delete the |nva|. + * + * This function returns the number of bytes written to |buf| if it + * succeeds, or one of the following negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_HEADER_COMP` + * Deflation process has failed. + * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE` + * The provided |buflen| size is too small to hold the output. + */ +NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, + uint8_t *buf, size_t buflen, + const nghttp2_nv *nva, + size_t nvlen); + +/** + * @function + * + * Deflates the |nva|, which has the |nvlen| name/value pairs, into + * the |veclen| size of buf vector |vec|. The each size of buffer + * must be set in len field of :type:`nghttp2_vec`. If and only if + * one chunk is filled up completely, next chunk will be used. If + * |vec| is not large enough to store the deflated header block, this + * function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller + * should use `nghttp2_hd_deflate_bound()` to know the upper bound of + * buffer size required to deflate given header name/value pairs. + * + * Once this function fails, subsequent call of this function always + * returns :enum:`NGHTTP2_ERR_HEADER_COMP`. + * + * After this function returns, it is safe to delete the |nva|. + * + * This function returns the number of bytes written to |vec| if it + * succeeds, or one of the following negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_HEADER_COMP` + * Deflation process has failed. + * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE` + * The provided |buflen| size is too small to hold the output. + */ +NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater, + const nghttp2_vec *vec, + size_t veclen, + const nghttp2_nv *nva, + size_t nvlen); + +/** + * @function + * + * Returns an upper bound on the compressed size after deflation of + * |nva| of length |nvlen|. + */ +NGHTTP2_EXTERN size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater, + const nghttp2_nv *nva, + size_t nvlen); + +/** + * @function + * + * Returns the number of entries that header table of |deflater| + * contains. This is the sum of the number of static table and + * dynamic table, so the return value is at least 61. + */ +NGHTTP2_EXTERN +size_t nghttp2_hd_deflate_get_num_table_entries(nghttp2_hd_deflater *deflater); + +/** + * @function + * + * Returns the table entry denoted by |idx| from header table of + * |deflater|. The |idx| is 1-based, and idx=1 returns first entry of + * static table. idx=62 returns first entry of dynamic table if it + * exists. Specifying idx=0 is error, and this function returns NULL. + * If |idx| is strictly greater than the number of entries the tables + * contain, this function returns NULL. + */ +NGHTTP2_EXTERN +const nghttp2_nv * +nghttp2_hd_deflate_get_table_entry(nghttp2_hd_deflater *deflater, size_t idx); + +/** + * @function + * + * Returns the used dynamic table size, including the overhead 32 + * bytes per entry described in RFC 7541. + */ +NGHTTP2_EXTERN +size_t nghttp2_hd_deflate_get_dynamic_table_size(nghttp2_hd_deflater *deflater); + +/** + * @function + * + * Returns the maximum dynamic table size. + */ +NGHTTP2_EXTERN +size_t +nghttp2_hd_deflate_get_max_dynamic_table_size(nghttp2_hd_deflater *deflater); + +struct nghttp2_hd_inflater; + +/** + * @struct + * + * HPACK inflater object. + */ +typedef struct nghttp2_hd_inflater nghttp2_hd_inflater; + +/** + * @function + * + * Initializes |*inflater_ptr| for inflating name/values pairs. + * + * If this function fails, |*inflater_ptr| is left untouched. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +NGHTTP2_EXTERN int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr); + +/** + * @function + * + * Like `nghttp2_hd_inflate_new()`, but with additional custom memory + * allocator specified in the |mem|. + * + * The |mem| can be ``NULL`` and the call is equivalent to + * `nghttp2_hd_inflate_new()`. + * + * This function does not take ownership |mem|. The application is + * responsible for freeing |mem|. + * + * The library code does not refer to |mem| pointer after this + * function returns, so the application can safely free it. + */ +NGHTTP2_EXTERN int nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr, + nghttp2_mem *mem); + +/** + * @function + * + * Deallocates any resources allocated for |inflater|. + */ +NGHTTP2_EXTERN void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater); + +/** + * @function + * + * Changes header table size in the |inflater|. This may trigger + * eviction in the dynamic table. + * + * The |settings_max_dynamic_table_size| should be the value + * transmitted in SETTINGS_HEADER_TABLE_SIZE. + * + * This function must not be called while header block is being + * inflated. In other words, this function must be called after + * initialization of |inflater|, but before calling + * `nghttp2_hd_inflate_hd2()`, or after + * `nghttp2_hd_inflate_end_headers()`. Otherwise, + * `NGHTTP2_ERR_INVALID_STATE` was returned. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_INVALID_STATE` + * The function is called while header block is being inflated. + * Probably, application missed to call + * `nghttp2_hd_inflate_end_headers()`. + */ +NGHTTP2_EXTERN int +nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater, + size_t settings_max_dynamic_table_size); + +/** + * @enum + * + * The flags for header inflation. + */ +typedef enum { + /** + * No flag set. + */ + NGHTTP2_HD_INFLATE_NONE = 0, + /** + * Indicates all headers were inflated. + */ + NGHTTP2_HD_INFLATE_FINAL = 0x01, + /** + * Indicates a header was emitted. + */ + NGHTTP2_HD_INFLATE_EMIT = 0x02 +} nghttp2_hd_inflate_flag; + +/** + * @function + * + * .. warning:: + * + * Deprecated. Use `nghttp2_hd_inflate_hd2()` instead. + * + * Inflates name/value block stored in |in| with length |inlen|. This + * function performs decompression. For each successful emission of + * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in + * |*inflate_flags| and name/value pair is assigned to the |nv_out| + * and the function returns. The caller must not free the members of + * |nv_out|. + * + * The |nv_out| may include pointers to the memory region in the |in|. + * The caller must retain the |in| while the |nv_out| is used. + * + * The application should call this function repeatedly until the + * ``(*inflate_flags) & NGHTTP2_HD_INFLATE_FINAL`` is nonzero and + * return value is non-negative. This means the all input values are + * processed successfully. Then the application must call + * `nghttp2_hd_inflate_end_headers()` to prepare for the next header + * block input. + * + * The caller can feed complete compressed header block. It also can + * feed it in several chunks. The caller must set |in_final| to + * nonzero if the given input is the last block of the compressed + * header. + * + * This function returns the number of bytes processed if it succeeds, + * or one of the following negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_HEADER_COMP` + * Inflation process has failed. + * :enum:`NGHTTP2_ERR_BUFFER_ERROR` + * The header field name or value is too large. + * + * Example follows:: + * + * int inflate_header_block(nghttp2_hd_inflater *hd_inflater, + * uint8_t *in, size_t inlen, int final) + * { + * ssize_t rv; + * + * for(;;) { + * nghttp2_nv nv; + * int inflate_flags = 0; + * + * rv = nghttp2_hd_inflate_hd(hd_inflater, &nv, &inflate_flags, + * in, inlen, final); + * + * if(rv < 0) { + * fprintf(stderr, "inflate failed with error code %zd", rv); + * return -1; + * } + * + * in += rv; + * inlen -= rv; + * + * if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) { + * fwrite(nv.name, nv.namelen, 1, stderr); + * fprintf(stderr, ": "); + * fwrite(nv.value, nv.valuelen, 1, stderr); + * fprintf(stderr, "\n"); + * } + * if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) { + * nghttp2_hd_inflate_end_headers(hd_inflater); + * break; + * } + * if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && + * inlen == 0) { + * break; + * } + * } + * + * return 0; + * } + * + */ +NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, + nghttp2_nv *nv_out, + int *inflate_flags, uint8_t *in, + size_t inlen, int in_final); + +/** + * @function + * + * Inflates name/value block stored in |in| with length |inlen|. This + * function performs decompression. For each successful emission of + * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in + * |*inflate_flags| and name/value pair is assigned to the |nv_out| + * and the function returns. The caller must not free the members of + * |nv_out|. + * + * The |nv_out| may include pointers to the memory region in the |in|. + * The caller must retain the |in| while the |nv_out| is used. + * + * The application should call this function repeatedly until the + * ``(*inflate_flags) & NGHTTP2_HD_INFLATE_FINAL`` is nonzero and + * return value is non-negative. If that happens, all given input + * data (|inlen| bytes) are processed successfully. Then the + * application must call `nghttp2_hd_inflate_end_headers()` to prepare + * for the next header block input. + * + * In other words, if |in_final| is nonzero, and this function returns + * |inlen|, you can assert that :enum:`NGHTTP2_HD_INFLATE_FINAL` is + * set in |*inflate_flags|. + * + * The caller can feed complete compressed header block. It also can + * feed it in several chunks. The caller must set |in_final| to + * nonzero if the given input is the last block of the compressed + * header. + * + * This function returns the number of bytes processed if it succeeds, + * or one of the following negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_HEADER_COMP` + * Inflation process has failed. + * :enum:`NGHTTP2_ERR_BUFFER_ERROR` + * The header field name or value is too large. + * + * Example follows:: + * + * int inflate_header_block(nghttp2_hd_inflater *hd_inflater, + * uint8_t *in, size_t inlen, int final) + * { + * ssize_t rv; + * + * for(;;) { + * nghttp2_nv nv; + * int inflate_flags = 0; + * + * rv = nghttp2_hd_inflate_hd2(hd_inflater, &nv, &inflate_flags, + * in, inlen, final); + * + * if(rv < 0) { + * fprintf(stderr, "inflate failed with error code %zd", rv); + * return -1; + * } + * + * in += rv; + * inlen -= rv; + * + * if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) { + * fwrite(nv.name, nv.namelen, 1, stderr); + * fprintf(stderr, ": "); + * fwrite(nv.value, nv.valuelen, 1, stderr); + * fprintf(stderr, "\n"); + * } + * if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) { + * nghttp2_hd_inflate_end_headers(hd_inflater); + * break; + * } + * if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && + * inlen == 0) { + * break; + * } + * } + * + * return 0; + * } + * + */ +NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, + nghttp2_nv *nv_out, + int *inflate_flags, + const uint8_t *in, size_t inlen, + int in_final); + +/** + * @function + * + * Signals the end of decompression for one header block. + * + * This function returns 0 if it succeeds. Currently this function + * always succeeds. + */ +NGHTTP2_EXTERN int +nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater); + +/** + * @function + * + * Returns the number of entries that header table of |inflater| + * contains. This is the sum of the number of static table and + * dynamic table, so the return value is at least 61. + */ +NGHTTP2_EXTERN +size_t nghttp2_hd_inflate_get_num_table_entries(nghttp2_hd_inflater *inflater); + +/** + * @function + * + * Returns the table entry denoted by |idx| from header table of + * |inflater|. The |idx| is 1-based, and idx=1 returns first entry of + * static table. idx=62 returns first entry of dynamic table if it + * exists. Specifying idx=0 is error, and this function returns NULL. + * If |idx| is strictly greater than the number of entries the tables + * contain, this function returns NULL. + */ +NGHTTP2_EXTERN +const nghttp2_nv * +nghttp2_hd_inflate_get_table_entry(nghttp2_hd_inflater *inflater, size_t idx); + +/** + * @function + * + * Returns the used dynamic table size, including the overhead 32 + * bytes per entry described in RFC 7541. + */ +NGHTTP2_EXTERN +size_t nghttp2_hd_inflate_get_dynamic_table_size(nghttp2_hd_inflater *inflater); + +/** + * @function + * + * Returns the maximum dynamic table size. + */ +NGHTTP2_EXTERN +size_t +nghttp2_hd_inflate_get_max_dynamic_table_size(nghttp2_hd_inflater *inflater); + +struct nghttp2_stream; + +/** + * @struct + * + * The structure to represent HTTP/2 stream. The details of this + * structure are intentionally hidden from the public API. + */ +typedef struct nghttp2_stream nghttp2_stream; + +/** + * @function + * + * Returns pointer to :type:`nghttp2_stream` object denoted by + * |stream_id|. If stream was not found, returns NULL. + * + * Returns imaginary root stream (see + * `nghttp2_session_get_root_stream()`) if 0 is given in |stream_id|. + * + * Unless |stream_id| == 0, the returned pointer is valid until next + * call of `nghttp2_session_send()`, `nghttp2_session_mem_send()`, + * `nghttp2_session_recv()`, and `nghttp2_session_mem_recv()`. + */ +NGHTTP2_EXTERN nghttp2_stream * +nghttp2_session_find_stream(nghttp2_session *session, int32_t stream_id); + +/** + * @enum + * + * State of stream as described in RFC 7540. + */ +typedef enum { + /** + * idle state. + */ + NGHTTP2_STREAM_STATE_IDLE = 1, + /** + * open state. + */ + NGHTTP2_STREAM_STATE_OPEN, + /** + * reserved (local) state. + */ + NGHTTP2_STREAM_STATE_RESERVED_LOCAL, + /** + * reserved (remote) state. + */ + NGHTTP2_STREAM_STATE_RESERVED_REMOTE, + /** + * half closed (local) state. + */ + NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL, + /** + * half closed (remote) state. + */ + NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE, + /** + * closed state. + */ + NGHTTP2_STREAM_STATE_CLOSED +} nghttp2_stream_proto_state; + +/** + * @function + * + * Returns state of |stream|. The root stream retrieved by + * `nghttp2_session_get_root_stream()` will have stream state + * :enum:`NGHTTP2_STREAM_STATE_IDLE`. + */ +NGHTTP2_EXTERN nghttp2_stream_proto_state +nghttp2_stream_get_state(nghttp2_stream *stream); + +/** + * @function + * + * Returns root of dependency tree, which is imaginary stream with + * stream ID 0. The returned pointer is valid until |session| is + * freed by `nghttp2_session_del()`. + */ +NGHTTP2_EXTERN nghttp2_stream * +nghttp2_session_get_root_stream(nghttp2_session *session); + +/** + * @function + * + * Returns the parent stream of |stream| in dependency tree. Returns + * NULL if there is no such stream. + */ +NGHTTP2_EXTERN nghttp2_stream * +nghttp2_stream_get_parent(nghttp2_stream *stream); + +NGHTTP2_EXTERN int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream); + +/** + * @function + * + * Returns the next sibling stream of |stream| in dependency tree. + * Returns NULL if there is no such stream. + */ +NGHTTP2_EXTERN nghttp2_stream * +nghttp2_stream_get_next_sibling(nghttp2_stream *stream); + +/** + * @function + * + * Returns the previous sibling stream of |stream| in dependency tree. + * Returns NULL if there is no such stream. + */ +NGHTTP2_EXTERN nghttp2_stream * +nghttp2_stream_get_previous_sibling(nghttp2_stream *stream); + +/** + * @function + * + * Returns the first child stream of |stream| in dependency tree. + * Returns NULL if there is no such stream. + */ +NGHTTP2_EXTERN nghttp2_stream * +nghttp2_stream_get_first_child(nghttp2_stream *stream); + +/** + * @function + * + * Returns dependency weight to the parent stream of |stream|. + */ +NGHTTP2_EXTERN int32_t nghttp2_stream_get_weight(nghttp2_stream *stream); + +/** + * @function + * + * Returns the sum of the weight for |stream|'s children. + */ +NGHTTP2_EXTERN int32_t +nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream); + +/** + * @functypedef + * + * Callback function invoked when the library outputs debug logging. + * The function is called with arguments suitable for ``vfprintf(3)`` + * + * The debug output is only enabled if the library is built with + * ``DEBUGBUILD`` macro defined. + */ +typedef void (*nghttp2_debug_vprintf_callback)(const char *format, + va_list args); + +/** + * @function + * + * Sets a debug output callback called by the library when built with + * ``DEBUGBUILD`` macro defined. If this option is not used, debug + * log is written into standard error output. + * + * For builds without ``DEBUGBUILD`` macro defined, this function is + * noop. + * + * Note that building with ``DEBUGBUILD`` may cause significant + * performance penalty to libnghttp2 because of extra processing. It + * should be used for debugging purpose only. + * + * .. Warning:: + * + * Building with ``DEBUGBUILD`` may cause significant performance + * penalty to libnghttp2 because of extra processing. It should be + * used for debugging purpose only. We write this two times because + * this is important. + */ +NGHTTP2_EXTERN void nghttp2_set_debug_vprintf_callback( + nghttp2_debug_vprintf_callback debug_vprintf_callback); + +#ifdef __cplusplus +} +#endif + +#endif /* NGHTTP2_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_buf.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_buf.c new file mode 100644 index 00000000..b40d5672 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_buf.c @@ -0,0 +1,506 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_buf.h" + +#include + +#include "nghttp2_helper.h" +#include "nghttp2_debug.h" + +void nghttp2_buf_init(nghttp2_buf *buf) { + buf->begin = NULL; + buf->end = NULL; + buf->pos = NULL; + buf->last = NULL; + buf->mark = NULL; +} + +int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem) { + nghttp2_buf_init(buf); + return nghttp2_buf_reserve(buf, initial, mem); +} + +void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem) { + if (buf == NULL) { + return; + } + + nghttp2_mem_free(mem, buf->begin); + buf->begin = NULL; +} + +int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem) { + uint8_t *ptr; + size_t cap; + + cap = nghttp2_buf_cap(buf); + + if (cap >= new_cap) { + return 0; + } + + new_cap = nghttp2_max(new_cap, cap * 2); + + ptr = nghttp2_mem_realloc(mem, buf->begin, new_cap); + if (ptr == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + buf->pos = ptr + (buf->pos - buf->begin); + buf->last = ptr + (buf->last - buf->begin); + buf->mark = ptr + (buf->mark - buf->begin); + buf->begin = ptr; + buf->end = ptr + new_cap; + + return 0; +} + +void nghttp2_buf_reset(nghttp2_buf *buf) { + buf->pos = buf->last = buf->mark = buf->begin; +} + +void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) { + buf->begin = buf->pos = buf->last = buf->mark = begin; + buf->end = begin + len; +} + +static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length, + nghttp2_mem *mem) { + int rv; + + *chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain)); + if (*chain == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + (*chain)->next = NULL; + + rv = nghttp2_buf_init2(&(*chain)->buf, chunk_length, mem); + if (rv != 0) { + nghttp2_mem_free(mem, *chain); + return NGHTTP2_ERR_NOMEM; + } + + return 0; +} + +static void buf_chain_del(nghttp2_buf_chain *chain, nghttp2_mem *mem) { + nghttp2_buf_free(&chain->buf, mem); + nghttp2_mem_free(mem, chain); +} + +int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk, + nghttp2_mem *mem) { + return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0, mem); +} + +int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length, + size_t max_chunk, size_t offset, nghttp2_mem *mem) { + return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset, + mem); +} + +int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length, + size_t max_chunk, size_t chunk_keep, size_t offset, + nghttp2_mem *mem) { + int rv; + nghttp2_buf_chain *chain; + + if (chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + rv = buf_chain_new(&chain, chunk_length, mem); + if (rv != 0) { + return rv; + } + + bufs->mem = mem; + bufs->offset = offset; + + bufs->head = chain; + bufs->cur = bufs->head; + + nghttp2_buf_shift_right(&bufs->cur->buf, offset); + + bufs->chunk_length = chunk_length; + bufs->chunk_used = 1; + bufs->max_chunk = max_chunk; + bufs->chunk_keep = chunk_keep; + + return 0; +} + +int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length) { + int rv; + nghttp2_buf_chain *chain; + + if (chunk_length < bufs->offset) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + rv = buf_chain_new(&chain, chunk_length, bufs->mem); + if (rv != 0) { + return rv; + } + + nghttp2_bufs_free(bufs); + + bufs->head = chain; + bufs->cur = bufs->head; + + nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset); + + bufs->chunk_length = chunk_length; + bufs->chunk_used = 1; + + return 0; +} + +void nghttp2_bufs_free(nghttp2_bufs *bufs) { + nghttp2_buf_chain *chain, *next_chain; + + if (bufs == NULL) { + return; + } + + for (chain = bufs->head; chain;) { + next_chain = chain->next; + + buf_chain_del(chain, bufs->mem); + + chain = next_chain; + } + + bufs->head = NULL; +} + +int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len, + nghttp2_mem *mem) { + nghttp2_buf_chain *chain; + + chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain)); + if (chain == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + chain->next = NULL; + + nghttp2_buf_wrap_init(&chain->buf, begin, len); + + bufs->mem = mem; + bufs->offset = 0; + + bufs->head = chain; + bufs->cur = bufs->head; + + bufs->chunk_length = len; + bufs->chunk_used = 1; + bufs->max_chunk = 1; + bufs->chunk_keep = 1; + + return 0; +} + +int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec, + size_t veclen, nghttp2_mem *mem) { + size_t i = 0; + nghttp2_buf_chain *cur_chain; + nghttp2_buf_chain *head_chain; + nghttp2_buf_chain **dst_chain = &head_chain; + + if (veclen == 0) { + return nghttp2_bufs_wrap_init(bufs, NULL, 0, mem); + } + + head_chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain) * veclen); + if (head_chain == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + for (i = 0; i < veclen; ++i) { + cur_chain = &head_chain[i]; + cur_chain->next = NULL; + nghttp2_buf_wrap_init(&cur_chain->buf, vec[i].base, vec[i].len); + + *dst_chain = cur_chain; + dst_chain = &cur_chain->next; + } + + bufs->mem = mem; + bufs->offset = 0; + + bufs->head = head_chain; + bufs->cur = bufs->head; + + /* We don't use chunk_length since no allocation is expected. */ + bufs->chunk_length = 0; + bufs->chunk_used = veclen; + bufs->max_chunk = veclen; + bufs->chunk_keep = veclen; + + return 0; +} + +void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs) { + if (bufs == NULL) { + return; + } + + if (bufs->head) { + nghttp2_mem_free(bufs->mem, bufs->head); + } +} + +void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs) { + nghttp2_buf_chain *ci; + + for (ci = bufs->cur; ci; ci = ci->next) { + if (nghttp2_buf_len(&ci->buf) == 0) { + return; + } else { + bufs->cur = ci; + } + } +} + +size_t nghttp2_bufs_len(nghttp2_bufs *bufs) { + nghttp2_buf_chain *ci; + size_t len; + + len = 0; + for (ci = bufs->head; ci; ci = ci->next) { + len += nghttp2_buf_len(&ci->buf); + } + + return len; +} + +static int bufs_alloc_chain(nghttp2_bufs *bufs) { + int rv; + nghttp2_buf_chain *chain; + + if (bufs->cur->next) { + bufs->cur = bufs->cur->next; + + return 0; + } + + if (bufs->max_chunk == bufs->chunk_used) { + return NGHTTP2_ERR_BUFFER_ERROR; + } + + rv = buf_chain_new(&chain, bufs->chunk_length, bufs->mem); + if (rv != 0) { + return rv; + } + + DEBUGF("new buffer %zu bytes allocated for bufs %p, used %zu\n", + bufs->chunk_length, bufs, bufs->chunk_used); + + ++bufs->chunk_used; + + bufs->cur->next = chain; + bufs->cur = chain; + + nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset); + + return 0; +} + +int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) { + int rv; + size_t nwrite; + nghttp2_buf *buf; + const uint8_t *p; + + p = data; + + while (len) { + buf = &bufs->cur->buf; + + nwrite = nghttp2_min(nghttp2_buf_avail(buf), len); + if (nwrite == 0) { + rv = bufs_alloc_chain(bufs); + if (rv != 0) { + return rv; + } + continue; + } + + buf->last = nghttp2_cpymem(buf->last, p, nwrite); + p += nwrite; + len -= nwrite; + } + + return 0; +} + +static int bufs_ensure_addb(nghttp2_bufs *bufs) { + int rv; + nghttp2_buf *buf; + + buf = &bufs->cur->buf; + + if (nghttp2_buf_avail(buf) > 0) { + return 0; + } + + rv = bufs_alloc_chain(bufs); + if (rv != 0) { + return rv; + } + + return 0; +} + +int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b) { + int rv; + + rv = bufs_ensure_addb(bufs); + if (rv != 0) { + return rv; + } + + *bufs->cur->buf.last++ = b; + + return 0; +} + +int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b) { + int rv; + + rv = bufs_ensure_addb(bufs); + if (rv != 0) { + return rv; + } + + *bufs->cur->buf.last = b; + + return 0; +} + +int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b) { + int rv; + + rv = bufs_ensure_addb(bufs); + if (rv != 0) { + return rv; + } + + *bufs->cur->buf.last++ |= b; + + return 0; +} + +int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b) { + int rv; + + rv = bufs_ensure_addb(bufs); + if (rv != 0) { + return rv; + } + + *bufs->cur->buf.last |= b; + + return 0; +} + +ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) { + size_t len; + nghttp2_buf_chain *chain; + nghttp2_buf *buf; + uint8_t *res; + nghttp2_buf resbuf; + + len = 0; + + for (chain = bufs->head; chain; chain = chain->next) { + len += nghttp2_buf_len(&chain->buf); + } + + if (len == 0) { + res = NULL; + return 0; + } + + res = nghttp2_mem_malloc(bufs->mem, len); + if (res == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_buf_wrap_init(&resbuf, res, len); + + for (chain = bufs->head; chain; chain = chain->next) { + buf = &chain->buf; + resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf)); + } + + *out = res; + + return (ssize_t)len; +} + +size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out) { + size_t len; + nghttp2_buf_chain *chain; + nghttp2_buf *buf; + nghttp2_buf resbuf; + + len = nghttp2_bufs_len(bufs); + + nghttp2_buf_wrap_init(&resbuf, out, len); + + for (chain = bufs->head; chain; chain = chain->next) { + buf = &chain->buf; + resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf)); + } + + return len; +} + +void nghttp2_bufs_reset(nghttp2_bufs *bufs) { + nghttp2_buf_chain *chain, *ci; + size_t k; + + k = bufs->chunk_keep; + + for (ci = bufs->head; ci; ci = ci->next) { + nghttp2_buf_reset(&ci->buf); + nghttp2_buf_shift_right(&ci->buf, bufs->offset); + + if (--k == 0) { + break; + } + } + + if (ci) { + chain = ci->next; + ci->next = NULL; + + for (ci = chain; ci;) { + chain = ci->next; + + buf_chain_del(ci, bufs->mem); + + ci = chain; + } + + bufs->chunk_used = bufs->chunk_keep; + } + + bufs->cur = bufs->head; +} + +int nghttp2_bufs_advance(nghttp2_bufs *bufs) { return bufs_alloc_chain(bufs); } + +int nghttp2_bufs_next_present(nghttp2_bufs *bufs) { + nghttp2_buf_chain *chain; + + chain = bufs->cur->next; + + return chain && nghttp2_buf_len(&chain->buf); +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_buf.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_buf.h new file mode 100644 index 00000000..7e33a528 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_buf.h @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_BUF_H +#define NGHTTP2_BUF_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +#include "nghttp2_int.h" +#include "nghttp2_mem.h" + +typedef struct { + /* This points to the beginning of the buffer. The effective range + of buffer is [begin, end). */ + uint8_t *begin; + /* This points to the memory one byte beyond the end of the + buffer. */ + uint8_t *end; + /* The position indicator for effective start of the buffer. pos <= + last must be hold. */ + uint8_t *pos; + /* The position indicator for effective one beyond of the end of the + buffer. last <= end must be hold. */ + uint8_t *last; + /* Mark arbitrary position in buffer [begin, end) */ + uint8_t *mark; +} nghttp2_buf; + +#define nghttp2_buf_len(BUF) ((size_t)((BUF)->last - (BUF)->pos)) +#define nghttp2_buf_avail(BUF) ((size_t)((BUF)->end - (BUF)->last)) +#define nghttp2_buf_mark_avail(BUF) ((size_t)((BUF)->mark - (BUF)->last)) +#define nghttp2_buf_cap(BUF) ((size_t)((BUF)->end - (BUF)->begin)) + +#define nghttp2_buf_pos_offset(BUF) ((size_t)((BUF)->pos - (BUF)->begin)) +#define nghttp2_buf_last_offset(BUF) ((size_t)((BUF)->last - (BUF)->begin)) + +#define nghttp2_buf_shift_right(BUF, AMT) \ + do { \ + (BUF)->pos += AMT; \ + (BUF)->last += AMT; \ + } while (0) + +#define nghttp2_buf_shift_left(BUF, AMT) \ + do { \ + (BUF)->pos -= AMT; \ + (BUF)->last -= AMT; \ + } while (0) + +/* + * Initializes the |buf|. No memory is allocated in this function. Use + * nghttp2_buf_reserve() to allocate memory. + */ +void nghttp2_buf_init(nghttp2_buf *buf); + +/* + * Initializes the |buf| and allocates at least |initial| bytes of + * memory. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem); + +/* + * Frees buffer in |buf|. + */ +void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem); + +/* + * Extends buffer so that nghttp2_buf_cap() returns at least + * |new_cap|. If extensions took place, buffer pointers in |buf| will + * change. + * + * This function returns 0 if it succeeds, or one of the followings + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem); + +/* + * Resets pos, last, mark member of |buf| to buf->begin. + */ +void nghttp2_buf_reset(nghttp2_buf *buf); + +/* + * Initializes |buf| using supplied buffer |begin| of length + * |len|. Semantically, the application should not call *_reserve() or + * nghttp2_free() functions for |buf|. + */ +void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len); + +struct nghttp2_buf_chain; + +typedef struct nghttp2_buf_chain nghttp2_buf_chain; + +/* Chains 2 buffers */ +struct nghttp2_buf_chain { + /* Points to the subsequent buffer. NULL if there is no such + buffer. */ + nghttp2_buf_chain *next; + nghttp2_buf buf; +}; + +typedef struct { + /* Points to the first buffer */ + nghttp2_buf_chain *head; + /* Buffer pointer where write occurs. */ + nghttp2_buf_chain *cur; + /* Memory allocator */ + nghttp2_mem *mem; + /* The buffer capacity of each buf. This field may be 0 if + nghttp2_bufs is initialized by nghttp2_bufs_wrap_init* family + functions. */ + size_t chunk_length; + /* The maximum number of nghttp2_buf_chain */ + size_t max_chunk; + /* The number of nghttp2_buf_chain allocated */ + size_t chunk_used; + /* The number of nghttp2_buf_chain to keep on reset */ + size_t chunk_keep; + /* pos offset from begin in each buffers. On initialization and + reset, buf->pos and buf->last are positioned at buf->begin + + offset. */ + size_t offset; +} nghttp2_bufs; + +/* + * This is the same as calling nghttp2_bufs_init2 with the given + * arguments and offset = 0. + */ +int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk, + nghttp2_mem *mem); + +/* + * This is the same as calling nghttp2_bufs_init3 with the given + * arguments and chunk_keep = max_chunk. + */ +int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length, + size_t max_chunk, size_t offset, nghttp2_mem *mem); + +/* + * Initializes |bufs|. Each buffer size is given in the + * |chunk_length|. The maximum number of buffers is given in the + * |max_chunk|. On reset, first |chunk_keep| buffers are kept and + * remaining buffers are deleted. Each buffer will have bufs->pos and + * bufs->last shifted to left by |offset| bytes on creation and reset. + * + * This function allocates first buffer. bufs->head and bufs->cur + * will point to the first buffer after this call. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_INVALID_ARGUMENT + * chunk_keep is 0; or max_chunk < chunk_keep; or offset is too + * long. + */ +int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length, + size_t max_chunk, size_t chunk_keep, size_t offset, + nghttp2_mem *mem); + +/* + * Frees any related resources to the |bufs|. + */ +void nghttp2_bufs_free(nghttp2_bufs *bufs); + +/* + * Initializes |bufs| using supplied buffer |begin| of length |len|. + * The first buffer bufs->head uses buffer |begin|. The buffer size + * is fixed and no extra chunk buffer is allocated. In other + * words, max_chunk = chunk_keep = 1. To free the resource allocated + * for |bufs|, use nghttp2_bufs_wrap_free(). + * + * Don't use the function which performs allocation, such as + * nghttp2_bufs_realloc(). + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len, + nghttp2_mem *mem); + +/* + * Initializes |bufs| using supplied |veclen| size of buf vector + * |vec|. The number of buffers is fixed and no extra chunk buffer is + * allocated. In other words, max_chunk = chunk_keep = |in_len|. To + * free the resource allocated for |bufs|, use + * nghttp2_bufs_wrap_free(). + * + * Don't use the function which performs allocation, such as + * nghttp2_bufs_realloc(). + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec, + size_t veclen, nghttp2_mem *mem); + +/* + * Frees any related resource to the |bufs|. This function does not + * free supplied buffer provided in nghttp2_bufs_wrap_init(). + */ +void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs); + +/* + * Reallocates internal buffer using |chunk_length|. The max_chunk, + * chunk_keep and offset do not change. After successful allocation + * of new buffer, previous buffers are deallocated without copying + * anything into new buffers. chunk_used is reset to 1. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_INVALID_ARGUMENT + * chunk_length < offset + */ +int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length); + +/* + * Appends the |data| of length |len| to the |bufs|. The write starts + * at bufs->cur->buf.last. A new buffers will be allocated to store + * all data. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_BUFFER_ERROR + * Out of buffer space. + */ +int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len); + +/* + * Appends a single byte |b| to the |bufs|. The write starts at + * bufs->cur->buf.last. A new buffers will be allocated to store all + * data. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_BUFFER_ERROR + * Out of buffer space. + */ +int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b); + +/* + * Behaves like nghttp2_bufs_addb(), but this does not update + * buf->last pointer. + */ +int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b); + +#define nghttp2_bufs_fast_addb(BUFS, B) \ + do { \ + *(BUFS)->cur->buf.last++ = B; \ + } while (0) + +#define nghttp2_bufs_fast_addb_hold(BUFS, B) \ + do { \ + *(BUFS)->cur->buf.last = B; \ + } while (0) + +/* + * Performs bitwise-OR of |b| at bufs->cur->buf.last. A new buffers + * will be allocated if necessary. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_BUFFER_ERROR + * Out of buffer space. + */ +int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b); + +/* + * Behaves like nghttp2_bufs_orb(), but does not update buf->last + * pointer. + */ +int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b); + +#define nghttp2_bufs_fast_orb(BUFS, B) \ + do { \ + uint8_t **p = &(BUFS)->cur->buf.last; \ + **p = (uint8_t)(**p | (B)); \ + ++(*p); \ + } while (0) + +#define nghttp2_bufs_fast_orb_hold(BUFS, B) \ + do { \ + uint8_t *p = (BUFS)->cur->buf.last; \ + *p = (uint8_t)(*p | (B)); \ + } while (0) + +/* + * Copies all data stored in |bufs| to the contiguous buffer. This + * function allocates the contiguous memory to store all data in + * |bufs| and assigns it to |*out|. + * + * The contents of |bufs| is left unchanged. + * + * This function returns the length of copied data and assigns the + * pointer to copied data to |*out| if it succeeds, or one of the + * following negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out); + +/* + * Copies all data stored in |bufs| to |out|. This function assumes + * that the buffer space pointed by |out| has at least + * nghttp2_bufs(bufs) bytes. + * + * The contents of |bufs| is left unchanged. + * + * This function returns the length of copied data. + */ +size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out); + +/* + * Resets |bufs| and makes the buffers empty. + */ +void nghttp2_bufs_reset(nghttp2_bufs *bufs); + +/* + * Moves bufs->cur to bufs->cur->next. If resulting bufs->cur is + * NULL, this function allocates new buffers and bufs->cur points to + * it. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + * NGHTTP2_ERR_BUFFER_ERROR + * Out of buffer space. + */ +int nghttp2_bufs_advance(nghttp2_bufs *bufs); + +/* Sets bufs->cur to bufs->head */ +#define nghttp2_bufs_rewind(BUFS) \ + do { \ + (BUFS)->cur = (BUFS)->head; \ + } while (0) + +/* + * Move bufs->cur, from the current position, using next member, to + * the last buf which has nghttp2_buf_len(buf) > 0 without seeing buf + * which satisfies nghttp2_buf_len(buf) == 0. If + * nghttp2_buf_len(&bufs->cur->buf) == 0 or bufs->cur->next is NULL, + * bufs->cur is unchanged. + */ +void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs); + +/* + * Returns nonzero if bufs->cur->next is not empty. + */ +int nghttp2_bufs_next_present(nghttp2_bufs *bufs); + +#define nghttp2_bufs_cur_avail(BUFS) nghttp2_buf_avail(&(BUFS)->cur->buf) + +/* + * Returns the total buffer length of |bufs|. + */ +size_t nghttp2_bufs_len(nghttp2_bufs *bufs); + +#endif /* NGHTTP2_BUF_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_callbacks.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_callbacks.c new file mode 100644 index 00000000..a2f7e3fb --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_callbacks.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_callbacks.h" +#include +#include +#ifdef INFRA_MEM_STATS +#include "infra_mem_stats.h" +#endif + +extern void *HAL_Malloc(uint32_t size); +extern void *HAL_Realloc(void *ptr, uint32_t size); +extern void HAL_Free(void *ptr); + +#if INFRA_MEM_STATS +#define NGHTTP2_CB_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "nghttp2.cb") +#define NGHTTP2_CB_FREE(ptr) LITE_free(ptr) +#else +#define NGHTTP2_CB_MALLOC(size) HAL_Malloc(size) +#define NGHTTP2_CB_FREE(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr) { + *callbacks_ptr = NGHTTP2_CB_MALLOC(sizeof(nghttp2_session_callbacks)); + + if (*callbacks_ptr == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + memset(*callbacks_ptr, 0, sizeof(nghttp2_session_callbacks)); + return 0; +} + +void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks) { + NGHTTP2_CB_FREE(callbacks); +} + +void nghttp2_session_callbacks_set_send_callback( + nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback) { + cbs->send_callback = send_callback; +} + +void nghttp2_session_callbacks_set_recv_callback( + nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback) { + cbs->recv_callback = recv_callback; +} + +void nghttp2_session_callbacks_set_on_frame_recv_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_frame_recv_callback on_frame_recv_callback) { + cbs->on_frame_recv_callback = on_frame_recv_callback; +} + +void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback) { + cbs->on_invalid_frame_recv_callback = on_invalid_frame_recv_callback; +} + +void nghttp2_session_callbacks_set_on_data_chunk_recv_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback) { + cbs->on_data_chunk_recv_callback = on_data_chunk_recv_callback; +} + +void nghttp2_session_callbacks_set_before_frame_send_callback( + nghttp2_session_callbacks *cbs, + nghttp2_before_frame_send_callback before_frame_send_callback) { + cbs->before_frame_send_callback = before_frame_send_callback; +} + +void nghttp2_session_callbacks_set_on_frame_send_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_frame_send_callback on_frame_send_callback) { + cbs->on_frame_send_callback = on_frame_send_callback; +} + +void nghttp2_session_callbacks_set_on_frame_not_send_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_frame_not_send_callback on_frame_not_send_callback) { + cbs->on_frame_not_send_callback = on_frame_not_send_callback; +} + +void nghttp2_session_callbacks_set_on_stream_close_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_stream_close_callback on_stream_close_callback) { + cbs->on_stream_close_callback = on_stream_close_callback; +} + +void nghttp2_session_callbacks_set_on_begin_headers_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_begin_headers_callback on_begin_headers_callback) { + cbs->on_begin_headers_callback = on_begin_headers_callback; +} + +void nghttp2_session_callbacks_set_on_header_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_header_callback on_header_callback) { + cbs->on_header_callback = on_header_callback; +} + +void nghttp2_session_callbacks_set_on_header_callback2( + nghttp2_session_callbacks *cbs, + nghttp2_on_header_callback2 on_header_callback2) { + cbs->on_header_callback2 = on_header_callback2; +} + +void nghttp2_session_callbacks_set_on_invalid_header_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_invalid_header_callback on_invalid_header_callback) { + cbs->on_invalid_header_callback = on_invalid_header_callback; +} + +void nghttp2_session_callbacks_set_on_invalid_header_callback2( + nghttp2_session_callbacks *cbs, + nghttp2_on_invalid_header_callback2 on_invalid_header_callback2) { + cbs->on_invalid_header_callback2 = on_invalid_header_callback2; +} + +void nghttp2_session_callbacks_set_select_padding_callback( + nghttp2_session_callbacks *cbs, + nghttp2_select_padding_callback select_padding_callback) { + cbs->select_padding_callback = select_padding_callback; +} + +void nghttp2_session_callbacks_set_data_source_read_length_callback( + nghttp2_session_callbacks *cbs, + nghttp2_data_source_read_length_callback data_source_read_length_callback) { + cbs->read_length_callback = data_source_read_length_callback; +} + +void nghttp2_session_callbacks_set_on_begin_frame_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_begin_frame_callback on_begin_frame_callback) { + cbs->on_begin_frame_callback = on_begin_frame_callback; +} + +void nghttp2_session_callbacks_set_send_data_callback( + nghttp2_session_callbacks *cbs, + nghttp2_send_data_callback send_data_callback) { + cbs->send_data_callback = send_data_callback; +} + +void nghttp2_session_callbacks_set_pack_extension_callback( + nghttp2_session_callbacks *cbs, + nghttp2_pack_extension_callback pack_extension_callback) { + cbs->pack_extension_callback = pack_extension_callback; +} + +void nghttp2_session_callbacks_set_unpack_extension_callback( + nghttp2_session_callbacks *cbs, + nghttp2_unpack_extension_callback unpack_extension_callback) { + cbs->unpack_extension_callback = unpack_extension_callback; +} + +void nghttp2_session_callbacks_set_on_extension_chunk_recv_callback( + nghttp2_session_callbacks *cbs, + nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback) { + cbs->on_extension_chunk_recv_callback = on_extension_chunk_recv_callback; +} + +void nghttp2_session_callbacks_set_error_callback( + nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback) { + cbs->error_callback = error_callback; +} + +void nghttp2_session_callbacks_set_error_callback2( + nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2) { + cbs->error_callback2 = error_callback2; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_callbacks.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_callbacks.h new file mode 100644 index 00000000..542df190 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_callbacks.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_CALLBACKS_H +#define NGHTTP2_CALLBACKS_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +/* + * Callback functions. + */ +struct nghttp2_session_callbacks { + /** + * Callback function invoked when the session wants to send data to + * the remote peer. This callback is not necessary if the + * application uses solely `nghttp2_session_mem_send()` to serialize + * data to transmit. + */ + nghttp2_send_callback send_callback; + /** + * Callback function invoked when the session wants to receive data + * from the remote peer. This callback is not necessary if the + * application uses solely `nghttp2_session_mem_recv()` to process + * received data. + */ + nghttp2_recv_callback recv_callback; + /** + * Callback function invoked by `nghttp2_session_recv()` when a + * frame is received. + */ + nghttp2_on_frame_recv_callback on_frame_recv_callback; + /** + * Callback function invoked by `nghttp2_session_recv()` when an + * invalid non-DATA frame is received. + */ + nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback; + /** + * Callback function invoked when a chunk of data in DATA frame is + * received. + */ + nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback; + /** + * Callback function invoked before a non-DATA frame is sent. + */ + nghttp2_before_frame_send_callback before_frame_send_callback; + /** + * Callback function invoked after a frame is sent. + */ + nghttp2_on_frame_send_callback on_frame_send_callback; + /** + * The callback function invoked when a non-DATA frame is not sent + * because of an error. + */ + nghttp2_on_frame_not_send_callback on_frame_not_send_callback; + /** + * Callback function invoked when the stream is closed. + */ + nghttp2_on_stream_close_callback on_stream_close_callback; + /** + * Callback function invoked when the reception of header block in + * HEADERS or PUSH_PROMISE is started. + */ + nghttp2_on_begin_headers_callback on_begin_headers_callback; + /** + * Callback function invoked when a header name/value pair is + * received. + */ + nghttp2_on_header_callback on_header_callback; + nghttp2_on_header_callback2 on_header_callback2; + /** + * Callback function invoked when a invalid header name/value pair + * is received which is silently ignored if these callbacks are not + * set. + */ + nghttp2_on_invalid_header_callback on_invalid_header_callback; + nghttp2_on_invalid_header_callback2 on_invalid_header_callback2; + /** + * Callback function invoked when the library asks application how + * many padding bytes are required for the transmission of the given + * frame. + */ + nghttp2_select_padding_callback select_padding_callback; + /** + * The callback function used to determine the length allowed in + * `nghttp2_data_source_read_callback()` + */ + nghttp2_data_source_read_length_callback read_length_callback; + /** + * Sets callback function invoked when a frame header is received. + */ + nghttp2_on_begin_frame_callback on_begin_frame_callback; + nghttp2_send_data_callback send_data_callback; + nghttp2_pack_extension_callback pack_extension_callback; + nghttp2_unpack_extension_callback unpack_extension_callback; + nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback; + nghttp2_error_callback error_callback; + nghttp2_error_callback2 error_callback2; +}; + +#endif /* NGHTTP2_CALLBACKS_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_debug.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_debug.c new file mode 100644 index 00000000..6533f989 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_debug.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_debug.h" + +#include + +#ifdef DEBUGBUILD + +static void nghttp2_default_debug_vfprintf_callback(const char *fmt, + va_list args) { + vfprintf(stderr, fmt, args); +} + +static nghttp2_debug_vprintf_callback static_debug_vprintf_callback = + nghttp2_default_debug_vfprintf_callback; + +void nghttp2_debug_vprintf(const char *format, ...) { + if (static_debug_vprintf_callback) { + va_list args; + va_start(args, format); + static_debug_vprintf_callback(format, args); + va_end(args); + } +} + +void nghttp2_set_debug_vprintf_callback( + nghttp2_debug_vprintf_callback debug_vprintf_callback) { + static_debug_vprintf_callback = debug_vprintf_callback; +} + +#else /* !DEBUGBUILD */ + +void nghttp2_set_debug_vprintf_callback( + nghttp2_debug_vprintf_callback debug_vprintf_callback) { + (void)debug_vprintf_callback; +} + +#endif /* !DEBUGBUILD */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_debug.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_debug.h new file mode 100644 index 00000000..6fed6ea0 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_debug.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_DEBUG_H +#define NGHTTP2_DEBUG_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +#ifdef DEBUGBUILD +#define DEBUGF(...) nghttp2_debug_vprintf(__VA_ARGS__) +void nghttp2_debug_vprintf(const char *format, ...); +#else +#define DEBUGF(...) \ + do { \ + } while (0) +#endif + +#endif /* NGHTTP2_DEBUG_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_frame.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_frame.c new file mode 100644 index 00000000..76c919ec --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_frame.c @@ -0,0 +1,977 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_frame.h" + +#include +#include +#include +#include + +#include "nghttp2_helper.h" +#include "nghttp2_net.h" +#include "nghttp2_priority_spec.h" +#include "nghttp2_debug.h" + +void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd) { + nghttp2_put_uint32be(&buf[0], (uint32_t)(hd->length << 8)); + buf[3] = hd->type; + buf[4] = hd->flags; + nghttp2_put_uint32be(&buf[5], (uint32_t)hd->stream_id); + /* ignore hd->reserved for now */ +} + +void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf) { + hd->length = nghttp2_get_uint32(&buf[0]) >> 8; + hd->type = buf[3]; + hd->flags = buf[4]; + hd->stream_id = nghttp2_get_uint32(&buf[5]) & NGHTTP2_STREAM_ID_MASK; + hd->reserved = 0; +} + +void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type, + uint8_t flags, int32_t stream_id) { + hd->length = length; + hd->type = type; + hd->flags = flags; + hd->stream_id = stream_id; + hd->reserved = 0; +} + +void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags, + int32_t stream_id, nghttp2_headers_category cat, + const nghttp2_priority_spec *pri_spec, + nghttp2_nv *nva, size_t nvlen) { + nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_HEADERS, flags, stream_id); + frame->padlen = 0; + frame->nva = nva; + frame->nvlen = nvlen; + frame->cat = cat; + + if (pri_spec) { + frame->pri_spec = *pri_spec; + } else { + nghttp2_priority_spec_default_init(&frame->pri_spec); + } +} + +void nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem) { + nghttp2_nv_array_del(frame->nva, mem); +} + +void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id, + const nghttp2_priority_spec *pri_spec) { + nghttp2_frame_hd_init(&frame->hd, NGHTTP2_PRIORITY_SPECLEN, NGHTTP2_PRIORITY, + NGHTTP2_FLAG_NONE, stream_id); + frame->pri_spec = *pri_spec; +} + +void nghttp2_frame_priority_free(nghttp2_priority *frame) { (void)frame; } + +void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id, + uint32_t error_code) { + nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE, + stream_id); + frame->error_code = error_code; +} + +void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame) { (void)frame; } + +void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags, + nghttp2_settings_entry *iv, size_t niv) { + nghttp2_frame_hd_init(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH, + NGHTTP2_SETTINGS, flags, 0); + frame->niv = niv; + frame->iv = iv; +} + +void nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem) { + nghttp2_mem_free(mem, frame->iv); +} + +void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags, + int32_t stream_id, + int32_t promised_stream_id, + nghttp2_nv *nva, size_t nvlen) { + nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_PUSH_PROMISE, flags, stream_id); + frame->padlen = 0; + frame->nva = nva; + frame->nvlen = nvlen; + frame->promised_stream_id = promised_stream_id; + frame->reserved = 0; +} + +void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame, + nghttp2_mem *mem) { + nghttp2_nv_array_del(frame->nva, mem); +} + +void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags, + const uint8_t *opaque_data) { + nghttp2_frame_hd_init(&frame->hd, 8, NGHTTP2_PING, flags, 0); + if (opaque_data) { + memcpy(frame->opaque_data, opaque_data, sizeof(frame->opaque_data)); + } else { + memset(frame->opaque_data, 0, sizeof(frame->opaque_data)); + } +} + +void nghttp2_frame_ping_free(nghttp2_ping *frame) { (void)frame; } + +void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id, + uint32_t error_code, uint8_t *opaque_data, + size_t opaque_data_len) { + nghttp2_frame_hd_init(&frame->hd, 8 + opaque_data_len, NGHTTP2_GOAWAY, + NGHTTP2_FLAG_NONE, 0); + frame->last_stream_id = last_stream_id; + frame->error_code = error_code; + frame->opaque_data = opaque_data; + frame->opaque_data_len = opaque_data_len; + frame->reserved = 0; +} + +void nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem) { + nghttp2_mem_free(mem, frame->opaque_data); +} + +void nghttp2_frame_window_update_init(nghttp2_window_update *frame, + uint8_t flags, int32_t stream_id, + int32_t window_size_increment) { + nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_WINDOW_UPDATE, flags, stream_id); + frame->window_size_increment = window_size_increment; + frame->reserved = 0; +} + +void nghttp2_frame_window_update_free(nghttp2_window_update *frame) { + (void)frame; +} + +size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen) { + /* We have iframe->padlen == 0, but iframe->frame.hd.flags may have + NGHTTP2_FLAG_PADDED set. This happens when receiving + CONTINUATION frame, since we don't reset flags after HEADERS was + received. */ + if (padlen == 0) { + return 0; + } + return padlen - ((frame->hd.flags & NGHTTP2_FLAG_PADDED) > 0); +} + +void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags, + int32_t stream_id) { + /* At this moment, the length of DATA frame is unknown */ + nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_DATA, flags, stream_id); + frame->padlen = 0; +} + +void nghttp2_frame_data_free(nghttp2_data *frame) { (void)frame; } + +void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type, + uint8_t flags, int32_t stream_id, + void *payload) { + nghttp2_frame_hd_init(&frame->hd, 0, type, flags, stream_id); + frame->payload = payload; +} + +void nghttp2_frame_extension_free(nghttp2_extension *frame) { (void)frame; } + +void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id, + uint8_t *origin, size_t origin_len, + uint8_t *field_value, size_t field_value_len) { + nghttp2_ext_altsvc *altsvc; + + nghttp2_frame_hd_init(&frame->hd, 2 + origin_len + field_value_len, + NGHTTP2_ALTSVC, NGHTTP2_FLAG_NONE, stream_id); + + altsvc = frame->payload; + altsvc->origin = origin; + altsvc->origin_len = origin_len; + altsvc->field_value = field_value; + altsvc->field_value_len = field_value_len; +} + +void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem) { + nghttp2_ext_altsvc *altsvc; + + altsvc = frame->payload; + /* We use the same buffer for altsvc->origin and + altsvc->field_value. */ + nghttp2_mem_free(mem, altsvc->origin); +} + +size_t nghttp2_frame_priority_len(uint8_t flags) { + if (flags & NGHTTP2_FLAG_PRIORITY) { + return NGHTTP2_PRIORITY_SPECLEN; + } + + return 0; +} + +size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame) { + return nghttp2_frame_priority_len(frame->hd.flags); +} + +/* + * Call this function after payload was serialized, but not before + * changing buf->pos and serializing frame header. + * + * This function assumes bufs->cur points to the last buf chain of the + * frame(s). + * + * This function serializes frame header for HEADERS/PUSH_PROMISE and + * handles their successive CONTINUATION frames. + * + * We don't process any padding here. + */ +static int frame_pack_headers_shared(nghttp2_bufs *bufs, + nghttp2_frame_hd *frame_hd) { + nghttp2_buf *buf; + nghttp2_buf_chain *ci, *ce; + nghttp2_frame_hd hd; + + buf = &bufs->head->buf; + + hd = *frame_hd; + hd.length = nghttp2_buf_len(buf); + + DEBUGF("send: HEADERS/PUSH_PROMISE, payloadlen=%zu\n", hd.length); + + /* We have multiple frame buffers, which means one or more + CONTINUATION frame is involved. Remove END_HEADERS flag from the + first frame. */ + if (bufs->head != bufs->cur) { + hd.flags = (uint8_t)(hd.flags & ~NGHTTP2_FLAG_END_HEADERS); + } + + buf->pos -= NGHTTP2_FRAME_HDLEN; + nghttp2_frame_pack_frame_hd(buf->pos, &hd); + + if (bufs->head != bufs->cur) { + /* 2nd and later frames are CONTINUATION frames. */ + hd.type = NGHTTP2_CONTINUATION; + /* We don't have no flags except for last CONTINUATION */ + hd.flags = NGHTTP2_FLAG_NONE; + + ce = bufs->cur; + + for (ci = bufs->head->next; ci != ce; ci = ci->next) { + buf = &ci->buf; + + hd.length = nghttp2_buf_len(buf); + + DEBUGF("send: int CONTINUATION, payloadlen=%zu\n", hd.length); + + buf->pos -= NGHTTP2_FRAME_HDLEN; + nghttp2_frame_pack_frame_hd(buf->pos, &hd); + } + + buf = &ci->buf; + hd.length = nghttp2_buf_len(buf); + /* Set END_HEADERS flag for last CONTINUATION */ + hd.flags = NGHTTP2_FLAG_END_HEADERS; + + DEBUGF("send: last CONTINUATION, payloadlen=%zu\n", hd.length); + + buf->pos -= NGHTTP2_FRAME_HDLEN; + nghttp2_frame_pack_frame_hd(buf->pos, &hd); + } + + return 0; +} + +int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame, + nghttp2_hd_deflater *deflater) { + size_t nv_offset; + int rv; + nghttp2_buf *buf; + + assert(bufs->head == bufs->cur); + + nv_offset = nghttp2_frame_headers_payload_nv_offset(frame); + + buf = &bufs->cur->buf; + + buf->pos += nv_offset; + buf->last = buf->pos; + + /* This call will adjust buf->last to the correct position */ + rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen); + + if (rv == NGHTTP2_ERR_BUFFER_ERROR) { + rv = NGHTTP2_ERR_HEADER_COMP; + } + + buf->pos -= nv_offset; + + if (rv != 0) { + return rv; + } + + if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { + nghttp2_frame_pack_priority_spec(buf->pos, &frame->pri_spec); + } + + frame->padlen = 0; + frame->hd.length = nghttp2_bufs_len(bufs); + + return frame_pack_headers_shared(bufs, &frame->hd); +} + +void nghttp2_frame_pack_priority_spec(uint8_t *buf, + const nghttp2_priority_spec *pri_spec) { + nghttp2_put_uint32be(buf, (uint32_t)pri_spec->stream_id); + if (pri_spec->exclusive) { + buf[0] |= 0x80; + } + buf[4] = (uint8_t)(pri_spec->weight - 1); +} + +void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec, + const uint8_t *payload) { + int32_t dep_stream_id; + uint8_t exclusive; + int32_t weight; + + dep_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; + exclusive = (payload[0] & 0x80) > 0; + weight = payload[4] + 1; + + nghttp2_priority_spec_init(pri_spec, dep_stream_id, weight, exclusive); +} + +int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, + const uint8_t *payload) { + if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { + nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload); + } else { + nghttp2_priority_spec_default_init(&frame->pri_spec); + } + + frame->nva = NULL; + frame->nvlen = 0; + + return 0; +} + +int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) { + nghttp2_buf *buf; + + assert(bufs->head == bufs->cur); + + buf = &bufs->head->buf; + + assert(nghttp2_buf_avail(buf) >= NGHTTP2_PRIORITY_SPECLEN); + + buf->pos -= NGHTTP2_FRAME_HDLEN; + + nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); + + nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec); + + buf->last += NGHTTP2_PRIORITY_SPECLEN; + + return 0; +} + +void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame, + const uint8_t *payload) { + nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload); +} + +int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs, + nghttp2_rst_stream *frame) { + nghttp2_buf *buf; + + assert(bufs->head == bufs->cur); + + buf = &bufs->head->buf; + + assert(nghttp2_buf_avail(buf) >= 4); + + buf->pos -= NGHTTP2_FRAME_HDLEN; + + nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); + + nghttp2_put_uint32be(buf->last, frame->error_code); + buf->last += 4; + + return 0; +} + +void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame, + const uint8_t *payload) { + frame->error_code = nghttp2_get_uint32(payload); +} + +int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame) { + nghttp2_buf *buf; + + assert(bufs->head == bufs->cur); + + buf = &bufs->head->buf; + + if (nghttp2_buf_avail(buf) < frame->hd.length) { + return NGHTTP2_ERR_FRAME_SIZE_ERROR; + } + + buf->pos -= NGHTTP2_FRAME_HDLEN; + + nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); + + buf->last += + nghttp2_frame_pack_settings_payload(buf->last, frame->iv, frame->niv); + + return 0; +} + +size_t nghttp2_frame_pack_settings_payload(uint8_t *buf, + const nghttp2_settings_entry *iv, + size_t niv) { + size_t i; + for (i = 0; i < niv; ++i, buf += NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) { + nghttp2_put_uint16be(buf, (uint16_t)iv[i].settings_id); + nghttp2_put_uint32be(buf + 2, iv[i].value); + } + return NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH * niv; +} + +void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame, + nghttp2_settings_entry *iv, + size_t niv) { + frame->iv = iv; + frame->niv = niv; +} + +void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv, + const uint8_t *payload) { + iv->settings_id = nghttp2_get_uint16(&payload[0]); + iv->value = nghttp2_get_uint32(&payload[2]); +} + +int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr, + size_t *niv_ptr, + const uint8_t *payload, + size_t payloadlen, + nghttp2_mem *mem) { + size_t i; + + *niv_ptr = payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH; + + if (*niv_ptr == 0) { + *iv_ptr = NULL; + + return 0; + } + + *iv_ptr = + nghttp2_mem_malloc(mem, (*niv_ptr) * sizeof(nghttp2_settings_entry)); + + if (*iv_ptr == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + for (i = 0; i < *niv_ptr; ++i) { + size_t off = i * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH; + nghttp2_frame_unpack_settings_entry(&(*iv_ptr)[i], &payload[off]); + } + + return 0; +} + +int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs, + nghttp2_push_promise *frame, + nghttp2_hd_deflater *deflater) { + size_t nv_offset = 4; + int rv; + nghttp2_buf *buf; + + assert(bufs->head == bufs->cur); + + buf = &bufs->cur->buf; + + buf->pos += nv_offset; + buf->last = buf->pos; + + /* This call will adjust buf->last to the correct position */ + rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen); + + if (rv == NGHTTP2_ERR_BUFFER_ERROR) { + rv = NGHTTP2_ERR_HEADER_COMP; + } + + buf->pos -= nv_offset; + + if (rv != 0) { + return rv; + } + + nghttp2_put_uint32be(buf->pos, (uint32_t)frame->promised_stream_id); + + frame->padlen = 0; + frame->hd.length = nghttp2_bufs_len(bufs); + + return frame_pack_headers_shared(bufs, &frame->hd); +} + +int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, + const uint8_t *payload) { + frame->promised_stream_id = + nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; + frame->nva = NULL; + frame->nvlen = 0; + return 0; +} + +int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) { + nghttp2_buf *buf; + + assert(bufs->head == bufs->cur); + + buf = &bufs->head->buf; + + assert(nghttp2_buf_avail(buf) >= 8); + + buf->pos -= NGHTTP2_FRAME_HDLEN; + + nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); + + buf->last = + nghttp2_cpymem(buf->last, frame->opaque_data, sizeof(frame->opaque_data)); + + return 0; +} + +void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame, + const uint8_t *payload) { + memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data)); +} + +int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame) { + int rv; + nghttp2_buf *buf; + + assert(bufs->head == bufs->cur); + + buf = &bufs->head->buf; + + buf->pos -= NGHTTP2_FRAME_HDLEN; + + nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); + + nghttp2_put_uint32be(buf->last, (uint32_t)frame->last_stream_id); + buf->last += 4; + + nghttp2_put_uint32be(buf->last, frame->error_code); + buf->last += 4; + + rv = nghttp2_bufs_add(bufs, frame->opaque_data, frame->opaque_data_len); + + if (rv == NGHTTP2_ERR_BUFFER_ERROR) { + return NGHTTP2_ERR_FRAME_SIZE_ERROR; + } + + if (rv != 0) { + return rv; + } + + return 0; +} + +void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame, + const uint8_t *payload, + uint8_t *var_gift_payload, + size_t var_gift_payloadlen) { + frame->last_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; + frame->error_code = nghttp2_get_uint32(payload + 4); + + frame->opaque_data = var_gift_payload; + frame->opaque_data_len = var_gift_payloadlen; +} + +int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame, + const uint8_t *payload, + size_t payloadlen, nghttp2_mem *mem) { + uint8_t *var_gift_payload; + size_t var_gift_payloadlen; + + if (payloadlen > 8) { + var_gift_payloadlen = payloadlen - 8; + } else { + var_gift_payloadlen = 0; + } + + payloadlen -= var_gift_payloadlen; + + if (!var_gift_payloadlen) { + var_gift_payload = NULL; + } else { + var_gift_payload = nghttp2_mem_malloc(mem, var_gift_payloadlen); + + if (var_gift_payload == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + memcpy(var_gift_payload, payload + 8, var_gift_payloadlen); + } + + nghttp2_frame_unpack_goaway_payload(frame, payload, var_gift_payload, + var_gift_payloadlen); + + return 0; +} + +int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs, + nghttp2_window_update *frame) { + nghttp2_buf *buf; + + assert(bufs->head == bufs->cur); + + buf = &bufs->head->buf; + + assert(nghttp2_buf_avail(buf) >= 4); + + buf->pos -= NGHTTP2_FRAME_HDLEN; + + nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); + + nghttp2_put_uint32be(buf->last, (uint32_t)frame->window_size_increment); + buf->last += 4; + + return 0; +} + +void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame, + const uint8_t *payload) { + frame->window_size_increment = + nghttp2_get_uint32(payload) & NGHTTP2_WINDOW_SIZE_INCREMENT_MASK; +} + +int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) { + int rv; + nghttp2_buf *buf; + nghttp2_ext_altsvc *altsvc; + + /* This is required with --disable-assert. */ + (void)rv; + + altsvc = frame->payload; + + buf = &bufs->head->buf; + + assert(nghttp2_buf_avail(buf) >= + 2 + altsvc->origin_len + altsvc->field_value_len); + + buf->pos -= NGHTTP2_FRAME_HDLEN; + + nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); + + nghttp2_put_uint16be(buf->last, (uint16_t)altsvc->origin_len); + buf->last += 2; + + rv = nghttp2_bufs_add(bufs, altsvc->origin, altsvc->origin_len); + + assert(rv == 0); + + rv = nghttp2_bufs_add(bufs, altsvc->field_value, altsvc->field_value_len); + + assert(rv == 0); + + return 0; +} + +void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame, + size_t origin_len, uint8_t *payload, + size_t payloadlen) { + nghttp2_ext_altsvc *altsvc; + uint8_t *p; + + altsvc = frame->payload; + p = payload; + + altsvc->origin = p; + + p += origin_len; + + altsvc->origin_len = origin_len; + + altsvc->field_value = p; + altsvc->field_value_len = (size_t)(payload + payloadlen - p); +} + +int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame, + const uint8_t *payload, + size_t payloadlen, nghttp2_mem *mem) { + uint8_t *buf; + size_t origin_len; + + if (payloadlen < 2) { + return NGHTTP2_FRAME_SIZE_ERROR; + } + + origin_len = nghttp2_get_uint16(payload); + + buf = nghttp2_mem_malloc(mem, payloadlen - 2); + if (!buf) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_cpymem(buf, payload + 2, payloadlen - 2); + + nghttp2_frame_unpack_altsvc_payload(frame, origin_len, buf, payloadlen - 2); + + return 0; +} + +nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv, + size_t niv, nghttp2_mem *mem) { + nghttp2_settings_entry *iv_copy; + size_t len = niv * sizeof(nghttp2_settings_entry); + + if (len == 0) { + return NULL; + } + + iv_copy = nghttp2_mem_malloc(mem, len); + + if (iv_copy == NULL) { + return NULL; + } + + memcpy(iv_copy, iv, len); + + return iv_copy; +} + +int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) { + return a->namelen == b->namelen && a->valuelen == b->valuelen && + memcmp(a->name, b->name, a->namelen) == 0 && + memcmp(a->value, b->value, a->valuelen) == 0; +} + +void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem) { + nghttp2_mem_free(mem, nva); +} + +static int bytes_compar(const uint8_t *a, size_t alen, const uint8_t *b, + size_t blen) { + int rv; + + if (alen == blen) { + return memcmp(a, b, alen); + } + + if (alen < blen) { + rv = memcmp(a, b, alen); + + if (rv == 0) { + return -1; + } + + return rv; + } + + rv = memcmp(a, b, blen); + + if (rv == 0) { + return 1; + } + + return rv; +} + +int nghttp2_nv_compare_name(const nghttp2_nv *lhs, const nghttp2_nv *rhs) { + return bytes_compar(lhs->name, lhs->namelen, rhs->name, rhs->namelen); +} + +static int nv_compar(const void *lhs, const void *rhs) { + const nghttp2_nv *a = (const nghttp2_nv *)lhs; + const nghttp2_nv *b = (const nghttp2_nv *)rhs; + int rv; + + rv = bytes_compar(a->name, a->namelen, b->name, b->namelen); + + if (rv == 0) { + return bytes_compar(a->value, a->valuelen, b->value, b->valuelen); + } + + return rv; +} + +void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen) { + qsort(nva, nvlen, sizeof(nghttp2_nv), nv_compar); +} + +int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva, + size_t nvlen, nghttp2_mem *mem) { + size_t i; + uint8_t *data = NULL; + size_t buflen = 0; + nghttp2_nv *p; + + if (nvlen == 0) { + *nva_ptr = NULL; + + return 0; + } + + for (i = 0; i < nvlen; ++i) { + /* + 1 for null-termination */ + if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) == 0) { + buflen += nva[i].namelen + 1; + } + if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) == 0) { + buflen += nva[i].valuelen + 1; + } + } + + buflen += sizeof(nghttp2_nv) * nvlen; + + *nva_ptr = nghttp2_mem_malloc(mem, buflen); + + if (*nva_ptr == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + p = *nva_ptr; + data = (uint8_t *)(*nva_ptr) + sizeof(nghttp2_nv) * nvlen; + + for (i = 0; i < nvlen; ++i) { + p->flags = nva[i].flags; + + if (nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) { + p->name = nva[i].name; + p->namelen = nva[i].namelen; + } else { + if (nva[i].namelen) { + memcpy(data, nva[i].name, nva[i].namelen); + } + p->name = data; + p->namelen = nva[i].namelen; + data[p->namelen] = '\0'; + nghttp2_downcase(p->name, p->namelen); + data += nva[i].namelen + 1; + } + + if (nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) { + p->value = nva[i].value; + p->valuelen = nva[i].valuelen; + } else { + if (nva[i].valuelen) { + memcpy(data, nva[i].value, nva[i].valuelen); + } + p->value = data; + p->valuelen = nva[i].valuelen; + data[p->valuelen] = '\0'; + data += nva[i].valuelen + 1; + } + + ++p; + } + return 0; +} + +int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) { + size_t i; + for (i = 0; i < niv; ++i) { + switch (iv[i].settings_id) { + case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: + break; + case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: + break; + case NGHTTP2_SETTINGS_ENABLE_PUSH: + if (iv[i].value != 0 && iv[i].value != 1) { + return 0; + } + break; + case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: + if (iv[i].value > (uint32_t)NGHTTP2_MAX_WINDOW_SIZE) { + return 0; + } + break; + case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: + if (iv[i].value < NGHTTP2_MAX_FRAME_SIZE_MIN || + iv[i].value > NGHTTP2_MAX_FRAME_SIZE_MAX) { + return 0; + } + break; + case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: + break; + } + } + return 1; +} + +static void frame_set_pad(nghttp2_buf *buf, size_t padlen, int framehd_only) { + size_t trail_padlen; + size_t newlen; + + DEBUGF("send: padlen=%zu, shift left 1 bytes\n", padlen); + + memmove(buf->pos - 1, buf->pos, NGHTTP2_FRAME_HDLEN); + + --buf->pos; + + buf->pos[4] |= NGHTTP2_FLAG_PADDED; + + newlen = (nghttp2_get_uint32(buf->pos) >> 8) + padlen; + nghttp2_put_uint32be(buf->pos, (uint32_t)((newlen << 8) + buf->pos[3])); + + if (framehd_only) { + return; + } + + trail_padlen = padlen - 1; + buf->pos[NGHTTP2_FRAME_HDLEN] = (uint8_t)trail_padlen; + + /* zero out padding */ + memset(buf->last, 0, trail_padlen); + /* extend buffers trail_padlen bytes, since we ate previous padlen - + trail_padlen byte(s) */ + buf->last += trail_padlen; +} + +int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd, + size_t padlen, int framehd_only) { + nghttp2_buf *buf; + + if (padlen == 0) { + DEBUGF("send: padlen = 0, nothing to do\n"); + + return 0; + } + + /* + * We have arranged bufs like this: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | |Frame header | Frame payload... : + * +-+-----------------+-------------------------------------------+ + * | |Frame header | Frame payload... : + * +-+-----------------+-------------------------------------------+ + * | |Frame header | Frame payload... : + * +-+-----------------+-------------------------------------------+ + * + * We arranged padding so that it is included in the first frame + * completely. For padded frame, we are going to adjust buf->pos of + * frame which includes padding and serialize (memmove) frame header + * in the correct position. Also extends buf->last to include + * padding. + */ + + buf = &bufs->head->buf; + + assert(nghttp2_buf_avail(buf) >= padlen - 1); + + frame_set_pad(buf, padlen, framehd_only); + + hd->length += padlen; + hd->flags |= NGHTTP2_FLAG_PADDED; + + DEBUGF("send: final payloadlen=%zu, padlen=%zu\n", hd->length, padlen); + + return 0; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_frame.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_frame.h new file mode 100644 index 00000000..07aeb8b7 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_frame.h @@ -0,0 +1,556 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_FRAME_H +#define NGHTTP2_FRAME_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" +#include "nghttp2_hd.h" +#include "nghttp2_buf.h" + +#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1) +#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1) +#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1) +#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1) +#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1) + +/* The number of bytes of frame header. */ +#define NGHTTP2_FRAME_HDLEN 9 + +#define NGHTTP2_MAX_FRAME_SIZE_MAX ((1 << 24) - 1) +#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14) + +#define NGHTTP2_MAX_PAYLOADLEN 16384 +/* The one frame buffer length for tranmission. We may use several of + them to support CONTINUATION. To account for Pad Length field, we + allocate extra 1 byte, which saves extra large memcopying. */ +#define NGHTTP2_FRAMEBUF_CHUNKLEN \ + (NGHTTP2_FRAME_HDLEN + 1 + NGHTTP2_MAX_PAYLOADLEN) + +/* The default length of DATA frame payload. */ +#define NGHTTP2_DATA_PAYLOADLEN NGHTTP2_MAX_FRAME_SIZE_MIN + +/* Maximum headers block size to send, calculated using + nghttp2_hd_deflate_bound(). This is the default value, and can be + overridden by nghttp2_option_set_max_send_header_block_size(). */ +#define NGHTTP2_MAX_HEADERSLEN 65536 + +/* The number of bytes for each SETTINGS entry */ +#define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 6 + +/* Length of priority related fields in HEADERS/PRIORITY frames */ +#define NGHTTP2_PRIORITY_SPECLEN 5 + +/* Maximum length of padding in bytes. */ +#define NGHTTP2_MAX_PADLEN 256 + +/* Union of extension frame payload */ +typedef union { + nghttp2_ext_altsvc altsvc; +} nghttp2_ext_frame_payload; + +void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd); + +void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf); + +/** + * Initializes frame header |hd| with given parameters. Reserved bit + * is set to 0. + */ +void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type, + uint8_t flags, int32_t stream_id); + +/** + * Returns the number of priority field depending on the |flags|. If + * |flags| has neither NGHTTP2_FLAG_PRIORITY_GROUP nor + * NGHTTP2_FLAG_PRIORITY_DEPENDENCY set, return 0. + */ +size_t nghttp2_frame_priority_len(uint8_t flags); + +/** + * Packs the |pri_spec| in |buf|. This function assumes |buf| has + * enough space for serialization. + */ +void nghttp2_frame_pack_priority_spec(uint8_t *buf, + const nghttp2_priority_spec *pri_spec); + +/** + * Unpacks the priority specification from payload |payload| of length + * |payloadlen| to |pri_spec|. The |flags| is used to determine what + * kind of priority specification is in |payload|. This function + * assumes the |payload| contains whole priority specification. + */ +void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec, + const uint8_t *payload); + +/* + * Returns the offset from the HEADERS frame payload where the + * compressed header block starts. The frame payload does not include + * frame header. + */ +size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame); + +/* + * Packs HEADERS frame |frame| in wire format and store it in |bufs|. + * This function expands |bufs| as necessary to store frame. + * + * The caller must make sure that nghttp2_bufs_reset(bufs) is called + * before calling this function. + * + * frame->hd.length is assigned after length is determined during + * packing process. CONTINUATION frames are also serialized in this + * function. This function does not handle padding. + * + * This function returns 0 if it succeeds, or returns one of the + * following negative error codes: + * + * NGHTTP2_ERR_HEADER_COMP + * The deflate operation failed. + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame, + nghttp2_hd_deflater *deflater); + +/* + * Unpacks HEADERS frame byte sequence into |frame|. This function + * only unapcks bytes that come before name/value header block and + * after possible Pad Length field. + * + * This function always succeeds and returns 0. + */ +int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, + const uint8_t *payload); + +/* + * Packs PRIORITY frame |frame| in wire format and store it in + * |bufs|. + * + * The caller must make sure that nghttp2_bufs_reset(bufs) is called + * before calling this function. + * + * This function always succeeds and returns 0. + */ +int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame); + +/* + * Unpacks PRIORITY wire format into |frame|. + */ +void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame, + const uint8_t *payload); + +/* + * Packs RST_STREAM frame |frame| in wire frame format and store it in + * |bufs|. + * + * The caller must make sure that nghttp2_bufs_reset(bufs) is called + * before calling this function. + * + * This function always succeeds and returns 0. + */ +int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs, + nghttp2_rst_stream *frame); + +/* + * Unpacks RST_STREAM frame byte sequence into |frame|. + */ +void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame, + const uint8_t *payload); + +/* + * Packs SETTINGS frame |frame| in wire format and store it in + * |bufs|. + * + * The caller must make sure that nghttp2_bufs_reset(bufs) is called + * before calling this function. + * + * This function returns 0 if it succeeds, or returns one of the + * following negative error codes: + * + * NGHTTP2_ERR_FRAME_SIZE_ERROR + * The length of the frame is too large. + */ +int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame); + +/* + * Packs the |iv|, which includes |niv| entries, in the |buf|, + * assuming the |buf| has at least 8 * |niv| bytes. + * + * Returns the number of bytes written into the |buf|. + */ +size_t nghttp2_frame_pack_settings_payload(uint8_t *buf, + const nghttp2_settings_entry *iv, + size_t niv); + +void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv, + const uint8_t *payload); + +/* + * Initializes payload of frame->settings. The |frame| takes + * ownership of |iv|. + */ +void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame, + nghttp2_settings_entry *iv, + size_t niv); + +/* + * Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are + * assigned to the |*niv_ptr|. This function allocates enough memory + * to store the result in |*iv_ptr|. The caller is responsible to free + * |*iv_ptr| after its use. + * + * This function returns 0 if it succeeds or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr, + size_t *niv_ptr, + const uint8_t *payload, + size_t payloadlen, nghttp2_mem *mem); + +/* + * Packs PUSH_PROMISE frame |frame| in wire format and store it in + * |bufs|. This function expands |bufs| as necessary to store + * frame. + * + * The caller must make sure that nghttp2_bufs_reset(bufs) is called + * before calling this function. + * + * frame->hd.length is assigned after length is determined during + * packing process. CONTINUATION frames are also serialized in this + * function. This function does not handle padding. + * + * This function returns 0 if it succeeds, or returns one of the + * following negative error codes: + * + * NGHTTP2_ERR_HEADER_COMP + * The deflate operation failed. + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs, + nghttp2_push_promise *frame, + nghttp2_hd_deflater *deflater); + +/* + * Unpacks PUSH_PROMISE frame byte sequence into |frame|. This + * function only unapcks bytes that come before name/value header + * block and after possible Pad Length field. + * + * This function returns 0 if it succeeds or one of the following + * negative error codes: + * + * NGHTTP2_ERR_PROTO + * TODO END_HEADERS flag is not set + */ +int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, + const uint8_t *payload); + +/* + * Packs PING frame |frame| in wire format and store it in + * |bufs|. + * + * The caller must make sure that nghttp2_bufs_reset(bufs) is called + * before calling this function. + * + * This function always succeeds and returns 0. + */ +int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame); + +/* + * Unpacks PING wire format into |frame|. + */ +void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame, + const uint8_t *payload); + +/* + * Packs GOAWAY frame |frame| in wire format and store it in |bufs|. + * This function expands |bufs| as necessary to store frame. + * + * The caller must make sure that nghttp2_bufs_reset(bufs) is called + * before calling this function. + * + * This function returns 0 if it succeeds or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_FRAME_SIZE_ERROR + * The length of the frame is too large. + */ +int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame); + +/* + * Unpacks GOAWAY wire format into |frame|. The |payload| of length + * |payloadlen| contains first 8 bytes of payload. The + * |var_gift_payload| of length |var_gift_payloadlen| contains + * remaining payload and its buffer is gifted to the function and then + * |frame|. The |var_gift_payloadlen| must be freed by + * nghttp2_frame_goaway_free(). + */ +void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame, + const uint8_t *payload, + uint8_t *var_gift_payload, + size_t var_gift_payloadlen); + +/* + * Unpacks GOAWAY wire format into |frame|. This function only exists + * for unit test. After allocating buffer for debug data, this + * function internally calls nghttp2_frame_unpack_goaway_payload(). + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame, + const uint8_t *payload, + size_t payloadlen, nghttp2_mem *mem); + +/* + * Packs WINDOW_UPDATE frame |frame| in wire frame format and store it + * in |bufs|. + * + * The caller must make sure that nghttp2_bufs_reset(bufs) is called + * before calling this function. + * + * This function always succeeds and returns 0. + */ +int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs, + nghttp2_window_update *frame); + +/* + * Unpacks WINDOW_UPDATE frame byte sequence into |frame|. + */ +void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame, + const uint8_t *payload); + +/* + * Packs ALTSVC frame |frame| in wire frame format and store it in + * |bufs|. + * + * The caller must make sure that nghttp2_bufs_reset(bufs) is called + * before calling this function. + * + * This function always succeeds and returns 0. + */ +int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext); + +/* + * Unpacks ALTSVC wire format into |frame|. The |payload| of + * |payloadlen| bytes contains frame payload. This function assumes + * that frame->payload points to the nghttp2_ext_altsvc object. + * + * This function always succeeds and returns 0. + */ +void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame, + size_t origin_len, uint8_t *payload, + size_t payloadlen); + +/* + * Unpacks ALTSVC wire format into |frame|. This function only exists + * for unit test. After allocating buffer for fields, this function + * internally calls nghttp2_frame_unpack_altsvc_payload(). + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_FRAME_SIZE_ERROR + * The payload is too small. + */ +int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame, + const uint8_t *payload, + size_t payloadlen, nghttp2_mem *mem); + +/* + * Initializes HEADERS frame |frame| with given values. |frame| takes + * ownership of |nva|, so caller must not free it. If |stream_id| is + * not assigned yet, it must be -1. + */ +void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags, + int32_t stream_id, nghttp2_headers_category cat, + const nghttp2_priority_spec *pri_spec, + nghttp2_nv *nva, size_t nvlen); + +void nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem); + +void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id, + const nghttp2_priority_spec *pri_spec); + +void nghttp2_frame_priority_free(nghttp2_priority *frame); + +void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id, + uint32_t error_code); + +void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame); + +/* + * Initializes PUSH_PROMISE frame |frame| with given values. |frame| + * takes ownership of |nva|, so caller must not free it. + */ +void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags, + int32_t stream_id, + int32_t promised_stream_id, + nghttp2_nv *nva, size_t nvlen); + +void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame, + nghttp2_mem *mem); + +/* + * Initializes SETTINGS frame |frame| with given values. |frame| takes + * ownership of |iv|, so caller must not free it. The |flags| are + * bitwise-OR of one or more of nghttp2_settings_flag. + */ +void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags, + nghttp2_settings_entry *iv, size_t niv); + +void nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem); + +/* + * Initializes PING frame |frame| with given values. If the + * |opqeue_data| is not NULL, it must point to 8 bytes memory region + * of data. The data pointed by |opaque_data| is copied. It can be + * NULL. In this case, 8 bytes NULL is used. + */ +void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags, + const uint8_t *opque_data); + +void nghttp2_frame_ping_free(nghttp2_ping *frame); + +/* + * Initializes GOAWAY frame |frame| with given values. On success, + * this function takes ownership of |opaque_data|, so caller must not + * free it. If the |opaque_data_len| is 0, opaque_data could be NULL. + */ +void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id, + uint32_t error_code, uint8_t *opaque_data, + size_t opaque_data_len); + +void nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem); + +void nghttp2_frame_window_update_init(nghttp2_window_update *frame, + uint8_t flags, int32_t stream_id, + int32_t window_size_increment); + +void nghttp2_frame_window_update_free(nghttp2_window_update *frame); + +void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type, + uint8_t flags, int32_t stream_id, + void *payload); + +void nghttp2_frame_extension_free(nghttp2_extension *frame); + +/* + * Initializes ALTSVC frame |frame| with given values. This function + * assumes that frame->payload points to nghttp2_ext_altsvc object. + * Also |origin| and |field_value| are allocated in single buffer, + * starting |origin|. On success, this function takes ownership of + * |origin|, so caller must not free it. + */ +void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id, + uint8_t *origin, size_t origin_len, + uint8_t *field_value, size_t field_value_len); + +/* + * Frees up resources under |frame|. This function does not free + * nghttp2_ext_altsvc object pointed by frame->payload. This function + * only frees origin pointed by nghttp2_ext_altsvc.origin. Therefore, + * other fields must be allocated in the same buffer with origin. + */ +void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem); + +/* + * Returns the number of padding bytes after payload. The total + * padding length is given in the |padlen|. The returned value does + * not include the Pad Length field. If |padlen| is 0, this function + * returns 0, regardless of frame->hd.flags. + */ +size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen); + +void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags, + int32_t stream_id); + +void nghttp2_frame_data_free(nghttp2_data *frame); + +/* + * Makes copy of |iv| and return the copy. The |niv| is the number of + * entries in |iv|. This function returns the pointer to the copy if + * it succeeds, or NULL. + */ +nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv, + size_t niv, nghttp2_mem *mem); + +/* + * Sorts the |nva| in ascending order of name and value. If names are + * equivalent, sort them by value. + */ +void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen); + +/* + * Copies name/value pairs from |nva|, which contains |nvlen| pairs, + * to |*nva_ptr|, which is dynamically allocated so that all items can + * be stored. The resultant name and value in nghttp2_nv are + * guaranteed to be NULL-terminated even if the input is not + * null-terminated. + * + * The |*nva_ptr| must be freed using nghttp2_nv_array_del(). + * + * This function returns 0 if it succeeds or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva, + size_t nvlen, nghttp2_mem *mem); + +/* + * Returns nonzero if the name/value pair |a| equals to |b|. The name + * is compared in case-sensitive, because we ensure that this function + * is called after the name is lower-cased. + */ +int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b); + +/* + * Frees |nva|. + */ +void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem); + +/* + * Checks that the |iv|, which includes |niv| entries, does not have + * invalid values. + * + * This function returns nonzero if it succeeds, or 0. + */ +int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv); + +/* + * Sets Pad Length field and flags and adjusts frame header position + * of each buffers in |bufs|. The number of padding is given in the + * |padlen| including Pad Length field. The |hd| is the frame header + * for the serialized data. This function fills zeros padding region + * unless framehd_only is nonzero. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_FRAME_SIZE_ERROR + * The length of the resulting frame is too large. + */ +int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd, + size_t padlen, int framehd_only); + +#endif /* NGHTTP2_FRAME_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd.c new file mode 100644 index 00000000..d7e80a23 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd.c @@ -0,0 +1,2317 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_hd.h" + +#include +#include +#include + +#include "nghttp2_helper.h" +#include "nghttp2_int.h" +#include "nghttp2_debug.h" + +/* Make scalar initialization form of nghttp2_hd_entry */ +#define MAKE_STATIC_ENT(N, V, T, H) \ + { \ + {NULL, NULL, (uint8_t *)(N), sizeof((N)) - 1, -1}, \ + {NULL, NULL, (uint8_t *)(V), sizeof((V)) - 1, -1}, \ + {(uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0}, \ + T, H \ + } + +/* Generated by mkstatictbl.py */ +/* 3rd parameter is nghttp2_token value for header field name. We use + first enum value if same header names are repeated (e.g., + :status). */ +static nghttp2_hd_static_entry static_table[] = { + MAKE_STATIC_ENT(":authority", "", 0, 3153725150u), + MAKE_STATIC_ENT(":method", "GET", 1, 695666056u), + MAKE_STATIC_ENT(":method", "POST", 1, 695666056u), + MAKE_STATIC_ENT(":path", "/", 3, 3292848686u), + MAKE_STATIC_ENT(":path", "/index.html", 3, 3292848686u), + MAKE_STATIC_ENT(":scheme", "http", 5, 2510477674u), + MAKE_STATIC_ENT(":scheme", "https", 5, 2510477674u), + MAKE_STATIC_ENT(":status", "200", 7, 4000288983u), + MAKE_STATIC_ENT(":status", "204", 7, 4000288983u), + MAKE_STATIC_ENT(":status", "206", 7, 4000288983u), + MAKE_STATIC_ENT(":status", "304", 7, 4000288983u), + MAKE_STATIC_ENT(":status", "400", 7, 4000288983u), + MAKE_STATIC_ENT(":status", "404", 7, 4000288983u), + MAKE_STATIC_ENT(":status", "500", 7, 4000288983u), + MAKE_STATIC_ENT("accept-charset", "", 14, 3664010344u), + MAKE_STATIC_ENT("accept-encoding", "gzip, deflate", 15, 3379649177u), + MAKE_STATIC_ENT("accept-language", "", 16, 1979086614u), + MAKE_STATIC_ENT("accept-ranges", "", 17, 1713753958u), + MAKE_STATIC_ENT("accept", "", 18, 136609321u), + MAKE_STATIC_ENT("access-control-allow-origin", "", 19, 2710797292u), + MAKE_STATIC_ENT("age", "", 20, 742476188u), + MAKE_STATIC_ENT("allow", "", 21, 2930878514u), + MAKE_STATIC_ENT("authorization", "", 22, 2436257726u), + MAKE_STATIC_ENT("cache-control", "", 23, 1355326669u), + MAKE_STATIC_ENT("content-disposition", "", 24, 3889184348u), + MAKE_STATIC_ENT("content-encoding", "", 25, 65203592u), + MAKE_STATIC_ENT("content-language", "", 26, 24973587u), + MAKE_STATIC_ENT("content-length", "", 27, 1308181789u), + MAKE_STATIC_ENT("content-location", "", 28, 2302364718u), + MAKE_STATIC_ENT("content-range", "", 29, 3555523146u), + MAKE_STATIC_ENT("content-type", "", 30, 4244048277u), + MAKE_STATIC_ENT("cookie", "", 31, 2007449791u), + MAKE_STATIC_ENT("date", "", 32, 3564297305u), + MAKE_STATIC_ENT("etag", "", 33, 113792960u), + MAKE_STATIC_ENT("expect", "", 34, 2530896728u), + MAKE_STATIC_ENT("expires", "", 35, 1049544579u), + MAKE_STATIC_ENT("from", "", 36, 2513272949u), + MAKE_STATIC_ENT("host", "", 37, 2952701295u), + MAKE_STATIC_ENT("if-match", "", 38, 3597694698u), + MAKE_STATIC_ENT("if-modified-since", "", 39, 2213050793u), + MAKE_STATIC_ENT("if-none-match", "", 40, 2536202615u), + MAKE_STATIC_ENT("if-range", "", 41, 2340978238u), + MAKE_STATIC_ENT("if-unmodified-since", "", 42, 3794814858u), + MAKE_STATIC_ENT("last-modified", "", 43, 3226950251u), + MAKE_STATIC_ENT("link", "", 44, 232457833u), + MAKE_STATIC_ENT("location", "", 45, 200649126u), + MAKE_STATIC_ENT("max-forwards", "", 46, 1826162134u), + MAKE_STATIC_ENT("proxy-authenticate", "", 47, 2709445359u), + MAKE_STATIC_ENT("proxy-authorization", "", 48, 2686392507u), + MAKE_STATIC_ENT("range", "", 49, 4208725202u), + MAKE_STATIC_ENT("referer", "", 50, 3969579366u), + MAKE_STATIC_ENT("refresh", "", 51, 3572655668u), + MAKE_STATIC_ENT("retry-after", "", 52, 3336180598u), + MAKE_STATIC_ENT("server", "", 53, 1085029842u), + MAKE_STATIC_ENT("set-cookie", "", 54, 1848371000u), + MAKE_STATIC_ENT("strict-transport-security", "", 55, 4138147361u), + MAKE_STATIC_ENT("transfer-encoding", "", 56, 3719590988u), + MAKE_STATIC_ENT("user-agent", "", 57, 606444526u), + MAKE_STATIC_ENT("vary", "", 58, 1085005381u), + MAKE_STATIC_ENT("via", "", 59, 1762798611u), + MAKE_STATIC_ENT("www-authenticate", "", 60, 779865858u), +}; + +static int memeq(const void *s1, const void *s2, size_t n) { + return memcmp(s1, s2, n) == 0; +} + +/* + * This function was generated by genlibtokenlookup.py. Inspired by + * h2o header lookup. https://github.com/h2o/h2o + */ +static int32_t lookup_token(const uint8_t *name, size_t namelen) { + switch (namelen) { + case 2: + switch (name[1]) { + case 'e': + if (memeq("t", name, 1)) { + return NGHTTP2_TOKEN_TE; + } + break; + } + break; + case 3: + switch (name[2]) { + case 'a': + if (memeq("vi", name, 2)) { + return NGHTTP2_TOKEN_VIA; + } + break; + case 'e': + if (memeq("ag", name, 2)) { + return NGHTTP2_TOKEN_AGE; + } + break; + } + break; + case 4: + switch (name[3]) { + case 'e': + if (memeq("dat", name, 3)) { + return NGHTTP2_TOKEN_DATE; + } + break; + case 'g': + if (memeq("eta", name, 3)) { + return NGHTTP2_TOKEN_ETAG; + } + break; + case 'k': + if (memeq("lin", name, 3)) { + return NGHTTP2_TOKEN_LINK; + } + break; + case 'm': + if (memeq("fro", name, 3)) { + return NGHTTP2_TOKEN_FROM; + } + break; + case 't': + if (memeq("hos", name, 3)) { + return NGHTTP2_TOKEN_HOST; + } + break; + case 'y': + if (memeq("var", name, 3)) { + return NGHTTP2_TOKEN_VARY; + } + break; + } + break; + case 5: + switch (name[4]) { + case 'e': + if (memeq("rang", name, 4)) { + return NGHTTP2_TOKEN_RANGE; + } + break; + case 'h': + if (memeq(":pat", name, 4)) { + return NGHTTP2_TOKEN__PATH; + } + break; + case 'w': + if (memeq("allo", name, 4)) { + return NGHTTP2_TOKEN_ALLOW; + } + break; + } + break; + case 6: + switch (name[5]) { + case 'e': + if (memeq("cooki", name, 5)) { + return NGHTTP2_TOKEN_COOKIE; + } + break; + case 'r': + if (memeq("serve", name, 5)) { + return NGHTTP2_TOKEN_SERVER; + } + break; + case 't': + if (memeq("accep", name, 5)) { + return NGHTTP2_TOKEN_ACCEPT; + } + if (memeq("expec", name, 5)) { + return NGHTTP2_TOKEN_EXPECT; + } + break; + } + break; + case 7: + switch (name[6]) { + case 'd': + if (memeq(":metho", name, 6)) { + return NGHTTP2_TOKEN__METHOD; + } + break; + case 'e': + if (memeq(":schem", name, 6)) { + return NGHTTP2_TOKEN__SCHEME; + } + if (memeq("upgrad", name, 6)) { + return NGHTTP2_TOKEN_UPGRADE; + } + break; + case 'h': + if (memeq("refres", name, 6)) { + return NGHTTP2_TOKEN_REFRESH; + } + break; + case 'r': + if (memeq("refere", name, 6)) { + return NGHTTP2_TOKEN_REFERER; + } + break; + case 's': + if (memeq(":statu", name, 6)) { + return NGHTTP2_TOKEN__STATUS; + } + if (memeq("expire", name, 6)) { + return NGHTTP2_TOKEN_EXPIRES; + } + break; + } + break; + case 8: + switch (name[7]) { + case 'e': + if (memeq("if-rang", name, 7)) { + return NGHTTP2_TOKEN_IF_RANGE; + } + break; + case 'h': + if (memeq("if-matc", name, 7)) { + return NGHTTP2_TOKEN_IF_MATCH; + } + break; + case 'n': + if (memeq("locatio", name, 7)) { + return NGHTTP2_TOKEN_LOCATION; + } + break; + } + break; + case 10: + switch (name[9]) { + case 'e': + if (memeq("keep-aliv", name, 9)) { + return NGHTTP2_TOKEN_KEEP_ALIVE; + } + if (memeq("set-cooki", name, 9)) { + return NGHTTP2_TOKEN_SET_COOKIE; + } + break; + case 'n': + if (memeq("connectio", name, 9)) { + return NGHTTP2_TOKEN_CONNECTION; + } + break; + case 't': + if (memeq("user-agen", name, 9)) { + return NGHTTP2_TOKEN_USER_AGENT; + } + break; + case 'y': + if (memeq(":authorit", name, 9)) { + return NGHTTP2_TOKEN__AUTHORITY; + } + break; + } + break; + case 11: + switch (name[10]) { + case 'r': + if (memeq("retry-afte", name, 10)) { + return NGHTTP2_TOKEN_RETRY_AFTER; + } + break; + } + break; + case 12: + switch (name[11]) { + case 'e': + if (memeq("content-typ", name, 11)) { + return NGHTTP2_TOKEN_CONTENT_TYPE; + } + break; + case 's': + if (memeq("max-forward", name, 11)) { + return NGHTTP2_TOKEN_MAX_FORWARDS; + } + break; + } + break; + case 13: + switch (name[12]) { + case 'd': + if (memeq("last-modifie", name, 12)) { + return NGHTTP2_TOKEN_LAST_MODIFIED; + } + break; + case 'e': + if (memeq("content-rang", name, 12)) { + return NGHTTP2_TOKEN_CONTENT_RANGE; + } + break; + case 'h': + if (memeq("if-none-matc", name, 12)) { + return NGHTTP2_TOKEN_IF_NONE_MATCH; + } + break; + case 'l': + if (memeq("cache-contro", name, 12)) { + return NGHTTP2_TOKEN_CACHE_CONTROL; + } + break; + case 'n': + if (memeq("authorizatio", name, 12)) { + return NGHTTP2_TOKEN_AUTHORIZATION; + } + break; + case 's': + if (memeq("accept-range", name, 12)) { + return NGHTTP2_TOKEN_ACCEPT_RANGES; + } + break; + } + break; + case 14: + switch (name[13]) { + case 'h': + if (memeq("content-lengt", name, 13)) { + return NGHTTP2_TOKEN_CONTENT_LENGTH; + } + break; + case 't': + if (memeq("accept-charse", name, 13)) { + return NGHTTP2_TOKEN_ACCEPT_CHARSET; + } + break; + } + break; + case 15: + switch (name[14]) { + case 'e': + if (memeq("accept-languag", name, 14)) { + return NGHTTP2_TOKEN_ACCEPT_LANGUAGE; + } + break; + case 'g': + if (memeq("accept-encodin", name, 14)) { + return NGHTTP2_TOKEN_ACCEPT_ENCODING; + } + break; + } + break; + case 16: + switch (name[15]) { + case 'e': + if (memeq("content-languag", name, 15)) { + return NGHTTP2_TOKEN_CONTENT_LANGUAGE; + } + if (memeq("www-authenticat", name, 15)) { + return NGHTTP2_TOKEN_WWW_AUTHENTICATE; + } + break; + case 'g': + if (memeq("content-encodin", name, 15)) { + return NGHTTP2_TOKEN_CONTENT_ENCODING; + } + break; + case 'n': + if (memeq("content-locatio", name, 15)) { + return NGHTTP2_TOKEN_CONTENT_LOCATION; + } + if (memeq("proxy-connectio", name, 15)) { + return NGHTTP2_TOKEN_PROXY_CONNECTION; + } + break; + } + break; + case 17: + switch (name[16]) { + case 'e': + if (memeq("if-modified-sinc", name, 16)) { + return NGHTTP2_TOKEN_IF_MODIFIED_SINCE; + } + break; + case 'g': + if (memeq("transfer-encodin", name, 16)) { + return NGHTTP2_TOKEN_TRANSFER_ENCODING; + } + break; + } + break; + case 18: + switch (name[17]) { + case 'e': + if (memeq("proxy-authenticat", name, 17)) { + return NGHTTP2_TOKEN_PROXY_AUTHENTICATE; + } + break; + } + break; + case 19: + switch (name[18]) { + case 'e': + if (memeq("if-unmodified-sinc", name, 18)) { + return NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE; + } + break; + case 'n': + if (memeq("content-dispositio", name, 18)) { + return NGHTTP2_TOKEN_CONTENT_DISPOSITION; + } + if (memeq("proxy-authorizatio", name, 18)) { + return NGHTTP2_TOKEN_PROXY_AUTHORIZATION; + } + break; + } + break; + case 25: + switch (name[24]) { + case 'y': + if (memeq("strict-transport-securit", name, 24)) { + return NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY; + } + break; + } + break; + case 27: + switch (name[26]) { + case 'n': + if (memeq("access-control-allow-origi", name, 26)) { + return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN; + } + break; + } + break; + } + return -1; +} + +void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv) { + ent->nv = *nv; + ent->cnv.name = nv->name->base; + ent->cnv.namelen = nv->name->len; + ent->cnv.value = nv->value->base; + ent->cnv.valuelen = nv->value->len; + ent->cnv.flags = nv->flags; + ent->next = NULL; + ent->hash = 0; + + nghttp2_rcbuf_incref(ent->nv.name); + nghttp2_rcbuf_incref(ent->nv.value); +} + +void nghttp2_hd_entry_free(nghttp2_hd_entry *ent) { + nghttp2_rcbuf_decref(ent->nv.value); + nghttp2_rcbuf_decref(ent->nv.name); +} + +static int name_eq(const nghttp2_hd_nv *a, const nghttp2_nv *b) { + return a->name->len == b->namelen && + memeq(a->name->base, b->name, b->namelen); +} + +static int value_eq(const nghttp2_hd_nv *a, const nghttp2_nv *b) { + return a->value->len == b->valuelen && + memeq(a->value->base, b->value, b->valuelen); +} + +static uint32_t name_hash(const nghttp2_nv *nv) { + /* 32 bit FNV-1a: http://isthe.com/chongo/tech/comp/fnv/ */ + uint32_t h = 2166136261u; + size_t i; + + for (i = 0; i < nv->namelen; ++i) { + h ^= nv->name[i]; + h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24); + } + + return h; +} + +static void hd_map_init(nghttp2_hd_map *map) { + memset(map, 0, sizeof(nghttp2_hd_map)); +} + +static void hd_map_insert(nghttp2_hd_map *map, nghttp2_hd_entry *ent) { + nghttp2_hd_entry **bucket; + + bucket = &map->table[ent->hash & (HD_MAP_SIZE - 1)]; + + if (*bucket == NULL) { + *bucket = ent; + return; + } + + /* lower index is linked near the root */ + ent->next = *bucket; + *bucket = ent; +} + +static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match, + const nghttp2_nv *nv, int32_t token, + uint32_t hash, int name_only) { + nghttp2_hd_entry *p; + nghttp2_hd_entry *res = NULL; + + *exact_match = 0; + + for (p = map->table[hash & (HD_MAP_SIZE - 1)]; p; p = p->next) { + if (token != p->nv.token || + (token == -1 && (hash != p->hash || !name_eq(&p->nv, nv)))) { + continue; + } + if (!res) { + res = p; + if (name_only) { + break; + } + } + if (value_eq(&p->nv, nv)) { + res = p; + *exact_match = 1; + break; + } + } + + return res; +} + +static void hd_map_remove(nghttp2_hd_map *map, nghttp2_hd_entry *ent) { + nghttp2_hd_entry **dst; + + dst = &map->table[ent->hash & (HD_MAP_SIZE - 1)]; + + for (; *dst; dst = &(*dst)->next) { + if (*dst != ent) { + continue; + } + + *dst = ent->next; + ent->next = NULL; + return; + } +} + +static int hd_ringbuf_init(nghttp2_hd_ringbuf *ringbuf, size_t bufsize, + nghttp2_mem *mem) { + size_t size; + for (size = 1; size < bufsize; size <<= 1) + ; + ringbuf->buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size); + if (ringbuf->buffer == NULL) { + return NGHTTP2_ERR_NOMEM; + } + ringbuf->mask = size - 1; + ringbuf->first = 0; + ringbuf->len = 0; + return 0; +} + +static nghttp2_hd_entry *hd_ringbuf_get(nghttp2_hd_ringbuf *ringbuf, + size_t idx) { + assert(idx < ringbuf->len); + return ringbuf->buffer[(ringbuf->first + idx) & ringbuf->mask]; +} + +static int hd_ringbuf_reserve(nghttp2_hd_ringbuf *ringbuf, size_t bufsize, + nghttp2_mem *mem) { + size_t i; + size_t size; + nghttp2_hd_entry **buffer; + + if (ringbuf->mask + 1 >= bufsize) { + return 0; + } + for (size = 1; size < bufsize; size <<= 1) + ; + buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size); + if (buffer == NULL) { + return NGHTTP2_ERR_NOMEM; + } + for (i = 0; i < ringbuf->len; ++i) { + buffer[i] = hd_ringbuf_get(ringbuf, i); + } + nghttp2_mem_free(mem, ringbuf->buffer); + ringbuf->buffer = buffer; + ringbuf->mask = size - 1; + ringbuf->first = 0; + return 0; +} + +static void hd_ringbuf_free(nghttp2_hd_ringbuf *ringbuf, nghttp2_mem *mem) { + size_t i; + if (ringbuf == NULL) { + return; + } + for (i = 0; i < ringbuf->len; ++i) { + nghttp2_hd_entry *ent = hd_ringbuf_get(ringbuf, i); + + nghttp2_hd_entry_free(ent); + nghttp2_mem_free(mem, ent); + } + nghttp2_mem_free(mem, ringbuf->buffer); +} + +static int hd_ringbuf_push_front(nghttp2_hd_ringbuf *ringbuf, + nghttp2_hd_entry *ent, nghttp2_mem *mem) { + int rv; + + rv = hd_ringbuf_reserve(ringbuf, ringbuf->len + 1, mem); + + if (rv != 0) { + return rv; + } + + ringbuf->buffer[--ringbuf->first & ringbuf->mask] = ent; + ++ringbuf->len; + + return 0; +} + +static void hd_ringbuf_pop_back(nghttp2_hd_ringbuf *ringbuf) { + assert(ringbuf->len > 0); + --ringbuf->len; +} + +static int hd_context_init(nghttp2_hd_context *context, nghttp2_mem *mem) { + int rv; + context->mem = mem; + context->bad = 0; + context->hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; + rv = hd_ringbuf_init( + &context->hd_table, + context->hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD, mem); + if (rv != 0) { + return rv; + } + + context->hd_table_bufsize = 0; + context->next_seq = 0; + + return 0; +} + +static void hd_context_free(nghttp2_hd_context *context) { + hd_ringbuf_free(&context->hd_table, context->mem); +} + +int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem) { + return nghttp2_hd_deflate_init2( + deflater, NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE, mem); +} + +int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, + size_t max_deflate_dynamic_table_size, + nghttp2_mem *mem) { + int rv; + rv = hd_context_init(&deflater->ctx, mem); + if (rv != 0) { + return rv; + } + + hd_map_init(&deflater->map); + + if (max_deflate_dynamic_table_size < NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE) { + deflater->notify_table_size_change = 1; + deflater->ctx.hd_table_bufsize_max = max_deflate_dynamic_table_size; + } else { + deflater->notify_table_size_change = 0; + } + + deflater->deflate_hd_table_bufsize_max = max_deflate_dynamic_table_size; + deflater->min_hd_table_bufsize_max = UINT32_MAX; + + return 0; +} + +int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem) { + int rv; + + rv = hd_context_init(&inflater->ctx, mem); + if (rv != 0) { + goto fail; + } + + inflater->settings_hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; + inflater->min_hd_table_bufsize_max = UINT32_MAX; + + inflater->nv_name_keep = NULL; + inflater->nv_value_keep = NULL; + + inflater->opcode = NGHTTP2_HD_OPCODE_NONE; + inflater->state = NGHTTP2_HD_STATE_INFLATE_START; + + nghttp2_buf_init(&inflater->namebuf); + nghttp2_buf_init(&inflater->valuebuf); + + inflater->namercbuf = NULL; + inflater->valuercbuf = NULL; + + inflater->huffman_encoded = 0; + inflater->index = 0; + inflater->left = 0; + inflater->shift = 0; + inflater->index_required = 0; + inflater->no_index = 0; + + return 0; + +fail: + return rv; +} + +static void hd_inflate_keep_free(nghttp2_hd_inflater *inflater) { + nghttp2_rcbuf_decref(inflater->nv_value_keep); + nghttp2_rcbuf_decref(inflater->nv_name_keep); + + inflater->nv_value_keep = NULL; + inflater->nv_name_keep = NULL; +} + +void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater) { + hd_context_free(&deflater->ctx); +} + +void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater) { + hd_inflate_keep_free(inflater); + + nghttp2_rcbuf_decref(inflater->valuercbuf); + nghttp2_rcbuf_decref(inflater->namercbuf); + + hd_context_free(&inflater->ctx); +} + +static size_t entry_room(size_t namelen, size_t valuelen) { + return NGHTTP2_HD_ENTRY_OVERHEAD + namelen + valuelen; +} + +static void emit_header(nghttp2_hd_nv *nv_out, nghttp2_hd_nv *nv) { + DEBUGF("inflatehd: header emission: %s: %s\n", nv->name->base, + nv->value->base); + /* ent->ref may be 0. This happens if the encoder emits literal + block larger than header table capacity with indexing. */ + *nv_out = *nv; +} + +static size_t count_encoded_length(size_t n, size_t prefix) { + size_t k = (size_t)((1 << prefix) - 1); + size_t len = 0; + + if (n < k) { + return 1; + } + + n -= k; + ++len; + + for (; n >= 128; n >>= 7, ++len) + ; + + return len + 1; +} + +static size_t encode_length(uint8_t *buf, size_t n, size_t prefix) { + size_t k = (size_t)((1 << prefix) - 1); + uint8_t *begin = buf; + + *buf = (uint8_t)(*buf & ~k); + + if (n < k) { + *buf = (uint8_t)(*buf | n); + return 1; + } + + *buf = (uint8_t)(*buf | k); + ++buf; + + n -= k; + + for (; n >= 128; n >>= 7) { + *buf++ = (uint8_t)((1 << 7) | (n & 0x7f)); + } + + *buf++ = (uint8_t)n; + + return (size_t)(buf - begin); +} + +/* + * Decodes |prefix| prefixed integer stored from |in|. The |last| + * represents the 1 beyond the last of the valid contiguous memory + * region from |in|. The decoded integer must be less than or equal + * to UINT32_MAX. + * + * If the |initial| is nonzero, it is used as a initial value, this + * function assumes the |in| starts with intermediate data. + * + * An entire integer is decoded successfully, decoded, the |*fin| is + * set to nonzero. + * + * This function stores the decoded integer in |*res| if it succeed, + * including partial decoding (in this case, number of shift to make + * in the next call will be stored in |*shift_ptr|) and returns number + * of bytes processed, or returns -1, indicating decoding error. + */ +static ssize_t decode_length(uint32_t *res, size_t *shift_ptr, int *fin, + uint32_t initial, size_t shift, const uint8_t *in, + const uint8_t *last, size_t prefix) { + uint32_t k = (uint8_t)((1 << prefix) - 1); + uint32_t n = initial; + const uint8_t *start = in; + + *shift_ptr = 0; + *fin = 0; + + if (n == 0) { + if ((*in & k) != k) { + *res = (*in) & k; + *fin = 1; + return 1; + } + + n = k; + + if (++in == last) { + *res = n; + return (ssize_t)(in - start); + } + } + + for (; in != last; ++in, shift += 7) { + uint32_t add = *in & 0x7f; + + if (shift >= 32) { + DEBUGF("inflate: shift exponent overflow\n"); + return -1; + } + + if ((UINT32_MAX >> shift) < add) { + DEBUGF("inflate: integer overflow on shift\n"); + return -1; + } + + add <<= shift; + + if (UINT32_MAX - add < n) { + DEBUGF("inflate: integer overflow on addition\n"); + return -1; + } + + n += add; + + if ((*in & (1 << 7)) == 0) { + break; + } + } + + *shift_ptr = shift; + + if (in == last) { + *res = n; + return (ssize_t)(in - start); + } + + *res = n; + *fin = 1; + return (ssize_t)(in + 1 - start); +} + +static int emit_table_size(nghttp2_bufs *bufs, size_t table_size) { + int rv; + uint8_t *bufp; + size_t blocklen; + uint8_t sb[16]; + + DEBUGF("deflatehd: emit table_size=%zu\n", table_size); + + blocklen = count_encoded_length(table_size, 5); + + if (sizeof(sb) < blocklen) { + return NGHTTP2_ERR_HEADER_COMP; + } + + bufp = sb; + + *bufp = 0x20u; + + encode_length(bufp, table_size, 5); + + rv = nghttp2_bufs_add(bufs, sb, blocklen); + if (rv != 0) { + return rv; + } + + return 0; +} + +static int emit_indexed_block(nghttp2_bufs *bufs, size_t idx) { + int rv; + size_t blocklen; + uint8_t sb[16]; + uint8_t *bufp; + + blocklen = count_encoded_length(idx + 1, 7); + + DEBUGF("deflatehd: emit indexed index=%zu, %zu bytes\n", idx, blocklen); + + if (sizeof(sb) < blocklen) { + return NGHTTP2_ERR_HEADER_COMP; + } + + bufp = sb; + *bufp = 0x80u; + encode_length(bufp, idx + 1, 7); + + rv = nghttp2_bufs_add(bufs, sb, blocklen); + if (rv != 0) { + return rv; + } + + return 0; +} + +static int emit_string(nghttp2_bufs *bufs, const uint8_t *str, size_t len) { + int rv; + uint8_t sb[16]; + uint8_t *bufp; + size_t blocklen; + size_t enclen; + int huffman = 0; + + enclen = nghttp2_hd_huff_encode_count(str, len); + + if (enclen < len) { + huffman = 1; + } else { + enclen = len; + } + + blocklen = count_encoded_length(enclen, 7); + + DEBUGF("deflatehd: emit string str=%.*s, length=%zu, huffman=%d, " + "encoded_length=%zu\n", + (int)len, (const char *)str, len, huffman, enclen); + + if (sizeof(sb) < blocklen) { + return NGHTTP2_ERR_HEADER_COMP; + } + + bufp = sb; + *bufp = huffman ? 1 << 7 : 0; + encode_length(bufp, enclen, 7); + + rv = nghttp2_bufs_add(bufs, sb, blocklen); + if (rv != 0) { + return rv; + } + + if (huffman) { + rv = nghttp2_hd_huff_encode(bufs, str, len); + } else { + assert(enclen == len); + rv = nghttp2_bufs_add(bufs, str, len); + } + + return rv; +} + +static uint8_t pack_first_byte(int indexing_mode) { + switch (indexing_mode) { + case NGHTTP2_HD_WITH_INDEXING: + return 0x40u; + case NGHTTP2_HD_WITHOUT_INDEXING: + return 0; + case NGHTTP2_HD_NEVER_INDEXING: + return 0x10u; + default: + assert(0); + } + /* This is required to compile with android NDK r10d + + --enable-werror */ + return 0; +} + +static int emit_indname_block(nghttp2_bufs *bufs, size_t idx, + const nghttp2_nv *nv, int indexing_mode) { + int rv; + uint8_t *bufp; + size_t blocklen; + uint8_t sb[16]; + size_t prefixlen; + + if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) { + prefixlen = 6; + } else { + prefixlen = 4; + } + + DEBUGF("deflatehd: emit indname index=%zu, valuelen=%zu, indexing_mode=%d\n", + idx, nv->valuelen, indexing_mode); + + blocklen = count_encoded_length(idx + 1, prefixlen); + + if (sizeof(sb) < blocklen) { + return NGHTTP2_ERR_HEADER_COMP; + } + + bufp = sb; + + *bufp = pack_first_byte(indexing_mode); + + encode_length(bufp, idx + 1, prefixlen); + + rv = nghttp2_bufs_add(bufs, sb, blocklen); + if (rv != 0) { + return rv; + } + + rv = emit_string(bufs, nv->value, nv->valuelen); + if (rv != 0) { + return rv; + } + + return 0; +} + +static int emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv, + int indexing_mode) { + int rv; + + DEBUGF( + "deflatehd: emit newname namelen=%zu, valuelen=%zu, indexing_mode=%d\n", + nv->namelen, nv->valuelen, indexing_mode); + + rv = nghttp2_bufs_addb(bufs, pack_first_byte(indexing_mode)); + if (rv != 0) { + return rv; + } + + rv = emit_string(bufs, nv->name, nv->namelen); + if (rv != 0) { + return rv; + } + + rv = emit_string(bufs, nv->value, nv->valuelen); + if (rv != 0) { + return rv; + } + + return 0; +} + +static int add_hd_table_incremental(nghttp2_hd_context *context, + nghttp2_hd_nv *nv, nghttp2_hd_map *map, + uint32_t hash) { + int rv; + nghttp2_hd_entry *new_ent; + size_t room; + nghttp2_mem *mem; + + mem = context->mem; + room = entry_room(nv->name->len, nv->value->len); + + while (context->hd_table_bufsize + room > context->hd_table_bufsize_max && + context->hd_table.len > 0) { + + size_t idx = context->hd_table.len - 1; + nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx); + + context->hd_table_bufsize -= + entry_room(ent->nv.name->len, ent->nv.value->len); + + DEBUGF("hpack: remove item from header table: %s: %s\n", + (char *)ent->nv.name->base, (char *)ent->nv.value->base); + + hd_ringbuf_pop_back(&context->hd_table); + if (map) { + hd_map_remove(map, ent); + } + + nghttp2_hd_entry_free(ent); + nghttp2_mem_free(mem, ent); + } + + if (room > context->hd_table_bufsize_max) { + /* The entry taking more than NGHTTP2_HD_MAX_BUFFER_SIZE is + immediately evicted. So we don't allocate memory for it. */ + return 0; + } + + new_ent = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry)); + if (new_ent == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_hd_entry_init(new_ent, nv); + + rv = hd_ringbuf_push_front(&context->hd_table, new_ent, mem); + + if (rv != 0) { + nghttp2_hd_entry_free(new_ent); + nghttp2_mem_free(mem, new_ent); + + return rv; + } + + new_ent->seq = context->next_seq++; + new_ent->hash = hash; + + if (map) { + hd_map_insert(map, new_ent); + } + + context->hd_table_bufsize += room; + + return 0; +} + +typedef struct { + ssize_t index; + /* Nonzero if both name and value are matched. */ + int name_value_match; +} search_result; + +static search_result search_static_table(const nghttp2_nv *nv, int32_t token, + int name_only) { + search_result res = {token, 0}; + int i; + nghttp2_hd_static_entry *ent; + + if (name_only) { + return res; + } + + for (i = token; + i <= NGHTTP2_TOKEN_WWW_AUTHENTICATE && static_table[i].token == token; + ++i) { + ent = &static_table[i]; + if (ent->value.len == nv->valuelen && + memcmp(ent->value.base, nv->value, nv->valuelen) == 0) { + res.index = i; + res.name_value_match = 1; + return res; + } + } + return res; +} + +static search_result search_hd_table(nghttp2_hd_context *context, + const nghttp2_nv *nv, int32_t token, + int indexing_mode, nghttp2_hd_map *map, + uint32_t hash) { + search_result res = {-1, 0}; + nghttp2_hd_entry *ent; + int exact_match; + int name_only = indexing_mode == NGHTTP2_HD_NEVER_INDEXING; + + exact_match = 0; + ent = hd_map_find(map, &exact_match, nv, token, hash, name_only); + + if (!exact_match && token >= 0 && token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) { + return search_static_table(nv, token, name_only); + } + + if (ent == NULL) { + return res; + } + + res.index = + (ssize_t)(context->next_seq - 1 - ent->seq + NGHTTP2_STATIC_TABLE_LENGTH); + res.name_value_match = exact_match; + + return res; +} + +static void hd_context_shrink_table_size(nghttp2_hd_context *context, + nghttp2_hd_map *map) { + nghttp2_mem *mem; + + mem = context->mem; + + while (context->hd_table_bufsize > context->hd_table_bufsize_max && + context->hd_table.len > 0) { + size_t idx = context->hd_table.len - 1; + nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx); + context->hd_table_bufsize -= + entry_room(ent->nv.name->len, ent->nv.value->len); + hd_ringbuf_pop_back(&context->hd_table); + if (map) { + hd_map_remove(map, ent); + } + + nghttp2_hd_entry_free(ent); + nghttp2_mem_free(mem, ent); + } +} + +int nghttp2_hd_deflate_change_table_size( + nghttp2_hd_deflater *deflater, size_t settings_max_dynamic_table_size) { + size_t next_bufsize = nghttp2_min(settings_max_dynamic_table_size, + deflater->deflate_hd_table_bufsize_max); + + deflater->ctx.hd_table_bufsize_max = next_bufsize; + + deflater->min_hd_table_bufsize_max = + nghttp2_min(deflater->min_hd_table_bufsize_max, next_bufsize); + + deflater->notify_table_size_change = 1; + + hd_context_shrink_table_size(&deflater->ctx, &deflater->map); + return 0; +} + +int nghttp2_hd_inflate_change_table_size( + nghttp2_hd_inflater *inflater, size_t settings_max_dynamic_table_size) { + switch (inflater->state) { + case NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE: + case NGHTTP2_HD_STATE_INFLATE_START: + break; + default: + return NGHTTP2_ERR_INVALID_STATE; + } + + /* It seems that encoder is not required to send dynamic table size + update if the table size is not changed after applying + SETTINGS_HEADER_TABLE_SIZE. RFC 7541 is ambiguous here, but this + is the intention of the editor. If new maximum table size is + strictly smaller than the current negotiated maximum size, + encoder must send dynamic table size update. In other cases, we + cannot expect it to do so. */ + if (inflater->ctx.hd_table_bufsize_max > settings_max_dynamic_table_size) { + inflater->state = NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE; + /* Remember minimum value, and validate that encoder sends the + value less than or equal to this. */ + inflater->min_hd_table_bufsize_max = settings_max_dynamic_table_size; + } + + inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size; + + inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size; + + hd_context_shrink_table_size(&inflater->ctx, NULL); + return 0; +} + +#define INDEX_RANGE_VALID(context, idx) \ + ((idx) < (context)->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH) + +static size_t get_max_index(nghttp2_hd_context *context) { + return context->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH; +} + +nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t idx) { + assert(INDEX_RANGE_VALID(context, idx)); + if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) { + return hd_ringbuf_get(&context->hd_table, idx - NGHTTP2_STATIC_TABLE_LENGTH) + ->nv; + } else { + nghttp2_hd_static_entry *ent = &static_table[idx]; + nghttp2_hd_nv nv = {&ent->name, &ent->value, ent->token, + NGHTTP2_NV_FLAG_NONE}; + return nv; + } +} + +static const nghttp2_nv *nghttp2_hd_table_get2(nghttp2_hd_context *context, + size_t idx) { + assert(INDEX_RANGE_VALID(context, idx)); + if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) { + return &hd_ringbuf_get(&context->hd_table, + idx - NGHTTP2_STATIC_TABLE_LENGTH) + ->cnv; + } + + return &static_table[idx].cnv; +} + +static int hd_deflate_decide_indexing(nghttp2_hd_deflater *deflater, + const nghttp2_nv *nv, int32_t token) { + if (token == NGHTTP2_TOKEN__PATH || token == NGHTTP2_TOKEN_AGE || + token == NGHTTP2_TOKEN_CONTENT_LENGTH || token == NGHTTP2_TOKEN_ETAG || + token == NGHTTP2_TOKEN_IF_MODIFIED_SINCE || + token == NGHTTP2_TOKEN_IF_NONE_MATCH || token == NGHTTP2_TOKEN_LOCATION || + token == NGHTTP2_TOKEN_SET_COOKIE || + entry_room(nv->namelen, nv->valuelen) > + deflater->ctx.hd_table_bufsize_max * 3 / 4) { + return NGHTTP2_HD_WITHOUT_INDEXING; + } + + return NGHTTP2_HD_WITH_INDEXING; +} + +static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs, + const nghttp2_nv *nv) { + int rv; + search_result res; + ssize_t idx; + int indexing_mode; + int32_t token; + nghttp2_mem *mem; + uint32_t hash = 0; + + DEBUGF("deflatehd: deflating %.*s: %.*s\n", (int)nv->namelen, nv->name, + (int)nv->valuelen, nv->value); + + mem = deflater->ctx.mem; + + token = lookup_token(nv->name, nv->namelen); + if (token == -1) { + hash = name_hash(nv); + } else if (token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) { + hash = static_table[token].hash; + } + + /* Don't index authorization header field since it may contain low + entropy secret data (e.g., id/password). Also cookie header + field with less than 20 bytes value is also never indexed. This + is the same criteria used in Firefox codebase. */ + indexing_mode = + token == NGHTTP2_TOKEN_AUTHORIZATION || + (token == NGHTTP2_TOKEN_COOKIE && nv->valuelen < 20) || + (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) + ? NGHTTP2_HD_NEVER_INDEXING + : hd_deflate_decide_indexing(deflater, nv, token); + + res = search_hd_table(&deflater->ctx, nv, token, indexing_mode, + &deflater->map, hash); + + idx = res.index; + + if (res.name_value_match) { + + DEBUGF("deflatehd: name/value match index=%zd\n", idx); + + rv = emit_indexed_block(bufs, (size_t)idx); + if (rv != 0) { + return rv; + } + + return 0; + } + + if (res.index != -1) { + DEBUGF("deflatehd: name match index=%zd\n", res.index); + } + + if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) { + nghttp2_hd_nv hd_nv; + + if (idx != -1 && idx < (ssize_t)NGHTTP2_STATIC_TABLE_LENGTH) { + hd_nv.name = nghttp2_hd_table_get(&deflater->ctx, (size_t)idx).name; + nghttp2_rcbuf_incref(hd_nv.name); + } else { + rv = nghttp2_rcbuf_new2(&hd_nv.name, nv->name, nv->namelen, mem); + if (rv != 0) { + return rv; + } + } + + rv = nghttp2_rcbuf_new2(&hd_nv.value, nv->value, nv->valuelen, mem); + + if (rv != 0) { + nghttp2_rcbuf_decref(hd_nv.name); + return rv; + } + + hd_nv.token = token; + hd_nv.flags = NGHTTP2_NV_FLAG_NONE; + + rv = add_hd_table_incremental(&deflater->ctx, &hd_nv, &deflater->map, hash); + + nghttp2_rcbuf_decref(hd_nv.value); + nghttp2_rcbuf_decref(hd_nv.name); + + if (rv != 0) { + return NGHTTP2_ERR_HEADER_COMP; + } + } + if (idx == -1) { + rv = emit_newname_block(bufs, nv, indexing_mode); + } else { + rv = emit_indname_block(bufs, (size_t)idx, nv, indexing_mode); + } + if (rv != 0) { + return rv; + } + + return 0; +} + +int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater, + nghttp2_bufs *bufs, const nghttp2_nv *nv, + size_t nvlen) { + size_t i; + int rv = 0; + + if (deflater->ctx.bad) { + return NGHTTP2_ERR_HEADER_COMP; + } + + if (deflater->notify_table_size_change) { + size_t min_hd_table_bufsize_max; + + min_hd_table_bufsize_max = deflater->min_hd_table_bufsize_max; + + deflater->notify_table_size_change = 0; + deflater->min_hd_table_bufsize_max = UINT32_MAX; + + if (deflater->ctx.hd_table_bufsize_max > min_hd_table_bufsize_max) { + + rv = emit_table_size(bufs, min_hd_table_bufsize_max); + + if (rv != 0) { + goto fail; + } + } + + rv = emit_table_size(bufs, deflater->ctx.hd_table_bufsize_max); + + if (rv != 0) { + goto fail; + } + } + + for (i = 0; i < nvlen; ++i) { + rv = deflate_nv(deflater, bufs, &nv[i]); + if (rv != 0) { + goto fail; + } + } + + DEBUGF("deflatehd: all input name/value pairs were deflated\n"); + + return 0; +fail: + DEBUGF("deflatehd: error return %d\n", rv); + + deflater->ctx.bad = 1; + return rv; +} + +ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf, + size_t buflen, const nghttp2_nv *nv, + size_t nvlen) { + nghttp2_bufs bufs; + int rv; + nghttp2_mem *mem; + + mem = deflater->ctx.mem; + + rv = nghttp2_bufs_wrap_init(&bufs, buf, buflen, mem); + + if (rv != 0) { + return rv; + } + + rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, nv, nvlen); + + buflen = nghttp2_bufs_len(&bufs); + + nghttp2_bufs_wrap_free(&bufs); + + if (rv == NGHTTP2_ERR_BUFFER_ERROR) { + return NGHTTP2_ERR_INSUFF_BUFSIZE; + } + + if (rv != 0) { + return rv; + } + + return (ssize_t)buflen; +} + +ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater, + const nghttp2_vec *vec, size_t veclen, + const nghttp2_nv *nv, size_t nvlen) { + nghttp2_bufs bufs; + int rv; + nghttp2_mem *mem; + size_t buflen; + + mem = deflater->ctx.mem; + + rv = nghttp2_bufs_wrap_init2(&bufs, vec, veclen, mem); + + if (rv != 0) { + return rv; + } + + rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, nv, nvlen); + + buflen = nghttp2_bufs_len(&bufs); + + nghttp2_bufs_wrap_free(&bufs); + + if (rv == NGHTTP2_ERR_BUFFER_ERROR) { + return NGHTTP2_ERR_INSUFF_BUFSIZE; + } + + if (rv != 0) { + return rv; + } + + return (ssize_t)buflen; +} + +size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater, + const nghttp2_nv *nva, size_t nvlen) { + size_t n = 0; + size_t i; + (void)deflater; + + /* Possible Maximum Header Table Size Change. Encoding (1u << 31) - + 1 using 4 bit prefix requires 6 bytes. We may emit this at most + twice. */ + n += 12; + + /* Use Literal Header Field without indexing - New Name, since it is + most space consuming format. Also we choose the less one between + non-huffman and huffman, so using literal byte count is + sufficient for upper bound. + + Encoding (1u << 31) - 1 using 7 bit prefix requires 6 bytes. We + need 2 of this for |nvlen| header fields. */ + n += 6 * 2 * nvlen; + + for (i = 0; i < nvlen; ++i) { + n += nva[i].namelen + nva[i].valuelen; + } + + return n; +} + +int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr, + size_t deflate_hd_table_bufsize_max) { + return nghttp2_hd_deflate_new2(deflater_ptr, deflate_hd_table_bufsize_max, + NULL); +} + +int nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr, + size_t deflate_hd_table_bufsize_max, + nghttp2_mem *mem) { + int rv; + nghttp2_hd_deflater *deflater; + + if (mem == NULL) { + mem = nghttp2_mem_default(); + } + + deflater = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_deflater)); + + if (deflater == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + rv = nghttp2_hd_deflate_init2(deflater, deflate_hd_table_bufsize_max, mem); + + if (rv != 0) { + nghttp2_mem_free(mem, deflater); + + return rv; + } + + *deflater_ptr = deflater; + + return 0; +} + +void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater) { + nghttp2_mem *mem; + + mem = deflater->ctx.mem; + + nghttp2_hd_deflate_free(deflater); + + nghttp2_mem_free(mem, deflater); +} + +static void hd_inflate_set_huffman_encoded(nghttp2_hd_inflater *inflater, + const uint8_t *in) { + inflater->huffman_encoded = (*in & (1 << 7)) != 0; +} + +/* + * Decodes the integer from the range [in, last). The result is + * assigned to |inflater->left|. If the |inflater->left| is 0, then + * it performs variable integer decoding from scratch. Otherwise, it + * uses the |inflater->left| as the initial value and continues to + * decode assuming that [in, last) begins with intermediary sequence. + * + * This function returns the number of bytes read if it succeeds, or + * one of the following negative error codes: + * + * NGHTTP2_ERR_HEADER_COMP + * Integer decoding failed + */ +static ssize_t hd_inflate_read_len(nghttp2_hd_inflater *inflater, int *rfin, + const uint8_t *in, const uint8_t *last, + size_t prefix, size_t maxlen) { + ssize_t rv; + uint32_t out; + + *rfin = 0; + + rv = decode_length(&out, &inflater->shift, rfin, (uint32_t)inflater->left, + inflater->shift, in, last, prefix); + + if (rv == -1) { + DEBUGF("inflatehd: integer decoding failed\n"); + return NGHTTP2_ERR_HEADER_COMP; + } + + if (out > maxlen) { + DEBUGF("inflatehd: integer exceeded the maximum value %zu\n", maxlen); + return NGHTTP2_ERR_HEADER_COMP; + } + + inflater->left = out; + + DEBUGF("inflatehd: decoded integer is %u\n", out); + + return rv; +} + +/* + * Reads |inflater->left| bytes from the range [in, last) and performs + * huffman decoding against them and pushes the result into the + * |buffer|. + * + * This function returns the number of bytes read if it succeeds, or + * one of the following negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + * NGHTTP2_ERR_HEADER_COMP + * Huffman decoding failed + */ +static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater, + nghttp2_buf *buf, const uint8_t *in, + const uint8_t *last) { + ssize_t readlen; + int fin = 0; + if ((size_t)(last - in) >= inflater->left) { + last = in + inflater->left; + fin = 1; + } + readlen = nghttp2_hd_huff_decode(&inflater->huff_decode_ctx, buf, in, + (size_t)(last - in), fin); + + if (readlen < 0) { + DEBUGF("inflatehd: huffman decoding failed\n"); + return readlen; + } + inflater->left -= (size_t)readlen; + return readlen; +} + +/* + * Reads |inflater->left| bytes from the range [in, last) and copies + * them into the |buffer|. + * + * This function returns the number of bytes read if it succeeds, or + * one of the following negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + * NGHTTP2_ERR_HEADER_COMP + * Header decompression failed + */ +static ssize_t hd_inflate_read(nghttp2_hd_inflater *inflater, nghttp2_buf *buf, + const uint8_t *in, const uint8_t *last) { + size_t len = nghttp2_min((size_t)(last - in), inflater->left); + + buf->last = nghttp2_cpymem(buf->last, in, len); + + inflater->left -= len; + return (ssize_t)len; +} + +/* + * Finalize indexed header representation reception. The referenced + * header is always emitted, and |*nv_out| is filled with that value. + */ +static void hd_inflate_commit_indexed(nghttp2_hd_inflater *inflater, + nghttp2_hd_nv *nv_out) { + nghttp2_hd_nv nv = nghttp2_hd_table_get(&inflater->ctx, inflater->index); + + emit_header(nv_out, &nv); +} + +/* + * Finalize literal header representation - new name- reception. If + * header is emitted, |*nv_out| is filled with that value and 0 is + * returned. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater, + nghttp2_hd_nv *nv_out) { + nghttp2_hd_nv nv; + int rv; + + if (inflater->no_index) { + nv.flags = NGHTTP2_NV_FLAG_NO_INDEX; + } else { + nv.flags = NGHTTP2_NV_FLAG_NONE; + } + + nv.name = inflater->namercbuf; + nv.value = inflater->valuercbuf; + nv.token = lookup_token(inflater->namercbuf->base, inflater->namercbuf->len); + + if (inflater->index_required) { + rv = add_hd_table_incremental(&inflater->ctx, &nv, NULL, 0); + + if (rv != 0) { + return rv; + } + } + + emit_header(nv_out, &nv); + + inflater->nv_name_keep = nv.name; + inflater->nv_value_keep = nv.value; + + inflater->namercbuf = NULL; + inflater->valuercbuf = NULL; + + return 0; +} + +/* + * Finalize literal header representation - indexed name- + * reception. If header is emitted, |*nv_out| is filled with that + * value and 0 is returned. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater, + nghttp2_hd_nv *nv_out) { + nghttp2_hd_nv nv; + int rv; + + nv = nghttp2_hd_table_get(&inflater->ctx, inflater->index); + + if (inflater->no_index) { + nv.flags = NGHTTP2_NV_FLAG_NO_INDEX; + } else { + nv.flags = NGHTTP2_NV_FLAG_NONE; + } + + nghttp2_rcbuf_incref(nv.name); + + nv.value = inflater->valuercbuf; + + if (inflater->index_required) { + rv = add_hd_table_incremental(&inflater->ctx, &nv, NULL, 0); + if (rv != 0) { + nghttp2_rcbuf_decref(nv.name); + return NGHTTP2_ERR_NOMEM; + } + } + + emit_header(nv_out, &nv); + + inflater->nv_name_keep = nv.name; + inflater->nv_value_keep = nv.value; + + inflater->valuercbuf = NULL; + + return 0; +} + +ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out, + int *inflate_flags, uint8_t *in, size_t inlen, + int in_final) { + return nghttp2_hd_inflate_hd2(inflater, nv_out, inflate_flags, in, inlen, + in_final); +} + +ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, + nghttp2_nv *nv_out, int *inflate_flags, + const uint8_t *in, size_t inlen, int in_final) { + ssize_t rv; + nghttp2_hd_nv hd_nv; + + rv = nghttp2_hd_inflate_hd_nv(inflater, &hd_nv, inflate_flags, in, inlen, + in_final); + + if (rv < 0) { + return rv; + } + + if (*inflate_flags & NGHTTP2_HD_INFLATE_EMIT) { + nv_out->name = hd_nv.name->base; + nv_out->namelen = hd_nv.name->len; + + nv_out->value = hd_nv.value->base; + nv_out->valuelen = hd_nv.value->len; + + nv_out->flags = hd_nv.flags; + } + + return rv; +} + +ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater, + nghttp2_hd_nv *nv_out, int *inflate_flags, + const uint8_t *in, size_t inlen, + int in_final) { + ssize_t rv = 0; + const uint8_t *first = in; + const uint8_t *last = in + inlen; + int rfin = 0; + int busy = 0; + nghttp2_mem *mem; + + mem = inflater->ctx.mem; + + if (inflater->ctx.bad) { + return NGHTTP2_ERR_HEADER_COMP; + } + + DEBUGF("inflatehd: start state=%d\n", inflater->state); + hd_inflate_keep_free(inflater); + *inflate_flags = NGHTTP2_HD_INFLATE_NONE; + for (; in != last || busy;) { + busy = 0; + switch (inflater->state) { + case NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE: + if ((*in & 0xe0u) != 0x20u) { + DEBUGF("inflatehd: header table size change was expected, but saw " + "0x%02x as first byte", + *in); + rv = NGHTTP2_ERR_HEADER_COMP; + goto fail; + } + /* fall through */ + case NGHTTP2_HD_STATE_INFLATE_START: + case NGHTTP2_HD_STATE_OPCODE: + if ((*in & 0xe0u) == 0x20u) { + DEBUGF("inflatehd: header table size change\n"); + if (inflater->state == NGHTTP2_HD_STATE_OPCODE) { + DEBUGF("inflatehd: header table size change must appear at the head " + "of header block\n"); + rv = NGHTTP2_ERR_HEADER_COMP; + goto fail; + } + inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED; + inflater->state = NGHTTP2_HD_STATE_READ_TABLE_SIZE; + } else if (*in & 0x80u) { + DEBUGF("inflatehd: indexed repr\n"); + inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED; + inflater->state = NGHTTP2_HD_STATE_READ_INDEX; + } else { + if (*in == 0x40u || *in == 0 || *in == 0x10u) { + DEBUGF("inflatehd: literal header repr - new name\n"); + inflater->opcode = NGHTTP2_HD_OPCODE_NEWNAME; + inflater->state = NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN; + } else { + DEBUGF("inflatehd: literal header repr - indexed name\n"); + inflater->opcode = NGHTTP2_HD_OPCODE_INDNAME; + inflater->state = NGHTTP2_HD_STATE_READ_INDEX; + } + inflater->index_required = (*in & 0x40) != 0; + inflater->no_index = (*in & 0xf0u) == 0x10u; + DEBUGF("inflatehd: indexing required=%d, no_index=%d\n", + inflater->index_required, inflater->no_index); + if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) { + ++in; + } + } + inflater->left = 0; + inflater->shift = 0; + break; + case NGHTTP2_HD_STATE_READ_TABLE_SIZE: + rfin = 0; + rv = hd_inflate_read_len( + inflater, &rfin, in, last, 5, + nghttp2_min(inflater->min_hd_table_bufsize_max, + inflater->settings_hd_table_bufsize_max)); + if (rv < 0) { + goto fail; + } + in += rv; + if (!rfin) { + goto almost_ok; + } + DEBUGF("inflatehd: table_size=%zu\n", inflater->left); + inflater->min_hd_table_bufsize_max = UINT32_MAX; + inflater->ctx.hd_table_bufsize_max = inflater->left; + hd_context_shrink_table_size(&inflater->ctx, NULL); + inflater->state = NGHTTP2_HD_STATE_INFLATE_START; + break; + case NGHTTP2_HD_STATE_READ_INDEX: { + size_t prefixlen; + + if (inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) { + prefixlen = 7; + } else if (inflater->index_required) { + prefixlen = 6; + } else { + prefixlen = 4; + } + + rfin = 0; + rv = hd_inflate_read_len(inflater, &rfin, in, last, prefixlen, + get_max_index(&inflater->ctx)); + if (rv < 0) { + goto fail; + } + + in += rv; + + if (!rfin) { + goto almost_ok; + } + + if (inflater->left == 0) { + rv = NGHTTP2_ERR_HEADER_COMP; + goto fail; + } + + DEBUGF("inflatehd: index=%zu\n", inflater->left); + if (inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) { + inflater->index = inflater->left; + --inflater->index; + + hd_inflate_commit_indexed(inflater, nv_out); + + inflater->state = NGHTTP2_HD_STATE_OPCODE; + *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT; + return (ssize_t)(in - first); + } else { + inflater->index = inflater->left; + --inflater->index; + + inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN; + } + break; + } + case NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN: + hd_inflate_set_huffman_encoded(inflater, in); + inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN; + inflater->left = 0; + inflater->shift = 0; + DEBUGF("inflatehd: huffman encoded=%d\n", inflater->huffman_encoded != 0); + /* Fall through */ + case NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN: + rfin = 0; + rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, NGHTTP2_HD_MAX_NV); + if (rv < 0) { + goto fail; + } + in += rv; + if (!rfin) { + DEBUGF("inflatehd: integer not fully decoded. current=%zu\n", + inflater->left); + + goto almost_ok; + } + + if (inflater->huffman_encoded) { + nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx); + + inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF; + + rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left * 2 + 1, + mem); + } else { + inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAME; + rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left + 1, mem); + } + + if (rv != 0) { + goto fail; + } + + nghttp2_buf_wrap_init(&inflater->namebuf, inflater->namercbuf->base, + inflater->namercbuf->len); + + break; + case NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF: + rv = hd_inflate_read_huff(inflater, &inflater->namebuf, in, last); + if (rv < 0) { + goto fail; + } + + in += rv; + + DEBUGF("inflatehd: %zd bytes read\n", rv); + + if (inflater->left) { + DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left); + + goto almost_ok; + } + + *inflater->namebuf.last = '\0'; + inflater->namercbuf->len = nghttp2_buf_len(&inflater->namebuf); + + inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN; + + break; + case NGHTTP2_HD_STATE_NEWNAME_READ_NAME: + rv = hd_inflate_read(inflater, &inflater->namebuf, in, last); + if (rv < 0) { + goto fail; + } + + in += rv; + + DEBUGF("inflatehd: %zd bytes read\n", rv); + if (inflater->left) { + DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left); + + goto almost_ok; + } + + *inflater->namebuf.last = '\0'; + inflater->namercbuf->len = nghttp2_buf_len(&inflater->namebuf); + + inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN; + + break; + case NGHTTP2_HD_STATE_CHECK_VALUELEN: + hd_inflate_set_huffman_encoded(inflater, in); + inflater->state = NGHTTP2_HD_STATE_READ_VALUELEN; + inflater->left = 0; + inflater->shift = 0; + DEBUGF("inflatehd: huffman encoded=%d\n", inflater->huffman_encoded != 0); + /* Fall through */ + case NGHTTP2_HD_STATE_READ_VALUELEN: + rfin = 0; + rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, NGHTTP2_HD_MAX_NV); + if (rv < 0) { + goto fail; + } + + in += rv; + + if (!rfin) { + goto almost_ok; + } + + DEBUGF("inflatehd: valuelen=%zu\n", inflater->left); + + if (inflater->huffman_encoded) { + nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx); + + inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF; + + rv = nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left * 2 + 1, + mem); + } else { + inflater->state = NGHTTP2_HD_STATE_READ_VALUE; + + rv = nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left + 1, mem); + } + + if (rv != 0) { + goto fail; + } + + nghttp2_buf_wrap_init(&inflater->valuebuf, inflater->valuercbuf->base, + inflater->valuercbuf->len); + + busy = 1; + + break; + case NGHTTP2_HD_STATE_READ_VALUEHUFF: + rv = hd_inflate_read_huff(inflater, &inflater->valuebuf, in, last); + if (rv < 0) { + goto fail; + } + + in += rv; + + DEBUGF("inflatehd: %zd bytes read\n", rv); + + if (inflater->left) { + DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left); + + goto almost_ok; + } + + *inflater->valuebuf.last = '\0'; + inflater->valuercbuf->len = nghttp2_buf_len(&inflater->valuebuf); + + if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) { + rv = hd_inflate_commit_newname(inflater, nv_out); + } else { + rv = hd_inflate_commit_indname(inflater, nv_out); + } + + if (rv != 0) { + goto fail; + } + + inflater->state = NGHTTP2_HD_STATE_OPCODE; + *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT; + + return (ssize_t)(in - first); + case NGHTTP2_HD_STATE_READ_VALUE: + rv = hd_inflate_read(inflater, &inflater->valuebuf, in, last); + if (rv < 0) { + DEBUGF("inflatehd: value read failure %zd: %s\n", rv, + nghttp2_strerror((int)rv)); + goto fail; + } + + in += rv; + + DEBUGF("inflatehd: %zd bytes read\n", rv); + + if (inflater->left) { + DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left); + goto almost_ok; + } + + *inflater->valuebuf.last = '\0'; + inflater->valuercbuf->len = nghttp2_buf_len(&inflater->valuebuf); + + if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) { + rv = hd_inflate_commit_newname(inflater, nv_out); + } else { + rv = hd_inflate_commit_indname(inflater, nv_out); + } + + if (rv != 0) { + goto fail; + } + + inflater->state = NGHTTP2_HD_STATE_OPCODE; + *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT; + + return (ssize_t)(in - first); + } + } + + assert(in == last); + + DEBUGF("inflatehd: all input bytes were processed\n"); + + if (in_final) { + DEBUGF("inflatehd: in_final set\n"); + + if (inflater->state != NGHTTP2_HD_STATE_OPCODE && + inflater->state != NGHTTP2_HD_STATE_INFLATE_START) { + DEBUGF("inflatehd: unacceptable state=%d\n", inflater->state); + rv = NGHTTP2_ERR_HEADER_COMP; + + goto fail; + } + *inflate_flags |= NGHTTP2_HD_INFLATE_FINAL; + } + return (ssize_t)(in - first); + +almost_ok: + if (in_final) { + DEBUGF("inflatehd: input ended prematurely\n"); + + rv = NGHTTP2_ERR_HEADER_COMP; + + goto fail; + } + return (ssize_t)(in - first); + +fail: + DEBUGF("inflatehd: error return %zd\n", rv); + + inflater->ctx.bad = 1; + return rv; +} + +int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater) { + hd_inflate_keep_free(inflater); + inflater->state = NGHTTP2_HD_STATE_INFLATE_START; + return 0; +} + +int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr) { + return nghttp2_hd_inflate_new2(inflater_ptr, NULL); +} + +int nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr, + nghttp2_mem *mem) { + int rv; + nghttp2_hd_inflater *inflater; + + if (mem == NULL) { + mem = nghttp2_mem_default(); + } + + inflater = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_inflater)); + + if (inflater == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + rv = nghttp2_hd_inflate_init(inflater, mem); + + if (rv != 0) { + nghttp2_mem_free(mem, inflater); + + return rv; + } + + *inflater_ptr = inflater; + + return 0; +} + +void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater) { + nghttp2_mem *mem; + + mem = inflater->ctx.mem; + nghttp2_hd_inflate_free(inflater); + + nghttp2_mem_free(mem, inflater); +} + +int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t idx, + nghttp2_nv *nv, int indexing_mode) { + + return emit_indname_block(bufs, idx, nv, indexing_mode); +} + +int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv, + int indexing_mode) { + return emit_newname_block(bufs, nv, indexing_mode); +} + +int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size) { + return emit_table_size(bufs, table_size); +} + +ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *fin, + uint32_t initial, size_t shift, uint8_t *in, + uint8_t *last, size_t prefix) { + return decode_length(res, shift_ptr, fin, initial, shift, in, last, prefix); +} + +static const nghttp2_nv *hd_get_table_entry(nghttp2_hd_context *context, + size_t idx) { + if (idx == 0) { + return NULL; + } + + --idx; + + if (!INDEX_RANGE_VALID(context, idx)) { + return NULL; + } + + return nghttp2_hd_table_get2(context, idx); +} + +size_t nghttp2_hd_deflate_get_num_table_entries(nghttp2_hd_deflater *deflater) { + return get_max_index(&deflater->ctx); +} + +const nghttp2_nv * +nghttp2_hd_deflate_get_table_entry(nghttp2_hd_deflater *deflater, size_t idx) { + return hd_get_table_entry(&deflater->ctx, idx); +} + +size_t +nghttp2_hd_deflate_get_dynamic_table_size(nghttp2_hd_deflater *deflater) { + return deflater->ctx.hd_table_bufsize; +} + +size_t +nghttp2_hd_deflate_get_max_dynamic_table_size(nghttp2_hd_deflater *deflater) { + return deflater->ctx.hd_table_bufsize_max; +} + +size_t nghttp2_hd_inflate_get_num_table_entries(nghttp2_hd_inflater *inflater) { + return get_max_index(&inflater->ctx); +} + +const nghttp2_nv * +nghttp2_hd_inflate_get_table_entry(nghttp2_hd_inflater *inflater, size_t idx) { + return hd_get_table_entry(&inflater->ctx, idx); +} + +size_t +nghttp2_hd_inflate_get_dynamic_table_size(nghttp2_hd_inflater *inflater) { + return inflater->ctx.hd_table_bufsize; +} + +size_t +nghttp2_hd_inflate_get_max_dynamic_table_size(nghttp2_hd_inflater *inflater) { + return inflater->ctx.hd_table_bufsize_max; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd.h new file mode 100644 index 00000000..584dad39 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd.h @@ -0,0 +1,413 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_HD_H +#define NGHTTP2_HD_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +#include "nghttp2_hd_huffman.h" +#include "nghttp2_buf.h" +#include "nghttp2_mem.h" +#include "nghttp2_rcbuf.h" + +#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE NGHTTP2_DEFAULT_HEADER_TABLE_SIZE +#define NGHTTP2_HD_ENTRY_OVERHEAD 32 + +/* The maximum length of one name/value pair. This is the sum of the + length of name and value. This is not specified by the spec. We + just chose the arbitrary size */ +#define NGHTTP2_HD_MAX_NV 65536 + +/* Default size of maximum table buffer size for encoder. Even if + remote decoder notifies larger buffer size for its decoding, + encoder only uses the memory up to this value. */ +#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12) + +/* Exported for unit test */ +#define NGHTTP2_STATIC_TABLE_LENGTH 61 + +/* Generated by genlibtokenlookup.py */ +typedef enum { + NGHTTP2_TOKEN__AUTHORITY = 0, + NGHTTP2_TOKEN__METHOD = 1, + NGHTTP2_TOKEN__PATH = 3, + NGHTTP2_TOKEN__SCHEME = 5, + NGHTTP2_TOKEN__STATUS = 7, + NGHTTP2_TOKEN_ACCEPT_CHARSET = 14, + NGHTTP2_TOKEN_ACCEPT_ENCODING = 15, + NGHTTP2_TOKEN_ACCEPT_LANGUAGE = 16, + NGHTTP2_TOKEN_ACCEPT_RANGES = 17, + NGHTTP2_TOKEN_ACCEPT = 18, + NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN = 19, + NGHTTP2_TOKEN_AGE = 20, + NGHTTP2_TOKEN_ALLOW = 21, + NGHTTP2_TOKEN_AUTHORIZATION = 22, + NGHTTP2_TOKEN_CACHE_CONTROL = 23, + NGHTTP2_TOKEN_CONTENT_DISPOSITION = 24, + NGHTTP2_TOKEN_CONTENT_ENCODING = 25, + NGHTTP2_TOKEN_CONTENT_LANGUAGE = 26, + NGHTTP2_TOKEN_CONTENT_LENGTH = 27, + NGHTTP2_TOKEN_CONTENT_LOCATION = 28, + NGHTTP2_TOKEN_CONTENT_RANGE = 29, + NGHTTP2_TOKEN_CONTENT_TYPE = 30, + NGHTTP2_TOKEN_COOKIE = 31, + NGHTTP2_TOKEN_DATE = 32, + NGHTTP2_TOKEN_ETAG = 33, + NGHTTP2_TOKEN_EXPECT = 34, + NGHTTP2_TOKEN_EXPIRES = 35, + NGHTTP2_TOKEN_FROM = 36, + NGHTTP2_TOKEN_HOST = 37, + NGHTTP2_TOKEN_IF_MATCH = 38, + NGHTTP2_TOKEN_IF_MODIFIED_SINCE = 39, + NGHTTP2_TOKEN_IF_NONE_MATCH = 40, + NGHTTP2_TOKEN_IF_RANGE = 41, + NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE = 42, + NGHTTP2_TOKEN_LAST_MODIFIED = 43, + NGHTTP2_TOKEN_LINK = 44, + NGHTTP2_TOKEN_LOCATION = 45, + NGHTTP2_TOKEN_MAX_FORWARDS = 46, + NGHTTP2_TOKEN_PROXY_AUTHENTICATE = 47, + NGHTTP2_TOKEN_PROXY_AUTHORIZATION = 48, + NGHTTP2_TOKEN_RANGE = 49, + NGHTTP2_TOKEN_REFERER = 50, + NGHTTP2_TOKEN_REFRESH = 51, + NGHTTP2_TOKEN_RETRY_AFTER = 52, + NGHTTP2_TOKEN_SERVER = 53, + NGHTTP2_TOKEN_SET_COOKIE = 54, + NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY = 55, + NGHTTP2_TOKEN_TRANSFER_ENCODING = 56, + NGHTTP2_TOKEN_USER_AGENT = 57, + NGHTTP2_TOKEN_VARY = 58, + NGHTTP2_TOKEN_VIA = 59, + NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60, + NGHTTP2_TOKEN_TE, + NGHTTP2_TOKEN_CONNECTION, + NGHTTP2_TOKEN_KEEP_ALIVE, + NGHTTP2_TOKEN_PROXY_CONNECTION, + NGHTTP2_TOKEN_UPGRADE, +} nghttp2_token; + +struct nghttp2_hd_entry; +typedef struct nghttp2_hd_entry nghttp2_hd_entry; + +typedef struct { + /* The buffer containing header field name. NULL-termination is + guaranteed. */ + nghttp2_rcbuf *name; + /* The buffer containing header field value. NULL-termination is + guaranteed. */ + nghttp2_rcbuf *value; + /* nghttp2_token value for name. It could be -1 if we have no token + for that header field name. */ + int32_t token; + /* Bitwise OR of one or more of nghttp2_nv_flag. */ + uint8_t flags; +} nghttp2_hd_nv; + +struct nghttp2_hd_entry { + /* The header field name/value pair */ + nghttp2_hd_nv nv; + /* This is solely for nghttp2_hd_{deflate,inflate}_get_table_entry + APIs to keep backward compatibility. */ + nghttp2_nv cnv; + /* The next entry which shares same bucket in hash table. */ + nghttp2_hd_entry *next; + /* The sequence number. We will increment it by one whenever we + store nghttp2_hd_entry to dynamic header table. */ + uint32_t seq; + /* The hash value for header name (nv.name). */ + uint32_t hash; +}; + +/* The entry used for static header table. */ +typedef struct { + nghttp2_rcbuf name; + nghttp2_rcbuf value; + nghttp2_nv cnv; + int32_t token; + uint32_t hash; +} nghttp2_hd_static_entry; + +typedef struct { + nghttp2_hd_entry **buffer; + size_t mask; + size_t first; + size_t len; +} nghttp2_hd_ringbuf; + +typedef enum { + NGHTTP2_HD_OPCODE_NONE, + NGHTTP2_HD_OPCODE_INDEXED, + NGHTTP2_HD_OPCODE_NEWNAME, + NGHTTP2_HD_OPCODE_INDNAME +} nghttp2_hd_opcode; + +typedef enum { + NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE, + NGHTTP2_HD_STATE_INFLATE_START, + NGHTTP2_HD_STATE_OPCODE, + NGHTTP2_HD_STATE_READ_TABLE_SIZE, + NGHTTP2_HD_STATE_READ_INDEX, + NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN, + NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN, + NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF, + NGHTTP2_HD_STATE_NEWNAME_READ_NAME, + NGHTTP2_HD_STATE_CHECK_VALUELEN, + NGHTTP2_HD_STATE_READ_VALUELEN, + NGHTTP2_HD_STATE_READ_VALUEHUFF, + NGHTTP2_HD_STATE_READ_VALUE +} nghttp2_hd_inflate_state; + +typedef enum { + NGHTTP2_HD_WITH_INDEXING, + NGHTTP2_HD_WITHOUT_INDEXING, + NGHTTP2_HD_NEVER_INDEXING +} nghttp2_hd_indexing_mode; + +typedef struct { + /* dynamic header table */ + nghttp2_hd_ringbuf hd_table; + /* Memory allocator */ + nghttp2_mem *mem; + /* Abstract buffer size of hd_table as described in the spec. This + is the sum of length of name/value in hd_table + + NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */ + size_t hd_table_bufsize; + /* The effective header table size. */ + size_t hd_table_bufsize_max; + /* Next sequence number for nghttp2_hd_entry */ + uint32_t next_seq; + /* If inflate/deflate error occurred, this value is set to 1 and + further invocation of inflate/deflate will fail with + NGHTTP2_ERR_HEADER_COMP. */ + uint8_t bad; +} nghttp2_hd_context; + +#define HD_MAP_SIZE 128 + +typedef struct { + nghttp2_hd_entry *table[HD_MAP_SIZE]; +} nghttp2_hd_map; + +struct nghttp2_hd_deflater { + nghttp2_hd_context ctx; + nghttp2_hd_map map; + /* The upper limit of the header table size the deflater accepts. */ + size_t deflate_hd_table_bufsize_max; + /* Minimum header table size notified in the next context update */ + size_t min_hd_table_bufsize_max; + /* If nonzero, send header table size using encoding context update + in the next deflate process */ + uint8_t notify_table_size_change; +}; + +struct nghttp2_hd_inflater { + nghttp2_hd_context ctx; + /* Stores current state of huffman decoding */ + nghttp2_hd_huff_decode_context huff_decode_ctx; + /* header buffer */ + nghttp2_buf namebuf, valuebuf; + nghttp2_rcbuf *namercbuf, *valuercbuf; + /* Pointer to the name/value pair which are used in the current + header emission. */ + nghttp2_rcbuf *nv_name_keep, *nv_value_keep; + /* The number of bytes to read */ + size_t left; + /* The index in indexed repr or indexed name */ + size_t index; + /* The maximum header table size the inflater supports. This is the + same value transmitted in SETTINGS_HEADER_TABLE_SIZE */ + size_t settings_hd_table_bufsize_max; + /* Minimum header table size set by nghttp2_hd_inflate_change_table_size */ + size_t min_hd_table_bufsize_max; + /* The number of next shift to decode integer */ + size_t shift; + nghttp2_hd_opcode opcode; + nghttp2_hd_inflate_state state; + /* nonzero if string is huffman encoded */ + uint8_t huffman_encoded; + /* nonzero if deflater requires that current entry is indexed */ + uint8_t index_required; + /* nonzero if deflater requires that current entry must not be + indexed */ + uint8_t no_index; +}; + +/* + * Initializes the |ent| members. The reference counts of nv->name + * and nv->value are increased by one for each. + */ +void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv); + +/* + * This function decreases the reference counts of nv->name and + * nv->value. + */ +void nghttp2_hd_entry_free(nghttp2_hd_entry *ent); + +/* + * Initializes |deflater| for deflating name/values pairs. + * + * The encoder only uses up to + * NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE bytes for header table + * even if the larger value is specified later in + * nghttp2_hd_change_table_size(). + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem); + +/* + * Initializes |deflater| for deflating name/values pairs. + * + * The encoder only uses up to |max_deflate_dynamic_table_size| bytes + * for header table even if the larger value is specified later in + * nghttp2_hd_change_table_size(). + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, + size_t max_deflate_dynamic_table_size, + nghttp2_mem *mem); + +/* + * Deallocates any resources allocated for |deflater|. + */ +void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater); + +/* + * Deflates the |nva|, which has the |nvlen| name/value pairs, into + * the |bufs|. + * + * This function expands |bufs| as necessary to store the result. If + * buffers is full and the process still requires more space, this + * function fails and returns NGHTTP2_ERR_HEADER_COMP. + * + * After this function returns, it is safe to delete the |nva|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_HEADER_COMP + * Deflation process has failed. + * NGHTTP2_ERR_BUFFER_ERROR + * Out of buffer space. + */ +int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater, + nghttp2_bufs *bufs, const nghttp2_nv *nva, + size_t nvlen); + +/* + * Initializes |inflater| for inflating name/values pairs. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem); + +/* + * Deallocates any resources allocated for |inflater|. + */ +void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater); + +/* + * Similar to nghttp2_hd_inflate_hd(), but this takes nghttp2_hd_nv + * instead of nghttp2_nv as output parameter |nv_out|. Other than + * that return values and semantics are the same as + * nghttp2_hd_inflate_hd(). + */ +ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater, + nghttp2_hd_nv *nv_out, int *inflate_flags, + const uint8_t *in, size_t inlen, int in_final); + +/* For unittesting purpose */ +int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index, + nghttp2_nv *nv, int indexing_mode); + +/* For unittesting purpose */ +int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv, + int indexing_mode); + +/* For unittesting purpose */ +int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size); + +/* For unittesting purpose */ +nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index); + +/* For unittesting purpose */ +ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *fin, + uint32_t initial, size_t shift, uint8_t *in, + uint8_t *last, size_t prefix); + +/* Huffman encoding/decoding functions */ + +/* + * Counts the required bytes to encode |src| with length |len|. + * + * This function returns the number of required bytes to encode given + * data, including padding of prefix of terminal symbol code. This + * function always succeeds. + */ +size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len); + +/* + * Encodes the given data |src| with length |srclen| to the |bufs|. + * This function expands extra buffers in |bufs| if necessary. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_BUFFER_ERROR + * Out of buffer space. + */ +int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src, + size_t srclen); + +void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx); + +/* + * Decodes the given data |src| with length |srclen|. The |ctx| must + * be initialized by nghttp2_hd_huff_decode_context_init(). The result + * will be written to |buf|. This function assumes that |buf| has the + * enough room to store the decoded byte string. + * + * The caller must set the |fin| to nonzero if the given input is the + * final block. + * + * This function returns the number of read bytes from the |in|. + * + * If this function fails, it returns one of the following negative + * return codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_HEADER_COMP + * Decoding process has failed. + */ +ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, + nghttp2_buf *buf, const uint8_t *src, + size_t srclen, int fin); + +#endif /* NGHTTP2_HD_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd_huffman.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd_huffman.c new file mode 100644 index 00000000..661668de --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd_huffman.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_hd_huffman.h" + +#include +#include +#include + +#include "nghttp2_hd.h" + +/* + * Encodes huffman code |sym| into |*dest_ptr|, whose least |rembits| + * bits are not filled yet. The |rembits| must be in range [1, 8], + * inclusive. At the end of the process, the |*dest_ptr| is updated + * and points where next output should be placed. The number of + * unfilled bits in the pointed location is returned. + */ +static ssize_t huff_encode_sym(nghttp2_bufs *bufs, size_t *avail_ptr, + size_t rembits, const nghttp2_huff_sym *sym) { + int rv; + size_t nbits = sym->nbits; + uint32_t code = sym->code; + + /* We assume that sym->nbits <= 32 */ + if (rembits > nbits) { + nghttp2_bufs_fast_orb_hold(bufs, (uint8_t)(code << (rembits - nbits))); + return (ssize_t)(rembits - nbits); + } + + if (rembits == nbits) { + nghttp2_bufs_fast_orb(bufs, (uint8_t)code); + --*avail_ptr; + return 8; + } + + nghttp2_bufs_fast_orb(bufs, (uint8_t)(code >> (nbits - rembits))); + --*avail_ptr; + + nbits -= rembits; + if (nbits & 0x7) { + /* align code to MSB byte boundary */ + code <<= 8 - (nbits & 0x7); + } + + if (*avail_ptr < (nbits + 7) / 8) { + /* slow path */ + if (nbits > 24) { + rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 24)); + if (rv != 0) { + return rv; + } + nbits -= 8; + } + if (nbits > 16) { + rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 16)); + if (rv != 0) { + return rv; + } + nbits -= 8; + } + if (nbits > 8) { + rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 8)); + if (rv != 0) { + return rv; + } + nbits -= 8; + } + if (nbits == 8) { + rv = nghttp2_bufs_addb(bufs, (uint8_t)code); + if (rv != 0) { + return rv; + } + *avail_ptr = nghttp2_bufs_cur_avail(bufs); + return 8; + } + + rv = nghttp2_bufs_addb_hold(bufs, (uint8_t)code); + if (rv != 0) { + return rv; + } + *avail_ptr = nghttp2_bufs_cur_avail(bufs); + return (ssize_t)(8 - nbits); + } + + /* fast path, since most code is less than 8 */ + if (nbits < 8) { + nghttp2_bufs_fast_addb_hold(bufs, (uint8_t)code); + *avail_ptr = nghttp2_bufs_cur_avail(bufs); + return (ssize_t)(8 - nbits); + } + + /* handle longer code path */ + if (nbits > 24) { + nghttp2_bufs_fast_addb(bufs, (uint8_t)(code >> 24)); + nbits -= 8; + } + + if (nbits > 16) { + nghttp2_bufs_fast_addb(bufs, (uint8_t)(code >> 16)); + nbits -= 8; + } + + if (nbits > 8) { + nghttp2_bufs_fast_addb(bufs, (uint8_t)(code >> 8)); + nbits -= 8; + } + + if (nbits == 8) { + nghttp2_bufs_fast_addb(bufs, (uint8_t)code); + *avail_ptr = nghttp2_bufs_cur_avail(bufs); + return 8; + } + + nghttp2_bufs_fast_addb_hold(bufs, (uint8_t)code); + *avail_ptr = nghttp2_bufs_cur_avail(bufs); + return (ssize_t)(8 - nbits); +} + +size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) { + size_t i; + size_t nbits = 0; + + for (i = 0; i < len; ++i) { + nbits += huff_sym_table[src[i]].nbits; + } + /* pad the prefix of EOS (256) */ + return (nbits + 7) / 8; +} + +int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src, + size_t srclen) { + int rv; + ssize_t rembits = 8; + size_t i; + size_t avail; + + avail = nghttp2_bufs_cur_avail(bufs); + + for (i = 0; i < srclen; ++i) { + const nghttp2_huff_sym *sym = &huff_sym_table[src[i]]; + if (rembits == 8) { + if (avail) { + nghttp2_bufs_fast_addb_hold(bufs, 0); + } else { + rv = nghttp2_bufs_addb_hold(bufs, 0); + if (rv != 0) { + return rv; + } + avail = nghttp2_bufs_cur_avail(bufs); + } + } + rembits = huff_encode_sym(bufs, &avail, (size_t)rembits, sym); + if (rembits < 0) { + return (int)rembits; + } + } + /* 256 is special terminal symbol, pad with its prefix */ + if (rembits < 8) { + /* if rembits < 8, we should have at least 1 buffer space + available */ + const nghttp2_huff_sym *sym = &huff_sym_table[256]; + assert(avail); + /* Caution we no longer adjust avail here */ + nghttp2_bufs_fast_orb( + bufs, (uint8_t)(sym->code >> (sym->nbits - (size_t)rembits))); + } + + return 0; +} + +void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) { + ctx->state = 0; + ctx->accept = 1; +} + +ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, + nghttp2_buf *buf, const uint8_t *src, + size_t srclen, int final) { + size_t i; + + /* We use the decoding algorithm described in + http://graphics.ics.uci.edu/pub/Prefix.pdf */ + for (i = 0; i < srclen; ++i) { + const nghttp2_huff_decode *t; + + t = &huff_decode_table[ctx->state][src[i] >> 4]; + if (t->flags & NGHTTP2_HUFF_FAIL) { + return NGHTTP2_ERR_HEADER_COMP; + } + if (t->flags & NGHTTP2_HUFF_SYM) { + *buf->last++ = t->sym; + } + + t = &huff_decode_table[t->state][src[i] & 0xf]; + if (t->flags & NGHTTP2_HUFF_FAIL) { + return NGHTTP2_ERR_HEADER_COMP; + } + if (t->flags & NGHTTP2_HUFF_SYM) { + *buf->last++ = t->sym; + } + + ctx->state = t->state; + ctx->accept = (t->flags & NGHTTP2_HUFF_ACCEPTED) != 0; + } + if (final && !ctx->accept) { + return NGHTTP2_ERR_HEADER_COMP; + } + return (ssize_t)i; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd_huffman.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd_huffman.h new file mode 100644 index 00000000..979f6b12 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd_huffman.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_HD_HUFFMAN_H +#define NGHTTP2_HD_HUFFMAN_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +typedef enum { + /* FSA accepts this state as the end of huffman encoding + sequence. */ + NGHTTP2_HUFF_ACCEPTED = 1, + /* This state emits symbol */ + NGHTTP2_HUFF_SYM = (1 << 1), + /* If state machine reaches this state, decoding fails. */ + NGHTTP2_HUFF_FAIL = (1 << 2) +} nghttp2_huff_decode_flag; + +typedef struct { + /* huffman decoding state, which is actually the node ID of internal + huffman tree. We have 257 leaf nodes, but they are identical to + root node other than emitting a symbol, so we have 256 internal + nodes [1..255], inclusive. */ + uint8_t state; + /* bitwise OR of zero or more of the nghttp2_huff_decode_flag */ + uint8_t flags; + /* symbol if NGHTTP2_HUFF_SYM flag set */ + uint8_t sym; +} nghttp2_huff_decode; + +typedef nghttp2_huff_decode huff_decode_table_type[16]; + +typedef struct { + /* Current huffman decoding state. We stripped leaf nodes, so the + value range is [0..255], inclusive. */ + uint8_t state; + /* nonzero if we can say that the decoding process succeeds at this + state */ + uint8_t accept; +} nghttp2_hd_huff_decode_context; + +typedef struct { + /* The number of bits in this code */ + uint32_t nbits; + /* Huffman code aligned to LSB */ + uint32_t code; +} nghttp2_huff_sym; + +extern const nghttp2_huff_sym huff_sym_table[]; +extern const nghttp2_huff_decode huff_decode_table[][16]; + +#endif /* NGHTTP2_HD_HUFFMAN_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd_huffman_data.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd_huffman_data.c new file mode 100644 index 00000000..085b2e92 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_hd_huffman_data.c @@ -0,0 +1,4942 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_hd_huffman.h" + +/* Generated by mkhufftbl.py */ + +const nghttp2_huff_sym huff_sym_table[] = { + {13, 0x1ff8u}, {23, 0x7fffd8u}, {28, 0xfffffe2u}, {28, 0xfffffe3u}, + {28, 0xfffffe4u}, {28, 0xfffffe5u}, {28, 0xfffffe6u}, {28, 0xfffffe7u}, + {28, 0xfffffe8u}, {24, 0xffffeau}, {30, 0x3ffffffcu}, {28, 0xfffffe9u}, + {28, 0xfffffeau}, {30, 0x3ffffffdu}, {28, 0xfffffebu}, {28, 0xfffffecu}, + {28, 0xfffffedu}, {28, 0xfffffeeu}, {28, 0xfffffefu}, {28, 0xffffff0u}, + {28, 0xffffff1u}, {28, 0xffffff2u}, {30, 0x3ffffffeu}, {28, 0xffffff3u}, + {28, 0xffffff4u}, {28, 0xffffff5u}, {28, 0xffffff6u}, {28, 0xffffff7u}, + {28, 0xffffff8u}, {28, 0xffffff9u}, {28, 0xffffffau}, {28, 0xffffffbu}, + {6, 0x14u}, {10, 0x3f8u}, {10, 0x3f9u}, {12, 0xffau}, + {13, 0x1ff9u}, {6, 0x15u}, {8, 0xf8u}, {11, 0x7fau}, + {10, 0x3fau}, {10, 0x3fbu}, {8, 0xf9u}, {11, 0x7fbu}, + {8, 0xfau}, {6, 0x16u}, {6, 0x17u}, {6, 0x18u}, + {5, 0x0u}, {5, 0x1u}, {5, 0x2u}, {6, 0x19u}, + {6, 0x1au}, {6, 0x1bu}, {6, 0x1cu}, {6, 0x1du}, + {6, 0x1eu}, {6, 0x1fu}, {7, 0x5cu}, {8, 0xfbu}, + {15, 0x7ffcu}, {6, 0x20u}, {12, 0xffbu}, {10, 0x3fcu}, + {13, 0x1ffau}, {6, 0x21u}, {7, 0x5du}, {7, 0x5eu}, + {7, 0x5fu}, {7, 0x60u}, {7, 0x61u}, {7, 0x62u}, + {7, 0x63u}, {7, 0x64u}, {7, 0x65u}, {7, 0x66u}, + {7, 0x67u}, {7, 0x68u}, {7, 0x69u}, {7, 0x6au}, + {7, 0x6bu}, {7, 0x6cu}, {7, 0x6du}, {7, 0x6eu}, + {7, 0x6fu}, {7, 0x70u}, {7, 0x71u}, {7, 0x72u}, + {8, 0xfcu}, {7, 0x73u}, {8, 0xfdu}, {13, 0x1ffbu}, + {19, 0x7fff0u}, {13, 0x1ffcu}, {14, 0x3ffcu}, {6, 0x22u}, + {15, 0x7ffdu}, {5, 0x3u}, {6, 0x23u}, {5, 0x4u}, + {6, 0x24u}, {5, 0x5u}, {6, 0x25u}, {6, 0x26u}, + {6, 0x27u}, {5, 0x6u}, {7, 0x74u}, {7, 0x75u}, + {6, 0x28u}, {6, 0x29u}, {6, 0x2au}, {5, 0x7u}, + {6, 0x2bu}, {7, 0x76u}, {6, 0x2cu}, {5, 0x8u}, + {5, 0x9u}, {6, 0x2du}, {7, 0x77u}, {7, 0x78u}, + {7, 0x79u}, {7, 0x7au}, {7, 0x7bu}, {15, 0x7ffeu}, + {11, 0x7fcu}, {14, 0x3ffdu}, {13, 0x1ffdu}, {28, 0xffffffcu}, + {20, 0xfffe6u}, {22, 0x3fffd2u}, {20, 0xfffe7u}, {20, 0xfffe8u}, + {22, 0x3fffd3u}, {22, 0x3fffd4u}, {22, 0x3fffd5u}, {23, 0x7fffd9u}, + {22, 0x3fffd6u}, {23, 0x7fffdau}, {23, 0x7fffdbu}, {23, 0x7fffdcu}, + {23, 0x7fffddu}, {23, 0x7fffdeu}, {24, 0xffffebu}, {23, 0x7fffdfu}, + {24, 0xffffecu}, {24, 0xffffedu}, {22, 0x3fffd7u}, {23, 0x7fffe0u}, + {24, 0xffffeeu}, {23, 0x7fffe1u}, {23, 0x7fffe2u}, {23, 0x7fffe3u}, + {23, 0x7fffe4u}, {21, 0x1fffdcu}, {22, 0x3fffd8u}, {23, 0x7fffe5u}, + {22, 0x3fffd9u}, {23, 0x7fffe6u}, {23, 0x7fffe7u}, {24, 0xffffefu}, + {22, 0x3fffdau}, {21, 0x1fffddu}, {20, 0xfffe9u}, {22, 0x3fffdbu}, + {22, 0x3fffdcu}, {23, 0x7fffe8u}, {23, 0x7fffe9u}, {21, 0x1fffdeu}, + {23, 0x7fffeau}, {22, 0x3fffddu}, {22, 0x3fffdeu}, {24, 0xfffff0u}, + {21, 0x1fffdfu}, {22, 0x3fffdfu}, {23, 0x7fffebu}, {23, 0x7fffecu}, + {21, 0x1fffe0u}, {21, 0x1fffe1u}, {22, 0x3fffe0u}, {21, 0x1fffe2u}, + {23, 0x7fffedu}, {22, 0x3fffe1u}, {23, 0x7fffeeu}, {23, 0x7fffefu}, + {20, 0xfffeau}, {22, 0x3fffe2u}, {22, 0x3fffe3u}, {22, 0x3fffe4u}, + {23, 0x7ffff0u}, {22, 0x3fffe5u}, {22, 0x3fffe6u}, {23, 0x7ffff1u}, + {26, 0x3ffffe0u}, {26, 0x3ffffe1u}, {20, 0xfffebu}, {19, 0x7fff1u}, + {22, 0x3fffe7u}, {23, 0x7ffff2u}, {22, 0x3fffe8u}, {25, 0x1ffffecu}, + {26, 0x3ffffe2u}, {26, 0x3ffffe3u}, {26, 0x3ffffe4u}, {27, 0x7ffffdeu}, + {27, 0x7ffffdfu}, {26, 0x3ffffe5u}, {24, 0xfffff1u}, {25, 0x1ffffedu}, + {19, 0x7fff2u}, {21, 0x1fffe3u}, {26, 0x3ffffe6u}, {27, 0x7ffffe0u}, + {27, 0x7ffffe1u}, {26, 0x3ffffe7u}, {27, 0x7ffffe2u}, {24, 0xfffff2u}, + {21, 0x1fffe4u}, {21, 0x1fffe5u}, {26, 0x3ffffe8u}, {26, 0x3ffffe9u}, + {28, 0xffffffdu}, {27, 0x7ffffe3u}, {27, 0x7ffffe4u}, {27, 0x7ffffe5u}, + {20, 0xfffecu}, {24, 0xfffff3u}, {20, 0xfffedu}, {21, 0x1fffe6u}, + {22, 0x3fffe9u}, {21, 0x1fffe7u}, {21, 0x1fffe8u}, {23, 0x7ffff3u}, + {22, 0x3fffeau}, {22, 0x3fffebu}, {25, 0x1ffffeeu}, {25, 0x1ffffefu}, + {24, 0xfffff4u}, {24, 0xfffff5u}, {26, 0x3ffffeau}, {23, 0x7ffff4u}, + {26, 0x3ffffebu}, {27, 0x7ffffe6u}, {26, 0x3ffffecu}, {26, 0x3ffffedu}, + {27, 0x7ffffe7u}, {27, 0x7ffffe8u}, {27, 0x7ffffe9u}, {27, 0x7ffffeau}, + {27, 0x7ffffebu}, {28, 0xffffffeu}, {27, 0x7ffffecu}, {27, 0x7ffffedu}, + {27, 0x7ffffeeu}, {27, 0x7ffffefu}, {27, 0x7fffff0u}, {26, 0x3ffffeeu}, + {30, 0x3fffffffu}}; + +const nghttp2_huff_decode huff_decode_table[][16] = { + /* 0 */ + { + {4, 0x00, 0}, + {5, 0x00, 0}, + {7, 0x00, 0}, + {8, 0x00, 0}, + {11, 0x00, 0}, + {12, 0x00, 0}, + {16, 0x00, 0}, + {19, 0x00, 0}, + {25, 0x00, 0}, + {28, 0x00, 0}, + {32, 0x00, 0}, + {35, 0x00, 0}, + {42, 0x00, 0}, + {49, 0x00, 0}, + {57, 0x00, 0}, + {64, 0x01, 0}, + }, + /* 1 */ + { + {0, 0x03, 48}, + {0, 0x03, 49}, + {0, 0x03, 50}, + {0, 0x03, 97}, + {0, 0x03, 99}, + {0, 0x03, 101}, + {0, 0x03, 105}, + {0, 0x03, 111}, + {0, 0x03, 115}, + {0, 0x03, 116}, + {13, 0x00, 0}, + {14, 0x00, 0}, + {17, 0x00, 0}, + {18, 0x00, 0}, + {20, 0x00, 0}, + {21, 0x00, 0}, + }, + /* 2 */ + { + {1, 0x02, 48}, + {22, 0x03, 48}, + {1, 0x02, 49}, + {22, 0x03, 49}, + {1, 0x02, 50}, + {22, 0x03, 50}, + {1, 0x02, 97}, + {22, 0x03, 97}, + {1, 0x02, 99}, + {22, 0x03, 99}, + {1, 0x02, 101}, + {22, 0x03, 101}, + {1, 0x02, 105}, + {22, 0x03, 105}, + {1, 0x02, 111}, + {22, 0x03, 111}, + }, + /* 3 */ + { + {2, 0x02, 48}, + {9, 0x02, 48}, + {23, 0x02, 48}, + {40, 0x03, 48}, + {2, 0x02, 49}, + {9, 0x02, 49}, + {23, 0x02, 49}, + {40, 0x03, 49}, + {2, 0x02, 50}, + {9, 0x02, 50}, + {23, 0x02, 50}, + {40, 0x03, 50}, + {2, 0x02, 97}, + {9, 0x02, 97}, + {23, 0x02, 97}, + {40, 0x03, 97}, + }, + /* 4 */ + { + {3, 0x02, 48}, + {6, 0x02, 48}, + {10, 0x02, 48}, + {15, 0x02, 48}, + {24, 0x02, 48}, + {31, 0x02, 48}, + {41, 0x02, 48}, + {56, 0x03, 48}, + {3, 0x02, 49}, + {6, 0x02, 49}, + {10, 0x02, 49}, + {15, 0x02, 49}, + {24, 0x02, 49}, + {31, 0x02, 49}, + {41, 0x02, 49}, + {56, 0x03, 49}, + }, + /* 5 */ + { + {3, 0x02, 50}, + {6, 0x02, 50}, + {10, 0x02, 50}, + {15, 0x02, 50}, + {24, 0x02, 50}, + {31, 0x02, 50}, + {41, 0x02, 50}, + {56, 0x03, 50}, + {3, 0x02, 97}, + {6, 0x02, 97}, + {10, 0x02, 97}, + {15, 0x02, 97}, + {24, 0x02, 97}, + {31, 0x02, 97}, + {41, 0x02, 97}, + {56, 0x03, 97}, + }, + /* 6 */ + { + {2, 0x02, 99}, + {9, 0x02, 99}, + {23, 0x02, 99}, + {40, 0x03, 99}, + {2, 0x02, 101}, + {9, 0x02, 101}, + {23, 0x02, 101}, + {40, 0x03, 101}, + {2, 0x02, 105}, + {9, 0x02, 105}, + {23, 0x02, 105}, + {40, 0x03, 105}, + {2, 0x02, 111}, + {9, 0x02, 111}, + {23, 0x02, 111}, + {40, 0x03, 111}, + }, + /* 7 */ + { + {3, 0x02, 99}, + {6, 0x02, 99}, + {10, 0x02, 99}, + {15, 0x02, 99}, + {24, 0x02, 99}, + {31, 0x02, 99}, + {41, 0x02, 99}, + {56, 0x03, 99}, + {3, 0x02, 101}, + {6, 0x02, 101}, + {10, 0x02, 101}, + {15, 0x02, 101}, + {24, 0x02, 101}, + {31, 0x02, 101}, + {41, 0x02, 101}, + {56, 0x03, 101}, + }, + /* 8 */ + { + {3, 0x02, 105}, + {6, 0x02, 105}, + {10, 0x02, 105}, + {15, 0x02, 105}, + {24, 0x02, 105}, + {31, 0x02, 105}, + {41, 0x02, 105}, + {56, 0x03, 105}, + {3, 0x02, 111}, + {6, 0x02, 111}, + {10, 0x02, 111}, + {15, 0x02, 111}, + {24, 0x02, 111}, + {31, 0x02, 111}, + {41, 0x02, 111}, + {56, 0x03, 111}, + }, + /* 9 */ + { + {1, 0x02, 115}, + {22, 0x03, 115}, + {1, 0x02, 116}, + {22, 0x03, 116}, + {0, 0x03, 32}, + {0, 0x03, 37}, + {0, 0x03, 45}, + {0, 0x03, 46}, + {0, 0x03, 47}, + {0, 0x03, 51}, + {0, 0x03, 52}, + {0, 0x03, 53}, + {0, 0x03, 54}, + {0, 0x03, 55}, + {0, 0x03, 56}, + {0, 0x03, 57}, + }, + /* 10 */ + { + {2, 0x02, 115}, + {9, 0x02, 115}, + {23, 0x02, 115}, + {40, 0x03, 115}, + {2, 0x02, 116}, + {9, 0x02, 116}, + {23, 0x02, 116}, + {40, 0x03, 116}, + {1, 0x02, 32}, + {22, 0x03, 32}, + {1, 0x02, 37}, + {22, 0x03, 37}, + {1, 0x02, 45}, + {22, 0x03, 45}, + {1, 0x02, 46}, + {22, 0x03, 46}, + }, + /* 11 */ + { + {3, 0x02, 115}, + {6, 0x02, 115}, + {10, 0x02, 115}, + {15, 0x02, 115}, + {24, 0x02, 115}, + {31, 0x02, 115}, + {41, 0x02, 115}, + {56, 0x03, 115}, + {3, 0x02, 116}, + {6, 0x02, 116}, + {10, 0x02, 116}, + {15, 0x02, 116}, + {24, 0x02, 116}, + {31, 0x02, 116}, + {41, 0x02, 116}, + {56, 0x03, 116}, + }, + /* 12 */ + { + {2, 0x02, 32}, + {9, 0x02, 32}, + {23, 0x02, 32}, + {40, 0x03, 32}, + {2, 0x02, 37}, + {9, 0x02, 37}, + {23, 0x02, 37}, + {40, 0x03, 37}, + {2, 0x02, 45}, + {9, 0x02, 45}, + {23, 0x02, 45}, + {40, 0x03, 45}, + {2, 0x02, 46}, + {9, 0x02, 46}, + {23, 0x02, 46}, + {40, 0x03, 46}, + }, + /* 13 */ + { + {3, 0x02, 32}, + {6, 0x02, 32}, + {10, 0x02, 32}, + {15, 0x02, 32}, + {24, 0x02, 32}, + {31, 0x02, 32}, + {41, 0x02, 32}, + {56, 0x03, 32}, + {3, 0x02, 37}, + {6, 0x02, 37}, + {10, 0x02, 37}, + {15, 0x02, 37}, + {24, 0x02, 37}, + {31, 0x02, 37}, + {41, 0x02, 37}, + {56, 0x03, 37}, + }, + /* 14 */ + { + {3, 0x02, 45}, + {6, 0x02, 45}, + {10, 0x02, 45}, + {15, 0x02, 45}, + {24, 0x02, 45}, + {31, 0x02, 45}, + {41, 0x02, 45}, + {56, 0x03, 45}, + {3, 0x02, 46}, + {6, 0x02, 46}, + {10, 0x02, 46}, + {15, 0x02, 46}, + {24, 0x02, 46}, + {31, 0x02, 46}, + {41, 0x02, 46}, + {56, 0x03, 46}, + }, + /* 15 */ + { + {1, 0x02, 47}, + {22, 0x03, 47}, + {1, 0x02, 51}, + {22, 0x03, 51}, + {1, 0x02, 52}, + {22, 0x03, 52}, + {1, 0x02, 53}, + {22, 0x03, 53}, + {1, 0x02, 54}, + {22, 0x03, 54}, + {1, 0x02, 55}, + {22, 0x03, 55}, + {1, 0x02, 56}, + {22, 0x03, 56}, + {1, 0x02, 57}, + {22, 0x03, 57}, + }, + /* 16 */ + { + {2, 0x02, 47}, + {9, 0x02, 47}, + {23, 0x02, 47}, + {40, 0x03, 47}, + {2, 0x02, 51}, + {9, 0x02, 51}, + {23, 0x02, 51}, + {40, 0x03, 51}, + {2, 0x02, 52}, + {9, 0x02, 52}, + {23, 0x02, 52}, + {40, 0x03, 52}, + {2, 0x02, 53}, + {9, 0x02, 53}, + {23, 0x02, 53}, + {40, 0x03, 53}, + }, + /* 17 */ + { + {3, 0x02, 47}, + {6, 0x02, 47}, + {10, 0x02, 47}, + {15, 0x02, 47}, + {24, 0x02, 47}, + {31, 0x02, 47}, + {41, 0x02, 47}, + {56, 0x03, 47}, + {3, 0x02, 51}, + {6, 0x02, 51}, + {10, 0x02, 51}, + {15, 0x02, 51}, + {24, 0x02, 51}, + {31, 0x02, 51}, + {41, 0x02, 51}, + {56, 0x03, 51}, + }, + /* 18 */ + { + {3, 0x02, 52}, + {6, 0x02, 52}, + {10, 0x02, 52}, + {15, 0x02, 52}, + {24, 0x02, 52}, + {31, 0x02, 52}, + {41, 0x02, 52}, + {56, 0x03, 52}, + {3, 0x02, 53}, + {6, 0x02, 53}, + {10, 0x02, 53}, + {15, 0x02, 53}, + {24, 0x02, 53}, + {31, 0x02, 53}, + {41, 0x02, 53}, + {56, 0x03, 53}, + }, + /* 19 */ + { + {2, 0x02, 54}, + {9, 0x02, 54}, + {23, 0x02, 54}, + {40, 0x03, 54}, + {2, 0x02, 55}, + {9, 0x02, 55}, + {23, 0x02, 55}, + {40, 0x03, 55}, + {2, 0x02, 56}, + {9, 0x02, 56}, + {23, 0x02, 56}, + {40, 0x03, 56}, + {2, 0x02, 57}, + {9, 0x02, 57}, + {23, 0x02, 57}, + {40, 0x03, 57}, + }, + /* 20 */ + { + {3, 0x02, 54}, + {6, 0x02, 54}, + {10, 0x02, 54}, + {15, 0x02, 54}, + {24, 0x02, 54}, + {31, 0x02, 54}, + {41, 0x02, 54}, + {56, 0x03, 54}, + {3, 0x02, 55}, + {6, 0x02, 55}, + {10, 0x02, 55}, + {15, 0x02, 55}, + {24, 0x02, 55}, + {31, 0x02, 55}, + {41, 0x02, 55}, + {56, 0x03, 55}, + }, + /* 21 */ + { + {3, 0x02, 56}, + {6, 0x02, 56}, + {10, 0x02, 56}, + {15, 0x02, 56}, + {24, 0x02, 56}, + {31, 0x02, 56}, + {41, 0x02, 56}, + {56, 0x03, 56}, + {3, 0x02, 57}, + {6, 0x02, 57}, + {10, 0x02, 57}, + {15, 0x02, 57}, + {24, 0x02, 57}, + {31, 0x02, 57}, + {41, 0x02, 57}, + {56, 0x03, 57}, + }, + /* 22 */ + { + {26, 0x00, 0}, + {27, 0x00, 0}, + {29, 0x00, 0}, + {30, 0x00, 0}, + {33, 0x00, 0}, + {34, 0x00, 0}, + {36, 0x00, 0}, + {37, 0x00, 0}, + {43, 0x00, 0}, + {46, 0x00, 0}, + {50, 0x00, 0}, + {53, 0x00, 0}, + {58, 0x00, 0}, + {61, 0x00, 0}, + {65, 0x00, 0}, + {68, 0x01, 0}, + }, + /* 23 */ + { + {0, 0x03, 61}, + {0, 0x03, 65}, + {0, 0x03, 95}, + {0, 0x03, 98}, + {0, 0x03, 100}, + {0, 0x03, 102}, + {0, 0x03, 103}, + {0, 0x03, 104}, + {0, 0x03, 108}, + {0, 0x03, 109}, + {0, 0x03, 110}, + {0, 0x03, 112}, + {0, 0x03, 114}, + {0, 0x03, 117}, + {38, 0x00, 0}, + {39, 0x00, 0}, + }, + /* 24 */ + { + {1, 0x02, 61}, + {22, 0x03, 61}, + {1, 0x02, 65}, + {22, 0x03, 65}, + {1, 0x02, 95}, + {22, 0x03, 95}, + {1, 0x02, 98}, + {22, 0x03, 98}, + {1, 0x02, 100}, + {22, 0x03, 100}, + {1, 0x02, 102}, + {22, 0x03, 102}, + {1, 0x02, 103}, + {22, 0x03, 103}, + {1, 0x02, 104}, + {22, 0x03, 104}, + }, + /* 25 */ + { + {2, 0x02, 61}, + {9, 0x02, 61}, + {23, 0x02, 61}, + {40, 0x03, 61}, + {2, 0x02, 65}, + {9, 0x02, 65}, + {23, 0x02, 65}, + {40, 0x03, 65}, + {2, 0x02, 95}, + {9, 0x02, 95}, + {23, 0x02, 95}, + {40, 0x03, 95}, + {2, 0x02, 98}, + {9, 0x02, 98}, + {23, 0x02, 98}, + {40, 0x03, 98}, + }, + /* 26 */ + { + {3, 0x02, 61}, + {6, 0x02, 61}, + {10, 0x02, 61}, + {15, 0x02, 61}, + {24, 0x02, 61}, + {31, 0x02, 61}, + {41, 0x02, 61}, + {56, 0x03, 61}, + {3, 0x02, 65}, + {6, 0x02, 65}, + {10, 0x02, 65}, + {15, 0x02, 65}, + {24, 0x02, 65}, + {31, 0x02, 65}, + {41, 0x02, 65}, + {56, 0x03, 65}, + }, + /* 27 */ + { + {3, 0x02, 95}, + {6, 0x02, 95}, + {10, 0x02, 95}, + {15, 0x02, 95}, + {24, 0x02, 95}, + {31, 0x02, 95}, + {41, 0x02, 95}, + {56, 0x03, 95}, + {3, 0x02, 98}, + {6, 0x02, 98}, + {10, 0x02, 98}, + {15, 0x02, 98}, + {24, 0x02, 98}, + {31, 0x02, 98}, + {41, 0x02, 98}, + {56, 0x03, 98}, + }, + /* 28 */ + { + {2, 0x02, 100}, + {9, 0x02, 100}, + {23, 0x02, 100}, + {40, 0x03, 100}, + {2, 0x02, 102}, + {9, 0x02, 102}, + {23, 0x02, 102}, + {40, 0x03, 102}, + {2, 0x02, 103}, + {9, 0x02, 103}, + {23, 0x02, 103}, + {40, 0x03, 103}, + {2, 0x02, 104}, + {9, 0x02, 104}, + {23, 0x02, 104}, + {40, 0x03, 104}, + }, + /* 29 */ + { + {3, 0x02, 100}, + {6, 0x02, 100}, + {10, 0x02, 100}, + {15, 0x02, 100}, + {24, 0x02, 100}, + {31, 0x02, 100}, + {41, 0x02, 100}, + {56, 0x03, 100}, + {3, 0x02, 102}, + {6, 0x02, 102}, + {10, 0x02, 102}, + {15, 0x02, 102}, + {24, 0x02, 102}, + {31, 0x02, 102}, + {41, 0x02, 102}, + {56, 0x03, 102}, + }, + /* 30 */ + { + {3, 0x02, 103}, + {6, 0x02, 103}, + {10, 0x02, 103}, + {15, 0x02, 103}, + {24, 0x02, 103}, + {31, 0x02, 103}, + {41, 0x02, 103}, + {56, 0x03, 103}, + {3, 0x02, 104}, + {6, 0x02, 104}, + {10, 0x02, 104}, + {15, 0x02, 104}, + {24, 0x02, 104}, + {31, 0x02, 104}, + {41, 0x02, 104}, + {56, 0x03, 104}, + }, + /* 31 */ + { + {1, 0x02, 108}, + {22, 0x03, 108}, + {1, 0x02, 109}, + {22, 0x03, 109}, + {1, 0x02, 110}, + {22, 0x03, 110}, + {1, 0x02, 112}, + {22, 0x03, 112}, + {1, 0x02, 114}, + {22, 0x03, 114}, + {1, 0x02, 117}, + {22, 0x03, 117}, + {0, 0x03, 58}, + {0, 0x03, 66}, + {0, 0x03, 67}, + {0, 0x03, 68}, + }, + /* 32 */ + { + {2, 0x02, 108}, + {9, 0x02, 108}, + {23, 0x02, 108}, + {40, 0x03, 108}, + {2, 0x02, 109}, + {9, 0x02, 109}, + {23, 0x02, 109}, + {40, 0x03, 109}, + {2, 0x02, 110}, + {9, 0x02, 110}, + {23, 0x02, 110}, + {40, 0x03, 110}, + {2, 0x02, 112}, + {9, 0x02, 112}, + {23, 0x02, 112}, + {40, 0x03, 112}, + }, + /* 33 */ + { + {3, 0x02, 108}, + {6, 0x02, 108}, + {10, 0x02, 108}, + {15, 0x02, 108}, + {24, 0x02, 108}, + {31, 0x02, 108}, + {41, 0x02, 108}, + {56, 0x03, 108}, + {3, 0x02, 109}, + {6, 0x02, 109}, + {10, 0x02, 109}, + {15, 0x02, 109}, + {24, 0x02, 109}, + {31, 0x02, 109}, + {41, 0x02, 109}, + {56, 0x03, 109}, + }, + /* 34 */ + { + {3, 0x02, 110}, + {6, 0x02, 110}, + {10, 0x02, 110}, + {15, 0x02, 110}, + {24, 0x02, 110}, + {31, 0x02, 110}, + {41, 0x02, 110}, + {56, 0x03, 110}, + {3, 0x02, 112}, + {6, 0x02, 112}, + {10, 0x02, 112}, + {15, 0x02, 112}, + {24, 0x02, 112}, + {31, 0x02, 112}, + {41, 0x02, 112}, + {56, 0x03, 112}, + }, + /* 35 */ + { + {2, 0x02, 114}, + {9, 0x02, 114}, + {23, 0x02, 114}, + {40, 0x03, 114}, + {2, 0x02, 117}, + {9, 0x02, 117}, + {23, 0x02, 117}, + {40, 0x03, 117}, + {1, 0x02, 58}, + {22, 0x03, 58}, + {1, 0x02, 66}, + {22, 0x03, 66}, + {1, 0x02, 67}, + {22, 0x03, 67}, + {1, 0x02, 68}, + {22, 0x03, 68}, + }, + /* 36 */ + { + {3, 0x02, 114}, + {6, 0x02, 114}, + {10, 0x02, 114}, + {15, 0x02, 114}, + {24, 0x02, 114}, + {31, 0x02, 114}, + {41, 0x02, 114}, + {56, 0x03, 114}, + {3, 0x02, 117}, + {6, 0x02, 117}, + {10, 0x02, 117}, + {15, 0x02, 117}, + {24, 0x02, 117}, + {31, 0x02, 117}, + {41, 0x02, 117}, + {56, 0x03, 117}, + }, + /* 37 */ + { + {2, 0x02, 58}, + {9, 0x02, 58}, + {23, 0x02, 58}, + {40, 0x03, 58}, + {2, 0x02, 66}, + {9, 0x02, 66}, + {23, 0x02, 66}, + {40, 0x03, 66}, + {2, 0x02, 67}, + {9, 0x02, 67}, + {23, 0x02, 67}, + {40, 0x03, 67}, + {2, 0x02, 68}, + {9, 0x02, 68}, + {23, 0x02, 68}, + {40, 0x03, 68}, + }, + /* 38 */ + { + {3, 0x02, 58}, + {6, 0x02, 58}, + {10, 0x02, 58}, + {15, 0x02, 58}, + {24, 0x02, 58}, + {31, 0x02, 58}, + {41, 0x02, 58}, + {56, 0x03, 58}, + {3, 0x02, 66}, + {6, 0x02, 66}, + {10, 0x02, 66}, + {15, 0x02, 66}, + {24, 0x02, 66}, + {31, 0x02, 66}, + {41, 0x02, 66}, + {56, 0x03, 66}, + }, + /* 39 */ + { + {3, 0x02, 67}, + {6, 0x02, 67}, + {10, 0x02, 67}, + {15, 0x02, 67}, + {24, 0x02, 67}, + {31, 0x02, 67}, + {41, 0x02, 67}, + {56, 0x03, 67}, + {3, 0x02, 68}, + {6, 0x02, 68}, + {10, 0x02, 68}, + {15, 0x02, 68}, + {24, 0x02, 68}, + {31, 0x02, 68}, + {41, 0x02, 68}, + {56, 0x03, 68}, + }, + /* 40 */ + { + {44, 0x00, 0}, + {45, 0x00, 0}, + {47, 0x00, 0}, + {48, 0x00, 0}, + {51, 0x00, 0}, + {52, 0x00, 0}, + {54, 0x00, 0}, + {55, 0x00, 0}, + {59, 0x00, 0}, + {60, 0x00, 0}, + {62, 0x00, 0}, + {63, 0x00, 0}, + {66, 0x00, 0}, + {67, 0x00, 0}, + {69, 0x00, 0}, + {72, 0x01, 0}, + }, + /* 41 */ + { + {0, 0x03, 69}, + {0, 0x03, 70}, + {0, 0x03, 71}, + {0, 0x03, 72}, + {0, 0x03, 73}, + {0, 0x03, 74}, + {0, 0x03, 75}, + {0, 0x03, 76}, + {0, 0x03, 77}, + {0, 0x03, 78}, + {0, 0x03, 79}, + {0, 0x03, 80}, + {0, 0x03, 81}, + {0, 0x03, 82}, + {0, 0x03, 83}, + {0, 0x03, 84}, + }, + /* 42 */ + { + {1, 0x02, 69}, + {22, 0x03, 69}, + {1, 0x02, 70}, + {22, 0x03, 70}, + {1, 0x02, 71}, + {22, 0x03, 71}, + {1, 0x02, 72}, + {22, 0x03, 72}, + {1, 0x02, 73}, + {22, 0x03, 73}, + {1, 0x02, 74}, + {22, 0x03, 74}, + {1, 0x02, 75}, + {22, 0x03, 75}, + {1, 0x02, 76}, + {22, 0x03, 76}, + }, + /* 43 */ + { + {2, 0x02, 69}, + {9, 0x02, 69}, + {23, 0x02, 69}, + {40, 0x03, 69}, + {2, 0x02, 70}, + {9, 0x02, 70}, + {23, 0x02, 70}, + {40, 0x03, 70}, + {2, 0x02, 71}, + {9, 0x02, 71}, + {23, 0x02, 71}, + {40, 0x03, 71}, + {2, 0x02, 72}, + {9, 0x02, 72}, + {23, 0x02, 72}, + {40, 0x03, 72}, + }, + /* 44 */ + { + {3, 0x02, 69}, + {6, 0x02, 69}, + {10, 0x02, 69}, + {15, 0x02, 69}, + {24, 0x02, 69}, + {31, 0x02, 69}, + {41, 0x02, 69}, + {56, 0x03, 69}, + {3, 0x02, 70}, + {6, 0x02, 70}, + {10, 0x02, 70}, + {15, 0x02, 70}, + {24, 0x02, 70}, + {31, 0x02, 70}, + {41, 0x02, 70}, + {56, 0x03, 70}, + }, + /* 45 */ + { + {3, 0x02, 71}, + {6, 0x02, 71}, + {10, 0x02, 71}, + {15, 0x02, 71}, + {24, 0x02, 71}, + {31, 0x02, 71}, + {41, 0x02, 71}, + {56, 0x03, 71}, + {3, 0x02, 72}, + {6, 0x02, 72}, + {10, 0x02, 72}, + {15, 0x02, 72}, + {24, 0x02, 72}, + {31, 0x02, 72}, + {41, 0x02, 72}, + {56, 0x03, 72}, + }, + /* 46 */ + { + {2, 0x02, 73}, + {9, 0x02, 73}, + {23, 0x02, 73}, + {40, 0x03, 73}, + {2, 0x02, 74}, + {9, 0x02, 74}, + {23, 0x02, 74}, + {40, 0x03, 74}, + {2, 0x02, 75}, + {9, 0x02, 75}, + {23, 0x02, 75}, + {40, 0x03, 75}, + {2, 0x02, 76}, + {9, 0x02, 76}, + {23, 0x02, 76}, + {40, 0x03, 76}, + }, + /* 47 */ + { + {3, 0x02, 73}, + {6, 0x02, 73}, + {10, 0x02, 73}, + {15, 0x02, 73}, + {24, 0x02, 73}, + {31, 0x02, 73}, + {41, 0x02, 73}, + {56, 0x03, 73}, + {3, 0x02, 74}, + {6, 0x02, 74}, + {10, 0x02, 74}, + {15, 0x02, 74}, + {24, 0x02, 74}, + {31, 0x02, 74}, + {41, 0x02, 74}, + {56, 0x03, 74}, + }, + /* 48 */ + { + {3, 0x02, 75}, + {6, 0x02, 75}, + {10, 0x02, 75}, + {15, 0x02, 75}, + {24, 0x02, 75}, + {31, 0x02, 75}, + {41, 0x02, 75}, + {56, 0x03, 75}, + {3, 0x02, 76}, + {6, 0x02, 76}, + {10, 0x02, 76}, + {15, 0x02, 76}, + {24, 0x02, 76}, + {31, 0x02, 76}, + {41, 0x02, 76}, + {56, 0x03, 76}, + }, + /* 49 */ + { + {1, 0x02, 77}, + {22, 0x03, 77}, + {1, 0x02, 78}, + {22, 0x03, 78}, + {1, 0x02, 79}, + {22, 0x03, 79}, + {1, 0x02, 80}, + {22, 0x03, 80}, + {1, 0x02, 81}, + {22, 0x03, 81}, + {1, 0x02, 82}, + {22, 0x03, 82}, + {1, 0x02, 83}, + {22, 0x03, 83}, + {1, 0x02, 84}, + {22, 0x03, 84}, + }, + /* 50 */ + { + {2, 0x02, 77}, + {9, 0x02, 77}, + {23, 0x02, 77}, + {40, 0x03, 77}, + {2, 0x02, 78}, + {9, 0x02, 78}, + {23, 0x02, 78}, + {40, 0x03, 78}, + {2, 0x02, 79}, + {9, 0x02, 79}, + {23, 0x02, 79}, + {40, 0x03, 79}, + {2, 0x02, 80}, + {9, 0x02, 80}, + {23, 0x02, 80}, + {40, 0x03, 80}, + }, + /* 51 */ + { + {3, 0x02, 77}, + {6, 0x02, 77}, + {10, 0x02, 77}, + {15, 0x02, 77}, + {24, 0x02, 77}, + {31, 0x02, 77}, + {41, 0x02, 77}, + {56, 0x03, 77}, + {3, 0x02, 78}, + {6, 0x02, 78}, + {10, 0x02, 78}, + {15, 0x02, 78}, + {24, 0x02, 78}, + {31, 0x02, 78}, + {41, 0x02, 78}, + {56, 0x03, 78}, + }, + /* 52 */ + { + {3, 0x02, 79}, + {6, 0x02, 79}, + {10, 0x02, 79}, + {15, 0x02, 79}, + {24, 0x02, 79}, + {31, 0x02, 79}, + {41, 0x02, 79}, + {56, 0x03, 79}, + {3, 0x02, 80}, + {6, 0x02, 80}, + {10, 0x02, 80}, + {15, 0x02, 80}, + {24, 0x02, 80}, + {31, 0x02, 80}, + {41, 0x02, 80}, + {56, 0x03, 80}, + }, + /* 53 */ + { + {2, 0x02, 81}, + {9, 0x02, 81}, + {23, 0x02, 81}, + {40, 0x03, 81}, + {2, 0x02, 82}, + {9, 0x02, 82}, + {23, 0x02, 82}, + {40, 0x03, 82}, + {2, 0x02, 83}, + {9, 0x02, 83}, + {23, 0x02, 83}, + {40, 0x03, 83}, + {2, 0x02, 84}, + {9, 0x02, 84}, + {23, 0x02, 84}, + {40, 0x03, 84}, + }, + /* 54 */ + { + {3, 0x02, 81}, + {6, 0x02, 81}, + {10, 0x02, 81}, + {15, 0x02, 81}, + {24, 0x02, 81}, + {31, 0x02, 81}, + {41, 0x02, 81}, + {56, 0x03, 81}, + {3, 0x02, 82}, + {6, 0x02, 82}, + {10, 0x02, 82}, + {15, 0x02, 82}, + {24, 0x02, 82}, + {31, 0x02, 82}, + {41, 0x02, 82}, + {56, 0x03, 82}, + }, + /* 55 */ + { + {3, 0x02, 83}, + {6, 0x02, 83}, + {10, 0x02, 83}, + {15, 0x02, 83}, + {24, 0x02, 83}, + {31, 0x02, 83}, + {41, 0x02, 83}, + {56, 0x03, 83}, + {3, 0x02, 84}, + {6, 0x02, 84}, + {10, 0x02, 84}, + {15, 0x02, 84}, + {24, 0x02, 84}, + {31, 0x02, 84}, + {41, 0x02, 84}, + {56, 0x03, 84}, + }, + /* 56 */ + { + {0, 0x03, 85}, + {0, 0x03, 86}, + {0, 0x03, 87}, + {0, 0x03, 89}, + {0, 0x03, 106}, + {0, 0x03, 107}, + {0, 0x03, 113}, + {0, 0x03, 118}, + {0, 0x03, 119}, + {0, 0x03, 120}, + {0, 0x03, 121}, + {0, 0x03, 122}, + {70, 0x00, 0}, + {71, 0x00, 0}, + {73, 0x00, 0}, + {74, 0x01, 0}, + }, + /* 57 */ + { + {1, 0x02, 85}, + {22, 0x03, 85}, + {1, 0x02, 86}, + {22, 0x03, 86}, + {1, 0x02, 87}, + {22, 0x03, 87}, + {1, 0x02, 89}, + {22, 0x03, 89}, + {1, 0x02, 106}, + {22, 0x03, 106}, + {1, 0x02, 107}, + {22, 0x03, 107}, + {1, 0x02, 113}, + {22, 0x03, 113}, + {1, 0x02, 118}, + {22, 0x03, 118}, + }, + /* 58 */ + { + {2, 0x02, 85}, + {9, 0x02, 85}, + {23, 0x02, 85}, + {40, 0x03, 85}, + {2, 0x02, 86}, + {9, 0x02, 86}, + {23, 0x02, 86}, + {40, 0x03, 86}, + {2, 0x02, 87}, + {9, 0x02, 87}, + {23, 0x02, 87}, + {40, 0x03, 87}, + {2, 0x02, 89}, + {9, 0x02, 89}, + {23, 0x02, 89}, + {40, 0x03, 89}, + }, + /* 59 */ + { + {3, 0x02, 85}, + {6, 0x02, 85}, + {10, 0x02, 85}, + {15, 0x02, 85}, + {24, 0x02, 85}, + {31, 0x02, 85}, + {41, 0x02, 85}, + {56, 0x03, 85}, + {3, 0x02, 86}, + {6, 0x02, 86}, + {10, 0x02, 86}, + {15, 0x02, 86}, + {24, 0x02, 86}, + {31, 0x02, 86}, + {41, 0x02, 86}, + {56, 0x03, 86}, + }, + /* 60 */ + { + {3, 0x02, 87}, + {6, 0x02, 87}, + {10, 0x02, 87}, + {15, 0x02, 87}, + {24, 0x02, 87}, + {31, 0x02, 87}, + {41, 0x02, 87}, + {56, 0x03, 87}, + {3, 0x02, 89}, + {6, 0x02, 89}, + {10, 0x02, 89}, + {15, 0x02, 89}, + {24, 0x02, 89}, + {31, 0x02, 89}, + {41, 0x02, 89}, + {56, 0x03, 89}, + }, + /* 61 */ + { + {2, 0x02, 106}, + {9, 0x02, 106}, + {23, 0x02, 106}, + {40, 0x03, 106}, + {2, 0x02, 107}, + {9, 0x02, 107}, + {23, 0x02, 107}, + {40, 0x03, 107}, + {2, 0x02, 113}, + {9, 0x02, 113}, + {23, 0x02, 113}, + {40, 0x03, 113}, + {2, 0x02, 118}, + {9, 0x02, 118}, + {23, 0x02, 118}, + {40, 0x03, 118}, + }, + /* 62 */ + { + {3, 0x02, 106}, + {6, 0x02, 106}, + {10, 0x02, 106}, + {15, 0x02, 106}, + {24, 0x02, 106}, + {31, 0x02, 106}, + {41, 0x02, 106}, + {56, 0x03, 106}, + {3, 0x02, 107}, + {6, 0x02, 107}, + {10, 0x02, 107}, + {15, 0x02, 107}, + {24, 0x02, 107}, + {31, 0x02, 107}, + {41, 0x02, 107}, + {56, 0x03, 107}, + }, + /* 63 */ + { + {3, 0x02, 113}, + {6, 0x02, 113}, + {10, 0x02, 113}, + {15, 0x02, 113}, + {24, 0x02, 113}, + {31, 0x02, 113}, + {41, 0x02, 113}, + {56, 0x03, 113}, + {3, 0x02, 118}, + {6, 0x02, 118}, + {10, 0x02, 118}, + {15, 0x02, 118}, + {24, 0x02, 118}, + {31, 0x02, 118}, + {41, 0x02, 118}, + {56, 0x03, 118}, + }, + /* 64 */ + { + {1, 0x02, 119}, + {22, 0x03, 119}, + {1, 0x02, 120}, + {22, 0x03, 120}, + {1, 0x02, 121}, + {22, 0x03, 121}, + {1, 0x02, 122}, + {22, 0x03, 122}, + {0, 0x03, 38}, + {0, 0x03, 42}, + {0, 0x03, 44}, + {0, 0x03, 59}, + {0, 0x03, 88}, + {0, 0x03, 90}, + {75, 0x00, 0}, + {78, 0x00, 0}, + }, + /* 65 */ + { + {2, 0x02, 119}, + {9, 0x02, 119}, + {23, 0x02, 119}, + {40, 0x03, 119}, + {2, 0x02, 120}, + {9, 0x02, 120}, + {23, 0x02, 120}, + {40, 0x03, 120}, + {2, 0x02, 121}, + {9, 0x02, 121}, + {23, 0x02, 121}, + {40, 0x03, 121}, + {2, 0x02, 122}, + {9, 0x02, 122}, + {23, 0x02, 122}, + {40, 0x03, 122}, + }, + /* 66 */ + { + {3, 0x02, 119}, + {6, 0x02, 119}, + {10, 0x02, 119}, + {15, 0x02, 119}, + {24, 0x02, 119}, + {31, 0x02, 119}, + {41, 0x02, 119}, + {56, 0x03, 119}, + {3, 0x02, 120}, + {6, 0x02, 120}, + {10, 0x02, 120}, + {15, 0x02, 120}, + {24, 0x02, 120}, + {31, 0x02, 120}, + {41, 0x02, 120}, + {56, 0x03, 120}, + }, + /* 67 */ + { + {3, 0x02, 121}, + {6, 0x02, 121}, + {10, 0x02, 121}, + {15, 0x02, 121}, + {24, 0x02, 121}, + {31, 0x02, 121}, + {41, 0x02, 121}, + {56, 0x03, 121}, + {3, 0x02, 122}, + {6, 0x02, 122}, + {10, 0x02, 122}, + {15, 0x02, 122}, + {24, 0x02, 122}, + {31, 0x02, 122}, + {41, 0x02, 122}, + {56, 0x03, 122}, + }, + /* 68 */ + { + {1, 0x02, 38}, + {22, 0x03, 38}, + {1, 0x02, 42}, + {22, 0x03, 42}, + {1, 0x02, 44}, + {22, 0x03, 44}, + {1, 0x02, 59}, + {22, 0x03, 59}, + {1, 0x02, 88}, + {22, 0x03, 88}, + {1, 0x02, 90}, + {22, 0x03, 90}, + {76, 0x00, 0}, + {77, 0x00, 0}, + {79, 0x00, 0}, + {81, 0x00, 0}, + }, + /* 69 */ + { + {2, 0x02, 38}, + {9, 0x02, 38}, + {23, 0x02, 38}, + {40, 0x03, 38}, + {2, 0x02, 42}, + {9, 0x02, 42}, + {23, 0x02, 42}, + {40, 0x03, 42}, + {2, 0x02, 44}, + {9, 0x02, 44}, + {23, 0x02, 44}, + {40, 0x03, 44}, + {2, 0x02, 59}, + {9, 0x02, 59}, + {23, 0x02, 59}, + {40, 0x03, 59}, + }, + /* 70 */ + { + {3, 0x02, 38}, + {6, 0x02, 38}, + {10, 0x02, 38}, + {15, 0x02, 38}, + {24, 0x02, 38}, + {31, 0x02, 38}, + {41, 0x02, 38}, + {56, 0x03, 38}, + {3, 0x02, 42}, + {6, 0x02, 42}, + {10, 0x02, 42}, + {15, 0x02, 42}, + {24, 0x02, 42}, + {31, 0x02, 42}, + {41, 0x02, 42}, + {56, 0x03, 42}, + }, + /* 71 */ + { + {3, 0x02, 44}, + {6, 0x02, 44}, + {10, 0x02, 44}, + {15, 0x02, 44}, + {24, 0x02, 44}, + {31, 0x02, 44}, + {41, 0x02, 44}, + {56, 0x03, 44}, + {3, 0x02, 59}, + {6, 0x02, 59}, + {10, 0x02, 59}, + {15, 0x02, 59}, + {24, 0x02, 59}, + {31, 0x02, 59}, + {41, 0x02, 59}, + {56, 0x03, 59}, + }, + /* 72 */ + { + {2, 0x02, 88}, + {9, 0x02, 88}, + {23, 0x02, 88}, + {40, 0x03, 88}, + {2, 0x02, 90}, + {9, 0x02, 90}, + {23, 0x02, 90}, + {40, 0x03, 90}, + {0, 0x03, 33}, + {0, 0x03, 34}, + {0, 0x03, 40}, + {0, 0x03, 41}, + {0, 0x03, 63}, + {80, 0x00, 0}, + {82, 0x00, 0}, + {84, 0x00, 0}, + }, + /* 73 */ + { + {3, 0x02, 88}, + {6, 0x02, 88}, + {10, 0x02, 88}, + {15, 0x02, 88}, + {24, 0x02, 88}, + {31, 0x02, 88}, + {41, 0x02, 88}, + {56, 0x03, 88}, + {3, 0x02, 90}, + {6, 0x02, 90}, + {10, 0x02, 90}, + {15, 0x02, 90}, + {24, 0x02, 90}, + {31, 0x02, 90}, + {41, 0x02, 90}, + {56, 0x03, 90}, + }, + /* 74 */ + { + {1, 0x02, 33}, + {22, 0x03, 33}, + {1, 0x02, 34}, + {22, 0x03, 34}, + {1, 0x02, 40}, + {22, 0x03, 40}, + {1, 0x02, 41}, + {22, 0x03, 41}, + {1, 0x02, 63}, + {22, 0x03, 63}, + {0, 0x03, 39}, + {0, 0x03, 43}, + {0, 0x03, 124}, + {83, 0x00, 0}, + {85, 0x00, 0}, + {88, 0x00, 0}, + }, + /* 75 */ + { + {2, 0x02, 33}, + {9, 0x02, 33}, + {23, 0x02, 33}, + {40, 0x03, 33}, + {2, 0x02, 34}, + {9, 0x02, 34}, + {23, 0x02, 34}, + {40, 0x03, 34}, + {2, 0x02, 40}, + {9, 0x02, 40}, + {23, 0x02, 40}, + {40, 0x03, 40}, + {2, 0x02, 41}, + {9, 0x02, 41}, + {23, 0x02, 41}, + {40, 0x03, 41}, + }, + /* 76 */ + { + {3, 0x02, 33}, + {6, 0x02, 33}, + {10, 0x02, 33}, + {15, 0x02, 33}, + {24, 0x02, 33}, + {31, 0x02, 33}, + {41, 0x02, 33}, + {56, 0x03, 33}, + {3, 0x02, 34}, + {6, 0x02, 34}, + {10, 0x02, 34}, + {15, 0x02, 34}, + {24, 0x02, 34}, + {31, 0x02, 34}, + {41, 0x02, 34}, + {56, 0x03, 34}, + }, + /* 77 */ + { + {3, 0x02, 40}, + {6, 0x02, 40}, + {10, 0x02, 40}, + {15, 0x02, 40}, + {24, 0x02, 40}, + {31, 0x02, 40}, + {41, 0x02, 40}, + {56, 0x03, 40}, + {3, 0x02, 41}, + {6, 0x02, 41}, + {10, 0x02, 41}, + {15, 0x02, 41}, + {24, 0x02, 41}, + {31, 0x02, 41}, + {41, 0x02, 41}, + {56, 0x03, 41}, + }, + /* 78 */ + { + {2, 0x02, 63}, + {9, 0x02, 63}, + {23, 0x02, 63}, + {40, 0x03, 63}, + {1, 0x02, 39}, + {22, 0x03, 39}, + {1, 0x02, 43}, + {22, 0x03, 43}, + {1, 0x02, 124}, + {22, 0x03, 124}, + {0, 0x03, 35}, + {0, 0x03, 62}, + {86, 0x00, 0}, + {87, 0x00, 0}, + {89, 0x00, 0}, + {90, 0x00, 0}, + }, + /* 79 */ + { + {3, 0x02, 63}, + {6, 0x02, 63}, + {10, 0x02, 63}, + {15, 0x02, 63}, + {24, 0x02, 63}, + {31, 0x02, 63}, + {41, 0x02, 63}, + {56, 0x03, 63}, + {2, 0x02, 39}, + {9, 0x02, 39}, + {23, 0x02, 39}, + {40, 0x03, 39}, + {2, 0x02, 43}, + {9, 0x02, 43}, + {23, 0x02, 43}, + {40, 0x03, 43}, + }, + /* 80 */ + { + {3, 0x02, 39}, + {6, 0x02, 39}, + {10, 0x02, 39}, + {15, 0x02, 39}, + {24, 0x02, 39}, + {31, 0x02, 39}, + {41, 0x02, 39}, + {56, 0x03, 39}, + {3, 0x02, 43}, + {6, 0x02, 43}, + {10, 0x02, 43}, + {15, 0x02, 43}, + {24, 0x02, 43}, + {31, 0x02, 43}, + {41, 0x02, 43}, + {56, 0x03, 43}, + }, + /* 81 */ + { + {2, 0x02, 124}, + {9, 0x02, 124}, + {23, 0x02, 124}, + {40, 0x03, 124}, + {1, 0x02, 35}, + {22, 0x03, 35}, + {1, 0x02, 62}, + {22, 0x03, 62}, + {0, 0x03, 0}, + {0, 0x03, 36}, + {0, 0x03, 64}, + {0, 0x03, 91}, + {0, 0x03, 93}, + {0, 0x03, 126}, + {91, 0x00, 0}, + {92, 0x00, 0}, + }, + /* 82 */ + { + {3, 0x02, 124}, + {6, 0x02, 124}, + {10, 0x02, 124}, + {15, 0x02, 124}, + {24, 0x02, 124}, + {31, 0x02, 124}, + {41, 0x02, 124}, + {56, 0x03, 124}, + {2, 0x02, 35}, + {9, 0x02, 35}, + {23, 0x02, 35}, + {40, 0x03, 35}, + {2, 0x02, 62}, + {9, 0x02, 62}, + {23, 0x02, 62}, + {40, 0x03, 62}, + }, + /* 83 */ + { + {3, 0x02, 35}, + {6, 0x02, 35}, + {10, 0x02, 35}, + {15, 0x02, 35}, + {24, 0x02, 35}, + {31, 0x02, 35}, + {41, 0x02, 35}, + {56, 0x03, 35}, + {3, 0x02, 62}, + {6, 0x02, 62}, + {10, 0x02, 62}, + {15, 0x02, 62}, + {24, 0x02, 62}, + {31, 0x02, 62}, + {41, 0x02, 62}, + {56, 0x03, 62}, + }, + /* 84 */ + { + {1, 0x02, 0}, + {22, 0x03, 0}, + {1, 0x02, 36}, + {22, 0x03, 36}, + {1, 0x02, 64}, + {22, 0x03, 64}, + {1, 0x02, 91}, + {22, 0x03, 91}, + {1, 0x02, 93}, + {22, 0x03, 93}, + {1, 0x02, 126}, + {22, 0x03, 126}, + {0, 0x03, 94}, + {0, 0x03, 125}, + {93, 0x00, 0}, + {94, 0x00, 0}, + }, + /* 85 */ + { + {2, 0x02, 0}, + {9, 0x02, 0}, + {23, 0x02, 0}, + {40, 0x03, 0}, + {2, 0x02, 36}, + {9, 0x02, 36}, + {23, 0x02, 36}, + {40, 0x03, 36}, + {2, 0x02, 64}, + {9, 0x02, 64}, + {23, 0x02, 64}, + {40, 0x03, 64}, + {2, 0x02, 91}, + {9, 0x02, 91}, + {23, 0x02, 91}, + {40, 0x03, 91}, + }, + /* 86 */ + { + {3, 0x02, 0}, + {6, 0x02, 0}, + {10, 0x02, 0}, + {15, 0x02, 0}, + {24, 0x02, 0}, + {31, 0x02, 0}, + {41, 0x02, 0}, + {56, 0x03, 0}, + {3, 0x02, 36}, + {6, 0x02, 36}, + {10, 0x02, 36}, + {15, 0x02, 36}, + {24, 0x02, 36}, + {31, 0x02, 36}, + {41, 0x02, 36}, + {56, 0x03, 36}, + }, + /* 87 */ + { + {3, 0x02, 64}, + {6, 0x02, 64}, + {10, 0x02, 64}, + {15, 0x02, 64}, + {24, 0x02, 64}, + {31, 0x02, 64}, + {41, 0x02, 64}, + {56, 0x03, 64}, + {3, 0x02, 91}, + {6, 0x02, 91}, + {10, 0x02, 91}, + {15, 0x02, 91}, + {24, 0x02, 91}, + {31, 0x02, 91}, + {41, 0x02, 91}, + {56, 0x03, 91}, + }, + /* 88 */ + { + {2, 0x02, 93}, + {9, 0x02, 93}, + {23, 0x02, 93}, + {40, 0x03, 93}, + {2, 0x02, 126}, + {9, 0x02, 126}, + {23, 0x02, 126}, + {40, 0x03, 126}, + {1, 0x02, 94}, + {22, 0x03, 94}, + {1, 0x02, 125}, + {22, 0x03, 125}, + {0, 0x03, 60}, + {0, 0x03, 96}, + {0, 0x03, 123}, + {95, 0x00, 0}, + }, + /* 89 */ + { + {3, 0x02, 93}, + {6, 0x02, 93}, + {10, 0x02, 93}, + {15, 0x02, 93}, + {24, 0x02, 93}, + {31, 0x02, 93}, + {41, 0x02, 93}, + {56, 0x03, 93}, + {3, 0x02, 126}, + {6, 0x02, 126}, + {10, 0x02, 126}, + {15, 0x02, 126}, + {24, 0x02, 126}, + {31, 0x02, 126}, + {41, 0x02, 126}, + {56, 0x03, 126}, + }, + /* 90 */ + { + {2, 0x02, 94}, + {9, 0x02, 94}, + {23, 0x02, 94}, + {40, 0x03, 94}, + {2, 0x02, 125}, + {9, 0x02, 125}, + {23, 0x02, 125}, + {40, 0x03, 125}, + {1, 0x02, 60}, + {22, 0x03, 60}, + {1, 0x02, 96}, + {22, 0x03, 96}, + {1, 0x02, 123}, + {22, 0x03, 123}, + {96, 0x00, 0}, + {110, 0x00, 0}, + }, + /* 91 */ + { + {3, 0x02, 94}, + {6, 0x02, 94}, + {10, 0x02, 94}, + {15, 0x02, 94}, + {24, 0x02, 94}, + {31, 0x02, 94}, + {41, 0x02, 94}, + {56, 0x03, 94}, + {3, 0x02, 125}, + {6, 0x02, 125}, + {10, 0x02, 125}, + {15, 0x02, 125}, + {24, 0x02, 125}, + {31, 0x02, 125}, + {41, 0x02, 125}, + {56, 0x03, 125}, + }, + /* 92 */ + { + {2, 0x02, 60}, + {9, 0x02, 60}, + {23, 0x02, 60}, + {40, 0x03, 60}, + {2, 0x02, 96}, + {9, 0x02, 96}, + {23, 0x02, 96}, + {40, 0x03, 96}, + {2, 0x02, 123}, + {9, 0x02, 123}, + {23, 0x02, 123}, + {40, 0x03, 123}, + {97, 0x00, 0}, + {101, 0x00, 0}, + {111, 0x00, 0}, + {133, 0x00, 0}, + }, + /* 93 */ + { + {3, 0x02, 60}, + {6, 0x02, 60}, + {10, 0x02, 60}, + {15, 0x02, 60}, + {24, 0x02, 60}, + {31, 0x02, 60}, + {41, 0x02, 60}, + {56, 0x03, 60}, + {3, 0x02, 96}, + {6, 0x02, 96}, + {10, 0x02, 96}, + {15, 0x02, 96}, + {24, 0x02, 96}, + {31, 0x02, 96}, + {41, 0x02, 96}, + {56, 0x03, 96}, + }, + /* 94 */ + { + {3, 0x02, 123}, + {6, 0x02, 123}, + {10, 0x02, 123}, + {15, 0x02, 123}, + {24, 0x02, 123}, + {31, 0x02, 123}, + {41, 0x02, 123}, + {56, 0x03, 123}, + {98, 0x00, 0}, + {99, 0x00, 0}, + {102, 0x00, 0}, + {105, 0x00, 0}, + {112, 0x00, 0}, + {119, 0x00, 0}, + {134, 0x00, 0}, + {153, 0x00, 0}, + }, + /* 95 */ + { + {0, 0x03, 92}, + {0, 0x03, 195}, + {0, 0x03, 208}, + {100, 0x00, 0}, + {103, 0x00, 0}, + {104, 0x00, 0}, + {106, 0x00, 0}, + {107, 0x00, 0}, + {113, 0x00, 0}, + {116, 0x00, 0}, + {120, 0x00, 0}, + {126, 0x00, 0}, + {135, 0x00, 0}, + {142, 0x00, 0}, + {154, 0x00, 0}, + {169, 0x00, 0}, + }, + /* 96 */ + { + {1, 0x02, 92}, + {22, 0x03, 92}, + {1, 0x02, 195}, + {22, 0x03, 195}, + {1, 0x02, 208}, + {22, 0x03, 208}, + {0, 0x03, 128}, + {0, 0x03, 130}, + {0, 0x03, 131}, + {0, 0x03, 162}, + {0, 0x03, 184}, + {0, 0x03, 194}, + {0, 0x03, 224}, + {0, 0x03, 226}, + {108, 0x00, 0}, + {109, 0x00, 0}, + }, + /* 97 */ + { + {2, 0x02, 92}, + {9, 0x02, 92}, + {23, 0x02, 92}, + {40, 0x03, 92}, + {2, 0x02, 195}, + {9, 0x02, 195}, + {23, 0x02, 195}, + {40, 0x03, 195}, + {2, 0x02, 208}, + {9, 0x02, 208}, + {23, 0x02, 208}, + {40, 0x03, 208}, + {1, 0x02, 128}, + {22, 0x03, 128}, + {1, 0x02, 130}, + {22, 0x03, 130}, + }, + /* 98 */ + { + {3, 0x02, 92}, + {6, 0x02, 92}, + {10, 0x02, 92}, + {15, 0x02, 92}, + {24, 0x02, 92}, + {31, 0x02, 92}, + {41, 0x02, 92}, + {56, 0x03, 92}, + {3, 0x02, 195}, + {6, 0x02, 195}, + {10, 0x02, 195}, + {15, 0x02, 195}, + {24, 0x02, 195}, + {31, 0x02, 195}, + {41, 0x02, 195}, + {56, 0x03, 195}, + }, + /* 99 */ + { + {3, 0x02, 208}, + {6, 0x02, 208}, + {10, 0x02, 208}, + {15, 0x02, 208}, + {24, 0x02, 208}, + {31, 0x02, 208}, + {41, 0x02, 208}, + {56, 0x03, 208}, + {2, 0x02, 128}, + {9, 0x02, 128}, + {23, 0x02, 128}, + {40, 0x03, 128}, + {2, 0x02, 130}, + {9, 0x02, 130}, + {23, 0x02, 130}, + {40, 0x03, 130}, + }, + /* 100 */ + { + {3, 0x02, 128}, + {6, 0x02, 128}, + {10, 0x02, 128}, + {15, 0x02, 128}, + {24, 0x02, 128}, + {31, 0x02, 128}, + {41, 0x02, 128}, + {56, 0x03, 128}, + {3, 0x02, 130}, + {6, 0x02, 130}, + {10, 0x02, 130}, + {15, 0x02, 130}, + {24, 0x02, 130}, + {31, 0x02, 130}, + {41, 0x02, 130}, + {56, 0x03, 130}, + }, + /* 101 */ + { + {1, 0x02, 131}, + {22, 0x03, 131}, + {1, 0x02, 162}, + {22, 0x03, 162}, + {1, 0x02, 184}, + {22, 0x03, 184}, + {1, 0x02, 194}, + {22, 0x03, 194}, + {1, 0x02, 224}, + {22, 0x03, 224}, + {1, 0x02, 226}, + {22, 0x03, 226}, + {0, 0x03, 153}, + {0, 0x03, 161}, + {0, 0x03, 167}, + {0, 0x03, 172}, + }, + /* 102 */ + { + {2, 0x02, 131}, + {9, 0x02, 131}, + {23, 0x02, 131}, + {40, 0x03, 131}, + {2, 0x02, 162}, + {9, 0x02, 162}, + {23, 0x02, 162}, + {40, 0x03, 162}, + {2, 0x02, 184}, + {9, 0x02, 184}, + {23, 0x02, 184}, + {40, 0x03, 184}, + {2, 0x02, 194}, + {9, 0x02, 194}, + {23, 0x02, 194}, + {40, 0x03, 194}, + }, + /* 103 */ + { + {3, 0x02, 131}, + {6, 0x02, 131}, + {10, 0x02, 131}, + {15, 0x02, 131}, + {24, 0x02, 131}, + {31, 0x02, 131}, + {41, 0x02, 131}, + {56, 0x03, 131}, + {3, 0x02, 162}, + {6, 0x02, 162}, + {10, 0x02, 162}, + {15, 0x02, 162}, + {24, 0x02, 162}, + {31, 0x02, 162}, + {41, 0x02, 162}, + {56, 0x03, 162}, + }, + /* 104 */ + { + {3, 0x02, 184}, + {6, 0x02, 184}, + {10, 0x02, 184}, + {15, 0x02, 184}, + {24, 0x02, 184}, + {31, 0x02, 184}, + {41, 0x02, 184}, + {56, 0x03, 184}, + {3, 0x02, 194}, + {6, 0x02, 194}, + {10, 0x02, 194}, + {15, 0x02, 194}, + {24, 0x02, 194}, + {31, 0x02, 194}, + {41, 0x02, 194}, + {56, 0x03, 194}, + }, + /* 105 */ + { + {2, 0x02, 224}, + {9, 0x02, 224}, + {23, 0x02, 224}, + {40, 0x03, 224}, + {2, 0x02, 226}, + {9, 0x02, 226}, + {23, 0x02, 226}, + {40, 0x03, 226}, + {1, 0x02, 153}, + {22, 0x03, 153}, + {1, 0x02, 161}, + {22, 0x03, 161}, + {1, 0x02, 167}, + {22, 0x03, 167}, + {1, 0x02, 172}, + {22, 0x03, 172}, + }, + /* 106 */ + { + {3, 0x02, 224}, + {6, 0x02, 224}, + {10, 0x02, 224}, + {15, 0x02, 224}, + {24, 0x02, 224}, + {31, 0x02, 224}, + {41, 0x02, 224}, + {56, 0x03, 224}, + {3, 0x02, 226}, + {6, 0x02, 226}, + {10, 0x02, 226}, + {15, 0x02, 226}, + {24, 0x02, 226}, + {31, 0x02, 226}, + {41, 0x02, 226}, + {56, 0x03, 226}, + }, + /* 107 */ + { + {2, 0x02, 153}, + {9, 0x02, 153}, + {23, 0x02, 153}, + {40, 0x03, 153}, + {2, 0x02, 161}, + {9, 0x02, 161}, + {23, 0x02, 161}, + {40, 0x03, 161}, + {2, 0x02, 167}, + {9, 0x02, 167}, + {23, 0x02, 167}, + {40, 0x03, 167}, + {2, 0x02, 172}, + {9, 0x02, 172}, + {23, 0x02, 172}, + {40, 0x03, 172}, + }, + /* 108 */ + { + {3, 0x02, 153}, + {6, 0x02, 153}, + {10, 0x02, 153}, + {15, 0x02, 153}, + {24, 0x02, 153}, + {31, 0x02, 153}, + {41, 0x02, 153}, + {56, 0x03, 153}, + {3, 0x02, 161}, + {6, 0x02, 161}, + {10, 0x02, 161}, + {15, 0x02, 161}, + {24, 0x02, 161}, + {31, 0x02, 161}, + {41, 0x02, 161}, + {56, 0x03, 161}, + }, + /* 109 */ + { + {3, 0x02, 167}, + {6, 0x02, 167}, + {10, 0x02, 167}, + {15, 0x02, 167}, + {24, 0x02, 167}, + {31, 0x02, 167}, + {41, 0x02, 167}, + {56, 0x03, 167}, + {3, 0x02, 172}, + {6, 0x02, 172}, + {10, 0x02, 172}, + {15, 0x02, 172}, + {24, 0x02, 172}, + {31, 0x02, 172}, + {41, 0x02, 172}, + {56, 0x03, 172}, + }, + /* 110 */ + { + {114, 0x00, 0}, + {115, 0x00, 0}, + {117, 0x00, 0}, + {118, 0x00, 0}, + {121, 0x00, 0}, + {123, 0x00, 0}, + {127, 0x00, 0}, + {130, 0x00, 0}, + {136, 0x00, 0}, + {139, 0x00, 0}, + {143, 0x00, 0}, + {146, 0x00, 0}, + {155, 0x00, 0}, + {162, 0x00, 0}, + {170, 0x00, 0}, + {180, 0x00, 0}, + }, + /* 111 */ + { + {0, 0x03, 176}, + {0, 0x03, 177}, + {0, 0x03, 179}, + {0, 0x03, 209}, + {0, 0x03, 216}, + {0, 0x03, 217}, + {0, 0x03, 227}, + {0, 0x03, 229}, + {0, 0x03, 230}, + {122, 0x00, 0}, + {124, 0x00, 0}, + {125, 0x00, 0}, + {128, 0x00, 0}, + {129, 0x00, 0}, + {131, 0x00, 0}, + {132, 0x00, 0}, + }, + /* 112 */ + { + {1, 0x02, 176}, + {22, 0x03, 176}, + {1, 0x02, 177}, + {22, 0x03, 177}, + {1, 0x02, 179}, + {22, 0x03, 179}, + {1, 0x02, 209}, + {22, 0x03, 209}, + {1, 0x02, 216}, + {22, 0x03, 216}, + {1, 0x02, 217}, + {22, 0x03, 217}, + {1, 0x02, 227}, + {22, 0x03, 227}, + {1, 0x02, 229}, + {22, 0x03, 229}, + }, + /* 113 */ + { + {2, 0x02, 176}, + {9, 0x02, 176}, + {23, 0x02, 176}, + {40, 0x03, 176}, + {2, 0x02, 177}, + {9, 0x02, 177}, + {23, 0x02, 177}, + {40, 0x03, 177}, + {2, 0x02, 179}, + {9, 0x02, 179}, + {23, 0x02, 179}, + {40, 0x03, 179}, + {2, 0x02, 209}, + {9, 0x02, 209}, + {23, 0x02, 209}, + {40, 0x03, 209}, + }, + /* 114 */ + { + {3, 0x02, 176}, + {6, 0x02, 176}, + {10, 0x02, 176}, + {15, 0x02, 176}, + {24, 0x02, 176}, + {31, 0x02, 176}, + {41, 0x02, 176}, + {56, 0x03, 176}, + {3, 0x02, 177}, + {6, 0x02, 177}, + {10, 0x02, 177}, + {15, 0x02, 177}, + {24, 0x02, 177}, + {31, 0x02, 177}, + {41, 0x02, 177}, + {56, 0x03, 177}, + }, + /* 115 */ + { + {3, 0x02, 179}, + {6, 0x02, 179}, + {10, 0x02, 179}, + {15, 0x02, 179}, + {24, 0x02, 179}, + {31, 0x02, 179}, + {41, 0x02, 179}, + {56, 0x03, 179}, + {3, 0x02, 209}, + {6, 0x02, 209}, + {10, 0x02, 209}, + {15, 0x02, 209}, + {24, 0x02, 209}, + {31, 0x02, 209}, + {41, 0x02, 209}, + {56, 0x03, 209}, + }, + /* 116 */ + { + {2, 0x02, 216}, + {9, 0x02, 216}, + {23, 0x02, 216}, + {40, 0x03, 216}, + {2, 0x02, 217}, + {9, 0x02, 217}, + {23, 0x02, 217}, + {40, 0x03, 217}, + {2, 0x02, 227}, + {9, 0x02, 227}, + {23, 0x02, 227}, + {40, 0x03, 227}, + {2, 0x02, 229}, + {9, 0x02, 229}, + {23, 0x02, 229}, + {40, 0x03, 229}, + }, + /* 117 */ + { + {3, 0x02, 216}, + {6, 0x02, 216}, + {10, 0x02, 216}, + {15, 0x02, 216}, + {24, 0x02, 216}, + {31, 0x02, 216}, + {41, 0x02, 216}, + {56, 0x03, 216}, + {3, 0x02, 217}, + {6, 0x02, 217}, + {10, 0x02, 217}, + {15, 0x02, 217}, + {24, 0x02, 217}, + {31, 0x02, 217}, + {41, 0x02, 217}, + {56, 0x03, 217}, + }, + /* 118 */ + { + {3, 0x02, 227}, + {6, 0x02, 227}, + {10, 0x02, 227}, + {15, 0x02, 227}, + {24, 0x02, 227}, + {31, 0x02, 227}, + {41, 0x02, 227}, + {56, 0x03, 227}, + {3, 0x02, 229}, + {6, 0x02, 229}, + {10, 0x02, 229}, + {15, 0x02, 229}, + {24, 0x02, 229}, + {31, 0x02, 229}, + {41, 0x02, 229}, + {56, 0x03, 229}, + }, + /* 119 */ + { + {1, 0x02, 230}, + {22, 0x03, 230}, + {0, 0x03, 129}, + {0, 0x03, 132}, + {0, 0x03, 133}, + {0, 0x03, 134}, + {0, 0x03, 136}, + {0, 0x03, 146}, + {0, 0x03, 154}, + {0, 0x03, 156}, + {0, 0x03, 160}, + {0, 0x03, 163}, + {0, 0x03, 164}, + {0, 0x03, 169}, + {0, 0x03, 170}, + {0, 0x03, 173}, + }, + /* 120 */ + { + {2, 0x02, 230}, + {9, 0x02, 230}, + {23, 0x02, 230}, + {40, 0x03, 230}, + {1, 0x02, 129}, + {22, 0x03, 129}, + {1, 0x02, 132}, + {22, 0x03, 132}, + {1, 0x02, 133}, + {22, 0x03, 133}, + {1, 0x02, 134}, + {22, 0x03, 134}, + {1, 0x02, 136}, + {22, 0x03, 136}, + {1, 0x02, 146}, + {22, 0x03, 146}, + }, + /* 121 */ + { + {3, 0x02, 230}, + {6, 0x02, 230}, + {10, 0x02, 230}, + {15, 0x02, 230}, + {24, 0x02, 230}, + {31, 0x02, 230}, + {41, 0x02, 230}, + {56, 0x03, 230}, + {2, 0x02, 129}, + {9, 0x02, 129}, + {23, 0x02, 129}, + {40, 0x03, 129}, + {2, 0x02, 132}, + {9, 0x02, 132}, + {23, 0x02, 132}, + {40, 0x03, 132}, + }, + /* 122 */ + { + {3, 0x02, 129}, + {6, 0x02, 129}, + {10, 0x02, 129}, + {15, 0x02, 129}, + {24, 0x02, 129}, + {31, 0x02, 129}, + {41, 0x02, 129}, + {56, 0x03, 129}, + {3, 0x02, 132}, + {6, 0x02, 132}, + {10, 0x02, 132}, + {15, 0x02, 132}, + {24, 0x02, 132}, + {31, 0x02, 132}, + {41, 0x02, 132}, + {56, 0x03, 132}, + }, + /* 123 */ + { + {2, 0x02, 133}, + {9, 0x02, 133}, + {23, 0x02, 133}, + {40, 0x03, 133}, + {2, 0x02, 134}, + {9, 0x02, 134}, + {23, 0x02, 134}, + {40, 0x03, 134}, + {2, 0x02, 136}, + {9, 0x02, 136}, + {23, 0x02, 136}, + {40, 0x03, 136}, + {2, 0x02, 146}, + {9, 0x02, 146}, + {23, 0x02, 146}, + {40, 0x03, 146}, + }, + /* 124 */ + { + {3, 0x02, 133}, + {6, 0x02, 133}, + {10, 0x02, 133}, + {15, 0x02, 133}, + {24, 0x02, 133}, + {31, 0x02, 133}, + {41, 0x02, 133}, + {56, 0x03, 133}, + {3, 0x02, 134}, + {6, 0x02, 134}, + {10, 0x02, 134}, + {15, 0x02, 134}, + {24, 0x02, 134}, + {31, 0x02, 134}, + {41, 0x02, 134}, + {56, 0x03, 134}, + }, + /* 125 */ + { + {3, 0x02, 136}, + {6, 0x02, 136}, + {10, 0x02, 136}, + {15, 0x02, 136}, + {24, 0x02, 136}, + {31, 0x02, 136}, + {41, 0x02, 136}, + {56, 0x03, 136}, + {3, 0x02, 146}, + {6, 0x02, 146}, + {10, 0x02, 146}, + {15, 0x02, 146}, + {24, 0x02, 146}, + {31, 0x02, 146}, + {41, 0x02, 146}, + {56, 0x03, 146}, + }, + /* 126 */ + { + {1, 0x02, 154}, + {22, 0x03, 154}, + {1, 0x02, 156}, + {22, 0x03, 156}, + {1, 0x02, 160}, + {22, 0x03, 160}, + {1, 0x02, 163}, + {22, 0x03, 163}, + {1, 0x02, 164}, + {22, 0x03, 164}, + {1, 0x02, 169}, + {22, 0x03, 169}, + {1, 0x02, 170}, + {22, 0x03, 170}, + {1, 0x02, 173}, + {22, 0x03, 173}, + }, + /* 127 */ + { + {2, 0x02, 154}, + {9, 0x02, 154}, + {23, 0x02, 154}, + {40, 0x03, 154}, + {2, 0x02, 156}, + {9, 0x02, 156}, + {23, 0x02, 156}, + {40, 0x03, 156}, + {2, 0x02, 160}, + {9, 0x02, 160}, + {23, 0x02, 160}, + {40, 0x03, 160}, + {2, 0x02, 163}, + {9, 0x02, 163}, + {23, 0x02, 163}, + {40, 0x03, 163}, + }, + /* 128 */ + { + {3, 0x02, 154}, + {6, 0x02, 154}, + {10, 0x02, 154}, + {15, 0x02, 154}, + {24, 0x02, 154}, + {31, 0x02, 154}, + {41, 0x02, 154}, + {56, 0x03, 154}, + {3, 0x02, 156}, + {6, 0x02, 156}, + {10, 0x02, 156}, + {15, 0x02, 156}, + {24, 0x02, 156}, + {31, 0x02, 156}, + {41, 0x02, 156}, + {56, 0x03, 156}, + }, + /* 129 */ + { + {3, 0x02, 160}, + {6, 0x02, 160}, + {10, 0x02, 160}, + {15, 0x02, 160}, + {24, 0x02, 160}, + {31, 0x02, 160}, + {41, 0x02, 160}, + {56, 0x03, 160}, + {3, 0x02, 163}, + {6, 0x02, 163}, + {10, 0x02, 163}, + {15, 0x02, 163}, + {24, 0x02, 163}, + {31, 0x02, 163}, + {41, 0x02, 163}, + {56, 0x03, 163}, + }, + /* 130 */ + { + {2, 0x02, 164}, + {9, 0x02, 164}, + {23, 0x02, 164}, + {40, 0x03, 164}, + {2, 0x02, 169}, + {9, 0x02, 169}, + {23, 0x02, 169}, + {40, 0x03, 169}, + {2, 0x02, 170}, + {9, 0x02, 170}, + {23, 0x02, 170}, + {40, 0x03, 170}, + {2, 0x02, 173}, + {9, 0x02, 173}, + {23, 0x02, 173}, + {40, 0x03, 173}, + }, + /* 131 */ + { + {3, 0x02, 164}, + {6, 0x02, 164}, + {10, 0x02, 164}, + {15, 0x02, 164}, + {24, 0x02, 164}, + {31, 0x02, 164}, + {41, 0x02, 164}, + {56, 0x03, 164}, + {3, 0x02, 169}, + {6, 0x02, 169}, + {10, 0x02, 169}, + {15, 0x02, 169}, + {24, 0x02, 169}, + {31, 0x02, 169}, + {41, 0x02, 169}, + {56, 0x03, 169}, + }, + /* 132 */ + { + {3, 0x02, 170}, + {6, 0x02, 170}, + {10, 0x02, 170}, + {15, 0x02, 170}, + {24, 0x02, 170}, + {31, 0x02, 170}, + {41, 0x02, 170}, + {56, 0x03, 170}, + {3, 0x02, 173}, + {6, 0x02, 173}, + {10, 0x02, 173}, + {15, 0x02, 173}, + {24, 0x02, 173}, + {31, 0x02, 173}, + {41, 0x02, 173}, + {56, 0x03, 173}, + }, + /* 133 */ + { + {137, 0x00, 0}, + {138, 0x00, 0}, + {140, 0x00, 0}, + {141, 0x00, 0}, + {144, 0x00, 0}, + {145, 0x00, 0}, + {147, 0x00, 0}, + {150, 0x00, 0}, + {156, 0x00, 0}, + {159, 0x00, 0}, + {163, 0x00, 0}, + {166, 0x00, 0}, + {171, 0x00, 0}, + {174, 0x00, 0}, + {181, 0x00, 0}, + {190, 0x00, 0}, + }, + /* 134 */ + { + {0, 0x03, 178}, + {0, 0x03, 181}, + {0, 0x03, 185}, + {0, 0x03, 186}, + {0, 0x03, 187}, + {0, 0x03, 189}, + {0, 0x03, 190}, + {0, 0x03, 196}, + {0, 0x03, 198}, + {0, 0x03, 228}, + {0, 0x03, 232}, + {0, 0x03, 233}, + {148, 0x00, 0}, + {149, 0x00, 0}, + {151, 0x00, 0}, + {152, 0x00, 0}, + }, + /* 135 */ + { + {1, 0x02, 178}, + {22, 0x03, 178}, + {1, 0x02, 181}, + {22, 0x03, 181}, + {1, 0x02, 185}, + {22, 0x03, 185}, + {1, 0x02, 186}, + {22, 0x03, 186}, + {1, 0x02, 187}, + {22, 0x03, 187}, + {1, 0x02, 189}, + {22, 0x03, 189}, + {1, 0x02, 190}, + {22, 0x03, 190}, + {1, 0x02, 196}, + {22, 0x03, 196}, + }, + /* 136 */ + { + {2, 0x02, 178}, + {9, 0x02, 178}, + {23, 0x02, 178}, + {40, 0x03, 178}, + {2, 0x02, 181}, + {9, 0x02, 181}, + {23, 0x02, 181}, + {40, 0x03, 181}, + {2, 0x02, 185}, + {9, 0x02, 185}, + {23, 0x02, 185}, + {40, 0x03, 185}, + {2, 0x02, 186}, + {9, 0x02, 186}, + {23, 0x02, 186}, + {40, 0x03, 186}, + }, + /* 137 */ + { + {3, 0x02, 178}, + {6, 0x02, 178}, + {10, 0x02, 178}, + {15, 0x02, 178}, + {24, 0x02, 178}, + {31, 0x02, 178}, + {41, 0x02, 178}, + {56, 0x03, 178}, + {3, 0x02, 181}, + {6, 0x02, 181}, + {10, 0x02, 181}, + {15, 0x02, 181}, + {24, 0x02, 181}, + {31, 0x02, 181}, + {41, 0x02, 181}, + {56, 0x03, 181}, + }, + /* 138 */ + { + {3, 0x02, 185}, + {6, 0x02, 185}, + {10, 0x02, 185}, + {15, 0x02, 185}, + {24, 0x02, 185}, + {31, 0x02, 185}, + {41, 0x02, 185}, + {56, 0x03, 185}, + {3, 0x02, 186}, + {6, 0x02, 186}, + {10, 0x02, 186}, + {15, 0x02, 186}, + {24, 0x02, 186}, + {31, 0x02, 186}, + {41, 0x02, 186}, + {56, 0x03, 186}, + }, + /* 139 */ + { + {2, 0x02, 187}, + {9, 0x02, 187}, + {23, 0x02, 187}, + {40, 0x03, 187}, + {2, 0x02, 189}, + {9, 0x02, 189}, + {23, 0x02, 189}, + {40, 0x03, 189}, + {2, 0x02, 190}, + {9, 0x02, 190}, + {23, 0x02, 190}, + {40, 0x03, 190}, + {2, 0x02, 196}, + {9, 0x02, 196}, + {23, 0x02, 196}, + {40, 0x03, 196}, + }, + /* 140 */ + { + {3, 0x02, 187}, + {6, 0x02, 187}, + {10, 0x02, 187}, + {15, 0x02, 187}, + {24, 0x02, 187}, + {31, 0x02, 187}, + {41, 0x02, 187}, + {56, 0x03, 187}, + {3, 0x02, 189}, + {6, 0x02, 189}, + {10, 0x02, 189}, + {15, 0x02, 189}, + {24, 0x02, 189}, + {31, 0x02, 189}, + {41, 0x02, 189}, + {56, 0x03, 189}, + }, + /* 141 */ + { + {3, 0x02, 190}, + {6, 0x02, 190}, + {10, 0x02, 190}, + {15, 0x02, 190}, + {24, 0x02, 190}, + {31, 0x02, 190}, + {41, 0x02, 190}, + {56, 0x03, 190}, + {3, 0x02, 196}, + {6, 0x02, 196}, + {10, 0x02, 196}, + {15, 0x02, 196}, + {24, 0x02, 196}, + {31, 0x02, 196}, + {41, 0x02, 196}, + {56, 0x03, 196}, + }, + /* 142 */ + { + {1, 0x02, 198}, + {22, 0x03, 198}, + {1, 0x02, 228}, + {22, 0x03, 228}, + {1, 0x02, 232}, + {22, 0x03, 232}, + {1, 0x02, 233}, + {22, 0x03, 233}, + {0, 0x03, 1}, + {0, 0x03, 135}, + {0, 0x03, 137}, + {0, 0x03, 138}, + {0, 0x03, 139}, + {0, 0x03, 140}, + {0, 0x03, 141}, + {0, 0x03, 143}, + }, + /* 143 */ + { + {2, 0x02, 198}, + {9, 0x02, 198}, + {23, 0x02, 198}, + {40, 0x03, 198}, + {2, 0x02, 228}, + {9, 0x02, 228}, + {23, 0x02, 228}, + {40, 0x03, 228}, + {2, 0x02, 232}, + {9, 0x02, 232}, + {23, 0x02, 232}, + {40, 0x03, 232}, + {2, 0x02, 233}, + {9, 0x02, 233}, + {23, 0x02, 233}, + {40, 0x03, 233}, + }, + /* 144 */ + { + {3, 0x02, 198}, + {6, 0x02, 198}, + {10, 0x02, 198}, + {15, 0x02, 198}, + {24, 0x02, 198}, + {31, 0x02, 198}, + {41, 0x02, 198}, + {56, 0x03, 198}, + {3, 0x02, 228}, + {6, 0x02, 228}, + {10, 0x02, 228}, + {15, 0x02, 228}, + {24, 0x02, 228}, + {31, 0x02, 228}, + {41, 0x02, 228}, + {56, 0x03, 228}, + }, + /* 145 */ + { + {3, 0x02, 232}, + {6, 0x02, 232}, + {10, 0x02, 232}, + {15, 0x02, 232}, + {24, 0x02, 232}, + {31, 0x02, 232}, + {41, 0x02, 232}, + {56, 0x03, 232}, + {3, 0x02, 233}, + {6, 0x02, 233}, + {10, 0x02, 233}, + {15, 0x02, 233}, + {24, 0x02, 233}, + {31, 0x02, 233}, + {41, 0x02, 233}, + {56, 0x03, 233}, + }, + /* 146 */ + { + {1, 0x02, 1}, + {22, 0x03, 1}, + {1, 0x02, 135}, + {22, 0x03, 135}, + {1, 0x02, 137}, + {22, 0x03, 137}, + {1, 0x02, 138}, + {22, 0x03, 138}, + {1, 0x02, 139}, + {22, 0x03, 139}, + {1, 0x02, 140}, + {22, 0x03, 140}, + {1, 0x02, 141}, + {22, 0x03, 141}, + {1, 0x02, 143}, + {22, 0x03, 143}, + }, + /* 147 */ + { + {2, 0x02, 1}, + {9, 0x02, 1}, + {23, 0x02, 1}, + {40, 0x03, 1}, + {2, 0x02, 135}, + {9, 0x02, 135}, + {23, 0x02, 135}, + {40, 0x03, 135}, + {2, 0x02, 137}, + {9, 0x02, 137}, + {23, 0x02, 137}, + {40, 0x03, 137}, + {2, 0x02, 138}, + {9, 0x02, 138}, + {23, 0x02, 138}, + {40, 0x03, 138}, + }, + /* 148 */ + { + {3, 0x02, 1}, + {6, 0x02, 1}, + {10, 0x02, 1}, + {15, 0x02, 1}, + {24, 0x02, 1}, + {31, 0x02, 1}, + {41, 0x02, 1}, + {56, 0x03, 1}, + {3, 0x02, 135}, + {6, 0x02, 135}, + {10, 0x02, 135}, + {15, 0x02, 135}, + {24, 0x02, 135}, + {31, 0x02, 135}, + {41, 0x02, 135}, + {56, 0x03, 135}, + }, + /* 149 */ + { + {3, 0x02, 137}, + {6, 0x02, 137}, + {10, 0x02, 137}, + {15, 0x02, 137}, + {24, 0x02, 137}, + {31, 0x02, 137}, + {41, 0x02, 137}, + {56, 0x03, 137}, + {3, 0x02, 138}, + {6, 0x02, 138}, + {10, 0x02, 138}, + {15, 0x02, 138}, + {24, 0x02, 138}, + {31, 0x02, 138}, + {41, 0x02, 138}, + {56, 0x03, 138}, + }, + /* 150 */ + { + {2, 0x02, 139}, + {9, 0x02, 139}, + {23, 0x02, 139}, + {40, 0x03, 139}, + {2, 0x02, 140}, + {9, 0x02, 140}, + {23, 0x02, 140}, + {40, 0x03, 140}, + {2, 0x02, 141}, + {9, 0x02, 141}, + {23, 0x02, 141}, + {40, 0x03, 141}, + {2, 0x02, 143}, + {9, 0x02, 143}, + {23, 0x02, 143}, + {40, 0x03, 143}, + }, + /* 151 */ + { + {3, 0x02, 139}, + {6, 0x02, 139}, + {10, 0x02, 139}, + {15, 0x02, 139}, + {24, 0x02, 139}, + {31, 0x02, 139}, + {41, 0x02, 139}, + {56, 0x03, 139}, + {3, 0x02, 140}, + {6, 0x02, 140}, + {10, 0x02, 140}, + {15, 0x02, 140}, + {24, 0x02, 140}, + {31, 0x02, 140}, + {41, 0x02, 140}, + {56, 0x03, 140}, + }, + /* 152 */ + { + {3, 0x02, 141}, + {6, 0x02, 141}, + {10, 0x02, 141}, + {15, 0x02, 141}, + {24, 0x02, 141}, + {31, 0x02, 141}, + {41, 0x02, 141}, + {56, 0x03, 141}, + {3, 0x02, 143}, + {6, 0x02, 143}, + {10, 0x02, 143}, + {15, 0x02, 143}, + {24, 0x02, 143}, + {31, 0x02, 143}, + {41, 0x02, 143}, + {56, 0x03, 143}, + }, + /* 153 */ + { + {157, 0x00, 0}, + {158, 0x00, 0}, + {160, 0x00, 0}, + {161, 0x00, 0}, + {164, 0x00, 0}, + {165, 0x00, 0}, + {167, 0x00, 0}, + {168, 0x00, 0}, + {172, 0x00, 0}, + {173, 0x00, 0}, + {175, 0x00, 0}, + {177, 0x00, 0}, + {182, 0x00, 0}, + {185, 0x00, 0}, + {191, 0x00, 0}, + {207, 0x00, 0}, + }, + /* 154 */ + { + {0, 0x03, 147}, + {0, 0x03, 149}, + {0, 0x03, 150}, + {0, 0x03, 151}, + {0, 0x03, 152}, + {0, 0x03, 155}, + {0, 0x03, 157}, + {0, 0x03, 158}, + {0, 0x03, 165}, + {0, 0x03, 166}, + {0, 0x03, 168}, + {0, 0x03, 174}, + {0, 0x03, 175}, + {0, 0x03, 180}, + {0, 0x03, 182}, + {0, 0x03, 183}, + }, + /* 155 */ + { + {1, 0x02, 147}, + {22, 0x03, 147}, + {1, 0x02, 149}, + {22, 0x03, 149}, + {1, 0x02, 150}, + {22, 0x03, 150}, + {1, 0x02, 151}, + {22, 0x03, 151}, + {1, 0x02, 152}, + {22, 0x03, 152}, + {1, 0x02, 155}, + {22, 0x03, 155}, + {1, 0x02, 157}, + {22, 0x03, 157}, + {1, 0x02, 158}, + {22, 0x03, 158}, + }, + /* 156 */ + { + {2, 0x02, 147}, + {9, 0x02, 147}, + {23, 0x02, 147}, + {40, 0x03, 147}, + {2, 0x02, 149}, + {9, 0x02, 149}, + {23, 0x02, 149}, + {40, 0x03, 149}, + {2, 0x02, 150}, + {9, 0x02, 150}, + {23, 0x02, 150}, + {40, 0x03, 150}, + {2, 0x02, 151}, + {9, 0x02, 151}, + {23, 0x02, 151}, + {40, 0x03, 151}, + }, + /* 157 */ + { + {3, 0x02, 147}, + {6, 0x02, 147}, + {10, 0x02, 147}, + {15, 0x02, 147}, + {24, 0x02, 147}, + {31, 0x02, 147}, + {41, 0x02, 147}, + {56, 0x03, 147}, + {3, 0x02, 149}, + {6, 0x02, 149}, + {10, 0x02, 149}, + {15, 0x02, 149}, + {24, 0x02, 149}, + {31, 0x02, 149}, + {41, 0x02, 149}, + {56, 0x03, 149}, + }, + /* 158 */ + { + {3, 0x02, 150}, + {6, 0x02, 150}, + {10, 0x02, 150}, + {15, 0x02, 150}, + {24, 0x02, 150}, + {31, 0x02, 150}, + {41, 0x02, 150}, + {56, 0x03, 150}, + {3, 0x02, 151}, + {6, 0x02, 151}, + {10, 0x02, 151}, + {15, 0x02, 151}, + {24, 0x02, 151}, + {31, 0x02, 151}, + {41, 0x02, 151}, + {56, 0x03, 151}, + }, + /* 159 */ + { + {2, 0x02, 152}, + {9, 0x02, 152}, + {23, 0x02, 152}, + {40, 0x03, 152}, + {2, 0x02, 155}, + {9, 0x02, 155}, + {23, 0x02, 155}, + {40, 0x03, 155}, + {2, 0x02, 157}, + {9, 0x02, 157}, + {23, 0x02, 157}, + {40, 0x03, 157}, + {2, 0x02, 158}, + {9, 0x02, 158}, + {23, 0x02, 158}, + {40, 0x03, 158}, + }, + /* 160 */ + { + {3, 0x02, 152}, + {6, 0x02, 152}, + {10, 0x02, 152}, + {15, 0x02, 152}, + {24, 0x02, 152}, + {31, 0x02, 152}, + {41, 0x02, 152}, + {56, 0x03, 152}, + {3, 0x02, 155}, + {6, 0x02, 155}, + {10, 0x02, 155}, + {15, 0x02, 155}, + {24, 0x02, 155}, + {31, 0x02, 155}, + {41, 0x02, 155}, + {56, 0x03, 155}, + }, + /* 161 */ + { + {3, 0x02, 157}, + {6, 0x02, 157}, + {10, 0x02, 157}, + {15, 0x02, 157}, + {24, 0x02, 157}, + {31, 0x02, 157}, + {41, 0x02, 157}, + {56, 0x03, 157}, + {3, 0x02, 158}, + {6, 0x02, 158}, + {10, 0x02, 158}, + {15, 0x02, 158}, + {24, 0x02, 158}, + {31, 0x02, 158}, + {41, 0x02, 158}, + {56, 0x03, 158}, + }, + /* 162 */ + { + {1, 0x02, 165}, + {22, 0x03, 165}, + {1, 0x02, 166}, + {22, 0x03, 166}, + {1, 0x02, 168}, + {22, 0x03, 168}, + {1, 0x02, 174}, + {22, 0x03, 174}, + {1, 0x02, 175}, + {22, 0x03, 175}, + {1, 0x02, 180}, + {22, 0x03, 180}, + {1, 0x02, 182}, + {22, 0x03, 182}, + {1, 0x02, 183}, + {22, 0x03, 183}, + }, + /* 163 */ + { + {2, 0x02, 165}, + {9, 0x02, 165}, + {23, 0x02, 165}, + {40, 0x03, 165}, + {2, 0x02, 166}, + {9, 0x02, 166}, + {23, 0x02, 166}, + {40, 0x03, 166}, + {2, 0x02, 168}, + {9, 0x02, 168}, + {23, 0x02, 168}, + {40, 0x03, 168}, + {2, 0x02, 174}, + {9, 0x02, 174}, + {23, 0x02, 174}, + {40, 0x03, 174}, + }, + /* 164 */ + { + {3, 0x02, 165}, + {6, 0x02, 165}, + {10, 0x02, 165}, + {15, 0x02, 165}, + {24, 0x02, 165}, + {31, 0x02, 165}, + {41, 0x02, 165}, + {56, 0x03, 165}, + {3, 0x02, 166}, + {6, 0x02, 166}, + {10, 0x02, 166}, + {15, 0x02, 166}, + {24, 0x02, 166}, + {31, 0x02, 166}, + {41, 0x02, 166}, + {56, 0x03, 166}, + }, + /* 165 */ + { + {3, 0x02, 168}, + {6, 0x02, 168}, + {10, 0x02, 168}, + {15, 0x02, 168}, + {24, 0x02, 168}, + {31, 0x02, 168}, + {41, 0x02, 168}, + {56, 0x03, 168}, + {3, 0x02, 174}, + {6, 0x02, 174}, + {10, 0x02, 174}, + {15, 0x02, 174}, + {24, 0x02, 174}, + {31, 0x02, 174}, + {41, 0x02, 174}, + {56, 0x03, 174}, + }, + /* 166 */ + { + {2, 0x02, 175}, + {9, 0x02, 175}, + {23, 0x02, 175}, + {40, 0x03, 175}, + {2, 0x02, 180}, + {9, 0x02, 180}, + {23, 0x02, 180}, + {40, 0x03, 180}, + {2, 0x02, 182}, + {9, 0x02, 182}, + {23, 0x02, 182}, + {40, 0x03, 182}, + {2, 0x02, 183}, + {9, 0x02, 183}, + {23, 0x02, 183}, + {40, 0x03, 183}, + }, + /* 167 */ + { + {3, 0x02, 175}, + {6, 0x02, 175}, + {10, 0x02, 175}, + {15, 0x02, 175}, + {24, 0x02, 175}, + {31, 0x02, 175}, + {41, 0x02, 175}, + {56, 0x03, 175}, + {3, 0x02, 180}, + {6, 0x02, 180}, + {10, 0x02, 180}, + {15, 0x02, 180}, + {24, 0x02, 180}, + {31, 0x02, 180}, + {41, 0x02, 180}, + {56, 0x03, 180}, + }, + /* 168 */ + { + {3, 0x02, 182}, + {6, 0x02, 182}, + {10, 0x02, 182}, + {15, 0x02, 182}, + {24, 0x02, 182}, + {31, 0x02, 182}, + {41, 0x02, 182}, + {56, 0x03, 182}, + {3, 0x02, 183}, + {6, 0x02, 183}, + {10, 0x02, 183}, + {15, 0x02, 183}, + {24, 0x02, 183}, + {31, 0x02, 183}, + {41, 0x02, 183}, + {56, 0x03, 183}, + }, + /* 169 */ + { + {0, 0x03, 188}, + {0, 0x03, 191}, + {0, 0x03, 197}, + {0, 0x03, 231}, + {0, 0x03, 239}, + {176, 0x00, 0}, + {178, 0x00, 0}, + {179, 0x00, 0}, + {183, 0x00, 0}, + {184, 0x00, 0}, + {186, 0x00, 0}, + {187, 0x00, 0}, + {192, 0x00, 0}, + {199, 0x00, 0}, + {208, 0x00, 0}, + {223, 0x00, 0}, + }, + /* 170 */ + { + {1, 0x02, 188}, + {22, 0x03, 188}, + {1, 0x02, 191}, + {22, 0x03, 191}, + {1, 0x02, 197}, + {22, 0x03, 197}, + {1, 0x02, 231}, + {22, 0x03, 231}, + {1, 0x02, 239}, + {22, 0x03, 239}, + {0, 0x03, 9}, + {0, 0x03, 142}, + {0, 0x03, 144}, + {0, 0x03, 145}, + {0, 0x03, 148}, + {0, 0x03, 159}, + }, + /* 171 */ + { + {2, 0x02, 188}, + {9, 0x02, 188}, + {23, 0x02, 188}, + {40, 0x03, 188}, + {2, 0x02, 191}, + {9, 0x02, 191}, + {23, 0x02, 191}, + {40, 0x03, 191}, + {2, 0x02, 197}, + {9, 0x02, 197}, + {23, 0x02, 197}, + {40, 0x03, 197}, + {2, 0x02, 231}, + {9, 0x02, 231}, + {23, 0x02, 231}, + {40, 0x03, 231}, + }, + /* 172 */ + { + {3, 0x02, 188}, + {6, 0x02, 188}, + {10, 0x02, 188}, + {15, 0x02, 188}, + {24, 0x02, 188}, + {31, 0x02, 188}, + {41, 0x02, 188}, + {56, 0x03, 188}, + {3, 0x02, 191}, + {6, 0x02, 191}, + {10, 0x02, 191}, + {15, 0x02, 191}, + {24, 0x02, 191}, + {31, 0x02, 191}, + {41, 0x02, 191}, + {56, 0x03, 191}, + }, + /* 173 */ + { + {3, 0x02, 197}, + {6, 0x02, 197}, + {10, 0x02, 197}, + {15, 0x02, 197}, + {24, 0x02, 197}, + {31, 0x02, 197}, + {41, 0x02, 197}, + {56, 0x03, 197}, + {3, 0x02, 231}, + {6, 0x02, 231}, + {10, 0x02, 231}, + {15, 0x02, 231}, + {24, 0x02, 231}, + {31, 0x02, 231}, + {41, 0x02, 231}, + {56, 0x03, 231}, + }, + /* 174 */ + { + {2, 0x02, 239}, + {9, 0x02, 239}, + {23, 0x02, 239}, + {40, 0x03, 239}, + {1, 0x02, 9}, + {22, 0x03, 9}, + {1, 0x02, 142}, + {22, 0x03, 142}, + {1, 0x02, 144}, + {22, 0x03, 144}, + {1, 0x02, 145}, + {22, 0x03, 145}, + {1, 0x02, 148}, + {22, 0x03, 148}, + {1, 0x02, 159}, + {22, 0x03, 159}, + }, + /* 175 */ + { + {3, 0x02, 239}, + {6, 0x02, 239}, + {10, 0x02, 239}, + {15, 0x02, 239}, + {24, 0x02, 239}, + {31, 0x02, 239}, + {41, 0x02, 239}, + {56, 0x03, 239}, + {2, 0x02, 9}, + {9, 0x02, 9}, + {23, 0x02, 9}, + {40, 0x03, 9}, + {2, 0x02, 142}, + {9, 0x02, 142}, + {23, 0x02, 142}, + {40, 0x03, 142}, + }, + /* 176 */ + { + {3, 0x02, 9}, + {6, 0x02, 9}, + {10, 0x02, 9}, + {15, 0x02, 9}, + {24, 0x02, 9}, + {31, 0x02, 9}, + {41, 0x02, 9}, + {56, 0x03, 9}, + {3, 0x02, 142}, + {6, 0x02, 142}, + {10, 0x02, 142}, + {15, 0x02, 142}, + {24, 0x02, 142}, + {31, 0x02, 142}, + {41, 0x02, 142}, + {56, 0x03, 142}, + }, + /* 177 */ + { + {2, 0x02, 144}, + {9, 0x02, 144}, + {23, 0x02, 144}, + {40, 0x03, 144}, + {2, 0x02, 145}, + {9, 0x02, 145}, + {23, 0x02, 145}, + {40, 0x03, 145}, + {2, 0x02, 148}, + {9, 0x02, 148}, + {23, 0x02, 148}, + {40, 0x03, 148}, + {2, 0x02, 159}, + {9, 0x02, 159}, + {23, 0x02, 159}, + {40, 0x03, 159}, + }, + /* 178 */ + { + {3, 0x02, 144}, + {6, 0x02, 144}, + {10, 0x02, 144}, + {15, 0x02, 144}, + {24, 0x02, 144}, + {31, 0x02, 144}, + {41, 0x02, 144}, + {56, 0x03, 144}, + {3, 0x02, 145}, + {6, 0x02, 145}, + {10, 0x02, 145}, + {15, 0x02, 145}, + {24, 0x02, 145}, + {31, 0x02, 145}, + {41, 0x02, 145}, + {56, 0x03, 145}, + }, + /* 179 */ + { + {3, 0x02, 148}, + {6, 0x02, 148}, + {10, 0x02, 148}, + {15, 0x02, 148}, + {24, 0x02, 148}, + {31, 0x02, 148}, + {41, 0x02, 148}, + {56, 0x03, 148}, + {3, 0x02, 159}, + {6, 0x02, 159}, + {10, 0x02, 159}, + {15, 0x02, 159}, + {24, 0x02, 159}, + {31, 0x02, 159}, + {41, 0x02, 159}, + {56, 0x03, 159}, + }, + /* 180 */ + { + {0, 0x03, 171}, + {0, 0x03, 206}, + {0, 0x03, 215}, + {0, 0x03, 225}, + {0, 0x03, 236}, + {0, 0x03, 237}, + {188, 0x00, 0}, + {189, 0x00, 0}, + {193, 0x00, 0}, + {196, 0x00, 0}, + {200, 0x00, 0}, + {203, 0x00, 0}, + {209, 0x00, 0}, + {216, 0x00, 0}, + {224, 0x00, 0}, + {238, 0x00, 0}, + }, + /* 181 */ + { + {1, 0x02, 171}, + {22, 0x03, 171}, + {1, 0x02, 206}, + {22, 0x03, 206}, + {1, 0x02, 215}, + {22, 0x03, 215}, + {1, 0x02, 225}, + {22, 0x03, 225}, + {1, 0x02, 236}, + {22, 0x03, 236}, + {1, 0x02, 237}, + {22, 0x03, 237}, + {0, 0x03, 199}, + {0, 0x03, 207}, + {0, 0x03, 234}, + {0, 0x03, 235}, + }, + /* 182 */ + { + {2, 0x02, 171}, + {9, 0x02, 171}, + {23, 0x02, 171}, + {40, 0x03, 171}, + {2, 0x02, 206}, + {9, 0x02, 206}, + {23, 0x02, 206}, + {40, 0x03, 206}, + {2, 0x02, 215}, + {9, 0x02, 215}, + {23, 0x02, 215}, + {40, 0x03, 215}, + {2, 0x02, 225}, + {9, 0x02, 225}, + {23, 0x02, 225}, + {40, 0x03, 225}, + }, + /* 183 */ + { + {3, 0x02, 171}, + {6, 0x02, 171}, + {10, 0x02, 171}, + {15, 0x02, 171}, + {24, 0x02, 171}, + {31, 0x02, 171}, + {41, 0x02, 171}, + {56, 0x03, 171}, + {3, 0x02, 206}, + {6, 0x02, 206}, + {10, 0x02, 206}, + {15, 0x02, 206}, + {24, 0x02, 206}, + {31, 0x02, 206}, + {41, 0x02, 206}, + {56, 0x03, 206}, + }, + /* 184 */ + { + {3, 0x02, 215}, + {6, 0x02, 215}, + {10, 0x02, 215}, + {15, 0x02, 215}, + {24, 0x02, 215}, + {31, 0x02, 215}, + {41, 0x02, 215}, + {56, 0x03, 215}, + {3, 0x02, 225}, + {6, 0x02, 225}, + {10, 0x02, 225}, + {15, 0x02, 225}, + {24, 0x02, 225}, + {31, 0x02, 225}, + {41, 0x02, 225}, + {56, 0x03, 225}, + }, + /* 185 */ + { + {2, 0x02, 236}, + {9, 0x02, 236}, + {23, 0x02, 236}, + {40, 0x03, 236}, + {2, 0x02, 237}, + {9, 0x02, 237}, + {23, 0x02, 237}, + {40, 0x03, 237}, + {1, 0x02, 199}, + {22, 0x03, 199}, + {1, 0x02, 207}, + {22, 0x03, 207}, + {1, 0x02, 234}, + {22, 0x03, 234}, + {1, 0x02, 235}, + {22, 0x03, 235}, + }, + /* 186 */ + { + {3, 0x02, 236}, + {6, 0x02, 236}, + {10, 0x02, 236}, + {15, 0x02, 236}, + {24, 0x02, 236}, + {31, 0x02, 236}, + {41, 0x02, 236}, + {56, 0x03, 236}, + {3, 0x02, 237}, + {6, 0x02, 237}, + {10, 0x02, 237}, + {15, 0x02, 237}, + {24, 0x02, 237}, + {31, 0x02, 237}, + {41, 0x02, 237}, + {56, 0x03, 237}, + }, + /* 187 */ + { + {2, 0x02, 199}, + {9, 0x02, 199}, + {23, 0x02, 199}, + {40, 0x03, 199}, + {2, 0x02, 207}, + {9, 0x02, 207}, + {23, 0x02, 207}, + {40, 0x03, 207}, + {2, 0x02, 234}, + {9, 0x02, 234}, + {23, 0x02, 234}, + {40, 0x03, 234}, + {2, 0x02, 235}, + {9, 0x02, 235}, + {23, 0x02, 235}, + {40, 0x03, 235}, + }, + /* 188 */ + { + {3, 0x02, 199}, + {6, 0x02, 199}, + {10, 0x02, 199}, + {15, 0x02, 199}, + {24, 0x02, 199}, + {31, 0x02, 199}, + {41, 0x02, 199}, + {56, 0x03, 199}, + {3, 0x02, 207}, + {6, 0x02, 207}, + {10, 0x02, 207}, + {15, 0x02, 207}, + {24, 0x02, 207}, + {31, 0x02, 207}, + {41, 0x02, 207}, + {56, 0x03, 207}, + }, + /* 189 */ + { + {3, 0x02, 234}, + {6, 0x02, 234}, + {10, 0x02, 234}, + {15, 0x02, 234}, + {24, 0x02, 234}, + {31, 0x02, 234}, + {41, 0x02, 234}, + {56, 0x03, 234}, + {3, 0x02, 235}, + {6, 0x02, 235}, + {10, 0x02, 235}, + {15, 0x02, 235}, + {24, 0x02, 235}, + {31, 0x02, 235}, + {41, 0x02, 235}, + {56, 0x03, 235}, + }, + /* 190 */ + { + {194, 0x00, 0}, + {195, 0x00, 0}, + {197, 0x00, 0}, + {198, 0x00, 0}, + {201, 0x00, 0}, + {202, 0x00, 0}, + {204, 0x00, 0}, + {205, 0x00, 0}, + {210, 0x00, 0}, + {213, 0x00, 0}, + {217, 0x00, 0}, + {220, 0x00, 0}, + {225, 0x00, 0}, + {231, 0x00, 0}, + {239, 0x00, 0}, + {246, 0x00, 0}, + }, + /* 191 */ + { + {0, 0x03, 192}, + {0, 0x03, 193}, + {0, 0x03, 200}, + {0, 0x03, 201}, + {0, 0x03, 202}, + {0, 0x03, 205}, + {0, 0x03, 210}, + {0, 0x03, 213}, + {0, 0x03, 218}, + {0, 0x03, 219}, + {0, 0x03, 238}, + {0, 0x03, 240}, + {0, 0x03, 242}, + {0, 0x03, 243}, + {0, 0x03, 255}, + {206, 0x00, 0}, + }, + /* 192 */ + { + {1, 0x02, 192}, + {22, 0x03, 192}, + {1, 0x02, 193}, + {22, 0x03, 193}, + {1, 0x02, 200}, + {22, 0x03, 200}, + {1, 0x02, 201}, + {22, 0x03, 201}, + {1, 0x02, 202}, + {22, 0x03, 202}, + {1, 0x02, 205}, + {22, 0x03, 205}, + {1, 0x02, 210}, + {22, 0x03, 210}, + {1, 0x02, 213}, + {22, 0x03, 213}, + }, + /* 193 */ + { + {2, 0x02, 192}, + {9, 0x02, 192}, + {23, 0x02, 192}, + {40, 0x03, 192}, + {2, 0x02, 193}, + {9, 0x02, 193}, + {23, 0x02, 193}, + {40, 0x03, 193}, + {2, 0x02, 200}, + {9, 0x02, 200}, + {23, 0x02, 200}, + {40, 0x03, 200}, + {2, 0x02, 201}, + {9, 0x02, 201}, + {23, 0x02, 201}, + {40, 0x03, 201}, + }, + /* 194 */ + { + {3, 0x02, 192}, + {6, 0x02, 192}, + {10, 0x02, 192}, + {15, 0x02, 192}, + {24, 0x02, 192}, + {31, 0x02, 192}, + {41, 0x02, 192}, + {56, 0x03, 192}, + {3, 0x02, 193}, + {6, 0x02, 193}, + {10, 0x02, 193}, + {15, 0x02, 193}, + {24, 0x02, 193}, + {31, 0x02, 193}, + {41, 0x02, 193}, + {56, 0x03, 193}, + }, + /* 195 */ + { + {3, 0x02, 200}, + {6, 0x02, 200}, + {10, 0x02, 200}, + {15, 0x02, 200}, + {24, 0x02, 200}, + {31, 0x02, 200}, + {41, 0x02, 200}, + {56, 0x03, 200}, + {3, 0x02, 201}, + {6, 0x02, 201}, + {10, 0x02, 201}, + {15, 0x02, 201}, + {24, 0x02, 201}, + {31, 0x02, 201}, + {41, 0x02, 201}, + {56, 0x03, 201}, + }, + /* 196 */ + { + {2, 0x02, 202}, + {9, 0x02, 202}, + {23, 0x02, 202}, + {40, 0x03, 202}, + {2, 0x02, 205}, + {9, 0x02, 205}, + {23, 0x02, 205}, + {40, 0x03, 205}, + {2, 0x02, 210}, + {9, 0x02, 210}, + {23, 0x02, 210}, + {40, 0x03, 210}, + {2, 0x02, 213}, + {9, 0x02, 213}, + {23, 0x02, 213}, + {40, 0x03, 213}, + }, + /* 197 */ + { + {3, 0x02, 202}, + {6, 0x02, 202}, + {10, 0x02, 202}, + {15, 0x02, 202}, + {24, 0x02, 202}, + {31, 0x02, 202}, + {41, 0x02, 202}, + {56, 0x03, 202}, + {3, 0x02, 205}, + {6, 0x02, 205}, + {10, 0x02, 205}, + {15, 0x02, 205}, + {24, 0x02, 205}, + {31, 0x02, 205}, + {41, 0x02, 205}, + {56, 0x03, 205}, + }, + /* 198 */ + { + {3, 0x02, 210}, + {6, 0x02, 210}, + {10, 0x02, 210}, + {15, 0x02, 210}, + {24, 0x02, 210}, + {31, 0x02, 210}, + {41, 0x02, 210}, + {56, 0x03, 210}, + {3, 0x02, 213}, + {6, 0x02, 213}, + {10, 0x02, 213}, + {15, 0x02, 213}, + {24, 0x02, 213}, + {31, 0x02, 213}, + {41, 0x02, 213}, + {56, 0x03, 213}, + }, + /* 199 */ + { + {1, 0x02, 218}, + {22, 0x03, 218}, + {1, 0x02, 219}, + {22, 0x03, 219}, + {1, 0x02, 238}, + {22, 0x03, 238}, + {1, 0x02, 240}, + {22, 0x03, 240}, + {1, 0x02, 242}, + {22, 0x03, 242}, + {1, 0x02, 243}, + {22, 0x03, 243}, + {1, 0x02, 255}, + {22, 0x03, 255}, + {0, 0x03, 203}, + {0, 0x03, 204}, + }, + /* 200 */ + { + {2, 0x02, 218}, + {9, 0x02, 218}, + {23, 0x02, 218}, + {40, 0x03, 218}, + {2, 0x02, 219}, + {9, 0x02, 219}, + {23, 0x02, 219}, + {40, 0x03, 219}, + {2, 0x02, 238}, + {9, 0x02, 238}, + {23, 0x02, 238}, + {40, 0x03, 238}, + {2, 0x02, 240}, + {9, 0x02, 240}, + {23, 0x02, 240}, + {40, 0x03, 240}, + }, + /* 201 */ + { + {3, 0x02, 218}, + {6, 0x02, 218}, + {10, 0x02, 218}, + {15, 0x02, 218}, + {24, 0x02, 218}, + {31, 0x02, 218}, + {41, 0x02, 218}, + {56, 0x03, 218}, + {3, 0x02, 219}, + {6, 0x02, 219}, + {10, 0x02, 219}, + {15, 0x02, 219}, + {24, 0x02, 219}, + {31, 0x02, 219}, + {41, 0x02, 219}, + {56, 0x03, 219}, + }, + /* 202 */ + { + {3, 0x02, 238}, + {6, 0x02, 238}, + {10, 0x02, 238}, + {15, 0x02, 238}, + {24, 0x02, 238}, + {31, 0x02, 238}, + {41, 0x02, 238}, + {56, 0x03, 238}, + {3, 0x02, 240}, + {6, 0x02, 240}, + {10, 0x02, 240}, + {15, 0x02, 240}, + {24, 0x02, 240}, + {31, 0x02, 240}, + {41, 0x02, 240}, + {56, 0x03, 240}, + }, + /* 203 */ + { + {2, 0x02, 242}, + {9, 0x02, 242}, + {23, 0x02, 242}, + {40, 0x03, 242}, + {2, 0x02, 243}, + {9, 0x02, 243}, + {23, 0x02, 243}, + {40, 0x03, 243}, + {2, 0x02, 255}, + {9, 0x02, 255}, + {23, 0x02, 255}, + {40, 0x03, 255}, + {1, 0x02, 203}, + {22, 0x03, 203}, + {1, 0x02, 204}, + {22, 0x03, 204}, + }, + /* 204 */ + { + {3, 0x02, 242}, + {6, 0x02, 242}, + {10, 0x02, 242}, + {15, 0x02, 242}, + {24, 0x02, 242}, + {31, 0x02, 242}, + {41, 0x02, 242}, + {56, 0x03, 242}, + {3, 0x02, 243}, + {6, 0x02, 243}, + {10, 0x02, 243}, + {15, 0x02, 243}, + {24, 0x02, 243}, + {31, 0x02, 243}, + {41, 0x02, 243}, + {56, 0x03, 243}, + }, + /* 205 */ + { + {3, 0x02, 255}, + {6, 0x02, 255}, + {10, 0x02, 255}, + {15, 0x02, 255}, + {24, 0x02, 255}, + {31, 0x02, 255}, + {41, 0x02, 255}, + {56, 0x03, 255}, + {2, 0x02, 203}, + {9, 0x02, 203}, + {23, 0x02, 203}, + {40, 0x03, 203}, + {2, 0x02, 204}, + {9, 0x02, 204}, + {23, 0x02, 204}, + {40, 0x03, 204}, + }, + /* 206 */ + { + {3, 0x02, 203}, + {6, 0x02, 203}, + {10, 0x02, 203}, + {15, 0x02, 203}, + {24, 0x02, 203}, + {31, 0x02, 203}, + {41, 0x02, 203}, + {56, 0x03, 203}, + {3, 0x02, 204}, + {6, 0x02, 204}, + {10, 0x02, 204}, + {15, 0x02, 204}, + {24, 0x02, 204}, + {31, 0x02, 204}, + {41, 0x02, 204}, + {56, 0x03, 204}, + }, + /* 207 */ + { + {211, 0x00, 0}, + {212, 0x00, 0}, + {214, 0x00, 0}, + {215, 0x00, 0}, + {218, 0x00, 0}, + {219, 0x00, 0}, + {221, 0x00, 0}, + {222, 0x00, 0}, + {226, 0x00, 0}, + {228, 0x00, 0}, + {232, 0x00, 0}, + {235, 0x00, 0}, + {240, 0x00, 0}, + {243, 0x00, 0}, + {247, 0x00, 0}, + {250, 0x00, 0}, + }, + /* 208 */ + { + {0, 0x03, 211}, + {0, 0x03, 212}, + {0, 0x03, 214}, + {0, 0x03, 221}, + {0, 0x03, 222}, + {0, 0x03, 223}, + {0, 0x03, 241}, + {0, 0x03, 244}, + {0, 0x03, 245}, + {0, 0x03, 246}, + {0, 0x03, 247}, + {0, 0x03, 248}, + {0, 0x03, 250}, + {0, 0x03, 251}, + {0, 0x03, 252}, + {0, 0x03, 253}, + }, + /* 209 */ + { + {1, 0x02, 211}, + {22, 0x03, 211}, + {1, 0x02, 212}, + {22, 0x03, 212}, + {1, 0x02, 214}, + {22, 0x03, 214}, + {1, 0x02, 221}, + {22, 0x03, 221}, + {1, 0x02, 222}, + {22, 0x03, 222}, + {1, 0x02, 223}, + {22, 0x03, 223}, + {1, 0x02, 241}, + {22, 0x03, 241}, + {1, 0x02, 244}, + {22, 0x03, 244}, + }, + /* 210 */ + { + {2, 0x02, 211}, + {9, 0x02, 211}, + {23, 0x02, 211}, + {40, 0x03, 211}, + {2, 0x02, 212}, + {9, 0x02, 212}, + {23, 0x02, 212}, + {40, 0x03, 212}, + {2, 0x02, 214}, + {9, 0x02, 214}, + {23, 0x02, 214}, + {40, 0x03, 214}, + {2, 0x02, 221}, + {9, 0x02, 221}, + {23, 0x02, 221}, + {40, 0x03, 221}, + }, + /* 211 */ + { + {3, 0x02, 211}, + {6, 0x02, 211}, + {10, 0x02, 211}, + {15, 0x02, 211}, + {24, 0x02, 211}, + {31, 0x02, 211}, + {41, 0x02, 211}, + {56, 0x03, 211}, + {3, 0x02, 212}, + {6, 0x02, 212}, + {10, 0x02, 212}, + {15, 0x02, 212}, + {24, 0x02, 212}, + {31, 0x02, 212}, + {41, 0x02, 212}, + {56, 0x03, 212}, + }, + /* 212 */ + { + {3, 0x02, 214}, + {6, 0x02, 214}, + {10, 0x02, 214}, + {15, 0x02, 214}, + {24, 0x02, 214}, + {31, 0x02, 214}, + {41, 0x02, 214}, + {56, 0x03, 214}, + {3, 0x02, 221}, + {6, 0x02, 221}, + {10, 0x02, 221}, + {15, 0x02, 221}, + {24, 0x02, 221}, + {31, 0x02, 221}, + {41, 0x02, 221}, + {56, 0x03, 221}, + }, + /* 213 */ + { + {2, 0x02, 222}, + {9, 0x02, 222}, + {23, 0x02, 222}, + {40, 0x03, 222}, + {2, 0x02, 223}, + {9, 0x02, 223}, + {23, 0x02, 223}, + {40, 0x03, 223}, + {2, 0x02, 241}, + {9, 0x02, 241}, + {23, 0x02, 241}, + {40, 0x03, 241}, + {2, 0x02, 244}, + {9, 0x02, 244}, + {23, 0x02, 244}, + {40, 0x03, 244}, + }, + /* 214 */ + { + {3, 0x02, 222}, + {6, 0x02, 222}, + {10, 0x02, 222}, + {15, 0x02, 222}, + {24, 0x02, 222}, + {31, 0x02, 222}, + {41, 0x02, 222}, + {56, 0x03, 222}, + {3, 0x02, 223}, + {6, 0x02, 223}, + {10, 0x02, 223}, + {15, 0x02, 223}, + {24, 0x02, 223}, + {31, 0x02, 223}, + {41, 0x02, 223}, + {56, 0x03, 223}, + }, + /* 215 */ + { + {3, 0x02, 241}, + {6, 0x02, 241}, + {10, 0x02, 241}, + {15, 0x02, 241}, + {24, 0x02, 241}, + {31, 0x02, 241}, + {41, 0x02, 241}, + {56, 0x03, 241}, + {3, 0x02, 244}, + {6, 0x02, 244}, + {10, 0x02, 244}, + {15, 0x02, 244}, + {24, 0x02, 244}, + {31, 0x02, 244}, + {41, 0x02, 244}, + {56, 0x03, 244}, + }, + /* 216 */ + { + {1, 0x02, 245}, + {22, 0x03, 245}, + {1, 0x02, 246}, + {22, 0x03, 246}, + {1, 0x02, 247}, + {22, 0x03, 247}, + {1, 0x02, 248}, + {22, 0x03, 248}, + {1, 0x02, 250}, + {22, 0x03, 250}, + {1, 0x02, 251}, + {22, 0x03, 251}, + {1, 0x02, 252}, + {22, 0x03, 252}, + {1, 0x02, 253}, + {22, 0x03, 253}, + }, + /* 217 */ + { + {2, 0x02, 245}, + {9, 0x02, 245}, + {23, 0x02, 245}, + {40, 0x03, 245}, + {2, 0x02, 246}, + {9, 0x02, 246}, + {23, 0x02, 246}, + {40, 0x03, 246}, + {2, 0x02, 247}, + {9, 0x02, 247}, + {23, 0x02, 247}, + {40, 0x03, 247}, + {2, 0x02, 248}, + {9, 0x02, 248}, + {23, 0x02, 248}, + {40, 0x03, 248}, + }, + /* 218 */ + { + {3, 0x02, 245}, + {6, 0x02, 245}, + {10, 0x02, 245}, + {15, 0x02, 245}, + {24, 0x02, 245}, + {31, 0x02, 245}, + {41, 0x02, 245}, + {56, 0x03, 245}, + {3, 0x02, 246}, + {6, 0x02, 246}, + {10, 0x02, 246}, + {15, 0x02, 246}, + {24, 0x02, 246}, + {31, 0x02, 246}, + {41, 0x02, 246}, + {56, 0x03, 246}, + }, + /* 219 */ + { + {3, 0x02, 247}, + {6, 0x02, 247}, + {10, 0x02, 247}, + {15, 0x02, 247}, + {24, 0x02, 247}, + {31, 0x02, 247}, + {41, 0x02, 247}, + {56, 0x03, 247}, + {3, 0x02, 248}, + {6, 0x02, 248}, + {10, 0x02, 248}, + {15, 0x02, 248}, + {24, 0x02, 248}, + {31, 0x02, 248}, + {41, 0x02, 248}, + {56, 0x03, 248}, + }, + /* 220 */ + { + {2, 0x02, 250}, + {9, 0x02, 250}, + {23, 0x02, 250}, + {40, 0x03, 250}, + {2, 0x02, 251}, + {9, 0x02, 251}, + {23, 0x02, 251}, + {40, 0x03, 251}, + {2, 0x02, 252}, + {9, 0x02, 252}, + {23, 0x02, 252}, + {40, 0x03, 252}, + {2, 0x02, 253}, + {9, 0x02, 253}, + {23, 0x02, 253}, + {40, 0x03, 253}, + }, + /* 221 */ + { + {3, 0x02, 250}, + {6, 0x02, 250}, + {10, 0x02, 250}, + {15, 0x02, 250}, + {24, 0x02, 250}, + {31, 0x02, 250}, + {41, 0x02, 250}, + {56, 0x03, 250}, + {3, 0x02, 251}, + {6, 0x02, 251}, + {10, 0x02, 251}, + {15, 0x02, 251}, + {24, 0x02, 251}, + {31, 0x02, 251}, + {41, 0x02, 251}, + {56, 0x03, 251}, + }, + /* 222 */ + { + {3, 0x02, 252}, + {6, 0x02, 252}, + {10, 0x02, 252}, + {15, 0x02, 252}, + {24, 0x02, 252}, + {31, 0x02, 252}, + {41, 0x02, 252}, + {56, 0x03, 252}, + {3, 0x02, 253}, + {6, 0x02, 253}, + {10, 0x02, 253}, + {15, 0x02, 253}, + {24, 0x02, 253}, + {31, 0x02, 253}, + {41, 0x02, 253}, + {56, 0x03, 253}, + }, + /* 223 */ + { + {0, 0x03, 254}, + {227, 0x00, 0}, + {229, 0x00, 0}, + {230, 0x00, 0}, + {233, 0x00, 0}, + {234, 0x00, 0}, + {236, 0x00, 0}, + {237, 0x00, 0}, + {241, 0x00, 0}, + {242, 0x00, 0}, + {244, 0x00, 0}, + {245, 0x00, 0}, + {248, 0x00, 0}, + {249, 0x00, 0}, + {251, 0x00, 0}, + {252, 0x00, 0}, + }, + /* 224 */ + { + {1, 0x02, 254}, + {22, 0x03, 254}, + {0, 0x03, 2}, + {0, 0x03, 3}, + {0, 0x03, 4}, + {0, 0x03, 5}, + {0, 0x03, 6}, + {0, 0x03, 7}, + {0, 0x03, 8}, + {0, 0x03, 11}, + {0, 0x03, 12}, + {0, 0x03, 14}, + {0, 0x03, 15}, + {0, 0x03, 16}, + {0, 0x03, 17}, + {0, 0x03, 18}, + }, + /* 225 */ + { + {2, 0x02, 254}, + {9, 0x02, 254}, + {23, 0x02, 254}, + {40, 0x03, 254}, + {1, 0x02, 2}, + {22, 0x03, 2}, + {1, 0x02, 3}, + {22, 0x03, 3}, + {1, 0x02, 4}, + {22, 0x03, 4}, + {1, 0x02, 5}, + {22, 0x03, 5}, + {1, 0x02, 6}, + {22, 0x03, 6}, + {1, 0x02, 7}, + {22, 0x03, 7}, + }, + /* 226 */ + { + {3, 0x02, 254}, + {6, 0x02, 254}, + {10, 0x02, 254}, + {15, 0x02, 254}, + {24, 0x02, 254}, + {31, 0x02, 254}, + {41, 0x02, 254}, + {56, 0x03, 254}, + {2, 0x02, 2}, + {9, 0x02, 2}, + {23, 0x02, 2}, + {40, 0x03, 2}, + {2, 0x02, 3}, + {9, 0x02, 3}, + {23, 0x02, 3}, + {40, 0x03, 3}, + }, + /* 227 */ + { + {3, 0x02, 2}, + {6, 0x02, 2}, + {10, 0x02, 2}, + {15, 0x02, 2}, + {24, 0x02, 2}, + {31, 0x02, 2}, + {41, 0x02, 2}, + {56, 0x03, 2}, + {3, 0x02, 3}, + {6, 0x02, 3}, + {10, 0x02, 3}, + {15, 0x02, 3}, + {24, 0x02, 3}, + {31, 0x02, 3}, + {41, 0x02, 3}, + {56, 0x03, 3}, + }, + /* 228 */ + { + {2, 0x02, 4}, + {9, 0x02, 4}, + {23, 0x02, 4}, + {40, 0x03, 4}, + {2, 0x02, 5}, + {9, 0x02, 5}, + {23, 0x02, 5}, + {40, 0x03, 5}, + {2, 0x02, 6}, + {9, 0x02, 6}, + {23, 0x02, 6}, + {40, 0x03, 6}, + {2, 0x02, 7}, + {9, 0x02, 7}, + {23, 0x02, 7}, + {40, 0x03, 7}, + }, + /* 229 */ + { + {3, 0x02, 4}, + {6, 0x02, 4}, + {10, 0x02, 4}, + {15, 0x02, 4}, + {24, 0x02, 4}, + {31, 0x02, 4}, + {41, 0x02, 4}, + {56, 0x03, 4}, + {3, 0x02, 5}, + {6, 0x02, 5}, + {10, 0x02, 5}, + {15, 0x02, 5}, + {24, 0x02, 5}, + {31, 0x02, 5}, + {41, 0x02, 5}, + {56, 0x03, 5}, + }, + /* 230 */ + { + {3, 0x02, 6}, + {6, 0x02, 6}, + {10, 0x02, 6}, + {15, 0x02, 6}, + {24, 0x02, 6}, + {31, 0x02, 6}, + {41, 0x02, 6}, + {56, 0x03, 6}, + {3, 0x02, 7}, + {6, 0x02, 7}, + {10, 0x02, 7}, + {15, 0x02, 7}, + {24, 0x02, 7}, + {31, 0x02, 7}, + {41, 0x02, 7}, + {56, 0x03, 7}, + }, + /* 231 */ + { + {1, 0x02, 8}, + {22, 0x03, 8}, + {1, 0x02, 11}, + {22, 0x03, 11}, + {1, 0x02, 12}, + {22, 0x03, 12}, + {1, 0x02, 14}, + {22, 0x03, 14}, + {1, 0x02, 15}, + {22, 0x03, 15}, + {1, 0x02, 16}, + {22, 0x03, 16}, + {1, 0x02, 17}, + {22, 0x03, 17}, + {1, 0x02, 18}, + {22, 0x03, 18}, + }, + /* 232 */ + { + {2, 0x02, 8}, + {9, 0x02, 8}, + {23, 0x02, 8}, + {40, 0x03, 8}, + {2, 0x02, 11}, + {9, 0x02, 11}, + {23, 0x02, 11}, + {40, 0x03, 11}, + {2, 0x02, 12}, + {9, 0x02, 12}, + {23, 0x02, 12}, + {40, 0x03, 12}, + {2, 0x02, 14}, + {9, 0x02, 14}, + {23, 0x02, 14}, + {40, 0x03, 14}, + }, + /* 233 */ + { + {3, 0x02, 8}, + {6, 0x02, 8}, + {10, 0x02, 8}, + {15, 0x02, 8}, + {24, 0x02, 8}, + {31, 0x02, 8}, + {41, 0x02, 8}, + {56, 0x03, 8}, + {3, 0x02, 11}, + {6, 0x02, 11}, + {10, 0x02, 11}, + {15, 0x02, 11}, + {24, 0x02, 11}, + {31, 0x02, 11}, + {41, 0x02, 11}, + {56, 0x03, 11}, + }, + /* 234 */ + { + {3, 0x02, 12}, + {6, 0x02, 12}, + {10, 0x02, 12}, + {15, 0x02, 12}, + {24, 0x02, 12}, + {31, 0x02, 12}, + {41, 0x02, 12}, + {56, 0x03, 12}, + {3, 0x02, 14}, + {6, 0x02, 14}, + {10, 0x02, 14}, + {15, 0x02, 14}, + {24, 0x02, 14}, + {31, 0x02, 14}, + {41, 0x02, 14}, + {56, 0x03, 14}, + }, + /* 235 */ + { + {2, 0x02, 15}, + {9, 0x02, 15}, + {23, 0x02, 15}, + {40, 0x03, 15}, + {2, 0x02, 16}, + {9, 0x02, 16}, + {23, 0x02, 16}, + {40, 0x03, 16}, + {2, 0x02, 17}, + {9, 0x02, 17}, + {23, 0x02, 17}, + {40, 0x03, 17}, + {2, 0x02, 18}, + {9, 0x02, 18}, + {23, 0x02, 18}, + {40, 0x03, 18}, + }, + /* 236 */ + { + {3, 0x02, 15}, + {6, 0x02, 15}, + {10, 0x02, 15}, + {15, 0x02, 15}, + {24, 0x02, 15}, + {31, 0x02, 15}, + {41, 0x02, 15}, + {56, 0x03, 15}, + {3, 0x02, 16}, + {6, 0x02, 16}, + {10, 0x02, 16}, + {15, 0x02, 16}, + {24, 0x02, 16}, + {31, 0x02, 16}, + {41, 0x02, 16}, + {56, 0x03, 16}, + }, + /* 237 */ + { + {3, 0x02, 17}, + {6, 0x02, 17}, + {10, 0x02, 17}, + {15, 0x02, 17}, + {24, 0x02, 17}, + {31, 0x02, 17}, + {41, 0x02, 17}, + {56, 0x03, 17}, + {3, 0x02, 18}, + {6, 0x02, 18}, + {10, 0x02, 18}, + {15, 0x02, 18}, + {24, 0x02, 18}, + {31, 0x02, 18}, + {41, 0x02, 18}, + {56, 0x03, 18}, + }, + /* 238 */ + { + {0, 0x03, 19}, + {0, 0x03, 20}, + {0, 0x03, 21}, + {0, 0x03, 23}, + {0, 0x03, 24}, + {0, 0x03, 25}, + {0, 0x03, 26}, + {0, 0x03, 27}, + {0, 0x03, 28}, + {0, 0x03, 29}, + {0, 0x03, 30}, + {0, 0x03, 31}, + {0, 0x03, 127}, + {0, 0x03, 220}, + {0, 0x03, 249}, + {253, 0x00, 0}, + }, + /* 239 */ + { + {1, 0x02, 19}, + {22, 0x03, 19}, + {1, 0x02, 20}, + {22, 0x03, 20}, + {1, 0x02, 21}, + {22, 0x03, 21}, + {1, 0x02, 23}, + {22, 0x03, 23}, + {1, 0x02, 24}, + {22, 0x03, 24}, + {1, 0x02, 25}, + {22, 0x03, 25}, + {1, 0x02, 26}, + {22, 0x03, 26}, + {1, 0x02, 27}, + {22, 0x03, 27}, + }, + /* 240 */ + { + {2, 0x02, 19}, + {9, 0x02, 19}, + {23, 0x02, 19}, + {40, 0x03, 19}, + {2, 0x02, 20}, + {9, 0x02, 20}, + {23, 0x02, 20}, + {40, 0x03, 20}, + {2, 0x02, 21}, + {9, 0x02, 21}, + {23, 0x02, 21}, + {40, 0x03, 21}, + {2, 0x02, 23}, + {9, 0x02, 23}, + {23, 0x02, 23}, + {40, 0x03, 23}, + }, + /* 241 */ + { + {3, 0x02, 19}, + {6, 0x02, 19}, + {10, 0x02, 19}, + {15, 0x02, 19}, + {24, 0x02, 19}, + {31, 0x02, 19}, + {41, 0x02, 19}, + {56, 0x03, 19}, + {3, 0x02, 20}, + {6, 0x02, 20}, + {10, 0x02, 20}, + {15, 0x02, 20}, + {24, 0x02, 20}, + {31, 0x02, 20}, + {41, 0x02, 20}, + {56, 0x03, 20}, + }, + /* 242 */ + { + {3, 0x02, 21}, + {6, 0x02, 21}, + {10, 0x02, 21}, + {15, 0x02, 21}, + {24, 0x02, 21}, + {31, 0x02, 21}, + {41, 0x02, 21}, + {56, 0x03, 21}, + {3, 0x02, 23}, + {6, 0x02, 23}, + {10, 0x02, 23}, + {15, 0x02, 23}, + {24, 0x02, 23}, + {31, 0x02, 23}, + {41, 0x02, 23}, + {56, 0x03, 23}, + }, + /* 243 */ + { + {2, 0x02, 24}, + {9, 0x02, 24}, + {23, 0x02, 24}, + {40, 0x03, 24}, + {2, 0x02, 25}, + {9, 0x02, 25}, + {23, 0x02, 25}, + {40, 0x03, 25}, + {2, 0x02, 26}, + {9, 0x02, 26}, + {23, 0x02, 26}, + {40, 0x03, 26}, + {2, 0x02, 27}, + {9, 0x02, 27}, + {23, 0x02, 27}, + {40, 0x03, 27}, + }, + /* 244 */ + { + {3, 0x02, 24}, + {6, 0x02, 24}, + {10, 0x02, 24}, + {15, 0x02, 24}, + {24, 0x02, 24}, + {31, 0x02, 24}, + {41, 0x02, 24}, + {56, 0x03, 24}, + {3, 0x02, 25}, + {6, 0x02, 25}, + {10, 0x02, 25}, + {15, 0x02, 25}, + {24, 0x02, 25}, + {31, 0x02, 25}, + {41, 0x02, 25}, + {56, 0x03, 25}, + }, + /* 245 */ + { + {3, 0x02, 26}, + {6, 0x02, 26}, + {10, 0x02, 26}, + {15, 0x02, 26}, + {24, 0x02, 26}, + {31, 0x02, 26}, + {41, 0x02, 26}, + {56, 0x03, 26}, + {3, 0x02, 27}, + {6, 0x02, 27}, + {10, 0x02, 27}, + {15, 0x02, 27}, + {24, 0x02, 27}, + {31, 0x02, 27}, + {41, 0x02, 27}, + {56, 0x03, 27}, + }, + /* 246 */ + { + {1, 0x02, 28}, + {22, 0x03, 28}, + {1, 0x02, 29}, + {22, 0x03, 29}, + {1, 0x02, 30}, + {22, 0x03, 30}, + {1, 0x02, 31}, + {22, 0x03, 31}, + {1, 0x02, 127}, + {22, 0x03, 127}, + {1, 0x02, 220}, + {22, 0x03, 220}, + {1, 0x02, 249}, + {22, 0x03, 249}, + {254, 0x00, 0}, + {255, 0x00, 0}, + }, + /* 247 */ + { + {2, 0x02, 28}, + {9, 0x02, 28}, + {23, 0x02, 28}, + {40, 0x03, 28}, + {2, 0x02, 29}, + {9, 0x02, 29}, + {23, 0x02, 29}, + {40, 0x03, 29}, + {2, 0x02, 30}, + {9, 0x02, 30}, + {23, 0x02, 30}, + {40, 0x03, 30}, + {2, 0x02, 31}, + {9, 0x02, 31}, + {23, 0x02, 31}, + {40, 0x03, 31}, + }, + /* 248 */ + { + {3, 0x02, 28}, + {6, 0x02, 28}, + {10, 0x02, 28}, + {15, 0x02, 28}, + {24, 0x02, 28}, + {31, 0x02, 28}, + {41, 0x02, 28}, + {56, 0x03, 28}, + {3, 0x02, 29}, + {6, 0x02, 29}, + {10, 0x02, 29}, + {15, 0x02, 29}, + {24, 0x02, 29}, + {31, 0x02, 29}, + {41, 0x02, 29}, + {56, 0x03, 29}, + }, + /* 249 */ + { + {3, 0x02, 30}, + {6, 0x02, 30}, + {10, 0x02, 30}, + {15, 0x02, 30}, + {24, 0x02, 30}, + {31, 0x02, 30}, + {41, 0x02, 30}, + {56, 0x03, 30}, + {3, 0x02, 31}, + {6, 0x02, 31}, + {10, 0x02, 31}, + {15, 0x02, 31}, + {24, 0x02, 31}, + {31, 0x02, 31}, + {41, 0x02, 31}, + {56, 0x03, 31}, + }, + /* 250 */ + { + {2, 0x02, 127}, + {9, 0x02, 127}, + {23, 0x02, 127}, + {40, 0x03, 127}, + {2, 0x02, 220}, + {9, 0x02, 220}, + {23, 0x02, 220}, + {40, 0x03, 220}, + {2, 0x02, 249}, + {9, 0x02, 249}, + {23, 0x02, 249}, + {40, 0x03, 249}, + {0, 0x03, 10}, + {0, 0x03, 13}, + {0, 0x03, 22}, + {0, 0x04, 0}, + }, + /* 251 */ + { + {3, 0x02, 127}, + {6, 0x02, 127}, + {10, 0x02, 127}, + {15, 0x02, 127}, + {24, 0x02, 127}, + {31, 0x02, 127}, + {41, 0x02, 127}, + {56, 0x03, 127}, + {3, 0x02, 220}, + {6, 0x02, 220}, + {10, 0x02, 220}, + {15, 0x02, 220}, + {24, 0x02, 220}, + {31, 0x02, 220}, + {41, 0x02, 220}, + {56, 0x03, 220}, + }, + /* 252 */ + { + {3, 0x02, 249}, + {6, 0x02, 249}, + {10, 0x02, 249}, + {15, 0x02, 249}, + {24, 0x02, 249}, + {31, 0x02, 249}, + {41, 0x02, 249}, + {56, 0x03, 249}, + {1, 0x02, 10}, + {22, 0x03, 10}, + {1, 0x02, 13}, + {22, 0x03, 13}, + {1, 0x02, 22}, + {22, 0x03, 22}, + {0, 0x04, 0}, + {0, 0x04, 0}, + }, + /* 253 */ + { + {2, 0x02, 10}, + {9, 0x02, 10}, + {23, 0x02, 10}, + {40, 0x03, 10}, + {2, 0x02, 13}, + {9, 0x02, 13}, + {23, 0x02, 13}, + {40, 0x03, 13}, + {2, 0x02, 22}, + {9, 0x02, 22}, + {23, 0x02, 22}, + {40, 0x03, 22}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + }, + /* 254 */ + { + {3, 0x02, 10}, + {6, 0x02, 10}, + {10, 0x02, 10}, + {15, 0x02, 10}, + {24, 0x02, 10}, + {31, 0x02, 10}, + {41, 0x02, 10}, + {56, 0x03, 10}, + {3, 0x02, 13}, + {6, 0x02, 13}, + {10, 0x02, 13}, + {15, 0x02, 13}, + {24, 0x02, 13}, + {31, 0x02, 13}, + {41, 0x02, 13}, + {56, 0x03, 13}, + }, + /* 255 */ + { + {3, 0x02, 22}, + {6, 0x02, 22}, + {10, 0x02, 22}, + {15, 0x02, 22}, + {24, 0x02, 22}, + {31, 0x02, 22}, + {41, 0x02, 22}, + {56, 0x03, 22}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + }, +}; diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_helper.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_helper.c new file mode 100644 index 00000000..8d80eb98 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_helper.c @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_helper.h" + +#include +#include + +#include "nghttp2_net.h" + +void nghttp2_put_uint16be(uint8_t *buf, uint16_t n) { + uint16_t x = nghttp2_htons(n); + memcpy(buf, &x, sizeof(uint16_t)); +} + +void nghttp2_put_uint32be(uint8_t *buf, uint32_t n) { + uint32_t x = nghttp2_htonl(n); + memcpy(buf, &x, sizeof(uint32_t)); +} + +uint16_t nghttp2_get_uint16(const uint8_t *data) { + uint16_t n; + memcpy(&n, data, sizeof(uint16_t)); + return nghttp2_ntohs(n); +} + +uint32_t nghttp2_get_uint32(const uint8_t *data) { + uint32_t n; + memcpy(&n, data, sizeof(uint32_t)); + return nghttp2_ntohl(n); +} + +/* Generated by gendowncasetbl.py */ +static const uint8_t DOWNCASE_TBL[] = { + 0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */, + 4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */, + 8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */, + 12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */, + 16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */, + 20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */, + 24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */, + 28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */, + 32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */, + 36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */, + 40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */, + 44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */, + 48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */, + 52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */, + 56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */, + 60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */, + 64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */, + 100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */, + 104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */, + 108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */, + 112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */, + 116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */, + 120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */, + 92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */, + 96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */, + 100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */, + 104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */, + 108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */, + 112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */, + 116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */, + 120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */, + 124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */, + 128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */, + 132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */, + 136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8a */, 139 /* 0x8b */, + 140 /* 0x8c */, 141 /* 0x8d */, 142 /* 0x8e */, 143 /* 0x8f */, + 144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */, + 148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */, + 152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9a */, 155 /* 0x9b */, + 156 /* 0x9c */, 157 /* 0x9d */, 158 /* 0x9e */, 159 /* 0x9f */, + 160 /* 0xa0 */, 161 /* 0xa1 */, 162 /* 0xa2 */, 163 /* 0xa3 */, + 164 /* 0xa4 */, 165 /* 0xa5 */, 166 /* 0xa6 */, 167 /* 0xa7 */, + 168 /* 0xa8 */, 169 /* 0xa9 */, 170 /* 0xaa */, 171 /* 0xab */, + 172 /* 0xac */, 173 /* 0xad */, 174 /* 0xae */, 175 /* 0xaf */, + 176 /* 0xb0 */, 177 /* 0xb1 */, 178 /* 0xb2 */, 179 /* 0xb3 */, + 180 /* 0xb4 */, 181 /* 0xb5 */, 182 /* 0xb6 */, 183 /* 0xb7 */, + 184 /* 0xb8 */, 185 /* 0xb9 */, 186 /* 0xba */, 187 /* 0xbb */, + 188 /* 0xbc */, 189 /* 0xbd */, 190 /* 0xbe */, 191 /* 0xbf */, + 192 /* 0xc0 */, 193 /* 0xc1 */, 194 /* 0xc2 */, 195 /* 0xc3 */, + 196 /* 0xc4 */, 197 /* 0xc5 */, 198 /* 0xc6 */, 199 /* 0xc7 */, + 200 /* 0xc8 */, 201 /* 0xc9 */, 202 /* 0xca */, 203 /* 0xcb */, + 204 /* 0xcc */, 205 /* 0xcd */, 206 /* 0xce */, 207 /* 0xcf */, + 208 /* 0xd0 */, 209 /* 0xd1 */, 210 /* 0xd2 */, 211 /* 0xd3 */, + 212 /* 0xd4 */, 213 /* 0xd5 */, 214 /* 0xd6 */, 215 /* 0xd7 */, + 216 /* 0xd8 */, 217 /* 0xd9 */, 218 /* 0xda */, 219 /* 0xdb */, + 220 /* 0xdc */, 221 /* 0xdd */, 222 /* 0xde */, 223 /* 0xdf */, + 224 /* 0xe0 */, 225 /* 0xe1 */, 226 /* 0xe2 */, 227 /* 0xe3 */, + 228 /* 0xe4 */, 229 /* 0xe5 */, 230 /* 0xe6 */, 231 /* 0xe7 */, + 232 /* 0xe8 */, 233 /* 0xe9 */, 234 /* 0xea */, 235 /* 0xeb */, + 236 /* 0xec */, 237 /* 0xed */, 238 /* 0xee */, 239 /* 0xef */, + 240 /* 0xf0 */, 241 /* 0xf1 */, 242 /* 0xf2 */, 243 /* 0xf3 */, + 244 /* 0xf4 */, 245 /* 0xf5 */, 246 /* 0xf6 */, 247 /* 0xf7 */, + 248 /* 0xf8 */, 249 /* 0xf9 */, 250 /* 0xfa */, 251 /* 0xfb */, + 252 /* 0xfc */, 253 /* 0xfd */, 254 /* 0xfe */, 255 /* 0xff */, +}; + +void nghttp2_downcase(uint8_t *s, size_t len) { + size_t i; + for (i = 0; i < len; ++i) { + s[i] = DOWNCASE_TBL[s[i]]; + } +} + +/* + * local_window_size + * ^ * + * | * recv_window_size + * | * * ^ + * | * * | + * 0+++++++++ + * | * * \ + * | * * | This rage is hidden in flow control. But it must be + * v * * / kept in order to restore it when window size is enlarged. + * recv_reduction + * (+ for negative direction) + * + * recv_window_size could be negative if we decrease + * local_window_size more than recv_window_size: + * + * local_window_size + * ^ * + * | * + * | * + * 0++++++++ + * | * ^ recv_window_size (negative) + * | * | + * v * * + * recv_reduction + */ +int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr, + int32_t *recv_window_size_ptr, + int32_t *recv_reduction_ptr, + int32_t *delta_ptr) { + if (*delta_ptr > 0) { + int32_t recv_reduction_delta; + int32_t delta; + int32_t new_recv_window_size = + nghttp2_max(0, *recv_window_size_ptr) - *delta_ptr; + + if (new_recv_window_size >= 0) { + *recv_window_size_ptr = new_recv_window_size; + return 0; + } + + delta = -new_recv_window_size; + + /* The delta size is strictly more than received bytes. Increase + local_window_size by that difference |delta|. */ + if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) { + return NGHTTP2_ERR_FLOW_CONTROL; + } + *local_window_size_ptr += delta; + /* If there is recv_reduction due to earlier window_size + reduction, we have to adjust it too. */ + recv_reduction_delta = nghttp2_min(*recv_reduction_ptr, delta); + *recv_reduction_ptr -= recv_reduction_delta; + if (*recv_window_size_ptr < 0) { + *recv_window_size_ptr += recv_reduction_delta; + } else { + /* If *recv_window_size_ptr > 0, then those bytes are going to + be returned to the remote peer (by WINDOW_UPDATE with the + adjusted *delta_ptr), so it is effectively 0 now. We set to + *recv_reduction_delta, because caller does not take into + account it in *delta_ptr. */ + *recv_window_size_ptr = recv_reduction_delta; + } + /* recv_reduction_delta must be paid from *delta_ptr, since it was + added in window size reduction (see below). */ + *delta_ptr -= recv_reduction_delta; + + return 0; + } + + if (*local_window_size_ptr + *delta_ptr < 0 || + *recv_window_size_ptr < INT32_MIN - *delta_ptr || + *recv_reduction_ptr > INT32_MAX + *delta_ptr) { + return NGHTTP2_ERR_FLOW_CONTROL; + } + /* Decreasing local window size. Note that we achieve this without + noticing to the remote peer. To do this, we cut + recv_window_size by -delta. This means that we don't send + WINDOW_UPDATE for -delta bytes. */ + *local_window_size_ptr += *delta_ptr; + *recv_window_size_ptr += *delta_ptr; + *recv_reduction_ptr -= *delta_ptr; + *delta_ptr = 0; + + return 0; +} + +int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr, + int32_t *recv_window_size_ptr, + int32_t *recv_reduction_ptr, + int32_t *delta_ptr) { + int32_t recv_reduction_delta; + int32_t delta; + + delta = *delta_ptr; + + assert(delta >= 0); + + /* The delta size is strictly more than received bytes. Increase + local_window_size by that difference |delta|. */ + if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) { + return NGHTTP2_ERR_FLOW_CONTROL; + } + + *local_window_size_ptr += delta; + /* If there is recv_reduction due to earlier window_size + reduction, we have to adjust it too. */ + recv_reduction_delta = nghttp2_min(*recv_reduction_ptr, delta); + *recv_reduction_ptr -= recv_reduction_delta; + + *recv_window_size_ptr += recv_reduction_delta; + + /* recv_reduction_delta must be paid from *delta_ptr, since it was + added in window size reduction (see below). */ + *delta_ptr -= recv_reduction_delta; + + return 0; +} + +int nghttp2_should_send_window_update(int32_t local_window_size, + int32_t recv_window_size) { + return recv_window_size > 0 && recv_window_size >= local_window_size / 2; +} + +const char *nghttp2_strerror(int error_code) { + switch (error_code) { + case 0: + return "Success"; + case NGHTTP2_ERR_INVALID_ARGUMENT: + return "Invalid argument"; + case NGHTTP2_ERR_BUFFER_ERROR: + return "Out of buffer space"; + case NGHTTP2_ERR_UNSUPPORTED_VERSION: + return "Unsupported SPDY version"; + case NGHTTP2_ERR_WOULDBLOCK: + return "Operation would block"; + case NGHTTP2_ERR_PROTO: + return "Protocol error"; + case NGHTTP2_ERR_INVALID_FRAME: + return "Invalid frame octets"; + case NGHTTP2_ERR_EOF: + return "EOF"; + case NGHTTP2_ERR_DEFERRED: + return "Data transfer deferred"; + case NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE: + return "No more Stream ID available"; + case NGHTTP2_ERR_STREAM_CLOSED: + return "Stream was already closed or invalid"; + case NGHTTP2_ERR_STREAM_CLOSING: + return "Stream is closing"; + case NGHTTP2_ERR_STREAM_SHUT_WR: + return "The transmission is not allowed for this stream"; + case NGHTTP2_ERR_INVALID_STREAM_ID: + return "Stream ID is invalid"; + case NGHTTP2_ERR_INVALID_STREAM_STATE: + return "Invalid stream state"; + case NGHTTP2_ERR_DEFERRED_DATA_EXIST: + return "Another DATA frame has already been deferred"; + case NGHTTP2_ERR_START_STREAM_NOT_ALLOWED: + return "request HEADERS is not allowed"; + case NGHTTP2_ERR_GOAWAY_ALREADY_SENT: + return "GOAWAY has already been sent"; + case NGHTTP2_ERR_INVALID_HEADER_BLOCK: + return "Invalid header block"; + case NGHTTP2_ERR_INVALID_STATE: + return "Invalid state"; + case NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE: + return "The user callback function failed due to the temporal error"; + case NGHTTP2_ERR_FRAME_SIZE_ERROR: + return "The length of the frame is invalid"; + case NGHTTP2_ERR_HEADER_COMP: + return "Header compression/decompression error"; + case NGHTTP2_ERR_FLOW_CONTROL: + return "Flow control error"; + case NGHTTP2_ERR_INSUFF_BUFSIZE: + return "Insufficient buffer size given to function"; + case NGHTTP2_ERR_PAUSE: + return "Callback was paused by the application"; + case NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS: + return "Too many inflight SETTINGS"; + case NGHTTP2_ERR_PUSH_DISABLED: + return "Server push is disabled by peer"; + case NGHTTP2_ERR_DATA_EXIST: + return "DATA or HEADERS frame has already been submitted for the stream"; + case NGHTTP2_ERR_SESSION_CLOSING: + return "The current session is closing"; + case NGHTTP2_ERR_HTTP_HEADER: + return "Invalid HTTP header field was received"; + case NGHTTP2_ERR_HTTP_MESSAGING: + return "Violation in HTTP messaging rule"; + case NGHTTP2_ERR_REFUSED_STREAM: + return "Stream was refused"; + case NGHTTP2_ERR_INTERNAL: + return "Internal error"; + case NGHTTP2_ERR_CANCEL: + return "Cancel"; + case NGHTTP2_ERR_SETTINGS_EXPECTED: + return "When a local endpoint expects to receive SETTINGS frame, it " + "receives an other type of frame"; + case NGHTTP2_ERR_NOMEM: + return "Out of memory"; + case NGHTTP2_ERR_CALLBACK_FAILURE: + return "The user callback function failed"; + case NGHTTP2_ERR_BAD_CLIENT_MAGIC: + return "Received bad client magic byte string"; + case NGHTTP2_ERR_FLOODED: + return "Flooding was detected in this HTTP/2 session, and it must be " + "closed"; + default: + return "Unknown error code"; + } +} + +/* Generated by gennmchartbl.py */ +static int VALID_HD_NAME_CHARS[] = { + 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, + 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, + 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, + 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, + 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, + 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, + 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, + 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, + 0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */, + 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, + 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, + 0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, + 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, + 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, + 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, + 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, + 0 /* @ */, 0 /* A */, 0 /* B */, 0 /* C */, + 0 /* D */, 0 /* E */, 0 /* F */, 0 /* G */, + 0 /* H */, 0 /* I */, 0 /* J */, 0 /* K */, + 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */, + 0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, + 0 /* T */, 0 /* U */, 0 /* V */, 0 /* W */, + 0 /* X */, 0 /* Y */, 0 /* Z */, 0 /* [ */, + 0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */, + 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, + 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, + 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, + 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, + 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, + 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, + 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, + 1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, + 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, + 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, + 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, + 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, + 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, + 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, + 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, + 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, + 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, + 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, + 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, + 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, + 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, + 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, + 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, + 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, + 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, + 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, + 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, + 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, + 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, + 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, + 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, + 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, + 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, + 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, + 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, + 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, + 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, + 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, + 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, + 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ +}; + +int nghttp2_check_header_name(const uint8_t *name, size_t len) { + const uint8_t *last; + if (len == 0) { + return 0; + } + if (*name == ':') { + if (len == 1) { + return 0; + } + ++name; + --len; + } + for (last = name + len; name != last; ++name) { + if (!VALID_HD_NAME_CHARS[*name]) { + return 0; + } + } + return 1; +} + +/* Generated by genvchartbl.py */ +static int VALID_HD_VALUE_CHARS[] = { + 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, + 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, + 0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */, + 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, + 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, + 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, + 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, + 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, + 1 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */, + 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, + 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, + 1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */, + 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, + 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, + 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, + 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, + 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, + 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, + 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, + 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, + 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, + 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, + 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, + 1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */, + 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, + 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, + 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, + 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, + 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, + 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, + 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, + 1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */, + 1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */, + 1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */, + 1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */, + 1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */, + 1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */, + 1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */, + 1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */, + 1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */, + 1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */, + 1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */, + 1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */, + 1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */, + 1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */, + 1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */, + 1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */, + 1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */, + 1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */, + 1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */, + 1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */, + 1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */, + 1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */, + 1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */, + 1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */, + 1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */, + 1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */, + 1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */, + 1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */, + 1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */, + 1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */, + 1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */, + 1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */, + 1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */ +}; + +int nghttp2_check_header_value(const uint8_t *value, size_t len) { + const uint8_t *last; + for (last = value + len; value != last; ++value) { + if (!VALID_HD_VALUE_CHARS[*value]) { + return 0; + } + } + return 1; +} + +uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len) { + if (len == 0) { + return dest; + } + + memcpy(dest, src, len); + + return dest + len; +} + +const char *nghttp2_http2_strerror(uint32_t error_code) { + switch (error_code) { + case NGHTTP2_NO_ERROR: + return "NO_ERROR"; + case NGHTTP2_PROTOCOL_ERROR: + return "PROTOCOL_ERROR"; + case NGHTTP2_INTERNAL_ERROR: + return "INTERNAL_ERROR"; + case NGHTTP2_FLOW_CONTROL_ERROR: + return "FLOW_CONTROL_ERROR"; + case NGHTTP2_SETTINGS_TIMEOUT: + return "SETTINGS_TIMEOUT"; + case NGHTTP2_STREAM_CLOSED: + return "STREAM_CLOSED"; + case NGHTTP2_FRAME_SIZE_ERROR: + return "FRAME_SIZE_ERROR"; + case NGHTTP2_REFUSED_STREAM: + return "REFUSED_STREAM"; + case NGHTTP2_CANCEL: + return "CANCEL"; + case NGHTTP2_COMPRESSION_ERROR: + return "COMPRESSION_ERROR"; + case NGHTTP2_CONNECT_ERROR: + return "CONNECT_ERROR"; + case NGHTTP2_ENHANCE_YOUR_CALM: + return "ENHANCE_YOUR_CALM"; + case NGHTTP2_INADEQUATE_SECURITY: + return "INADEQUATE_SECURITY"; + case NGHTTP2_HTTP_1_1_REQUIRED: + return "HTTP_1_1_REQUIRED"; + default: + return "unknown"; + } +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_helper.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_helper.h new file mode 100644 index 00000000..be85fd2f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_helper.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_HELPER_H +#define NGHTTP2_HELPER_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#include "nghttp2.h" +#include "nghttp2_mem.h" + +#define nghttp2_min(A, B) ((A) < (B) ? (A) : (B)) +#define nghttp2_max(A, B) ((A) > (B) ? (A) : (B)) + +#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0) + +#define nghttp2_struct_of(ptr, type, member) \ + ((type *)(void *)((char *)(ptr)-offsetof(type, member))) + +/* + * Copies 2 byte unsigned integer |n| in host byte order to |buf| in + * network byte order. + */ +void nghttp2_put_uint16be(uint8_t *buf, uint16_t n); + +/* + * Copies 4 byte unsigned integer |n| in host byte order to |buf| in + * network byte order. + */ +void nghttp2_put_uint32be(uint8_t *buf, uint32_t n); + +/* + * Retrieves 2 byte unsigned integer stored in |data| in network byte + * order and returns it in host byte order. + */ +uint16_t nghttp2_get_uint16(const uint8_t *data); + +/* + * Retrieves 4 byte unsigned integer stored in |data| in network byte + * order and returns it in host byte order. + */ +uint32_t nghttp2_get_uint32(const uint8_t *data); + +void nghttp2_downcase(uint8_t *s, size_t len); + +/* + * Adjusts |*local_window_size_ptr|, |*recv_window_size_ptr|, + * |*recv_reduction_ptr| with |*delta_ptr| which is the + * WINDOW_UPDATE's window_size_increment sent from local side. If + * |delta| is strictly larger than |*recv_window_size_ptr|, + * |*local_window_size_ptr| is increased by delta - + * *recv_window_size_ptr. If |delta| is negative, + * |*local_window_size_ptr| is decreased by delta. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_FLOW_CONTROL + * local_window_size overflow or gets negative. + */ +int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr, + int32_t *recv_window_size_ptr, + int32_t *recv_reduction_ptr, + int32_t *delta_ptr); + +/* + * This function works like nghttp2_adjust_local_window_size(). The + * difference is that this function assumes *delta_ptr >= 0, and + * *recv_window_size_ptr is not decreased by *delta_ptr. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_FLOW_CONTROL + * local_window_size overflow or gets negative. + */ +int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr, + int32_t *recv_window_size_ptr, + int32_t *recv_reduction_ptr, + int32_t *delta_ptr); + +/* + * Returns non-zero if the function decided that WINDOW_UPDATE should + * be sent. + */ +int nghttp2_should_send_window_update(int32_t local_window_size, + int32_t recv_window_size); + +/* + * Copies the buffer |src| of length |len| to the destination pointed + * by the |dest|, assuming that the |dest| is at lest |len| bytes long + * . Returns dest + len. + */ +uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len); + +#endif /* NGHTTP2_HELPER_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_http.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_http.c new file mode 100644 index 00000000..49caa100 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_http.c @@ -0,0 +1,577 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_http.h" + +#include +#include +#include + +#include "nghttp2_hd.h" +#include "nghttp2_helper.h" + +static uint8_t downcase(uint8_t c) { + return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c; +} + +static int memieq(const void *a, const void *b, size_t n) { + size_t i; + const uint8_t *aa = a, *bb = b; + + for (i = 0; i < n; ++i) { + if (downcase(aa[i]) != downcase(bb[i])) { + return 0; + } + } + return 1; +} + +#define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N))) + +static int64_t parse_uint(const uint8_t *s, size_t len) { + int64_t n = 0; + size_t i; + if (len == 0) { + return -1; + } + for (i = 0; i < len; ++i) { + if ('0' <= s[i] && s[i] <= '9') { + if (n > INT64_MAX / 10) { + return -1; + } + n *= 10; + if (n > INT64_MAX - (s[i] - '0')) { + return -1; + } + n += s[i] - '0'; + continue; + } + return -1; + } + return n; +} + +static int lws(const uint8_t *s, size_t n) { + size_t i; + for (i = 0; i < n; ++i) { + if (s[i] != ' ' && s[i] != '\t') { + return 0; + } + } + return 1; +} + +static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv, + int flag) { + if (stream->http_flags & flag) { + return 0; + } + if (lws(nv->value->base, nv->value->len)) { + return 0; + } + stream->http_flags = (uint16_t)(stream->http_flags | flag); + return 1; +} + +static int expect_response_body(nghttp2_stream *stream) { + return (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_HEAD) == 0 && + stream->status_code / 100 != 1 && stream->status_code != 304 && + stream->status_code != 204; +} + +/* For "http" or "https" URIs, OPTIONS request may have "*" in :path + header field to represent system-wide OPTIONS request. Otherwise, + :path header field value must start with "/". This function must + be called after ":method" header field was received. This function + returns nonzero if path is valid.*/ +static int check_path(nghttp2_stream *stream) { + return (stream->http_flags & NGHTTP2_HTTP_FLAG_SCHEME_HTTP) == 0 || + ((stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_REGULAR) || + ((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_OPTIONS) && + (stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_ASTERISK))); +} + +static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, + int trailer) { + if (nv->name->base[0] == ':') { + if (trailer || + (stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + } + + switch (nv->token) { + case NGHTTP2_TOKEN__AUTHORITY: + if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + break; + case NGHTTP2_TOKEN__METHOD: + if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__METHOD)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + switch (nv->value->len) { + case 4: + if (lstreq("HEAD", nv->value->base, nv->value->len)) { + stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD; + } + break; + case 7: + switch (nv->value->base[6]) { + case 'T': + if (lstreq("CONNECT", nv->value->base, nv->value->len)) { + if (stream->stream_id % 2 == 0) { + /* we won't allow CONNECT for push */ + return NGHTTP2_ERR_HTTP_HEADER; + } + stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT; + if (stream->http_flags & + (NGHTTP2_HTTP_FLAG__PATH | NGHTTP2_HTTP_FLAG__SCHEME)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + } + break; + case 'S': + if (lstreq("OPTIONS", nv->value->base, nv->value->len)) { + stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_OPTIONS; + } + break; + } + break; + } + break; + case NGHTTP2_TOKEN__PATH: + if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) { + return NGHTTP2_ERR_HTTP_HEADER; + } + if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + if (nv->value->base[0] == '/') { + stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_REGULAR; + } else if (nv->value->len == 1 && nv->value->base[0] == '*') { + stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_ASTERISK; + } + break; + case NGHTTP2_TOKEN__SCHEME: + if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) { + return NGHTTP2_ERR_HTTP_HEADER; + } + if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + if ((nv->value->len == 4 && memieq("http", nv->value->base, 4)) || + (nv->value->len == 5 && memieq("https", nv->value->base, 5))) { + stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP; + } + break; + case NGHTTP2_TOKEN_HOST: + if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + break; + case NGHTTP2_TOKEN_CONTENT_LENGTH: { + if (stream->content_length != -1) { + return NGHTTP2_ERR_HTTP_HEADER; + } + stream->content_length = parse_uint(nv->value->base, nv->value->len); + if (stream->content_length == -1) { + return NGHTTP2_ERR_HTTP_HEADER; + } + break; + } + /* disallowed header fields */ + case NGHTTP2_TOKEN_CONNECTION: + case NGHTTP2_TOKEN_KEEP_ALIVE: + case NGHTTP2_TOKEN_PROXY_CONNECTION: + case NGHTTP2_TOKEN_TRANSFER_ENCODING: + case NGHTTP2_TOKEN_UPGRADE: + return NGHTTP2_ERR_HTTP_HEADER; + case NGHTTP2_TOKEN_TE: + if (!lstrieq("trailers", nv->value->base, nv->value->len)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + break; + default: + if (nv->name->base[0] == ':') { + return NGHTTP2_ERR_HTTP_HEADER; + } + } + + if (nv->name->base[0] != ':') { + stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED; + } + + return 0; +} + +static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, + int trailer) { + if (nv->name->base[0] == ':') { + if (trailer || + (stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + } + + switch (nv->token) { + case NGHTTP2_TOKEN__STATUS: { + if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__STATUS)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + if (nv->value->len != 3) { + return NGHTTP2_ERR_HTTP_HEADER; + } + stream->status_code = (int16_t)parse_uint(nv->value->base, nv->value->len); + if (stream->status_code == -1 || stream->status_code == 101) { + return NGHTTP2_ERR_HTTP_HEADER; + } + break; + } + case NGHTTP2_TOKEN_CONTENT_LENGTH: { + if (stream->status_code == 204) { + /* content-length header field in 204 response is prohibited by + RFC 7230. But some widely used servers send content-length: + 0. Until they get fixed, we ignore it. */ + if (stream->content_length != -1) { + /* Found multiple content-length field */ + return NGHTTP2_ERR_HTTP_HEADER; + } + if (!lstrieq("0", nv->value->base, nv->value->len)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + stream->content_length = 0; + return NGHTTP2_ERR_REMOVE_HTTP_HEADER; + } + if (stream->status_code / 100 == 1 || + (stream->status_code == 200 && + (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT))) { + return NGHTTP2_ERR_HTTP_HEADER; + } + if (stream->content_length != -1) { + return NGHTTP2_ERR_HTTP_HEADER; + } + stream->content_length = parse_uint(nv->value->base, nv->value->len); + if (stream->content_length == -1) { + return NGHTTP2_ERR_HTTP_HEADER; + } + break; + } + /* disallowed header fields */ + case NGHTTP2_TOKEN_CONNECTION: + case NGHTTP2_TOKEN_KEEP_ALIVE: + case NGHTTP2_TOKEN_PROXY_CONNECTION: + case NGHTTP2_TOKEN_TRANSFER_ENCODING: + case NGHTTP2_TOKEN_UPGRADE: + return NGHTTP2_ERR_HTTP_HEADER; + case NGHTTP2_TOKEN_TE: + if (!lstrieq("trailers", nv->value->base, nv->value->len)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + break; + default: + if (nv->name->base[0] == ':') { + return NGHTTP2_ERR_HTTP_HEADER; + } + } + + if (nv->name->base[0] != ':') { + stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED; + } + + return 0; +} + +/* Generated by genauthroitychartbl.py */ +static char VALID_AUTHORITY_CHARS[] = { + 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, + 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, + 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, + 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, + 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, + 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, + 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, + 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, + 0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */, + 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, + 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, + 1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, + 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, + 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, + 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, + 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, + 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, + 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, + 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, + 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, + 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, + 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, + 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, + 0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */, + 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, + 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, + 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, + 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, + 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, + 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, + 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, + 0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, + 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, + 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, + 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, + 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, + 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, + 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, + 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, + 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, + 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, + 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, + 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, + 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, + 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, + 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, + 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, + 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, + 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, + 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, + 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, + 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, + 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, + 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, + 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, + 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, + 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, + 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, + 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, + 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, + 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, + 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, + 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, + 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ +}; + +static int check_authority(const uint8_t *value, size_t len) { + const uint8_t *last; + for (last = value + len; value != last; ++value) { + if (!VALID_AUTHORITY_CHARS[*value]) { + return 0; + } + } + return 1; +} + +static int check_scheme(const uint8_t *value, size_t len) { + const uint8_t *last; + if (len == 0) { + return 0; + } + + if (!(('A' <= *value && *value <= 'Z') || ('a' <= *value && *value <= 'z'))) { + return 0; + } + + last = value + len; + ++value; + + for (; value != last; ++value) { + if (!(('A' <= *value && *value <= 'Z') || + ('a' <= *value && *value <= 'z') || + ('0' <= *value && *value <= '9') || *value == '+' || *value == '-' || + *value == '.')) { + return 0; + } + } + return 1; +} + +int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream, + nghttp2_frame *frame, nghttp2_hd_nv *nv, + int trailer) { + int rv; + + /* We are strict for pseudo header field. One bad character should + lead to fail. OTOH, we should be a bit forgiving for regular + headers, since existing public internet has so much illegal + headers floating around and if we kill the stream because of + this, we may disrupt many web sites and/or libraries. So we + become conservative here, and just ignore those illegal regular + headers. */ + if (!nghttp2_check_header_name(nv->name->base, nv->name->len)) { + size_t i; + if (nv->name->len > 0 && nv->name->base[0] == ':') { + return NGHTTP2_ERR_HTTP_HEADER; + } + /* header field name must be lower-cased without exception */ + for (i = 0; i < nv->name->len; ++i) { + uint8_t c = nv->name->base[i]; + if ('A' <= c && c <= 'Z') { + return NGHTTP2_ERR_HTTP_HEADER; + } + } + /* When ignoring regular headers, we set this flag so that we + still enforce header field ordering rule for pseudo header + fields. */ + stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED; + return NGHTTP2_ERR_IGN_HTTP_HEADER; + } + + if (nv->token == NGHTTP2_TOKEN__AUTHORITY || + nv->token == NGHTTP2_TOKEN_HOST) { + rv = check_authority(nv->value->base, nv->value->len); + } else if (nv->token == NGHTTP2_TOKEN__SCHEME) { + rv = check_scheme(nv->value->base, nv->value->len); + } else { + rv = nghttp2_check_header_value(nv->value->base, nv->value->len); + } + + if (rv == 0) { + assert(nv->name->len > 0); + if (nv->name->base[0] == ':') { + return NGHTTP2_ERR_HTTP_HEADER; + } + /* When ignoring regular headers, we set this flag so that we + still enforce header field ordering rule for pseudo header + fields. */ + stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED; + return NGHTTP2_ERR_IGN_HTTP_HEADER; + } + + if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) { + return http_request_on_header(stream, nv, trailer); + } + + return http_response_on_header(stream, nv, trailer); +} + +int nghttp2_http_on_request_headers(nghttp2_stream *stream, + nghttp2_frame *frame) { + if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) { + if ((stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0) { + return -1; + } + stream->content_length = -1; + } else { + if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) != + NGHTTP2_HTTP_FLAG_REQ_HEADERS || + (stream->http_flags & + (NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) { + return -1; + } + if (!check_path(stream)) { + return -1; + } + } + + if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { + /* we are going to reuse data fields for upcoming response. Clear + them now, except for method flags. */ + stream->http_flags &= NGHTTP2_HTTP_FLAG_METH_ALL; + stream->content_length = -1; + } + + return 0; +} + +int nghttp2_http_on_response_headers(nghttp2_stream *stream) { + if ((stream->http_flags & NGHTTP2_HTTP_FLAG__STATUS) == 0) { + return -1; + } + + if (stream->status_code / 100 == 1) { + /* non-final response */ + stream->http_flags = + (uint16_t)((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) | + NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE); + stream->content_length = -1; + stream->status_code = -1; + return 0; + } + + stream->http_flags = + (uint16_t)(stream->http_flags & ~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE); + + if (!expect_response_body(stream)) { + stream->content_length = 0; + } else if (stream->http_flags & (NGHTTP2_HTTP_FLAG_METH_CONNECT | + NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND)) { + stream->content_length = -1; + } + + return 0; +} + +int nghttp2_http_on_trailer_headers(nghttp2_stream *stream, + nghttp2_frame *frame) { + (void)stream; + + if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) { + return -1; + } + + return 0; +} + +int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream) { + if (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) { + return -1; + } + + if (stream->content_length != -1 && + stream->content_length != stream->recv_content_length) { + return -1; + } + + return 0; +} + +int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n) { + stream->recv_content_length += (int64_t)n; + + if ((stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) || + (stream->content_length != -1 && + stream->recv_content_length > stream->content_length)) { + return -1; + } + + return 0; +} + +void nghttp2_http_record_request_method(nghttp2_stream *stream, + nghttp2_frame *frame) { + const nghttp2_nv *nva; + size_t nvlen; + size_t i; + + switch (frame->hd.type) { + case NGHTTP2_HEADERS: + nva = frame->headers.nva; + nvlen = frame->headers.nvlen; + break; + case NGHTTP2_PUSH_PROMISE: + nva = frame->push_promise.nva; + nvlen = frame->push_promise.nvlen; + break; + default: + return; + } + + /* TODO we should do this strictly. */ + for (i = 0; i < nvlen; ++i) { + const nghttp2_nv *nv = &nva[i]; + if (!(nv->namelen == 7 && nv->name[6] == 'd' && + memcmp(":metho", nv->name, nv->namelen - 1) == 0)) { + continue; + } + if (lstreq("CONNECT", nv->value, nv->valuelen)) { + stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT; + return; + } + if (lstreq("HEAD", nv->value, nv->valuelen)) { + stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD; + return; + } + return; + } +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_http.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_http.h new file mode 100644 index 00000000..bde7023d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_http.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_HTTP_H +#define NGHTTP2_HTTP_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" +#include "nghttp2_session.h" +#include "nghttp2_stream.h" + +/* + * This function is called when HTTP header field |nv| in |frame| is + * received for |stream|. This function will validate |nv| against + * the current state of stream. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_HTTP_HEADER + * Invalid HTTP header field was received. + * NGHTTP2_ERR_IGN_HTTP_HEADER + * Invalid HTTP header field was received but it can be treated as + * if it was not received because of compatibility reasons. + */ +int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream, + nghttp2_frame *frame, nghttp2_hd_nv *nv, + int trailer); + +/* + * This function is called when request header is received. This + * function performs validation and returns 0 if it succeeds, or -1. + */ +int nghttp2_http_on_request_headers(nghttp2_stream *stream, + nghttp2_frame *frame); + +/* + * This function is called when response header is received. This + * function performs validation and returns 0 if it succeeds, or -1. + */ +int nghttp2_http_on_response_headers(nghttp2_stream *stream); + +/* + * This function is called trailer header (for both request and + * response) is received. This function performs validation and + * returns 0 if it succeeds, or -1. + */ +int nghttp2_http_on_trailer_headers(nghttp2_stream *stream, + nghttp2_frame *frame); + +/* + * This function is called when END_STREAM flag is seen in incoming + * frame. This function performs validation and returns 0 if it + * succeeds, or -1. + */ +int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream); + +/* + * This function is called when chunk of data is received. This + * function performs validation and returns 0 if it succeeds, or -1. + */ +int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n); + +/* + * This function inspects header field in |frame| and records its + * method in stream->http_flags. If frame->hd.type is neither + * NGHTTP2_HEADERS nor NGHTTP2_PUSH_PROMISE, this function does + * nothing. + */ +void nghttp2_http_record_request_method(nghttp2_stream *stream, + nghttp2_frame *frame); + +#endif /* NGHTTP2_HTTP_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_int.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_int.h new file mode 100644 index 00000000..56c071a4 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_int.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_INT_H +#define NGHTTP2_INT_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +/* Macros, types and constants for internal use */ + +/* "less" function, return nonzero if |lhs| is less than |rhs|. */ +typedef int (*nghttp2_less)(const void *lhs, const void *rhs); + +/* Internal error code. They must be in the range [-499, -100], + inclusive. */ +typedef enum { + NGHTTP2_ERR_CREDENTIAL_PENDING = -101, + NGHTTP2_ERR_IGN_HEADER_BLOCK = -103, + NGHTTP2_ERR_IGN_PAYLOAD = -104, + /* + * Invalid HTTP header field was received but it can be treated as + * if it was not received because of compatibility reasons. + */ + NGHTTP2_ERR_IGN_HTTP_HEADER = -105, + /* + * Invalid HTTP header field was received, and it is ignored. + * Unlike NGHTTP2_ERR_IGN_HTTP_HEADER, this does not invoke + * nghttp2_on_invalid_header_callback. + */ + NGHTTP2_ERR_REMOVE_HTTP_HEADER = -106 +} nghttp2_internal_error; + +#endif /* NGHTTP2_INT_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_map.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_map.c new file mode 100644 index 00000000..9de8299a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_map.c @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_map.h" + +#include + +#define INITIAL_TABLE_LENGTH 256 + +int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) { + map->mem = mem; + map->tablelen = INITIAL_TABLE_LENGTH; + map->table = + nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_entry *)); + if (map->table == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + map->size = 0; + + return 0; +} + +void nghttp2_map_free(nghttp2_map *map) { + nghttp2_mem_free(map->mem, map->table); +} + +void nghttp2_map_each_free(nghttp2_map *map, + int (*func)(nghttp2_map_entry *entry, void *ptr), + void *ptr) { + uint32_t i; + for (i = 0; i < map->tablelen; ++i) { + nghttp2_map_entry *entry; + for (entry = map->table[i]; entry;) { + nghttp2_map_entry *next = entry->next; + func(entry, ptr); + entry = next; + } + map->table[i] = NULL; + } +} + +int nghttp2_map_each(nghttp2_map *map, + int (*func)(nghttp2_map_entry *entry, void *ptr), + void *ptr) { + int rv; + uint32_t i; + for (i = 0; i < map->tablelen; ++i) { + nghttp2_map_entry *entry; + for (entry = map->table[i]; entry; entry = entry->next) { + rv = func(entry, ptr); + if (rv != 0) { + return rv; + } + } + } + return 0; +} + +void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key) { + entry->key = key; + entry->next = NULL; +} + +/* Same hash function in android HashMap source code. */ +/* The |mod| must be power of 2 */ +static uint32_t hash(int32_t key, uint32_t mod) { + uint32_t h = (uint32_t)key; + h ^= (h >> 20) ^ (h >> 12); + h ^= (h >> 7) ^ (h >> 4); + return h & (mod - 1); +} + +static int insert(nghttp2_map_entry **table, uint32_t tablelen, + nghttp2_map_entry *entry) { + uint32_t h = hash(entry->key, tablelen); + if (table[h] == NULL) { + table[h] = entry; + } else { + nghttp2_map_entry *p; + /* We won't allow duplicated key, so check it out. */ + for (p = table[h]; p; p = p->next) { + if (p->key == entry->key) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + } + entry->next = table[h]; + table[h] = entry; + } + return 0; +} + +/* new_tablelen must be power of 2 */ +static int resize(nghttp2_map *map, uint32_t new_tablelen) { + uint32_t i; + nghttp2_map_entry **new_table; + + new_table = + nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_entry *)); + if (new_table == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + for (i = 0; i < map->tablelen; ++i) { + nghttp2_map_entry *entry; + for (entry = map->table[i]; entry;) { + nghttp2_map_entry *next = entry->next; + entry->next = NULL; + /* This function must succeed */ + insert(new_table, new_tablelen, entry); + entry = next; + } + } + nghttp2_mem_free(map->mem, map->table); + map->tablelen = new_tablelen; + map->table = new_table; + + return 0; +} + +int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) { + int rv; + /* Load factor is 0.75 */ + if ((map->size + 1) * 4 > map->tablelen * 3) { + rv = resize(map, map->tablelen * 2); + if (rv != 0) { + return rv; + } + } + rv = insert(map->table, map->tablelen, new_entry); + if (rv != 0) { + return rv; + } + ++map->size; + return 0; +} + +nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key) { + uint32_t h; + nghttp2_map_entry *entry; + h = hash(key, map->tablelen); + for (entry = map->table[h]; entry; entry = entry->next) { + if (entry->key == key) { + return entry; + } + } + return NULL; +} + +int nghttp2_map_remove(nghttp2_map *map, key_type key) { + uint32_t h; + nghttp2_map_entry **dst; + + h = hash(key, map->tablelen); + + for (dst = &map->table[h]; *dst; dst = &(*dst)->next) { + if ((*dst)->key != key) { + continue; + } + + *dst = (*dst)->next; + --map->size; + return 0; + } + return NGHTTP2_ERR_INVALID_ARGUMENT; +} + +size_t nghttp2_map_size(nghttp2_map *map) { return map->size; } diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_map.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_map.h new file mode 100644 index 00000000..48096a2d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_map.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_MAP_H +#define NGHTTP2_MAP_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" +#include "nghttp2_int.h" +#include "nghttp2_mem.h" + +/* Implementation of unordered map */ + +typedef int32_t key_type; + +typedef struct nghttp2_map_entry { + struct nghttp2_map_entry *next; + key_type key; +#if SIZEOF_INT_P == 4 + /* we requires 8 bytes aligment */ + int64_t pad; +#endif +} nghttp2_map_entry; + +typedef struct { + nghttp2_map_entry **table; + nghttp2_mem *mem; + size_t size; + uint32_t tablelen; +} nghttp2_map; + +/* + * Initializes the map |map|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem); + +/* + * Deallocates any resources allocated for |map|. The stored entries + * are not freed by this function. Use nghttp2_map_each_free() to free + * each entries. + */ +void nghttp2_map_free(nghttp2_map *map); + +/* + * Deallocates each entries using |func| function and any resources + * allocated for |map|. The |func| function is responsible for freeing + * given the |entry| object. The |ptr| will be passed to the |func| as + * send argument. The return value of the |func| will be ignored. + */ +void nghttp2_map_each_free(nghttp2_map *map, + int (*func)(nghttp2_map_entry *entry, void *ptr), + void *ptr); + +/* + * Initializes the |entry| with the |key|. All entries to be inserted + * to the map must be initialized with this function. + */ +void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key); + +/* + * Inserts the new |entry| with the key |entry->key| to the map |map|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_INVALID_ARGUMENT + * The item associated by |key| already exists. + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry); + +/* + * Returns the entry associated by the key |key|. If there is no such + * entry, this function returns NULL. + */ +nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key); + +/* + * Removes the entry associated by the key |key| from the |map|. The + * removed entry is not freed by this function. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_INVALID_ARGUMENT + * The entry associated by |key| does not exist. + */ +int nghttp2_map_remove(nghttp2_map *map, key_type key); + +/* + * Returns the number of items stored in the map |map|. + */ +size_t nghttp2_map_size(nghttp2_map *map); + +/* + * Applies the function |func| to each entry in the |map| with the + * optional user supplied pointer |ptr|. + * + * If the |func| returns 0, this function calls the |func| with the + * next entry. If the |func| returns nonzero, it will not call the + * |func| for further entries and return the return value of the + * |func| immediately. Thus, this function returns 0 if all the + * invocations of the |func| return 0, or nonzero value which the last + * invocation of |func| returns. + * + * Don't use this function to free each entry. Use + * nghttp2_map_each_free() instead. + */ +int nghttp2_map_each(nghttp2_map *map, + int (*func)(nghttp2_map_entry *entry, void *ptr), + void *ptr); + +#endif /* NGHTTP2_MAP_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_mem.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_mem.c new file mode 100644 index 00000000..5a669731 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_mem.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include +#include "nghttp2_mem.h" +#ifdef INFRA_MEM_STATS +#include "infra_mem_stats.h" +#endif + +extern void *HAL_Malloc(uint32_t size); +extern void *HAL_Realloc(void *ptr, uint32_t size); +extern void HAL_Free(void *ptr); + + +static void *default_malloc(size_t size, void *mem_user_data) +{ + (void)mem_user_data; + +#ifdef INFRA_MEM_STATS + return LITE_malloc(size, MEM_MAGIC, "nghttp2"); +#else + return HAL_Malloc(size); +#endif +} + +static void default_free(void *ptr, void *mem_user_data) +{ + (void)mem_user_data; + if (ptr != NULL) { +#ifdef INFRA_MEM_STATS + LITE_free(ptr); +#else + HAL_Free((void *)ptr); + ptr = NULL; +#endif + } +} + +static void *default_calloc(size_t nmemb, size_t size, void *mem_user_data) +{ + /* (void)mem_user_data; */ + +#ifdef INFRA_MEM_STATS + return LITE_calloc(nmemb, size, MEM_MAGIC, "nghttp2"); +#else + void *ptr = HAL_Malloc(nmemb * size); + if (ptr != NULL) { + memset(ptr, 0, nmemb * size); + } + return ptr; +#endif +} + +static void *default_realloc(void *ptr, size_t size, void *mem_user_data) +{ + (void)mem_user_data; + +#ifdef INFRA_MEM_STATS + return LITE_realloc(ptr, size, MEM_MAGIC, "nghttp2"); +#else + return HAL_Realloc(ptr, size); +#endif +} + +static nghttp2_mem mem_default = {NULL, default_malloc, default_free, + default_calloc, default_realloc + }; + +nghttp2_mem *nghttp2_mem_default(void) +{ + return &mem_default; +} + +void *nghttp2_mem_malloc(nghttp2_mem *mem, size_t size) +{ + return mem->malloc(size, mem->mem_user_data); +} + +void nghttp2_mem_free(nghttp2_mem *mem, void *ptr) +{ + mem->free(ptr, mem->mem_user_data); +} + +void nghttp2_mem_free2(nghttp2_free free_func, void *ptr, void *mem_user_data) +{ + free_func(ptr, mem_user_data); +} + +void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size) +{ + return mem->calloc(nmemb, size, mem->mem_user_data); +} + +void *nghttp2_mem_realloc(nghttp2_mem *mem, void *ptr, size_t size) +{ + return mem->realloc(ptr, size, mem->mem_user_data); +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_mem.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_mem.h new file mode 100644 index 00000000..be33ac5d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_mem.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_MEM_H +#define NGHTTP2_MEM_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" +#ifdef INFRA_MEM_STATS +#include "infra_mem_stats.h" +#endif + +/* The default, system standard memory allocator */ +nghttp2_mem *nghttp2_mem_default(void); + +/* Convenient wrapper functions to call allocator function in + |mem|. */ +void *nghttp2_mem_malloc(nghttp2_mem *mem, size_t size); +void nghttp2_mem_free(nghttp2_mem *mem, void *ptr); +void nghttp2_mem_free2(nghttp2_free free_func, void *ptr, void *mem_user_data); +void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size); +void *nghttp2_mem_realloc(nghttp2_mem *mem, void *ptr, size_t size); + +#endif /* NGHTTP2_MEM_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_net.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_net.c new file mode 100644 index 00000000..c71af3e1 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_net.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include +#include +#include "nghttp2_net.h" + +#if IOT_BYTE_ORDER == LITTLE_ENDIAN + uint32_t nghttp2_htonl(uint32_t hostlong) { + uint32_t res; + unsigned char *p = (unsigned char *)&res; + *p++ = hostlong >> 24; + *p++ = (hostlong >> 16) & 0xffu; + *p++ = (hostlong >> 8) & 0xffu; + *p = hostlong & 0xffu; + return res; +} + +uint16_t nghttp2_htons(uint16_t hostshort) { + uint16_t res; + unsigned char *p = (unsigned char *)&res; + *p++ = hostshort >> 8; + *p = hostshort & 0xffu; + return res; +} + +uint32_t nghttp2_ntohl(uint32_t netlong) { + uint32_t res; + unsigned char *p = (unsigned char *)&netlong; + res = *p++ << 24; + res += *p++ << 16; + res += *p++ << 8; + res += *p; + return res; +} + +uint16_t nghttp2_ntohs(uint16_t netshort) { + uint16_t res; + unsigned char *p = (unsigned char *)&netshort; + res = *p++ << 8; + res += *p; + return res; +} +#endif diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_net.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_net.h new file mode 100644 index 00000000..b1adc401 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_net.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_NET_H +#define NGHTTP2_NET_H + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + +#define IOT_BYTE_ORDER LITTLE_ENDIAN + +#if IOT_BYTE_ORDER == BIG_ENDIAN +#define nghttp2_htonl(x) (x) +#define nghttp2_htons(x) (x) +#define nghttp2_ntohl(x) (x) +#define nghttp2_ntohs(x) (x) +#else +/* Windows requires ws2_32 library for ntonl family functions. We + define inline functions for those function so that we don't have + dependeny on that lib. */ + +#ifdef _MSC_VER +#define STIN +#else +#define STIN +#endif + +STIN uint32_t nghttp2_htonl(uint32_t hostlong); + +STIN uint16_t nghttp2_htons(uint16_t hostshort); + +STIN uint32_t nghttp2_ntohl(uint32_t netlong); + +STIN uint16_t nghttp2_ntohs(uint16_t netshort); + +#endif +#endif /* NGHTTP2_NET_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_npn.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_npn.c new file mode 100644 index 00000000..0527ec94 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_npn.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_npn.h" + +#include + +static int select_next_protocol(unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, + const char *key, unsigned int keylen) { + unsigned int i; + for (i = 0; i + keylen <= inlen; i += (unsigned int)(in[i] + 1)) { + if (memcmp(&in[i], key, keylen) == 0) { + *out = (unsigned char *)&in[i + 1]; + *outlen = in[i]; + return 0; + } + } + return -1; +} + +#define NGHTTP2_HTTP_1_1_ALPN "\x8http/1.1" +#define NGHTTP2_HTTP_1_1_ALPN_LEN (sizeof(NGHTTP2_HTTP_1_1_ALPN) - 1) + +int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen) { + if (select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN, + NGHTTP2_PROTO_ALPN_LEN) == 0) { + return 1; + } + if (select_next_protocol(out, outlen, in, inlen, NGHTTP2_HTTP_1_1_ALPN, + NGHTTP2_HTTP_1_1_ALPN_LEN) == 0) { + return 0; + } + return -1; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_npn.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_npn.h new file mode 100644 index 00000000..c9fe50c9 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_npn.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_NPN_H +#define NGHTTP2_NPN_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +#endif /* NGHTTP2_NPN_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_option.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_option.c new file mode 100644 index 00000000..1d62f5b6 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_option.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include +#include "nghttp2_option.h" +#include "nghttp2_session.h" +#ifdef INFRA_MEM_STATS +#include "infra_mem_stats.h" +#endif + +extern void *HAL_Malloc(uint32_t size); +extern void *HAL_Realloc(void *ptr, uint32_t size); +extern void HAL_Free(void *ptr); + +#if INFRA_MEM_STATS +#define NGHTTP2_OPTION_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "nghttp2.option") +#define NGHTTP2_OPTION_FREE(ptr) LITE_free(ptr) +#else +#define NGHTTP2_OPTION_MALLOC(size) HAL_Malloc(size) +#define NGHTTP2_OPTION_FREE(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +int nghttp2_option_new(nghttp2_option **option_ptr) { + *option_ptr = NGHTTP2_OPTION_MALLOC(sizeof(nghttp2_option)); + + if (*option_ptr == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + memset(*option_ptr, 0, sizeof(nghttp2_option)); + return 0; +} + +void nghttp2_option_del(nghttp2_option *option) { NGHTTP2_OPTION_FREE(option); } + +void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val) { + option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE; + option->no_auto_window_update = val; +} + +void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option, + uint32_t val) { + option->opt_set_mask |= NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS; + option->peer_max_concurrent_streams = val; +} + +void nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val) { + option->opt_set_mask |= NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC; + option->no_recv_client_magic = val; +} + +void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val) { + option->opt_set_mask |= NGHTTP2_OPT_NO_HTTP_MESSAGING; + option->no_http_messaging = val; +} + +void nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option, + uint32_t val) { + option->opt_set_mask |= NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS; + option->max_reserved_remote_streams = val; +} + +static void set_ext_type(uint8_t *ext_types, uint8_t type) { + ext_types[type / 8] = (uint8_t)(ext_types[type / 8] | (1 << (type & 0x7))); +} + +void nghttp2_option_set_user_recv_extension_type(nghttp2_option *option, + uint8_t type) { + if (type < 10) { + return; + } + + option->opt_set_mask |= NGHTTP2_OPT_USER_RECV_EXT_TYPES; + set_ext_type(option->user_recv_ext_types, type); +} + +void nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option, + uint8_t type) { + switch (type) { + case NGHTTP2_ALTSVC: + option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES; + option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ALTSVC; + return; + default: + return; + } +} + +void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option, int val) { + option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_PING_ACK; + option->no_auto_ping_ack = val; +} + +void nghttp2_option_set_max_send_header_block_length(nghttp2_option *option, + size_t val) { + option->opt_set_mask |= NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH; + option->max_send_header_block_length = val; +} + +void nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option, + size_t val) { + option->opt_set_mask |= NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE; + option->max_deflate_dynamic_table_size = val; +} + +void nghttp2_option_set_no_closed_streams(nghttp2_option *option, int val) { + option->opt_set_mask |= NGHTTP2_OPT_NO_CLOSED_STREAMS; + option->no_closed_streams = val; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_option.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_option.h new file mode 100644 index 00000000..16b64e09 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_option.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_OPTION_H +#define NGHTTP2_OPTION_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +/** + * Configuration options + */ +typedef enum { + /** + * This option prevents the library from sending WINDOW_UPDATE for a + * connection automatically. If this option is set to nonzero, the + * library won't send WINDOW_UPDATE for DATA until application calls + * nghttp2_session_consume() to indicate the amount of consumed + * DATA. By default, this option is set to zero. + */ + NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE = 1, + /** + * This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of + * remote endpoint as if it is received in SETTINGS frame. Without + * specifying this option, before the local endpoint receives + * SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote + * endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. This may + * cause problem if local endpoint submits lots of requests + * initially and sending them at once to the remote peer may lead to + * the rejection of some requests. Specifying this option to the + * sensible value, say 100, may avoid this kind of issue. This value + * will be overwritten if the local endpoint receives + * SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint. + */ + NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1, + NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2, + NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3, + NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4, + NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5, + NGHTTP2_OPT_NO_AUTO_PING_ACK = 1 << 6, + NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES = 1 << 7, + NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH = 1 << 8, + NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9, + NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10, +} nghttp2_option_flag; + +/** + * Struct to store option values for nghttp2_session. + */ +struct nghttp2_option { + /** + * NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH + */ + size_t max_send_header_block_length; + /** + * NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE + */ + size_t max_deflate_dynamic_table_size; + /** + * Bitwise OR of nghttp2_option_flag to determine that which fields + * are specified. + */ + uint32_t opt_set_mask; + /** + * NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS + */ + uint32_t peer_max_concurrent_streams; + /** + * NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS + */ + uint32_t max_reserved_remote_streams; + /** + * NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES + */ + uint32_t builtin_recv_ext_types; + /** + * NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE + */ + int no_auto_window_update; + /** + * NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC + */ + int no_recv_client_magic; + /** + * NGHTTP2_OPT_NO_HTTP_MESSAGING + */ + int no_http_messaging; + /** + * NGHTTP2_OPT_NO_AUTO_PING_ACK + */ + int no_auto_ping_ack; + /** + * NGHTTP2_OPT_NO_CLOSED_STREAMS + */ + int no_closed_streams; + /** + * NGHTTP2_OPT_USER_RECV_EXT_TYPES + */ + uint8_t user_recv_ext_types[32]; +}; + +#endif /* NGHTTP2_OPTION_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_outbound_item.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_outbound_item.c new file mode 100644 index 00000000..3d35983d --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_outbound_item.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_outbound_item.h" + +#include +#include + +void nghttp2_outbound_item_init(nghttp2_outbound_item *item) { + item->cycle = 0; + item->qnext = NULL; + item->queued = 0; + + memset(&item->aux_data, 0, sizeof(nghttp2_aux_data)); +} + +void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) { + nghttp2_frame *frame; + + if (item == NULL) { + return; + } + + frame = &item->frame; + + switch (frame->hd.type) { + case NGHTTP2_DATA: + nghttp2_frame_data_free(&frame->data); + break; + case NGHTTP2_HEADERS: + nghttp2_frame_headers_free(&frame->headers, mem); + break; + case NGHTTP2_PRIORITY: + nghttp2_frame_priority_free(&frame->priority); + break; + case NGHTTP2_RST_STREAM: + nghttp2_frame_rst_stream_free(&frame->rst_stream); + break; + case NGHTTP2_SETTINGS: + nghttp2_frame_settings_free(&frame->settings, mem); + break; + case NGHTTP2_PUSH_PROMISE: + nghttp2_frame_push_promise_free(&frame->push_promise, mem); + break; + case NGHTTP2_PING: + nghttp2_frame_ping_free(&frame->ping); + break; + case NGHTTP2_GOAWAY: + nghttp2_frame_goaway_free(&frame->goaway, mem); + break; + case NGHTTP2_WINDOW_UPDATE: + nghttp2_frame_window_update_free(&frame->window_update); + break; + default: { + nghttp2_ext_aux_data *aux_data; + + aux_data = &item->aux_data.ext; + + if (aux_data->builtin == 0) { + nghttp2_frame_extension_free(&frame->ext); + break; + } + + switch (frame->hd.type) { + case NGHTTP2_ALTSVC: + nghttp2_frame_altsvc_free(&frame->ext, mem); + break; + default: + assert(0); + break; + } + } + } +} + +void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q) { + q->head = q->tail = NULL; + q->n = 0; +} + +void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q, + nghttp2_outbound_item *item) { + if (q->tail) { + q->tail = q->tail->qnext = item; + } else { + q->head = q->tail = item; + } + ++q->n; +} + +void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q) { + nghttp2_outbound_item *item; + if (!q->head) { + return; + } + item = q->head; + q->head = q->head->qnext; + item->qnext = NULL; + if (!q->head) { + q->tail = NULL; + } + --q->n; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_outbound_item.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_outbound_item.h new file mode 100644 index 00000000..33918356 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_outbound_item.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_OUTBOUND_ITEM_H +#define NGHTTP2_OUTBOUND_ITEM_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" +#include "nghttp2_frame.h" +#include "nghttp2_mem.h" + +/* struct used for HEADERS and PUSH_PROMISE frame */ +typedef struct { + nghttp2_data_provider data_prd; + void *stream_user_data; + /* error code when request HEADERS is canceled by RST_STREAM while + it is in queue. */ + uint32_t error_code; + /* nonzero if request HEADERS is canceled. The error code is stored + in |error_code|. */ + uint8_t canceled; +} nghttp2_headers_aux_data; + +/* struct used for DATA frame */ +typedef struct { + /** + * The data to be sent for this DATA frame. + */ + nghttp2_data_provider data_prd; + /** + * The flags of DATA frame. We use separate flags here and + * nghttp2_data frame. The latter contains flags actually sent to + * peer. This |flags| may contain NGHTTP2_FLAG_END_STREAM and only + * when |eof| becomes nonzero, flags in nghttp2_data has + * NGHTTP2_FLAG_END_STREAM set. + */ + uint8_t flags; + /** + * The flag to indicate whether EOF was reached or not. Initially + * |eof| is 0. It becomes 1 after all data were read. + */ + uint8_t eof; + /** + * The flag to indicate that NGHTTP2_DATA_FLAG_NO_COPY is used. + */ + uint8_t no_copy; +} nghttp2_data_aux_data; + +typedef enum { + NGHTTP2_GOAWAY_AUX_NONE = 0x0, + /* indicates that session should be terminated after the + transmission of this frame. */ + NGHTTP2_GOAWAY_AUX_TERM_ON_SEND = 0x1, + /* indicates that this GOAWAY is just a notification for graceful + shutdown. No nghttp2_session.goaway_flags should be updated on + the reaction to this frame. */ + NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2 +} nghttp2_goaway_aux_flag; + +/* struct used for GOAWAY frame */ +typedef struct { + /* bitwise-OR of one or more of nghttp2_goaway_aux_flag. */ + uint8_t flags; +} nghttp2_goaway_aux_data; + +/* struct used for extension frame */ +typedef struct { + /* nonzero if this extension frame is serialized by library + function, instead of user-defined callbacks. */ + uint8_t builtin; +} nghttp2_ext_aux_data; + +/* Additional data which cannot be stored in nghttp2_frame struct */ +typedef union { + nghttp2_data_aux_data data; + nghttp2_headers_aux_data headers; + nghttp2_goaway_aux_data goaway; + nghttp2_ext_aux_data ext; +} nghttp2_aux_data; + +struct nghttp2_outbound_item; +typedef struct nghttp2_outbound_item nghttp2_outbound_item; + +struct nghttp2_outbound_item { + nghttp2_frame frame; + /* Storage for extension frame payload. frame->ext.payload points + to this structure to avoid frequent memory allocation. */ + nghttp2_ext_frame_payload ext_frame_payload; + nghttp2_aux_data aux_data; + /* The priority used in priority comparion. Smaller is served + earlier. For PING, SETTINGS and non-DATA frames (excluding + response HEADERS frame) have dedicated cycle value defined above. + For DATA frame, cycle is computed by taking into account of + effective weight and frame payload length previously sent, so + that the amount of transmission is distributed across streams + proportional to effective weight (inside a tree). */ + uint64_t cycle; + nghttp2_outbound_item *qnext; + /* nonzero if this object is queued, except for DATA or HEADERS + which are attached to stream as item. */ + uint8_t queued; +}; + +/* + * Initializes |item|. No memory allocation is done in this function. + * Don't call nghttp2_outbound_item_free() until frame member is + * initialized. + */ +void nghttp2_outbound_item_init(nghttp2_outbound_item *item); + +/* + * Deallocates resource for |item|. If |item| is NULL, this function + * does nothing. + */ +void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem); + +/* + * queue for nghttp2_outbound_item. + */ +typedef struct { + nghttp2_outbound_item *head, *tail; + /* number of items in this queue. */ + size_t n; +} nghttp2_outbound_queue; + +void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q); + +/* Pushes |item| into |q| */ +void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q, + nghttp2_outbound_item *item); + +/* Pops |item| at the top from |q|. If |q| is empty, nothing + happens. */ +void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q); + +/* Returns the top item. */ +#define nghttp2_outbound_queue_top(Q) ((Q)->head) + +/* Returns the size of the queue */ +#define nghttp2_outbound_queue_size(Q) ((Q)->n) + +#endif /* NGHTTP2_OUTBOUND_ITEM_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_pq.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_pq.c new file mode 100644 index 00000000..79aa1562 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_pq.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_pq.h" + +#include +#include + +#include "nghttp2_helper.h" + +int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) { + pq->mem = mem; + pq->capacity = 0; + pq->q = NULL; + pq->length = 0; + pq->less = less; + return 0; +} + +void nghttp2_pq_free(nghttp2_pq *pq) { + nghttp2_mem_free(pq->mem, pq->q); + pq->q = NULL; +} + +static void swap(nghttp2_pq *pq, size_t i, size_t j) { + nghttp2_pq_entry *a = pq->q[i]; + nghttp2_pq_entry *b = pq->q[j]; + + pq->q[i] = b; + b->index = i; + pq->q[j] = a; + a->index = j; +} + +static void bubble_up(nghttp2_pq *pq, size_t index) { + size_t parent; + while (index != 0) { + parent = (index - 1) / 2; + if (!pq->less(pq->q[index], pq->q[parent])) { + return; + } + swap(pq, parent, index); + index = parent; + } +} + +int nghttp2_pq_push(nghttp2_pq *pq, nghttp2_pq_entry *item) { + if (pq->capacity <= pq->length) { + void *nq; + size_t ncapacity; + + ncapacity = nghttp2_max(4, (pq->capacity * 2)); + + nq = nghttp2_mem_realloc(pq->mem, pq->q, + ncapacity * sizeof(nghttp2_pq_entry *)); + if (nq == NULL) { + return NGHTTP2_ERR_NOMEM; + } + pq->capacity = ncapacity; + pq->q = nq; + } + pq->q[pq->length] = item; + item->index = pq->length; + ++pq->length; + bubble_up(pq, pq->length - 1); + return 0; +} + +nghttp2_pq_entry *nghttp2_pq_top(nghttp2_pq *pq) { + if (pq->length == 0) { + return NULL; + } else { + return pq->q[0]; + } +} + +static void bubble_down(nghttp2_pq *pq, size_t index) { + size_t i, j, minindex; + for (;;) { + j = index * 2 + 1; + minindex = index; + for (i = 0; i < 2; ++i, ++j) { + if (j >= pq->length) { + break; + } + if (pq->less(pq->q[j], pq->q[minindex])) { + minindex = j; + } + } + if (minindex == index) { + return; + } + swap(pq, index, minindex); + index = minindex; + } +} + +void nghttp2_pq_pop(nghttp2_pq *pq) { + if (pq->length > 0) { + pq->q[0] = pq->q[pq->length - 1]; + pq->q[0]->index = 0; + --pq->length; + bubble_down(pq, 0); + } +} + +void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item) { + assert(pq->q[item->index] == item); + + if (item->index == 0) { + nghttp2_pq_pop(pq); + return; + } + + if (item->index == pq->length - 1) { + --pq->length; + return; + } + + pq->q[item->index] = pq->q[pq->length - 1]; + pq->q[item->index]->index = item->index; + --pq->length; + + if (pq->less(item, pq->q[item->index])) { + bubble_down(pq, item->index); + } else { + bubble_up(pq, item->index); + } +} + +int nghttp2_pq_empty(nghttp2_pq *pq) { return pq->length == 0; } + +size_t nghttp2_pq_size(nghttp2_pq *pq) { return pq->length; } + +void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg) { + size_t i; + int rv = 0; + if (pq->length == 0) { + return; + } + for (i = 0; i < pq->length; ++i) { + rv |= (*fun)(pq->q[i], arg); + } + if (rv) { + for (i = pq->length; i > 0; --i) { + bubble_down(pq, i - 1); + } + } +} + +int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg) { + size_t i; + + if (pq->length == 0) { + return 0; + } + for (i = 0; i < pq->length; ++i) { + if ((*fun)(pq->q[i], arg)) { + return 1; + } + } + return 0; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_pq.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_pq.h new file mode 100644 index 00000000..a527db13 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_pq.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_PQ_H +#define NGHTTP2_PQ_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" +#include "nghttp2_int.h" +#include "nghttp2_mem.h" + +/* Implementation of priority queue */ + +typedef struct { + size_t index; +} nghttp2_pq_entry; + +typedef struct { + /* The pointer to the pointer to the item stored */ + nghttp2_pq_entry **q; + /* Memory allocator */ + nghttp2_mem *mem; + /* The number of items stored */ + size_t length; + /* The maximum number of items this pq can store. This is + automatically extended when length is reached to this value. */ + size_t capacity; + /* The less function between items */ + nghttp2_less less; +} nghttp2_pq; + +/* + * Initializes priority queue |pq| with compare function |cmp|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem); + +/* + * Deallocates any resources allocated for |pq|. The stored items are + * not freed by this function. + */ +void nghttp2_pq_free(nghttp2_pq *pq); + +/* + * Adds |item| to the priority queue |pq|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_pq_push(nghttp2_pq *pq, nghttp2_pq_entry *item); + +/* + * Returns item at the top of the queue |pq|. If the queue is empty, + * this function returns NULL. + */ +nghttp2_pq_entry *nghttp2_pq_top(nghttp2_pq *pq); + +/* + * Pops item at the top of the queue |pq|. The popped item is not + * freed by this function. + */ +void nghttp2_pq_pop(nghttp2_pq *pq); + +/* + * Returns nonzero if the queue |pq| is empty. + */ +int nghttp2_pq_empty(nghttp2_pq *pq); + +/* + * Returns the number of items in the queue |pq|. + */ +size_t nghttp2_pq_size(nghttp2_pq *pq); + +typedef int (*nghttp2_pq_item_cb)(nghttp2_pq_entry *item, void *arg); + +/* + * Updates each item in |pq| using function |fun| and re-construct + * priority queue. The |fun| must return non-zero if it modifies the + * item in a way that it affects ordering in the priority queue. The + * |arg| is passed to the 2nd parameter of |fun|. + */ +void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg); + +/* + * Applys |fun| to each item in |pq|. The |arg| is passed as arg + * parameter to callback function. This function must not change the + * ordering key. If the return value from callback is nonzero, this + * function returns 1 immediately without iterating remaining items. + * Otherwise this function returns 0. + */ +int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg); + +/* + * Removes |item| from priority queue. + */ +void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item); + +#endif /* NGHTTP2_PQ_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_priority_spec.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_priority_spec.c new file mode 100644 index 00000000..b3d64e60 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_priority_spec.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_priority_spec.h" + +void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec, + int32_t stream_id, int32_t weight, + int exclusive) { + pri_spec->stream_id = stream_id; + pri_spec->weight = weight; + pri_spec->exclusive = exclusive != 0; +} + +void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec) { + pri_spec->stream_id = 0; + pri_spec->weight = NGHTTP2_DEFAULT_WEIGHT; + pri_spec->exclusive = 0; +} + +int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec) { + return pri_spec->stream_id == 0 && + pri_spec->weight == NGHTTP2_DEFAULT_WEIGHT && pri_spec->exclusive == 0; +} + +void nghttp2_priority_spec_normalize_weight(nghttp2_priority_spec *pri_spec) { + if (pri_spec->weight < NGHTTP2_MIN_WEIGHT) { + pri_spec->weight = NGHTTP2_MIN_WEIGHT; + } else if (pri_spec->weight > NGHTTP2_MAX_WEIGHT) { + pri_spec->weight = NGHTTP2_MAX_WEIGHT; + } +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_priority_spec.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_priority_spec.h new file mode 100644 index 00000000..d5f99564 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_priority_spec.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_PRIORITY_SPEC_H +#define NGHTTP2_PRIORITY_SPEC_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +/* + * This function normalizes pri_spec->weight if it is out of range. + * If pri_spec->weight is less than NGHTTP2_MIN_WEIGHT, it is set to + * NGHTTP2_MIN_WEIGHT. If pri_spec->weight is larger than + * NGHTTP2_MAX_WEIGHT, it is set to NGHTTP2_MAX_WEIGHT. + */ +void nghttp2_priority_spec_normalize_weight(nghttp2_priority_spec *pri_spec); + +#endif /* NGHTTP2_PRIORITY_SPEC_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_queue.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_queue.c new file mode 100644 index 00000000..4c45dfe0 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_queue.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + +#include "nghttp2_queue.h" + +#include +#include +#ifdef INFRA_MEM_STATS +#include "infra_mem_stats.h" +#endif + +extern void *HAL_Malloc(uint32_t size); +extern void *HAL_Realloc(void *ptr, uint32_t size); +extern void HAL_Free(void *ptr); + +#if INFRA_MEM_STATS +#define NGHTTP2_QUEUE_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "nghttp2.queue") +#define NGHTTP2_QUEUE_FREE(ptr) LITE_free(ptr) +#else +#define NGHTTP2_QUEUE_MALLOC(size) HAL_Malloc(size) +#define NGHTTP2_QUEUE_FREE(ptr) {HAL_Free((void *)ptr);ptr = NULL;} +#endif + +void nghttp2_queue_init(nghttp2_queue *queue) { + queue->front = queue->back = NULL; +} + +void nghttp2_queue_free(nghttp2_queue *queue) { + if (!queue) { + return; + } else { + nghttp2_queue_cell *p = queue->front; + while (p) { + nghttp2_queue_cell *next = p->next; + NGHTTP2_QUEUE_FREE(p); + p = next; + } + } +} + +int nghttp2_queue_push(nghttp2_queue *queue, void *data) { + nghttp2_queue_cell *new_cell = + (nghttp2_queue_cell *)NGHTTP2_QUEUE_MALLOC(sizeof(nghttp2_queue_cell)); + if (!new_cell) { + return NGHTTP2_ERR_NOMEM; + } + new_cell->data = data; + new_cell->next = NULL; + if (queue->back) { + queue->back->next = new_cell; + queue->back = new_cell; + + } else { + queue->front = queue->back = new_cell; + } + return 0; +} + +void nghttp2_queue_pop(nghttp2_queue *queue) { + nghttp2_queue_cell *front = queue->front; + assert(front); + queue->front = front->next; + if (front == queue->back) { + queue->back = NULL; + } + NGHTTP2_QUEUE_FREE(front); +} + +void *nghttp2_queue_front(nghttp2_queue *queue) { + assert(queue->front); + return queue->front->data; +} + +void *nghttp2_queue_back(nghttp2_queue *queue) { + assert(queue->back); + return queue->back->data; +} + +int nghttp2_queue_empty(nghttp2_queue *queue) { return queue->front == NULL; } diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_queue.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_queue.h new file mode 100644 index 00000000..3ffdc14a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_queue.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_QUEUE_H +#define NGHTTP2_QUEUE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +typedef struct nghttp2_queue_cell { + void *data; + struct nghttp2_queue_cell *next; +} nghttp2_queue_cell; + +typedef struct { + nghttp2_queue_cell *front, *back; +} nghttp2_queue; + +void nghttp2_queue_init(nghttp2_queue *queue); +void nghttp2_queue_free(nghttp2_queue *queue); +int nghttp2_queue_push(nghttp2_queue *queue, void *data); +void nghttp2_queue_pop(nghttp2_queue *queue); +void *nghttp2_queue_front(nghttp2_queue *queue); +void *nghttp2_queue_back(nghttp2_queue *queue); +int nghttp2_queue_empty(nghttp2_queue *queue); + +#endif /* NGHTTP2_QUEUE_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_rcbuf.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_rcbuf.c new file mode 100644 index 00000000..0fc440eb --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_rcbuf.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_rcbuf.h" + +#include +#include + +#include "nghttp2_mem.h" +#include "nghttp2_helper.h" + +int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size, + nghttp2_mem *mem) { + uint8_t *p; + + p = nghttp2_mem_malloc(mem, sizeof(nghttp2_rcbuf) + size); + if (p == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + *rcbuf_ptr = (void *)p; + + (*rcbuf_ptr)->mem_user_data = mem->mem_user_data; + (*rcbuf_ptr)->free = mem->free; + (*rcbuf_ptr)->base = p + sizeof(nghttp2_rcbuf); + (*rcbuf_ptr)->len = size; + (*rcbuf_ptr)->ref = 1; + + return 0; +} + +int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src, + size_t srclen, nghttp2_mem *mem) { + int rv; + + rv = nghttp2_rcbuf_new(rcbuf_ptr, srclen + 1, mem); + if (rv != 0) { + return rv; + } + + (*rcbuf_ptr)->len = srclen; + *nghttp2_cpymem((*rcbuf_ptr)->base, src, srclen) = '\0'; + + return 0; +} + +/* + * Frees |rcbuf| itself, regardless of its reference cout. + */ +void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf) { + nghttp2_mem_free2(rcbuf->free, rcbuf, rcbuf->mem_user_data); +} + +void nghttp2_rcbuf_incref(nghttp2_rcbuf *rcbuf) { + if (rcbuf->ref == -1) { + return; + } + + ++rcbuf->ref; +} + +void nghttp2_rcbuf_decref(nghttp2_rcbuf *rcbuf) { + if (rcbuf == NULL || rcbuf->ref == -1) { + return; + } + + assert(rcbuf->ref > 0); + + if (--rcbuf->ref == 0) { + nghttp2_rcbuf_del(rcbuf); + } +} + +nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf) { + nghttp2_vec res = {rcbuf->base, rcbuf->len}; + return res; +} + +int nghttp2_rcbuf_is_static(const nghttp2_rcbuf *rcbuf) { + return rcbuf->ref == -1; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_rcbuf.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_rcbuf.h new file mode 100644 index 00000000..edb1c59b --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_rcbuf.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_RCBUF_H +#define NGHTTP2_RCBUF_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +struct nghttp2_rcbuf { + /* custom memory allocator belongs to the mem parameter when + creating this object. */ + void *mem_user_data; + nghttp2_free free; + /* The pointer to the underlying buffer */ + uint8_t *base; + /* Size of buffer pointed by |base|. */ + size_t len; + /* Reference count */ + int32_t ref; +}; + +/* + * Allocates nghttp2_rcbuf object with |size| as initial buffer size. + * When the function succeeds, the reference count becomes 1. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM: + * Out of memory. + */ +int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size, nghttp2_mem *mem); + +/* + * Like nghttp2_rcbuf_new(), but initializes the buffer with |src| of + * length |srclen|. This function allocates additional byte at the + * end and puts '\0' into it, so that the resulting buffer could be + * used as NULL-terminated string. Still (*rcbuf_ptr)->len equals to + * |srclen|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM: + * Out of memory. + */ +int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src, + size_t srclen, nghttp2_mem *mem); + +/* + * Frees |rcbuf| itself, regardless of its reference cout. + */ +void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf); + +#endif /* NGHTTP2_RCBUF_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_session.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_session.c new file mode 100644 index 00000000..6299b0f5 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_session.c @@ -0,0 +1,7504 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_session.h" + +#include +#include +#include +#include +#include + +#include "nghttp2_helper.h" +#include "nghttp2_net.h" +#include "nghttp2_priority_spec.h" +#include "nghttp2_option.h" +#include "nghttp2_http.h" +#include "nghttp2_pq.h" +#include "nghttp2_debug.h" + +extern int HAL_Vsnprintf(char *str, const int len, const char *format, va_list ap); + +/* + * Returns non-zero if the number of outgoing opened streams is larger + * than or equal to + * remote_settings.max_concurrent_streams. + */ +static int +session_is_outgoing_concurrent_streams_max(nghttp2_session *session) { + return session->remote_settings.max_concurrent_streams <= + session->num_outgoing_streams; +} + +/* + * Returns non-zero if the number of incoming opened streams is larger + * than or equal to + * local_settings.max_concurrent_streams. + */ +static int +session_is_incoming_concurrent_streams_max(nghttp2_session *session) { + return session->local_settings.max_concurrent_streams <= + session->num_incoming_streams; +} + +/* + * Returns non-zero if the number of incoming opened streams is larger + * than or equal to + * session->pending_local_max_concurrent_stream. + */ +static int +session_is_incoming_concurrent_streams_pending_max(nghttp2_session *session) { + return session->pending_local_max_concurrent_stream <= + session->num_incoming_streams; +} + +/* + * Returns non-zero if |lib_error| is non-fatal error. + */ +static int is_non_fatal(int lib_error_code) { + return lib_error_code < 0 && lib_error_code > NGHTTP2_ERR_FATAL; +} + +int nghttp2_is_fatal(int lib_error_code) { + return lib_error_code < NGHTTP2_ERR_FATAL; +} + +static int session_enforce_http_messaging(nghttp2_session *session) { + return (session->opt_flags & NGHTTP2_OPTMASK_NO_HTTP_MESSAGING) == 0; +} + +/* + * Returns nonzero if |frame| is trailer headers. + */ +static int session_trailer_headers(nghttp2_session *session, + nghttp2_stream *stream, + nghttp2_frame *frame) { + if (!stream || frame->hd.type != NGHTTP2_HEADERS) { + return 0; + } + if (session->server) { + return frame->headers.cat == NGHTTP2_HCAT_HEADERS; + } + + return frame->headers.cat == NGHTTP2_HCAT_HEADERS && + (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) == 0; +} + +/* Returns nonzero if the |stream| is in reserved(remote) state */ +static int state_reserved_remote(nghttp2_session *session, + nghttp2_stream *stream) { + return stream->state == NGHTTP2_STREAM_RESERVED && + !nghttp2_session_is_my_stream_id(session, stream->stream_id); +} + +/* Returns nonzero if the |stream| is in reserved(local) state */ +static int state_reserved_local(nghttp2_session *session, + nghttp2_stream *stream) { + return stream->state == NGHTTP2_STREAM_RESERVED && + nghttp2_session_is_my_stream_id(session, stream->stream_id); +} + +/* + * Checks whether received stream_id is valid. This function returns + * 1 if it succeeds, or 0. + */ +static int session_is_new_peer_stream_id(nghttp2_session *session, + int32_t stream_id) { + return stream_id != 0 && + !nghttp2_session_is_my_stream_id(session, stream_id) && + session->last_recv_stream_id < stream_id; +} + +static int session_detect_idle_stream(nghttp2_session *session, + int32_t stream_id) { + /* Assume that stream object with stream_id does not exist */ + if (nghttp2_session_is_my_stream_id(session, stream_id)) { + if (session->last_sent_stream_id < stream_id) { + return 1; + } + return 0; + } + if (session_is_new_peer_stream_id(session, stream_id)) { + return 1; + } + return 0; +} + +static int check_ext_type_set(const uint8_t *ext_types, uint8_t type) { + return (ext_types[type / 8] & (1 << (type & 0x7))) > 0; +} + +static int session_call_error_callback(nghttp2_session *session, + int lib_error_code, const char *fmt, + ...) { + size_t bufsize; + va_list ap; + char *buf; + int rv; + nghttp2_mem *mem; + + if (!session->callbacks.error_callback && + !session->callbacks.error_callback2) { + return 0; + } + + mem = &session->mem; + + va_start(ap, fmt); + rv = HAL_Vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + + if (rv < 0) { + return NGHTTP2_ERR_NOMEM; + } + + bufsize = (size_t)(rv + 1); + + buf = nghttp2_mem_malloc(mem, bufsize); + if (buf == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + va_start(ap, fmt); + rv = HAL_Vsnprintf(buf, bufsize, fmt, ap); + va_end(ap); + + if (rv < 0) { + nghttp2_mem_free(mem, buf); + /* vsnprintf may return error because of various things we can + imagine, but typically we don't want to drop session just for + debug callback. */ + DEBUGF("error_callback: vsnprintf failed. The template was %s\n", fmt); + return 0; + } + + if (session->callbacks.error_callback2) { + rv = session->callbacks.error_callback2(session, lib_error_code, buf, + (size_t)rv, session->user_data); + } else { + rv = session->callbacks.error_callback(session, buf, (size_t)rv, + session->user_data); + } + + nghttp2_mem_free(mem, buf); + + if (rv != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static int session_terminate_session(nghttp2_session *session, + int32_t last_stream_id, + uint32_t error_code, const char *reason) { + int rv; + const uint8_t *debug_data; + size_t debug_datalen; + + if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) { + return 0; + } + + if (reason == NULL) { + debug_data = NULL; + debug_datalen = 0; + } else { + debug_data = (const uint8_t *)reason; + debug_datalen = strlen(reason); + } + + rv = nghttp2_session_add_goaway(session, last_stream_id, error_code, + debug_data, debug_datalen, + NGHTTP2_GOAWAY_AUX_TERM_ON_SEND); + + if (rv != 0) { + return rv; + } + + session->goaway_flags |= NGHTTP2_GOAWAY_TERM_ON_SEND; + + return 0; +} + +int nghttp2_session_terminate_session(nghttp2_session *session, + uint32_t error_code) { + return session_terminate_session(session, session->last_proc_stream_id, + error_code, NULL); +} + +int nghttp2_session_terminate_session2(nghttp2_session *session, + int32_t last_stream_id, + uint32_t error_code) { + return session_terminate_session(session, last_stream_id, error_code, NULL); +} + +int nghttp2_session_terminate_session_with_reason(nghttp2_session *session, + uint32_t error_code, + const char *reason) { + return session_terminate_session(session, session->last_proc_stream_id, + error_code, reason); +} + +int nghttp2_session_is_my_stream_id(nghttp2_session *session, + int32_t stream_id) { + int rem; + if (stream_id == 0) { + return 0; + } + rem = stream_id & 0x1; + if (session->server) { + return rem == 0; + } + return rem == 1; +} + +nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session, + int32_t stream_id) { + nghttp2_stream *stream; + + stream = (nghttp2_stream *)nghttp2_map_find(&session->streams, stream_id); + + if (stream == NULL || (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) || + stream->state == NGHTTP2_STREAM_IDLE) { + return NULL; + } + + return stream; +} + +nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session, + int32_t stream_id) { + return (nghttp2_stream *)nghttp2_map_find(&session->streams, stream_id); +} + +static void session_inbound_frame_reset(nghttp2_session *session) { + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_mem *mem = &session->mem; + /* A bit risky code, since if this function is called from + nghttp2_session_new(), we rely on the fact that + iframe->frame.hd.type is 0, so that no free is performed. */ + switch (iframe->frame.hd.type) { + case NGHTTP2_DATA: + break; + case NGHTTP2_HEADERS: + nghttp2_frame_headers_free(&iframe->frame.headers, mem); + break; + case NGHTTP2_PRIORITY: + nghttp2_frame_priority_free(&iframe->frame.priority); + break; + case NGHTTP2_RST_STREAM: + nghttp2_frame_rst_stream_free(&iframe->frame.rst_stream); + break; + case NGHTTP2_SETTINGS: + nghttp2_frame_settings_free(&iframe->frame.settings, mem); + + nghttp2_mem_free(mem, iframe->iv); + + iframe->iv = NULL; + iframe->niv = 0; + iframe->max_niv = 0; + + break; + case NGHTTP2_PUSH_PROMISE: + nghttp2_frame_push_promise_free(&iframe->frame.push_promise, mem); + break; + case NGHTTP2_PING: + nghttp2_frame_ping_free(&iframe->frame.ping); + break; + case NGHTTP2_GOAWAY: + nghttp2_frame_goaway_free(&iframe->frame.goaway, mem); + break; + case NGHTTP2_WINDOW_UPDATE: + nghttp2_frame_window_update_free(&iframe->frame.window_update); + break; + default: + /* extension frame */ + if (check_ext_type_set(session->user_recv_ext_types, + iframe->frame.hd.type)) { + nghttp2_frame_extension_free(&iframe->frame.ext); + } else { + switch (iframe->frame.hd.type) { + case NGHTTP2_ALTSVC: + if ((session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ALTSVC) == 0) { + break; + } + nghttp2_frame_altsvc_free(&iframe->frame.ext, mem); + break; + } + } + + break; + } + + memset(&iframe->frame, 0, sizeof(nghttp2_frame)); + memset(&iframe->ext_frame_payload, 0, sizeof(nghttp2_ext_frame_payload)); + + iframe->state = NGHTTP2_IB_READ_HEAD; + + nghttp2_buf_wrap_init(&iframe->sbuf, iframe->raw_sbuf, + sizeof(iframe->raw_sbuf)); + iframe->sbuf.mark += NGHTTP2_FRAME_HDLEN; + + nghttp2_buf_free(&iframe->lbuf, mem); + nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0); + + iframe->raw_lbuf = NULL; + + iframe->payloadleft = 0; + iframe->padlen = 0; +} + +static void init_settings(nghttp2_settings_storage *settings) { + settings->header_table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; + settings->enable_push = 1; + settings->max_concurrent_streams = NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS; + settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE; + settings->max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN; + settings->max_header_list_size = UINT32_MAX; +} + +static void active_outbound_item_reset(nghttp2_active_outbound_item *aob, + nghttp2_mem *mem) { + DEBUGF("send: reset nghttp2_active_outbound_item\n"); + DEBUGF("send: aob->item = %p\n", aob->item); + nghttp2_outbound_item_free(aob->item, mem); + nghttp2_mem_free(mem, aob->item); + aob->item = NULL; + nghttp2_bufs_reset(&aob->framebufs); + aob->state = NGHTTP2_OB_POP_ITEM; +} + +int nghttp2_enable_strict_preface = 1; + +static int session_new(nghttp2_session **session_ptr, + const nghttp2_session_callbacks *callbacks, + void *user_data, int server, + const nghttp2_option *option, nghttp2_mem *mem) { + int rv; + size_t nbuffer; + size_t max_deflate_dynamic_table_size = + NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE; + + if (mem == NULL) { + mem = nghttp2_mem_default(); + } + + *session_ptr = nghttp2_mem_calloc(mem, 1, sizeof(nghttp2_session)); + if (*session_ptr == NULL) { + rv = NGHTTP2_ERR_NOMEM; + goto fail_session; + } + + (*session_ptr)->mem = *mem; + mem = &(*session_ptr)->mem; + + /* next_stream_id is initialized in either + nghttp2_session_client_new2 or nghttp2_session_server_new2 */ + + nghttp2_stream_init(&(*session_ptr)->root, 0, NGHTTP2_STREAM_FLAG_NONE, + NGHTTP2_STREAM_IDLE, NGHTTP2_DEFAULT_WEIGHT, 0, 0, NULL, + mem); + + (*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; + (*session_ptr)->recv_window_size = 0; + (*session_ptr)->consumed_size = 0; + (*session_ptr)->recv_reduction = 0; + (*session_ptr)->local_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; + + (*session_ptr)->goaway_flags = NGHTTP2_GOAWAY_NONE; + (*session_ptr)->local_last_stream_id = (1u << 31) - 1; + (*session_ptr)->remote_last_stream_id = (1u << 31) - 1; + + (*session_ptr)->pending_local_max_concurrent_stream = + NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS; + (*session_ptr)->pending_enable_push = 1; + + if (server) { + (*session_ptr)->server = 1; + } + + init_settings(&(*session_ptr)->remote_settings); + init_settings(&(*session_ptr)->local_settings); + + (*session_ptr)->max_incoming_reserved_streams = + NGHTTP2_MAX_INCOMING_RESERVED_STREAMS; + + /* Limit max outgoing concurrent streams to sensible value */ + (*session_ptr)->remote_settings.max_concurrent_streams = 100; + + (*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN; + + if (option) { + if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) && + option->no_auto_window_update) { + + (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE; + } + + if (option->opt_set_mask & NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS) { + + (*session_ptr)->remote_settings.max_concurrent_streams = + option->peer_max_concurrent_streams; + } + + if (option->opt_set_mask & NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS) { + + (*session_ptr)->max_incoming_reserved_streams = + option->max_reserved_remote_streams; + } + + if ((option->opt_set_mask & NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC) && + option->no_recv_client_magic) { + + (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC; + } + + if ((option->opt_set_mask & NGHTTP2_OPT_NO_HTTP_MESSAGING) && + option->no_http_messaging) { + + (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_HTTP_MESSAGING; + } + + if (option->opt_set_mask & NGHTTP2_OPT_USER_RECV_EXT_TYPES) { + memcpy((*session_ptr)->user_recv_ext_types, option->user_recv_ext_types, + sizeof((*session_ptr)->user_recv_ext_types)); + } + + if (option->opt_set_mask & NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES) { + (*session_ptr)->builtin_recv_ext_types = option->builtin_recv_ext_types; + } + + if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_PING_ACK) && + option->no_auto_ping_ack) { + (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_PING_ACK; + } + + if (option->opt_set_mask & NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH) { + (*session_ptr)->max_send_header_block_length = + option->max_send_header_block_length; + } + + if (option->opt_set_mask & NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE) { + max_deflate_dynamic_table_size = option->max_deflate_dynamic_table_size; + } + + if ((option->opt_set_mask & NGHTTP2_OPT_NO_CLOSED_STREAMS) && + option->no_closed_streams) { + (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_CLOSED_STREAMS; + } + } + + rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater, + max_deflate_dynamic_table_size, mem); + if (rv != 0) { + goto fail_hd_deflater; + } + rv = nghttp2_hd_inflate_init(&(*session_ptr)->hd_inflater, mem); + if (rv != 0) { + goto fail_hd_inflater; + } + rv = nghttp2_map_init(&(*session_ptr)->streams, mem); + if (rv != 0) { + goto fail_map; + } + + nbuffer = ((*session_ptr)->max_send_header_block_length + + NGHTTP2_FRAMEBUF_CHUNKLEN - 1) / + NGHTTP2_FRAMEBUF_CHUNKLEN; + + if (nbuffer == 0) { + nbuffer = 1; + } + + /* 1 for Pad Field. */ + rv = nghttp2_bufs_init3(&(*session_ptr)->aob.framebufs, + NGHTTP2_FRAMEBUF_CHUNKLEN, nbuffer, 1, + NGHTTP2_FRAME_HDLEN + 1, mem); + if (rv != 0) { + goto fail_aob_framebuf; + } + + active_outbound_item_reset(&(*session_ptr)->aob, mem); + + (*session_ptr)->callbacks = *callbacks; + (*session_ptr)->user_data = user_data; + + session_inbound_frame_reset(*session_ptr); + + if (nghttp2_enable_strict_preface) { + nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe; + + if (server && ((*session_ptr)->opt_flags & + NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC) == 0) { + iframe->state = NGHTTP2_IB_READ_CLIENT_MAGIC; + iframe->payloadleft = NGHTTP2_CLIENT_MAGIC_LEN; + } else { + iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS; + } + + if (!server) { + (*session_ptr)->aob.state = NGHTTP2_OB_SEND_CLIENT_MAGIC; + nghttp2_bufs_add(&(*session_ptr)->aob.framebufs, NGHTTP2_CLIENT_MAGIC, + NGHTTP2_CLIENT_MAGIC_LEN); + } + } + + return 0; + +fail_aob_framebuf: + nghttp2_map_free(&(*session_ptr)->streams); +fail_map: + nghttp2_hd_inflate_free(&(*session_ptr)->hd_inflater); +fail_hd_inflater: + nghttp2_hd_deflate_free(&(*session_ptr)->hd_deflater); +fail_hd_deflater: + nghttp2_mem_free(mem, *session_ptr); +fail_session: + return rv; +} + +int nghttp2_session_client_new(nghttp2_session **session_ptr, + const nghttp2_session_callbacks *callbacks, + void *user_data) { + return nghttp2_session_client_new3(session_ptr, callbacks, user_data, NULL, + NULL); +} + +int nghttp2_session_client_new2(nghttp2_session **session_ptr, + const nghttp2_session_callbacks *callbacks, + void *user_data, const nghttp2_option *option) { + return nghttp2_session_client_new3(session_ptr, callbacks, user_data, option, + NULL); +} + +int nghttp2_session_client_new3(nghttp2_session **session_ptr, + const nghttp2_session_callbacks *callbacks, + void *user_data, const nghttp2_option *option, + nghttp2_mem *mem) { + int rv; + nghttp2_session *session; + + rv = session_new(&session, callbacks, user_data, 0, option, mem); + + if (rv != 0) { + return rv; + } + /* IDs for use in client */ + session->next_stream_id = 1; + + *session_ptr = session; + + return 0; +} + +int nghttp2_session_server_new(nghttp2_session **session_ptr, + const nghttp2_session_callbacks *callbacks, + void *user_data) { + return nghttp2_session_server_new3(session_ptr, callbacks, user_data, NULL, + NULL); +} + +int nghttp2_session_server_new2(nghttp2_session **session_ptr, + const nghttp2_session_callbacks *callbacks, + void *user_data, const nghttp2_option *option) { + return nghttp2_session_server_new3(session_ptr, callbacks, user_data, option, + NULL); +} + +int nghttp2_session_server_new3(nghttp2_session **session_ptr, + const nghttp2_session_callbacks *callbacks, + void *user_data, const nghttp2_option *option, + nghttp2_mem *mem) { + int rv; + nghttp2_session *session; + + rv = session_new(&session, callbacks, user_data, 1, option, mem); + + if (rv != 0) { + return rv; + } + /* IDs for use in client */ + session->next_stream_id = 2; + + *session_ptr = session; + + return 0; +} + +static int free_streams(nghttp2_map_entry *entry, void *ptr) { + nghttp2_session *session; + nghttp2_stream *stream; + nghttp2_outbound_item *item; + nghttp2_mem *mem; + + session = (nghttp2_session *)ptr; + mem = &session->mem; + stream = (nghttp2_stream *)entry; + item = stream->item; + + if (item && !item->queued && item != session->aob.item) { + nghttp2_outbound_item_free(item, mem); + nghttp2_mem_free(mem, item); + } + + nghttp2_stream_free(stream); + nghttp2_mem_free(mem, stream); + + return 0; +} + +static void ob_q_free(nghttp2_outbound_queue *q, nghttp2_mem *mem) { + nghttp2_outbound_item *item, *next; + for (item = q->head; item;) { + next = item->qnext; + nghttp2_outbound_item_free(item, mem); + nghttp2_mem_free(mem, item); + item = next; + } +} + +static int inflight_settings_new(nghttp2_inflight_settings **settings_ptr, + const nghttp2_settings_entry *iv, size_t niv, + nghttp2_mem *mem) { + *settings_ptr = nghttp2_mem_malloc(mem, sizeof(nghttp2_inflight_settings)); + if (!*settings_ptr) { + return NGHTTP2_ERR_NOMEM; + } + + if (niv > 0) { + (*settings_ptr)->iv = nghttp2_frame_iv_copy(iv, niv, mem); + if (!(*settings_ptr)->iv) { + nghttp2_mem_free(mem, *settings_ptr); + return NGHTTP2_ERR_NOMEM; + } + } else { + (*settings_ptr)->iv = NULL; + } + + (*settings_ptr)->niv = niv; + (*settings_ptr)->next = NULL; + + return 0; +} + +static void inflight_settings_del(nghttp2_inflight_settings *settings, + nghttp2_mem *mem) { + if (!settings) { + return; + } + + nghttp2_mem_free(mem, settings->iv); + nghttp2_mem_free(mem, settings); +} + +void nghttp2_session_del(nghttp2_session *session) { + nghttp2_mem *mem; + nghttp2_inflight_settings *settings; + + if (session == NULL) { + return; + } + + mem = &session->mem; + + for (settings = session->inflight_settings_head; settings;) { + nghttp2_inflight_settings *next = settings->next; + inflight_settings_del(settings, mem); + settings = next; + } + + nghttp2_stream_free(&session->root); + + /* Have to free streams first, so that we can check + stream->item->queued */ + nghttp2_map_each_free(&session->streams, free_streams, session); + nghttp2_map_free(&session->streams); + + ob_q_free(&session->ob_urgent, mem); + ob_q_free(&session->ob_reg, mem); + ob_q_free(&session->ob_syn, mem); + + active_outbound_item_reset(&session->aob, mem); + session_inbound_frame_reset(session); + nghttp2_hd_deflate_free(&session->hd_deflater); + nghttp2_hd_inflate_free(&session->hd_inflater); + nghttp2_bufs_free(&session->aob.framebufs); + nghttp2_mem_free(mem, session); +} + +int nghttp2_session_reprioritize_stream( + nghttp2_session *session, nghttp2_stream *stream, + const nghttp2_priority_spec *pri_spec_in) { + int rv; + nghttp2_stream *dep_stream = NULL; + nghttp2_priority_spec pri_spec_default; + const nghttp2_priority_spec *pri_spec = pri_spec_in; + + assert(pri_spec->stream_id != stream->stream_id); + + if (!nghttp2_stream_in_dep_tree(stream)) { + return 0; + } + + if (pri_spec->stream_id != 0) { + dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); + + if (!dep_stream && + session_detect_idle_stream(session, pri_spec->stream_id)) { + + nghttp2_priority_spec_default_init(&pri_spec_default); + + dep_stream = nghttp2_session_open_stream( + session, pri_spec->stream_id, NGHTTP2_FLAG_NONE, &pri_spec_default, + NGHTTP2_STREAM_IDLE, NULL); + + if (dep_stream == NULL) { + return NGHTTP2_ERR_NOMEM; + } + } else if (!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) { + nghttp2_priority_spec_default_init(&pri_spec_default); + pri_spec = &pri_spec_default; + } + } + + if (pri_spec->stream_id == 0) { + dep_stream = &session->root; + } else if (nghttp2_stream_dep_find_ancestor(dep_stream, stream)) { + DEBUGF("stream: cycle detected, dep_stream(%p)=%d stream(%p)=%d\n", + dep_stream, dep_stream->stream_id, stream, stream->stream_id); + + nghttp2_stream_dep_remove_subtree(dep_stream); + rv = nghttp2_stream_dep_add_subtree(stream->dep_prev, dep_stream); + if (rv != 0) { + return rv; + } + } + + assert(dep_stream); + + if (dep_stream == stream->dep_prev && !pri_spec->exclusive) { + /* This is minor optimization when just weight is changed. */ + nghttp2_stream_change_weight(stream, pri_spec->weight); + + return 0; + } + + nghttp2_stream_dep_remove_subtree(stream); + + /* We have to update weight after removing stream from tree */ + stream->weight = pri_spec->weight; + + if (pri_spec->exclusive) { + rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream); + } else { + rv = nghttp2_stream_dep_add_subtree(dep_stream, stream); + } + + if (rv != 0) { + return rv; + } + + return 0; +} + +int nghttp2_session_add_item(nghttp2_session *session, + nghttp2_outbound_item *item) { + /* TODO Return error if stream is not found for the frame requiring + stream presence. */ + int rv = 0; + nghttp2_stream *stream; + nghttp2_frame *frame; + + frame = &item->frame; + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + + switch (frame->hd.type) { + case NGHTTP2_DATA: + if (!stream) { + return NGHTTP2_ERR_STREAM_CLOSED; + } + + if (stream->item) { + return NGHTTP2_ERR_DATA_EXIST; + } + + rv = nghttp2_stream_attach_item(stream, item); + + if (rv != 0) { + return rv; + } + + return 0; + case NGHTTP2_HEADERS: + /* We push request HEADERS and push response HEADERS to + dedicated queue because their transmission is affected by + SETTINGS_MAX_CONCURRENT_STREAMS */ + /* TODO If 2 HEADERS are submitted for reserved stream, then + both of them are queued into ob_syn, which is not + desirable. */ + if (frame->headers.cat == NGHTTP2_HCAT_REQUEST || + (stream && stream->state == NGHTTP2_STREAM_RESERVED)) { + nghttp2_outbound_queue_push(&session->ob_syn, item); + item->queued = 1; + return 0; + ; + } + + nghttp2_outbound_queue_push(&session->ob_reg, item); + item->queued = 1; + return 0; + case NGHTTP2_SETTINGS: + case NGHTTP2_PING: + nghttp2_outbound_queue_push(&session->ob_urgent, item); + item->queued = 1; + return 0; + case NGHTTP2_RST_STREAM: + if (stream) { + stream->state = NGHTTP2_STREAM_CLOSING; + } + nghttp2_outbound_queue_push(&session->ob_reg, item); + item->queued = 1; + return 0; + case NGHTTP2_PUSH_PROMISE: { + nghttp2_headers_aux_data *aux_data; + nghttp2_priority_spec pri_spec; + + aux_data = &item->aux_data.headers; + + if (!stream) { + return NGHTTP2_ERR_STREAM_CLOSED; + } + + nghttp2_priority_spec_init(&pri_spec, stream->stream_id, + NGHTTP2_DEFAULT_WEIGHT, 0); + + if (!nghttp2_session_open_stream( + session, frame->push_promise.promised_stream_id, + NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_RESERVED, + aux_data->stream_user_data)) { + return NGHTTP2_ERR_NOMEM; + } + + /* We don't have to call nghttp2_session_adjust_closed_stream() + here, since stream->stream_id is local stream_id, and it does + not affect closed stream count. */ + + nghttp2_outbound_queue_push(&session->ob_reg, item); + item->queued = 1; + + return 0; + } + case NGHTTP2_WINDOW_UPDATE: + if (stream) { + stream->window_update_queued = 1; + } else if (frame->hd.stream_id == 0) { + session->window_update_queued = 1; + } + nghttp2_outbound_queue_push(&session->ob_reg, item); + item->queued = 1; + return 0; + default: + nghttp2_outbound_queue_push(&session->ob_reg, item); + item->queued = 1; + return 0; + } +} + +int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id, + uint32_t error_code) { + int rv; + nghttp2_outbound_item *item; + nghttp2_frame *frame; + nghttp2_stream *stream; + nghttp2_mem *mem; + + mem = &session->mem; + stream = nghttp2_session_get_stream(session, stream_id); + if (stream && stream->state == NGHTTP2_STREAM_CLOSING) { + return 0; + } + + /* Cancel pending request HEADERS in ob_syn if this RST_STREAM + refers to that stream. */ + if (!session->server && nghttp2_session_is_my_stream_id(session, stream_id) && + nghttp2_outbound_queue_top(&session->ob_syn)) { + nghttp2_headers_aux_data *aux_data; + nghttp2_frame *headers_frame; + + headers_frame = &nghttp2_outbound_queue_top(&session->ob_syn)->frame; + assert(headers_frame->hd.type == NGHTTP2_HEADERS); + + if (headers_frame->hd.stream_id <= stream_id && + (uint32_t)stream_id < session->next_stream_id) { + + for (item = session->ob_syn.head; item; item = item->qnext) { + aux_data = &item->aux_data.headers; + + if (item->frame.hd.stream_id < stream_id) { + continue; + } + + /* stream_id in ob_syn queue must be strictly increasing. If + we found larger ID, then we can break here. */ + if (item->frame.hd.stream_id > stream_id || aux_data->canceled) { + break; + } + + aux_data->error_code = error_code; + aux_data->canceled = 1; + + return 0; + } + } + } + + item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); + if (item == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_outbound_item_init(item); + + frame = &item->frame; + + nghttp2_frame_rst_stream_init(&frame->rst_stream, stream_id, error_code); + rv = nghttp2_session_add_item(session, item); + if (rv != 0) { + nghttp2_frame_rst_stream_free(&frame->rst_stream); + nghttp2_mem_free(mem, item); + return rv; + } + return 0; +} + +nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, + int32_t stream_id, uint8_t flags, + nghttp2_priority_spec *pri_spec_in, + nghttp2_stream_state initial_state, + void *stream_user_data) { + int rv; + nghttp2_stream *stream; + nghttp2_stream *dep_stream = NULL; + int stream_alloc = 0; + nghttp2_priority_spec pri_spec_default; + nghttp2_priority_spec *pri_spec = pri_spec_in; + nghttp2_mem *mem; + + mem = &session->mem; + stream = nghttp2_session_get_stream_raw(session, stream_id); + + if (stream) { + assert(stream->state == NGHTTP2_STREAM_IDLE); + assert(nghttp2_stream_in_dep_tree(stream)); + nghttp2_session_detach_idle_stream(session, stream); + rv = nghttp2_stream_dep_remove(stream); + if (rv != 0) { + return NULL; + } + } else { + stream = nghttp2_mem_malloc(mem, sizeof(nghttp2_stream)); + if (stream == NULL) { + return NULL; + } + + stream_alloc = 1; + } + + if (pri_spec->stream_id != 0) { + dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); + + if (!dep_stream && + session_detect_idle_stream(session, pri_spec->stream_id)) { + /* Depends on idle stream, which does not exist in memory. + Assign default priority for it. */ + nghttp2_priority_spec_default_init(&pri_spec_default); + + dep_stream = nghttp2_session_open_stream( + session, pri_spec->stream_id, NGHTTP2_FLAG_NONE, &pri_spec_default, + NGHTTP2_STREAM_IDLE, NULL); + + if (dep_stream == NULL) { + if (stream_alloc) { + nghttp2_mem_free(mem, stream); + } + + return NULL; + } + } else if (!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) { + /* If dep_stream is not part of dependency tree, stream will get + default priority. This handles the case when + pri_spec->stream_id == stream_id. This happens because we + don't check pri_spec->stream_id against new stream ID in + nghttp2_submit_request. This also handles the case when idle + stream created by PRIORITY frame was opened. Somehow we + first remove the idle stream from dependency tree. This is + done to simplify code base, but ideally we should retain old + dependency. But I'm not sure this adds values. */ + nghttp2_priority_spec_default_init(&pri_spec_default); + pri_spec = &pri_spec_default; + } + } + + if (initial_state == NGHTTP2_STREAM_RESERVED) { + flags |= NGHTTP2_STREAM_FLAG_PUSH; + } + + if (stream_alloc) { + nghttp2_stream_init(stream, stream_id, flags, initial_state, + pri_spec->weight, + (int32_t)session->remote_settings.initial_window_size, + (int32_t)session->local_settings.initial_window_size, + stream_user_data, mem); + + rv = nghttp2_map_insert(&session->streams, &stream->map_entry); + if (rv != 0) { + nghttp2_stream_free(stream); + nghttp2_mem_free(mem, stream); + return NULL; + } + } else { + stream->flags = flags; + stream->state = initial_state; + stream->weight = pri_spec->weight; + stream->stream_user_data = stream_user_data; + } + + switch (initial_state) { + case NGHTTP2_STREAM_RESERVED: + if (nghttp2_session_is_my_stream_id(session, stream_id)) { + /* reserved (local) */ + nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); + } else { + /* reserved (remote) */ + nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); + ++session->num_incoming_reserved_streams; + } + /* Reserved stream does not count in the concurrent streams + limit. That is one of the DOS vector. */ + break; + case NGHTTP2_STREAM_IDLE: + /* Idle stream does not count toward the concurrent streams limit. + This is used as anchor node in dependency tree. */ + nghttp2_session_keep_idle_stream(session, stream); + break; + default: + if (nghttp2_session_is_my_stream_id(session, stream_id)) { + ++session->num_outgoing_streams; + } else { + ++session->num_incoming_streams; + } + } + + if (pri_spec->stream_id == 0) { + dep_stream = &session->root; + } + + assert(dep_stream); + + if (pri_spec->exclusive) { + rv = nghttp2_stream_dep_insert(dep_stream, stream); + if (rv != 0) { + return NULL; + } + } else { + nghttp2_stream_dep_add(dep_stream, stream); + } + + return stream; +} + +int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, + uint32_t error_code) { + int rv; + nghttp2_stream *stream; + nghttp2_mem *mem; + int is_my_stream_id; + + mem = &session->mem; + stream = nghttp2_session_get_stream(session, stream_id); + + if (!stream) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + DEBUGF("stream: stream(%p)=%d close\n", stream, stream->stream_id); + + if (stream->item) { + nghttp2_outbound_item *item; + + item = stream->item; + + rv = nghttp2_stream_detach_item(stream); + + if (rv != 0) { + return rv; + } + + /* If item is queued, it will be deleted when it is popped + (nghttp2_session_prep_frame() will fail). If session->aob.item + points to this item, let active_outbound_item_reset() + free the item. */ + if (!item->queued && item != session->aob.item) { + nghttp2_outbound_item_free(item, mem); + nghttp2_mem_free(mem, item); + } + } + + /* We call on_stream_close_callback even if stream->state is + NGHTTP2_STREAM_INITIAL. This will happen while sending request + HEADERS, a local endpoint receives RST_STREAM for that stream. It + may be PROTOCOL_ERROR, but without notifying stream closure will + hang the stream in a local endpoint. + */ + + if (session->callbacks.on_stream_close_callback) { + if (session->callbacks.on_stream_close_callback( + session, stream_id, error_code, session->user_data) != 0) { + + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + + is_my_stream_id = nghttp2_session_is_my_stream_id(session, stream_id); + + /* pushed streams which is not opened yet is not counted toward max + concurrent limits */ + if ((stream->flags & NGHTTP2_STREAM_FLAG_PUSH)) { + if (!is_my_stream_id) { + --session->num_incoming_reserved_streams; + } + } else { + if (is_my_stream_id) { + --session->num_outgoing_streams; + } else { + --session->num_incoming_streams; + } + } + + /* Closes both directions just in case they are not closed yet */ + stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED; + + if ((session->opt_flags & NGHTTP2_OPTMASK_NO_CLOSED_STREAMS) == 0 && + session->server && !is_my_stream_id && + nghttp2_stream_in_dep_tree(stream)) { + /* On server side, retain stream at most MAX_CONCURRENT_STREAMS + combined with the current active incoming streams to make + dependency tree work better. */ + nghttp2_session_keep_closed_stream(session, stream); + } else { + rv = nghttp2_session_destroy_stream(session, stream); + if (rv != 0) { + return rv; + } + } + + return 0; +} + +int nghttp2_session_destroy_stream(nghttp2_session *session, + nghttp2_stream *stream) { + nghttp2_mem *mem; + int rv; + + DEBUGF("stream: destroy closed stream(%p)=%d\n", stream, stream->stream_id); + + mem = &session->mem; + + if (nghttp2_stream_in_dep_tree(stream)) { + rv = nghttp2_stream_dep_remove(stream); + if (rv != 0) { + return rv; + } + } + + nghttp2_map_remove(&session->streams, stream->stream_id); + nghttp2_stream_free(stream); + nghttp2_mem_free(mem, stream); + + return 0; +} + +void nghttp2_session_keep_closed_stream(nghttp2_session *session, + nghttp2_stream *stream) { + DEBUGF("stream: keep closed stream(%p)=%d, state=%d\n", stream, + stream->stream_id, stream->state); + + if (session->closed_stream_tail) { + session->closed_stream_tail->closed_next = stream; + stream->closed_prev = session->closed_stream_tail; + } else { + session->closed_stream_head = stream; + } + session->closed_stream_tail = stream; + + ++session->num_closed_streams; +} + +void nghttp2_session_keep_idle_stream(nghttp2_session *session, + nghttp2_stream *stream) { + DEBUGF("stream: keep idle stream(%p)=%d, state=%d\n", stream, + stream->stream_id, stream->state); + + if (session->idle_stream_tail) { + session->idle_stream_tail->closed_next = stream; + stream->closed_prev = session->idle_stream_tail; + } else { + session->idle_stream_head = stream; + } + session->idle_stream_tail = stream; + + ++session->num_idle_streams; +} + +void nghttp2_session_detach_idle_stream(nghttp2_session *session, + nghttp2_stream *stream) { + nghttp2_stream *prev_stream, *next_stream; + + DEBUGF("stream: detach idle stream(%p)=%d, state=%d\n", stream, + stream->stream_id, stream->state); + + prev_stream = stream->closed_prev; + next_stream = stream->closed_next; + + if (prev_stream) { + prev_stream->closed_next = next_stream; + } else { + session->idle_stream_head = next_stream; + } + + if (next_stream) { + next_stream->closed_prev = prev_stream; + } else { + session->idle_stream_tail = prev_stream; + } + + stream->closed_prev = NULL; + stream->closed_next = NULL; + + --session->num_idle_streams; +} + +int nghttp2_session_adjust_closed_stream(nghttp2_session *session) { + size_t num_stream_max; + int rv; + + if (session->local_settings.max_concurrent_streams == + NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS) { + num_stream_max = session->pending_local_max_concurrent_stream; + } else { + num_stream_max = session->local_settings.max_concurrent_streams; + } + + DEBUGF("stream: adjusting kept closed streams num_closed_streams=%zu, " + "num_incoming_streams=%zu, max_concurrent_streams=%zu\n", + session->num_closed_streams, session->num_incoming_streams, + num_stream_max); + + while (session->num_closed_streams > 0 && + session->num_closed_streams + session->num_incoming_streams > + num_stream_max) { + nghttp2_stream *head_stream; + nghttp2_stream *next; + + head_stream = session->closed_stream_head; + + assert(head_stream); + + next = head_stream->closed_next; + + rv = nghttp2_session_destroy_stream(session, head_stream); + if (rv != 0) { + return rv; + } + + /* head_stream is now freed */ + + session->closed_stream_head = next; + + if (session->closed_stream_head) { + session->closed_stream_head->closed_prev = NULL; + } else { + session->closed_stream_tail = NULL; + } + + --session->num_closed_streams; + } + + return 0; +} + +int nghttp2_session_adjust_idle_stream(nghttp2_session *session) { + size_t max; + int rv; + + /* Make minimum number of idle streams 16, and maximum 100, which + are arbitrary chosen numbers. */ + max = nghttp2_min( + 100, nghttp2_max( + 16, nghttp2_min(session->local_settings.max_concurrent_streams, + session->pending_local_max_concurrent_stream))); + + DEBUGF("stream: adjusting kept idle streams num_idle_streams=%zu, max=%zu\n", + session->num_idle_streams, max); + + while (session->num_idle_streams > max) { + nghttp2_stream *head; + nghttp2_stream *next; + + head = session->idle_stream_head; + assert(head); + + next = head->closed_next; + + rv = nghttp2_session_destroy_stream(session, head); + if (rv != 0) { + return rv; + } + + /* head is now destroyed */ + + session->idle_stream_head = next; + + if (session->idle_stream_head) { + session->idle_stream_head->closed_prev = NULL; + } else { + session->idle_stream_tail = NULL; + } + + --session->num_idle_streams; + } + + return 0; +} + +/* + * Closes stream with stream ID |stream_id| if both transmission and + * reception of the stream were disallowed. The |error_code| indicates + * the reason of the closure. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_INVALID_ARGUMENT + * The stream is not found. + * NGHTTP2_ERR_CALLBACK_FAILURE + * The callback function failed. + */ +int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session, + nghttp2_stream *stream) { + if ((stream->shut_flags & NGHTTP2_SHUT_RDWR) == NGHTTP2_SHUT_RDWR) { + return nghttp2_session_close_stream(session, stream->stream_id, + NGHTTP2_NO_ERROR); + } + return 0; +} + +/* + * Returns nonzero if local endpoint allows reception of new stream + * from remote. + */ +static int session_allow_incoming_new_stream(nghttp2_session *session) { + return (session->goaway_flags & + (NGHTTP2_GOAWAY_TERM_ON_SEND | NGHTTP2_GOAWAY_SENT)) == 0; +} + +/* + * This function returns nonzero if session is closing. + */ +static int session_is_closing(nghttp2_session *session) { + return (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) != 0 || + (nghttp2_session_want_read(session) == 0 && + nghttp2_session_want_write(session) == 0); +} + +/* + * Check that we can send a frame to the |stream|. This function + * returns 0 if we can send a frame to the |frame|, or one of the + * following negative error codes: + * + * NGHTTP2_ERR_STREAM_CLOSED + * The stream is already closed. + * NGHTTP2_ERR_STREAM_SHUT_WR + * The stream is half-closed for transmission. + * NGHTTP2_ERR_SESSION_CLOSING + * This session is closing. + */ +static int session_predicate_for_stream_send(nghttp2_session *session, + nghttp2_stream *stream) { + if (stream == NULL) { + return NGHTTP2_ERR_STREAM_CLOSED; + } + if (session_is_closing(session)) { + return NGHTTP2_ERR_SESSION_CLOSING; + } + if (stream->shut_flags & NGHTTP2_SHUT_WR) { + return NGHTTP2_ERR_STREAM_SHUT_WR; + } + return 0; +} + +int nghttp2_session_check_request_allowed(nghttp2_session *session) { + return !session->server && session->next_stream_id <= INT32_MAX && + (session->goaway_flags & NGHTTP2_GOAWAY_RECV) == 0 && + !session_is_closing(session); +} + +/* + * This function checks request HEADERS frame, which opens stream, can + * be sent at this time. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_START_STREAM_NOT_ALLOWED + * New stream cannot be created because of GOAWAY: session is + * going down or received last_stream_id is strictly less than + * frame->hd.stream_id. + * NGHTTP2_ERR_STREAM_CLOSING + * request HEADERS was canceled by RST_STREAM while it is in queue. + */ +static int session_predicate_request_headers_send(nghttp2_session *session, + nghttp2_outbound_item *item) { + if (item->aux_data.headers.canceled) { + return NGHTTP2_ERR_STREAM_CLOSING; + } + /* If we are terminating session (NGHTTP2_GOAWAY_TERM_ON_SEND), + GOAWAY was received from peer, or session is about to close, new + request is not allowed. */ + if ((session->goaway_flags & NGHTTP2_GOAWAY_RECV) || + session_is_closing(session)) { + return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED; + } + return 0; +} + +/* + * This function checks HEADERS, which is the first frame from the + * server, with the |stream| can be sent at this time. The |stream| + * can be NULL. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_STREAM_CLOSED + * The stream is already closed or does not exist. + * NGHTTP2_ERR_STREAM_SHUT_WR + * The transmission is not allowed for this stream (e.g., a frame + * with END_STREAM flag set has already sent) + * NGHTTP2_ERR_INVALID_STREAM_ID + * The stream ID is invalid. + * NGHTTP2_ERR_STREAM_CLOSING + * RST_STREAM was queued for this stream. + * NGHTTP2_ERR_INVALID_STREAM_STATE + * The state of the stream is not valid. + * NGHTTP2_ERR_SESSION_CLOSING + * This session is closing. + * NGHTTP2_ERR_PROTO + * Client side attempted to send response. + */ +static int session_predicate_response_headers_send(nghttp2_session *session, + nghttp2_stream *stream) { + int rv; + rv = session_predicate_for_stream_send(session, stream); + if (rv != 0) { + return rv; + } + assert(stream); + if (!session->server) { + return NGHTTP2_ERR_PROTO; + } + if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { + return NGHTTP2_ERR_INVALID_STREAM_ID; + } + switch (stream->state) { + case NGHTTP2_STREAM_OPENING: + return 0; + case NGHTTP2_STREAM_CLOSING: + return NGHTTP2_ERR_STREAM_CLOSING; + default: + return NGHTTP2_ERR_INVALID_STREAM_STATE; + } +} + +/* + * This function checks HEADERS for reserved stream can be sent. The + * |stream| must be reserved state and the |session| is server side. + * The |stream| can be NULL. + * + * This function returns 0 if it succeeds, or one of the following + * error codes: + * + * NGHTTP2_ERR_STREAM_CLOSED + * The stream is already closed. + * NGHTTP2_ERR_STREAM_SHUT_WR + * The stream is half-closed for transmission. + * NGHTTP2_ERR_PROTO + * The stream is not reserved state + * NGHTTP2_ERR_STREAM_CLOSED + * RST_STREAM was queued for this stream. + * NGHTTP2_ERR_SESSION_CLOSING + * This session is closing. + * NGHTTP2_ERR_START_STREAM_NOT_ALLOWED + * New stream cannot be created because GOAWAY is already sent or + * received. + * NGHTTP2_ERR_PROTO + * Client side attempted to send push response. + */ +static int +session_predicate_push_response_headers_send(nghttp2_session *session, + nghttp2_stream *stream) { + int rv; + /* TODO Should disallow HEADERS if GOAWAY has already been issued? */ + rv = session_predicate_for_stream_send(session, stream); + if (rv != 0) { + return rv; + } + assert(stream); + if (!session->server) { + return NGHTTP2_ERR_PROTO; + } + if (stream->state != NGHTTP2_STREAM_RESERVED) { + return NGHTTP2_ERR_PROTO; + } + if (session->goaway_flags & NGHTTP2_GOAWAY_RECV) { + return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED; + } + return 0; +} + +/* + * This function checks HEADERS, which is neither stream-opening nor + * first response header, with the |stream| can be sent at this time. + * The |stream| can be NULL. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_STREAM_CLOSED + * The stream is already closed or does not exist. + * NGHTTP2_ERR_STREAM_SHUT_WR + * The transmission is not allowed for this stream (e.g., a frame + * with END_STREAM flag set has already sent) + * NGHTTP2_ERR_STREAM_CLOSING + * RST_STREAM was queued for this stream. + * NGHTTP2_ERR_INVALID_STREAM_STATE + * The state of the stream is not valid. + * NGHTTP2_ERR_SESSION_CLOSING + * This session is closing. + */ +static int session_predicate_headers_send(nghttp2_session *session, + nghttp2_stream *stream) { + int rv; + rv = session_predicate_for_stream_send(session, stream); + if (rv != 0) { + return rv; + } + assert(stream); + + switch (stream->state) { + case NGHTTP2_STREAM_OPENED: + return 0; + case NGHTTP2_STREAM_CLOSING: + return NGHTTP2_ERR_STREAM_CLOSING; + default: + if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { + return 0; + } + return NGHTTP2_ERR_INVALID_STREAM_STATE; + } +} + +/* + * This function checks PUSH_PROMISE frame |frame| with the |stream| + * can be sent at this time. The |stream| can be NULL. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_START_STREAM_NOT_ALLOWED + * New stream cannot be created because GOAWAY is already sent or + * received. + * NGHTTP2_ERR_PROTO + * The client side attempts to send PUSH_PROMISE, or the server + * sends PUSH_PROMISE for the stream not initiated by the client. + * NGHTTP2_ERR_STREAM_CLOSED + * The stream is already closed or does not exist. + * NGHTTP2_ERR_STREAM_CLOSING + * RST_STREAM was queued for this stream. + * NGHTTP2_ERR_STREAM_SHUT_WR + * The transmission is not allowed for this stream (e.g., a frame + * with END_STREAM flag set has already sent) + * NGHTTP2_ERR_PUSH_DISABLED + * The remote peer disabled reception of PUSH_PROMISE. + * NGHTTP2_ERR_SESSION_CLOSING + * This session is closing. + */ +static int session_predicate_push_promise_send(nghttp2_session *session, + nghttp2_stream *stream) { + int rv; + + if (!session->server) { + return NGHTTP2_ERR_PROTO; + } + + rv = session_predicate_for_stream_send(session, stream); + if (rv != 0) { + return rv; + } + + assert(stream); + + if (session->remote_settings.enable_push == 0) { + return NGHTTP2_ERR_PUSH_DISABLED; + } + if (stream->state == NGHTTP2_STREAM_CLOSING) { + return NGHTTP2_ERR_STREAM_CLOSING; + } + if (session->goaway_flags & NGHTTP2_GOAWAY_RECV) { + return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED; + } + return 0; +} + +/* + * This function checks WINDOW_UPDATE with the stream ID |stream_id| + * can be sent at this time. Note that END_STREAM flag of the previous + * frame does not affect the transmission of the WINDOW_UPDATE frame. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_STREAM_CLOSED + * The stream is already closed or does not exist. + * NGHTTP2_ERR_STREAM_CLOSING + * RST_STREAM was queued for this stream. + * NGHTTP2_ERR_INVALID_STREAM_STATE + * The state of the stream is not valid. + * NGHTTP2_ERR_SESSION_CLOSING + * This session is closing. + */ +static int session_predicate_window_update_send(nghttp2_session *session, + int32_t stream_id) { + nghttp2_stream *stream; + + if (session_is_closing(session)) { + return NGHTTP2_ERR_SESSION_CLOSING; + } + + if (stream_id == 0) { + /* Connection-level window update */ + return 0; + } + stream = nghttp2_session_get_stream(session, stream_id); + if (stream == NULL) { + return NGHTTP2_ERR_STREAM_CLOSED; + } + if (stream->state == NGHTTP2_STREAM_CLOSING) { + return NGHTTP2_ERR_STREAM_CLOSING; + } + if (state_reserved_local(session, stream)) { + return NGHTTP2_ERR_INVALID_STREAM_STATE; + } + return 0; +} + +static int session_predicate_altsvc_send(nghttp2_session *session, + int32_t stream_id) { + nghttp2_stream *stream; + + if (session_is_closing(session)) { + return NGHTTP2_ERR_SESSION_CLOSING; + } + + if (stream_id == 0) { + return 0; + } + + stream = nghttp2_session_get_stream(session, stream_id); + if (stream == NULL) { + return NGHTTP2_ERR_STREAM_CLOSED; + } + if (stream->state == NGHTTP2_STREAM_CLOSING) { + return NGHTTP2_ERR_STREAM_CLOSING; + } + + return 0; +} + +/* Take into account settings max frame size and both connection-level + flow control here */ +static ssize_t +nghttp2_session_enforce_flow_control_limits(nghttp2_session *session, + nghttp2_stream *stream, + ssize_t requested_window_size) { + ssize_t window_size = 0; + window_size = nghttp2_min(nghttp2_min(nghttp2_min(requested_window_size, + stream->remote_window_size), + session->remote_window_size), + (int32_t)session->remote_settings.max_frame_size); + return window_size; +} + +/* + * Returns the maximum length of next data read. If the + * connection-level and/or stream-wise flow control are enabled, the + * return value takes into account those current window sizes. The remote + * settings for max frame size is also taken into account. + */ +static size_t nghttp2_session_next_data_read(nghttp2_session *session, + nghttp2_stream *stream) { + ssize_t window_size; + + window_size = nghttp2_session_enforce_flow_control_limits( + session, stream, NGHTTP2_DATA_PAYLOADLEN); + + DEBUGF("send: available window=%zd\n", window_size); + + return window_size > 0 ? (size_t)window_size : 0; +} + +/* + * This function checks DATA with the |stream| can be sent at this + * time. The |stream| can be NULL. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_STREAM_CLOSED + * The stream is already closed or does not exist. + * NGHTTP2_ERR_STREAM_SHUT_WR + * The transmission is not allowed for this stream (e.g., a frame + * with END_STREAM flag set has already sent) + * NGHTTP2_ERR_STREAM_CLOSING + * RST_STREAM was queued for this stream. + * NGHTTP2_ERR_INVALID_STREAM_STATE + * The state of the stream is not valid. + * NGHTTP2_ERR_SESSION_CLOSING + * This session is closing. + */ +static int nghttp2_session_predicate_data_send(nghttp2_session *session, + nghttp2_stream *stream) { + int rv; + rv = session_predicate_for_stream_send(session, stream); + if (rv != 0) { + return rv; + } + assert(stream); + if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { + /* Request body data */ + /* If stream->state is NGHTTP2_STREAM_CLOSING, RST_STREAM was + queued but not yet sent. In this case, we won't send DATA + frames. */ + if (stream->state == NGHTTP2_STREAM_CLOSING) { + return NGHTTP2_ERR_STREAM_CLOSING; + } + if (stream->state == NGHTTP2_STREAM_RESERVED) { + return NGHTTP2_ERR_INVALID_STREAM_STATE; + } + return 0; + } + /* Response body data */ + if (stream->state == NGHTTP2_STREAM_OPENED) { + return 0; + } + if (stream->state == NGHTTP2_STREAM_CLOSING) { + return NGHTTP2_ERR_STREAM_CLOSING; + } + return NGHTTP2_ERR_INVALID_STREAM_STATE; +} + +static ssize_t session_call_select_padding(nghttp2_session *session, + const nghttp2_frame *frame, + size_t max_payloadlen) { + ssize_t rv; + + if (frame->hd.length >= max_payloadlen) { + return (ssize_t)frame->hd.length; + } + + if (session->callbacks.select_padding_callback) { + size_t max_paddedlen; + + max_paddedlen = + nghttp2_min(frame->hd.length + NGHTTP2_MAX_PADLEN, max_payloadlen); + + rv = session->callbacks.select_padding_callback( + session, frame, max_paddedlen, session->user_data); + if (rv < (ssize_t)frame->hd.length || rv > (ssize_t)max_paddedlen) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + return rv; + } + return (ssize_t)frame->hd.length; +} + +/* Add padding to HEADERS or PUSH_PROMISE. We use + frame->headers.padlen in this function to use the fact that + frame->push_promise has also padlen in the same position. */ +static int session_headers_add_pad(nghttp2_session *session, + nghttp2_frame *frame) { + int rv; + ssize_t padded_payloadlen; + nghttp2_active_outbound_item *aob; + nghttp2_bufs *framebufs; + size_t padlen; + size_t max_payloadlen; + + aob = &session->aob; + framebufs = &aob->framebufs; + + max_payloadlen = nghttp2_min(NGHTTP2_MAX_PAYLOADLEN, + frame->hd.length + NGHTTP2_MAX_PADLEN); + + padded_payloadlen = + session_call_select_padding(session, frame, max_payloadlen); + + if (nghttp2_is_fatal((int)padded_payloadlen)) { + return (int)padded_payloadlen; + } + + padlen = (size_t)padded_payloadlen - frame->hd.length; + + DEBUGF("send: padding selected: payloadlen=%zd, padlen=%zu\n", + padded_payloadlen, padlen); + + rv = nghttp2_frame_add_pad(framebufs, &frame->hd, padlen, 0); + + if (rv != 0) { + return rv; + } + + frame->headers.padlen = padlen; + + return 0; +} + +static size_t session_estimate_headers_payload(nghttp2_session *session, + const nghttp2_nv *nva, + size_t nvlen, + size_t additional) { + return nghttp2_hd_deflate_bound(&session->hd_deflater, nva, nvlen) + + additional; +} + +static int session_pack_extension(nghttp2_session *session, nghttp2_bufs *bufs, + nghttp2_frame *frame) { + ssize_t rv; + nghttp2_buf *buf; + size_t buflen; + size_t framelen; + + assert(session->callbacks.pack_extension_callback); + + buf = &bufs->head->buf; + buflen = nghttp2_min(nghttp2_buf_avail(buf), NGHTTP2_MAX_PAYLOADLEN); + + rv = session->callbacks.pack_extension_callback(session, buf->last, buflen, + frame, session->user_data); + if (rv == NGHTTP2_ERR_CANCEL) { + return (int)rv; + } + + if (rv < 0 || (size_t)rv > buflen) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + framelen = (size_t)rv; + + frame->hd.length = framelen; + + assert(buf->pos == buf->last); + buf->last += framelen; + buf->pos -= NGHTTP2_FRAME_HDLEN; + + nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); + + return 0; +} + +/* + * This function serializes frame for transmission. + * + * This function returns 0 if it succeeds, or one of negative error + * codes, including both fatal and non-fatal ones. + */ +static int session_prep_frame(nghttp2_session *session, + nghttp2_outbound_item *item) { + int rv; + nghttp2_frame *frame; + nghttp2_mem *mem; + + mem = &session->mem; + frame = &item->frame; + + switch (frame->hd.type) { + case NGHTTP2_DATA: { + size_t next_readmax; + nghttp2_stream *stream; + + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + + if (stream) { + assert(stream->item == item); + } + + rv = nghttp2_session_predicate_data_send(session, stream); + if (rv != 0) { + /* If stream was already closed, nghttp2_session_get_stream() + returns NULL, but item is still attached to the stream. + Search stream including closed again.*/ + stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); + if (stream) { + int rv2; + + rv2 = nghttp2_stream_detach_item(stream); + + if (nghttp2_is_fatal(rv2)) { + return rv2; + } + } + + return rv; + } + /* Assuming stream is not NULL */ + assert(stream); + next_readmax = nghttp2_session_next_data_read(session, stream); + + if (next_readmax == 0) { + + /* This must be true since we only pop DATA frame item from + queue when session->remote_window_size > 0 */ + assert(session->remote_window_size > 0); + + rv = nghttp2_stream_defer_item(stream, + NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + session->aob.item = NULL; + active_outbound_item_reset(&session->aob, mem); + return NGHTTP2_ERR_DEFERRED; + } + + rv = nghttp2_session_pack_data(session, &session->aob.framebufs, + next_readmax, frame, &item->aux_data.data, + stream); + if (rv == NGHTTP2_ERR_PAUSE) { + return rv; + } + if (rv == NGHTTP2_ERR_DEFERRED) { + rv = nghttp2_stream_defer_item(stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + session->aob.item = NULL; + active_outbound_item_reset(&session->aob, mem); + return NGHTTP2_ERR_DEFERRED; + } + if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + rv = nghttp2_stream_detach_item(stream); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id, + NGHTTP2_INTERNAL_ERROR); + if (nghttp2_is_fatal(rv)) { + return rv; + } + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + } + if (rv != 0) { + int rv2; + + rv2 = nghttp2_stream_detach_item(stream); + + if (nghttp2_is_fatal(rv2)) { + return rv2; + } + + return rv; + } + return 0; + } + case NGHTTP2_HEADERS: { + nghttp2_headers_aux_data *aux_data; + size_t estimated_payloadlen; + + aux_data = &item->aux_data.headers; + + if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) { + /* initial HEADERS, which opens stream */ + nghttp2_stream *stream; + + stream = nghttp2_session_open_stream( + session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, + &frame->headers.pri_spec, NGHTTP2_STREAM_INITIAL, + aux_data->stream_user_data); + + if (stream == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + /* We don't call nghttp2_session_adjust_closed_stream() here, + since we don't keep closed stream in client side */ + + rv = session_predicate_request_headers_send(session, item); + if (rv != 0) { + return rv; + } + + if (session_enforce_http_messaging(session)) { + nghttp2_http_record_request_method(stream, frame); + } + } else { + nghttp2_stream *stream; + + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + + if (stream && stream->state == NGHTTP2_STREAM_RESERVED) { + rv = session_predicate_push_response_headers_send(session, stream); + if (rv == 0) { + frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE; + + if (aux_data->stream_user_data) { + stream->stream_user_data = aux_data->stream_user_data; + } + } + } else if (session_predicate_response_headers_send(session, stream) == + 0) { + frame->headers.cat = NGHTTP2_HCAT_RESPONSE; + rv = 0; + } else { + frame->headers.cat = NGHTTP2_HCAT_HEADERS; + + rv = session_predicate_headers_send(session, stream); + } + + if (rv != 0) { + return rv; + } + } + + estimated_payloadlen = session_estimate_headers_payload( + session, frame->headers.nva, frame->headers.nvlen, + NGHTTP2_PRIORITY_SPECLEN); + + if (estimated_payloadlen > session->max_send_header_block_length) { + return NGHTTP2_ERR_FRAME_SIZE_ERROR; + } + + rv = nghttp2_frame_pack_headers(&session->aob.framebufs, &frame->headers, + &session->hd_deflater); + + if (rv != 0) { + return rv; + } + + DEBUGF("send: before padding, HEADERS serialized in %zd bytes\n", + nghttp2_bufs_len(&session->aob.framebufs)); + + rv = session_headers_add_pad(session, frame); + + if (rv != 0) { + return rv; + } + + DEBUGF("send: HEADERS finally serialized in %zd bytes\n", + nghttp2_bufs_len(&session->aob.framebufs)); + + if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) { + assert(session->last_sent_stream_id < frame->hd.stream_id); + session->last_sent_stream_id = frame->hd.stream_id; + } + + return 0; + } + case NGHTTP2_PRIORITY: { + if (session_is_closing(session)) { + return NGHTTP2_ERR_SESSION_CLOSING; + } + /* PRIORITY frame can be sent at any time and to any stream + ID. */ + nghttp2_frame_pack_priority(&session->aob.framebufs, &frame->priority); + + /* Peer can send PRIORITY frame against idle stream to create + "anchor" in dependency tree. Only client can do this in + nghttp2. In nghttp2, only server retains non-active (closed + or idle) streams in memory, so we don't open stream here. */ + return 0; + } + case NGHTTP2_RST_STREAM: + if (session_is_closing(session)) { + return NGHTTP2_ERR_SESSION_CLOSING; + } + nghttp2_frame_pack_rst_stream(&session->aob.framebufs, &frame->rst_stream); + return 0; + case NGHTTP2_SETTINGS: { + if (frame->hd.flags & NGHTTP2_FLAG_ACK) { + assert(session->obq_flood_counter_ > 0); + --session->obq_flood_counter_; + /* When session is about to close, don't send SETTINGS ACK. + We are required to send SETTINGS without ACK though; for + example, we have to send SETTINGS as a part of connection + preface. */ + if (session_is_closing(session)) { + return NGHTTP2_ERR_SESSION_CLOSING; + } + } + + rv = nghttp2_frame_pack_settings(&session->aob.framebufs, &frame->settings); + if (rv != 0) { + return rv; + } + return 0; + } + case NGHTTP2_PUSH_PROMISE: { + nghttp2_stream *stream; + size_t estimated_payloadlen; + + /* stream could be NULL if associated stream was already + closed. */ + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + + /* predicate should fail if stream is NULL. */ + rv = session_predicate_push_promise_send(session, stream); + if (rv != 0) { + return rv; + } + + assert(stream); + + estimated_payloadlen = session_estimate_headers_payload( + session, frame->push_promise.nva, frame->push_promise.nvlen, 0); + + if (estimated_payloadlen > session->max_send_header_block_length) { + return NGHTTP2_ERR_FRAME_SIZE_ERROR; + } + + rv = nghttp2_frame_pack_push_promise( + &session->aob.framebufs, &frame->push_promise, &session->hd_deflater); + if (rv != 0) { + return rv; + } + rv = session_headers_add_pad(session, frame); + if (rv != 0) { + return rv; + } + + assert(session->last_sent_stream_id + 2 <= + frame->push_promise.promised_stream_id); + session->last_sent_stream_id = frame->push_promise.promised_stream_id; + + return 0; + } + case NGHTTP2_PING: + if (frame->hd.flags & NGHTTP2_FLAG_ACK) { + assert(session->obq_flood_counter_ > 0); + --session->obq_flood_counter_; + } + /* PING frame is allowed to be sent unless termination GOAWAY is + sent */ + if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) { + return NGHTTP2_ERR_SESSION_CLOSING; + } + nghttp2_frame_pack_ping(&session->aob.framebufs, &frame->ping); + return 0; + case NGHTTP2_GOAWAY: + rv = nghttp2_frame_pack_goaway(&session->aob.framebufs, &frame->goaway); + if (rv != 0) { + return rv; + } + session->local_last_stream_id = frame->goaway.last_stream_id; + + return 0; + case NGHTTP2_WINDOW_UPDATE: + rv = session_predicate_window_update_send(session, frame->hd.stream_id); + if (rv != 0) { + return rv; + } + nghttp2_frame_pack_window_update(&session->aob.framebufs, + &frame->window_update); + return 0; + case NGHTTP2_CONTINUATION: + /* We never handle CONTINUATION here. */ + assert(0); + return 0; + default: { + nghttp2_ext_aux_data *aux_data; + + /* extension frame */ + + aux_data = &item->aux_data.ext; + + if (aux_data->builtin == 0) { + if (session_is_closing(session)) { + return NGHTTP2_ERR_SESSION_CLOSING; + } + + return session_pack_extension(session, &session->aob.framebufs, frame); + } + + switch (frame->hd.type) { + case NGHTTP2_ALTSVC: + rv = session_predicate_altsvc_send(session, frame->hd.stream_id); + if (rv != 0) { + return rv; + } + + nghttp2_frame_pack_altsvc(&session->aob.framebufs, &frame->ext); + + return 0; + default: + /* Unreachable here */ + assert(0); + return 0; + } + } + } +} + +nghttp2_outbound_item * +nghttp2_session_get_next_ob_item(nghttp2_session *session) { + if (nghttp2_outbound_queue_top(&session->ob_urgent)) { + return nghttp2_outbound_queue_top(&session->ob_urgent); + } + + if (nghttp2_outbound_queue_top(&session->ob_reg)) { + return nghttp2_outbound_queue_top(&session->ob_reg); + } + + if (!session_is_outgoing_concurrent_streams_max(session)) { + if (nghttp2_outbound_queue_top(&session->ob_syn)) { + return nghttp2_outbound_queue_top(&session->ob_syn); + } + } + + if (session->remote_window_size > 0) { + return nghttp2_stream_next_outbound_item(&session->root); + } + + return NULL; +} + +nghttp2_outbound_item * +nghttp2_session_pop_next_ob_item(nghttp2_session *session) { + nghttp2_outbound_item *item; + + item = nghttp2_outbound_queue_top(&session->ob_urgent); + if (item) { + nghttp2_outbound_queue_pop(&session->ob_urgent); + item->queued = 0; + return item; + } + + item = nghttp2_outbound_queue_top(&session->ob_reg); + if (item) { + nghttp2_outbound_queue_pop(&session->ob_reg); + item->queued = 0; + return item; + } + + if (!session_is_outgoing_concurrent_streams_max(session)) { + item = nghttp2_outbound_queue_top(&session->ob_syn); + if (item) { + nghttp2_outbound_queue_pop(&session->ob_syn); + item->queued = 0; + return item; + } + } + + if (session->remote_window_size > 0) { + return nghttp2_stream_next_outbound_item(&session->root); + } + + return NULL; +} + +static int session_call_before_frame_send(nghttp2_session *session, + nghttp2_frame *frame) { + int rv; + if (session->callbacks.before_frame_send_callback) { + rv = session->callbacks.before_frame_send_callback(session, frame, + session->user_data); + if (rv == NGHTTP2_ERR_CANCEL) { + return rv; + } + + if (rv != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + return 0; +} + +static int session_call_on_frame_send(nghttp2_session *session, + nghttp2_frame *frame) { + int rv; + if (session->callbacks.on_frame_send_callback) { + rv = session->callbacks.on_frame_send_callback(session, frame, + session->user_data); + if (rv != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + return 0; +} + +static int find_stream_on_goaway_func(nghttp2_map_entry *entry, void *ptr) { + nghttp2_close_stream_on_goaway_arg *arg; + nghttp2_stream *stream; + + arg = (nghttp2_close_stream_on_goaway_arg *)ptr; + stream = (nghttp2_stream *)entry; + + if (nghttp2_session_is_my_stream_id(arg->session, stream->stream_id)) { + if (arg->incoming) { + return 0; + } + } else if (!arg->incoming) { + return 0; + } + + if (stream->state != NGHTTP2_STREAM_IDLE && + (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) == 0 && + stream->stream_id > arg->last_stream_id) { + /* We are collecting streams to close because we cannot call + nghttp2_session_close_stream() inside nghttp2_map_each(). + Reuse closed_next member.. bad choice? */ + assert(stream->closed_next == NULL); + assert(stream->closed_prev == NULL); + + if (arg->head) { + stream->closed_next = arg->head; + arg->head = stream; + } else { + arg->head = stream; + } + } + + return 0; +} + +/* Closes non-idle and non-closed streams whose stream ID > + last_stream_id. If incoming is nonzero, we are going to close + incoming streams. Otherwise, close outgoing streams. */ +static int session_close_stream_on_goaway(nghttp2_session *session, + int32_t last_stream_id, + int incoming) { + int rv; + nghttp2_stream *stream, *next_stream; + nghttp2_close_stream_on_goaway_arg arg = {session, NULL, last_stream_id, + incoming}; + + rv = nghttp2_map_each(&session->streams, find_stream_on_goaway_func, &arg); + assert(rv == 0); + + stream = arg.head; + while (stream) { + next_stream = stream->closed_next; + stream->closed_next = NULL; + rv = nghttp2_session_close_stream(session, stream->stream_id, + NGHTTP2_REFUSED_STREAM); + + /* stream may be deleted here */ + + stream = next_stream; + + if (nghttp2_is_fatal(rv)) { + /* Clean up closed_next member just in case */ + while (stream) { + next_stream = stream->closed_next; + stream->closed_next = NULL; + stream = next_stream; + } + return rv; + } + } + + return 0; +} + +static void reschedule_stream(nghttp2_stream *stream) { + stream->last_writelen = stream->item->frame.hd.length; + + nghttp2_stream_reschedule(stream); +} + +static int session_update_stream_consumed_size(nghttp2_session *session, + nghttp2_stream *stream, + size_t delta_size); + +static int session_update_connection_consumed_size(nghttp2_session *session, + size_t delta_size); + +static int session_update_recv_connection_window_size(nghttp2_session *session, + size_t delta_size); + +static int session_update_recv_stream_window_size(nghttp2_session *session, + nghttp2_stream *stream, + size_t delta_size, + int send_window_update); + +/* + * Called after a frame is sent. This function runs + * on_frame_send_callback and handles stream closure upon END_STREAM + * or RST_STREAM. This function does not reset session->aob. It is a + * responsibility of session_after_frame_sent2. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_CALLBACK_FAILURE + * The callback function failed. + */ +static int session_after_frame_sent1(nghttp2_session *session) { + int rv; + nghttp2_active_outbound_item *aob = &session->aob; + nghttp2_outbound_item *item = aob->item; + nghttp2_bufs *framebufs = &aob->framebufs; + nghttp2_frame *frame; + nghttp2_stream *stream; + + frame = &item->frame; + + if (frame->hd.type == NGHTTP2_DATA) { + nghttp2_data_aux_data *aux_data; + + aux_data = &item->aux_data.data; + + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + /* We update flow control window after a frame was completely + sent. This is possible because we choose payload length not to + exceed the window */ + session->remote_window_size -= (int32_t)frame->hd.length; + if (stream) { + stream->remote_window_size -= (int32_t)frame->hd.length; + } + + if (stream && aux_data->eof) { + rv = nghttp2_stream_detach_item(stream); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + /* Call on_frame_send_callback after + nghttp2_stream_detach_item(), so that application can issue + nghttp2_submit_data() in the callback. */ + if (session->callbacks.on_frame_send_callback) { + rv = session_call_on_frame_send(session, frame); + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + + if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { + int stream_closed; + + stream_closed = + (stream->shut_flags & NGHTTP2_SHUT_RDWR) == NGHTTP2_SHUT_RDWR; + + nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); + + rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); + if (nghttp2_is_fatal(rv)) { + return rv; + } + /* stream may be NULL if it was closed */ + if (stream_closed) { + stream = NULL; + } + } + return 0; + } + + if (session->callbacks.on_frame_send_callback) { + rv = session_call_on_frame_send(session, frame); + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + + return 0; + } + + /* non-DATA frame */ + + if (frame->hd.type == NGHTTP2_HEADERS || + frame->hd.type == NGHTTP2_PUSH_PROMISE) { + if (nghttp2_bufs_next_present(framebufs)) { + DEBUGF("send: CONTINUATION exists, just return\n"); + return 0; + } + } + rv = session_call_on_frame_send(session, frame); + if (nghttp2_is_fatal(rv)) { + return rv; + } + switch (frame->hd.type) { + case NGHTTP2_HEADERS: { + nghttp2_headers_aux_data *aux_data; + + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + if (!stream) { + return 0; + } + + switch (frame->headers.cat) { + case NGHTTP2_HCAT_REQUEST: { + stream->state = NGHTTP2_STREAM_OPENING; + if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { + nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); + } + rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); + if (nghttp2_is_fatal(rv)) { + return rv; + } + /* We assume aux_data is a pointer to nghttp2_headers_aux_data */ + aux_data = &item->aux_data.headers; + if (aux_data->data_prd.read_callback) { + /* nghttp2_submit_data() makes a copy of aux_data->data_prd */ + rv = nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, + frame->hd.stream_id, &aux_data->data_prd); + if (nghttp2_is_fatal(rv)) { + return rv; + } + /* TODO nghttp2_submit_data() may fail if stream has already + DATA frame item. We might have to handle it here. */ + } + return 0; + } + case NGHTTP2_HCAT_PUSH_RESPONSE: + stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH); + ++session->num_outgoing_streams; + /* Fall through */ + case NGHTTP2_HCAT_RESPONSE: + stream->state = NGHTTP2_STREAM_OPENED; + /* Fall through */ + case NGHTTP2_HCAT_HEADERS: + if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { + nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); + } + rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); + if (nghttp2_is_fatal(rv)) { + return rv; + } + /* We assume aux_data is a pointer to nghttp2_headers_aux_data */ + aux_data = &item->aux_data.headers; + if (aux_data->data_prd.read_callback) { + rv = nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, + frame->hd.stream_id, &aux_data->data_prd); + if (nghttp2_is_fatal(rv)) { + return rv; + } + /* TODO nghttp2_submit_data() may fail if stream has already + DATA frame item. We might have to handle it here. */ + } + return 0; + default: + /* Unreachable */ + assert(0); + return 0; + } + } + case NGHTTP2_PRIORITY: + if (session->server) { + return 0; + ; + } + + stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); + + if (!stream) { + if (!session_detect_idle_stream(session, frame->hd.stream_id)) { + return 0; + } + + stream = nghttp2_session_open_stream( + session, frame->hd.stream_id, NGHTTP2_FLAG_NONE, + &frame->priority.pri_spec, NGHTTP2_STREAM_IDLE, NULL); + if (!stream) { + return NGHTTP2_ERR_NOMEM; + } + } else { + rv = nghttp2_session_reprioritize_stream(session, stream, + &frame->priority.pri_spec); + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + + rv = nghttp2_session_adjust_idle_stream(session); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + return 0; + case NGHTTP2_RST_STREAM: + rv = nghttp2_session_close_stream(session, frame->hd.stream_id, + frame->rst_stream.error_code); + if (nghttp2_is_fatal(rv)) { + return rv; + } + return 0; + case NGHTTP2_GOAWAY: { + nghttp2_goaway_aux_data *aux_data; + + aux_data = &item->aux_data.goaway; + + if ((aux_data->flags & NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE) == 0) { + + if (aux_data->flags & NGHTTP2_GOAWAY_AUX_TERM_ON_SEND) { + session->goaway_flags |= NGHTTP2_GOAWAY_TERM_SENT; + } + + session->goaway_flags |= NGHTTP2_GOAWAY_SENT; + + rv = session_close_stream_on_goaway(session, frame->goaway.last_stream_id, + 1); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + + return 0; + } + case NGHTTP2_WINDOW_UPDATE: + if (frame->hd.stream_id == 0) { + session->window_update_queued = 0; + if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { + rv = session_update_connection_consumed_size(session, 0); + } else { + rv = session_update_recv_connection_window_size(session, 0); + } + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + return 0; + } + + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + if (!stream) { + return 0; + } + + stream->window_update_queued = 0; + + /* We don't have to send WINDOW_UPDATE if END_STREAM from peer + is seen. */ + if (stream->shut_flags & NGHTTP2_SHUT_RD) { + return 0; + } + + if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { + rv = session_update_stream_consumed_size(session, stream, 0); + } else { + rv = session_update_recv_stream_window_size(session, stream, 0, 1); + } + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + return 0; + default: + return 0; + } +} + +/* + * Called after a frame is sent and session_after_frame_sent1. This + * function is responsible to reset session->aob. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_CALLBACK_FAILURE + * The callback function failed. + */ +static int session_after_frame_sent2(nghttp2_session *session) { + int rv; + nghttp2_active_outbound_item *aob = &session->aob; + nghttp2_outbound_item *item = aob->item; + nghttp2_bufs *framebufs = &aob->framebufs; + nghttp2_frame *frame; + nghttp2_mem *mem; + nghttp2_stream *stream; + nghttp2_data_aux_data *aux_data; + + mem = &session->mem; + frame = &item->frame; + + if (frame->hd.type != NGHTTP2_DATA) { + + if (frame->hd.type == NGHTTP2_HEADERS || + frame->hd.type == NGHTTP2_PUSH_PROMISE) { + + if (nghttp2_bufs_next_present(framebufs)) { + framebufs->cur = framebufs->cur->next; + + DEBUGF("send: next CONTINUATION frame, %zu bytes\n", + nghttp2_buf_len(&framebufs->cur->buf)); + + return 0; + } + } + + active_outbound_item_reset(&session->aob, mem); + + return 0; + } + + /* DATA frame */ + + aux_data = &item->aux_data.data; + + /* On EOF, we have already detached data. Please note that + application may issue nghttp2_submit_data() in + on_frame_send_callback (call from session_after_frame_sent1), + which attach data to stream. We don't want to detach it. */ + if (aux_data->eof) { + active_outbound_item_reset(aob, mem); + + return 0; + } + + /* Reset no_copy here because next write may not use this. */ + aux_data->no_copy = 0; + + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + + /* If session is closed or RST_STREAM was queued, we won't send + further data. */ + if (nghttp2_session_predicate_data_send(session, stream) != 0) { + if (stream) { + rv = nghttp2_stream_detach_item(stream); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + + active_outbound_item_reset(aob, mem); + + return 0; + } + + aob->item = NULL; + active_outbound_item_reset(&session->aob, mem); + + return 0; +} + +static int session_call_send_data(nghttp2_session *session, + nghttp2_outbound_item *item, + nghttp2_bufs *framebufs) { + int rv; + nghttp2_buf *buf; + size_t length; + nghttp2_frame *frame; + nghttp2_data_aux_data *aux_data; + + buf = &framebufs->cur->buf; + frame = &item->frame; + length = frame->hd.length - frame->data.padlen; + aux_data = &item->aux_data.data; + + rv = session->callbacks.send_data_callback(session, frame, buf->pos, length, + &aux_data->data_prd.source, + session->user_data); + + switch (rv) { + case 0: + case NGHTTP2_ERR_WOULDBLOCK: + case NGHTTP2_ERR_PAUSE: + case NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE: + return rv; + default: + return NGHTTP2_ERR_CALLBACK_FAILURE; + } +} + +static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, + const uint8_t **data_ptr, + int fast_cb) { + int rv; + nghttp2_active_outbound_item *aob; + nghttp2_bufs *framebufs; + nghttp2_mem *mem; + + mem = &session->mem; + aob = &session->aob; + framebufs = &aob->framebufs; + + /* We may have idle streams more than we expect (e.g., + nghttp2_session_change_stream_priority() or + nghttp2_session_create_idle_stream()). Adjust them here. */ + rv = nghttp2_session_adjust_idle_stream(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + for (;;) { + switch (aob->state) { + case NGHTTP2_OB_POP_ITEM: { + nghttp2_outbound_item *item; + + item = nghttp2_session_pop_next_ob_item(session); + if (item == NULL) { + return 0; + } + + rv = session_prep_frame(session, item); + if (rv == NGHTTP2_ERR_PAUSE) { + return 0; + } + if (rv == NGHTTP2_ERR_DEFERRED) { + DEBUGF("send: frame transmission deferred\n"); + break; + } + if (rv < 0) { + int32_t opened_stream_id = 0; + uint32_t error_code = NGHTTP2_INTERNAL_ERROR; + + DEBUGF("send: frame preparation failed with %s\n", + nghttp2_strerror(rv)); + /* TODO If the error comes from compressor, the connection + must be closed. */ + if (item->frame.hd.type != NGHTTP2_DATA && + session->callbacks.on_frame_not_send_callback && is_non_fatal(rv)) { + nghttp2_frame *frame = &item->frame; + /* The library is responsible for the transmission of + WINDOW_UPDATE frame, so we don't call error callback for + it. */ + if (frame->hd.type != NGHTTP2_WINDOW_UPDATE && + session->callbacks.on_frame_not_send_callback( + session, frame, rv, session->user_data) != 0) { + + nghttp2_outbound_item_free(item, mem); + nghttp2_mem_free(mem, item); + + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + /* We have to close stream opened by failed request HEADERS + or PUSH_PROMISE. */ + switch (item->frame.hd.type) { + case NGHTTP2_HEADERS: + if (item->frame.headers.cat == NGHTTP2_HCAT_REQUEST) { + opened_stream_id = item->frame.hd.stream_id; + if (item->aux_data.headers.canceled) { + error_code = item->aux_data.headers.error_code; + } else { + /* Set error_code to REFUSED_STREAM so that application + can send request again. */ + error_code = NGHTTP2_REFUSED_STREAM; + } + } + break; + case NGHTTP2_PUSH_PROMISE: + opened_stream_id = item->frame.push_promise.promised_stream_id; + break; + } + if (opened_stream_id) { + /* careful not to override rv */ + int rv2; + rv2 = nghttp2_session_close_stream(session, opened_stream_id, + error_code); + + if (nghttp2_is_fatal(rv2)) { + return rv2; + } + } + + nghttp2_outbound_item_free(item, mem); + nghttp2_mem_free(mem, item); + active_outbound_item_reset(aob, mem); + + if (rv == NGHTTP2_ERR_HEADER_COMP) { + /* If header compression error occurred, should terminiate + connection. */ + rv = nghttp2_session_terminate_session(session, + NGHTTP2_INTERNAL_ERROR); + } + if (nghttp2_is_fatal(rv)) { + return rv; + } + break; + } + + aob->item = item; + + nghttp2_bufs_rewind(framebufs); + + if (item->frame.hd.type != NGHTTP2_DATA) { + nghttp2_frame *frame; + + frame = &item->frame; + + DEBUGF("send: next frame: payloadlen=%zu, type=%u, flags=0x%02x, " + "stream_id=%d\n", + frame->hd.length, frame->hd.type, frame->hd.flags, + frame->hd.stream_id); + + rv = session_call_before_frame_send(session, frame); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + if (rv == NGHTTP2_ERR_CANCEL) { + int32_t opened_stream_id = 0; + uint32_t error_code = NGHTTP2_INTERNAL_ERROR; + + if (session->callbacks.on_frame_not_send_callback) { + if (session->callbacks.on_frame_not_send_callback( + session, frame, rv, session->user_data) != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + + /* We have to close stream opened by canceled request + HEADERS or PUSH_PROMISE. */ + switch (item->frame.hd.type) { + case NGHTTP2_HEADERS: + if (item->frame.headers.cat == NGHTTP2_HCAT_REQUEST) { + opened_stream_id = item->frame.hd.stream_id; + /* We don't have to check + item->aux_data.headers.canceled since it has already + been checked. */ + /* Set error_code to REFUSED_STREAM so that application + can send request again. */ + error_code = NGHTTP2_REFUSED_STREAM; + } + break; + case NGHTTP2_PUSH_PROMISE: + opened_stream_id = item->frame.push_promise.promised_stream_id; + break; + } + if (opened_stream_id) { + /* careful not to override rv */ + int rv2; + rv2 = nghttp2_session_close_stream(session, opened_stream_id, + error_code); + + if (nghttp2_is_fatal(rv2)) { + return rv2; + } + } + + active_outbound_item_reset(aob, mem); + + break; + } + } else { + DEBUGF("send: next frame: DATA\n"); + + if (item->aux_data.data.no_copy) { + aob->state = NGHTTP2_OB_SEND_NO_COPY; + break; + } + } + + DEBUGF("send: start transmitting frame type=%u, length=%zd\n", + framebufs->cur->buf.pos[3], + framebufs->cur->buf.last - framebufs->cur->buf.pos); + + aob->state = NGHTTP2_OB_SEND_DATA; + + break; + } + case NGHTTP2_OB_SEND_DATA: { + size_t datalen; + nghttp2_buf *buf; + + buf = &framebufs->cur->buf; + + if (buf->pos == buf->last) { + DEBUGF("send: end transmission of a frame\n"); + + /* Frame has completely sent */ + if (fast_cb) { + rv = session_after_frame_sent2(session); + } else { + rv = session_after_frame_sent1(session); + if (rv < 0) { + /* FATAL */ + assert(nghttp2_is_fatal(rv)); + return rv; + } + rv = session_after_frame_sent2(session); + } + if (rv < 0) { + /* FATAL */ + assert(nghttp2_is_fatal(rv)); + return rv; + } + /* We have already adjusted the next state */ + break; + } + + *data_ptr = buf->pos; + datalen = nghttp2_buf_len(buf); + + /* We increment the offset here. If send_callback does not send + everything, we will adjust it. */ + buf->pos += datalen; + + return (ssize_t)datalen; + } + case NGHTTP2_OB_SEND_NO_COPY: { + nghttp2_stream *stream; + nghttp2_frame *frame; + int pause; + + DEBUGF("send: no copy DATA\n"); + + frame = &aob->item->frame; + + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + if (stream == NULL) { + DEBUGF("send: no copy DATA cancelled because stream was closed\n"); + + active_outbound_item_reset(aob, mem); + + break; + } + + rv = session_call_send_data(session, aob->item, framebufs); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + rv = nghttp2_stream_detach_item(stream); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id, + NGHTTP2_INTERNAL_ERROR); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + active_outbound_item_reset(aob, mem); + + break; + } + + if (rv == NGHTTP2_ERR_WOULDBLOCK) { + return 0; + } + + pause = (rv == NGHTTP2_ERR_PAUSE); + + rv = session_after_frame_sent1(session); + if (rv < 0) { + assert(nghttp2_is_fatal(rv)); + return rv; + } + rv = session_after_frame_sent2(session); + if (rv < 0) { + assert(nghttp2_is_fatal(rv)); + return rv; + } + + /* We have already adjusted the next state */ + + if (pause) { + return 0; + } + + break; + } + case NGHTTP2_OB_SEND_CLIENT_MAGIC: { + size_t datalen; + nghttp2_buf *buf; + + buf = &framebufs->cur->buf; + + if (buf->pos == buf->last) { + DEBUGF("send: end transmission of client magic\n"); + active_outbound_item_reset(aob, mem); + break; + } + + *data_ptr = buf->pos; + datalen = nghttp2_buf_len(buf); + + buf->pos += datalen; + + return (ssize_t)datalen; + } + } + } +} + +ssize_t nghttp2_session_mem_send(nghttp2_session *session, + const uint8_t **data_ptr) { + int rv; + ssize_t len; + + *data_ptr = NULL; + + len = nghttp2_session_mem_send_internal(session, data_ptr, 1); + if (len <= 0) { + return len; + } + + if (session->aob.item) { + /* We have to call session_after_frame_sent1 here to handle stream + closure upon transmission of frames. Otherwise, END_STREAM may + be reached to client before we call nghttp2_session_mem_send + again and we may get exceeding number of incoming streams. */ + rv = session_after_frame_sent1(session); + if (rv < 0) { + assert(nghttp2_is_fatal(rv)); + return (ssize_t)rv; + } + } + + return len; +} + +int nghttp2_session_send(nghttp2_session *session) { + const uint8_t *data = NULL; + ssize_t datalen; + ssize_t sentlen; + nghttp2_bufs *framebufs; + + framebufs = &session->aob.framebufs; + + for (;;) { + datalen = nghttp2_session_mem_send_internal(session, &data, 0); + if (datalen <= 0) { + return (int)datalen; + } + sentlen = session->callbacks.send_callback(session, data, (size_t)datalen, + 0, session->user_data); + if (sentlen < 0) { + if (sentlen == NGHTTP2_ERR_WOULDBLOCK) { + /* Transmission canceled. Rewind the offset */ + framebufs->cur->buf.pos -= datalen; + + return 0; + } + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + /* Rewind the offset to the amount of unsent bytes */ + framebufs->cur->buf.pos -= datalen - sentlen; + } +} + +static ssize_t session_recv(nghttp2_session *session, uint8_t *buf, + size_t len) { + ssize_t rv; + rv = session->callbacks.recv_callback(session, buf, len, 0, + session->user_data); + if (rv > 0) { + if ((size_t)rv > len) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } else if (rv < 0 && rv != NGHTTP2_ERR_WOULDBLOCK && rv != NGHTTP2_ERR_EOF) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + return rv; +} + +static int session_call_on_begin_frame(nghttp2_session *session, + const nghttp2_frame_hd *hd) { + int rv; + + if (session->callbacks.on_begin_frame_callback) { + + rv = session->callbacks.on_begin_frame_callback(session, hd, + session->user_data); + + if (rv != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + + return 0; +} + +static int session_call_on_frame_received(nghttp2_session *session, + nghttp2_frame *frame) { + int rv; + if (session->callbacks.on_frame_recv_callback) { + rv = session->callbacks.on_frame_recv_callback(session, frame, + session->user_data); + if (rv != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + return 0; +} + +static int session_call_on_begin_headers(nghttp2_session *session, + nghttp2_frame *frame) { + int rv; + DEBUGF("recv: call on_begin_headers callback stream_id=%d\n", + frame->hd.stream_id); + if (session->callbacks.on_begin_headers_callback) { + rv = session->callbacks.on_begin_headers_callback(session, frame, + session->user_data); + if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + return rv; + } + if (rv != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + return 0; +} + +static int session_call_on_header(nghttp2_session *session, + const nghttp2_frame *frame, + const nghttp2_hd_nv *nv) { + int rv = 0; + if (session->callbacks.on_header_callback2) { + rv = session->callbacks.on_header_callback2( + session, frame, nv->name, nv->value, nv->flags, session->user_data); + } else if (session->callbacks.on_header_callback) { + rv = session->callbacks.on_header_callback( + session, frame, nv->name->base, nv->name->len, nv->value->base, + nv->value->len, nv->flags, session->user_data); + } + + if (rv == NGHTTP2_ERR_PAUSE || rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + return rv; + } + if (rv != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static int session_call_on_invalid_header(nghttp2_session *session, + const nghttp2_frame *frame, + const nghttp2_hd_nv *nv) { + int rv; + if (session->callbacks.on_invalid_header_callback2) { + rv = session->callbacks.on_invalid_header_callback2( + session, frame, nv->name, nv->value, nv->flags, session->user_data); + } else if (session->callbacks.on_invalid_header_callback) { + rv = session->callbacks.on_invalid_header_callback( + session, frame, nv->name->base, nv->name->len, nv->value->base, + nv->value->len, nv->flags, session->user_data); + } else { + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + } + + if (rv == NGHTTP2_ERR_PAUSE || rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + return rv; + } + if (rv != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static int +session_call_on_extension_chunk_recv_callback(nghttp2_session *session, + const uint8_t *data, size_t len) { + int rv; + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_frame *frame = &iframe->frame; + + if (session->callbacks.on_extension_chunk_recv_callback) { + rv = session->callbacks.on_extension_chunk_recv_callback( + session, &frame->hd, data, len, session->user_data); + if (rv == NGHTTP2_ERR_CANCEL) { + return rv; + } + if (rv != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + + return 0; +} + +static int session_call_unpack_extension_callback(nghttp2_session *session) { + int rv; + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_frame *frame = &iframe->frame; + void *payload = NULL; + + rv = session->callbacks.unpack_extension_callback( + session, &payload, &frame->hd, session->user_data); + if (rv == NGHTTP2_ERR_CANCEL) { + return rv; + } + if (rv != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + frame->ext.payload = payload; + + return 0; +} + +/* + * Handles frame size error. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +static int session_handle_frame_size_error(nghttp2_session *session) { + /* TODO Currently no callback is called for this error, because we + call this callback before reading any payload */ + return nghttp2_session_terminate_session(session, NGHTTP2_FRAME_SIZE_ERROR); +} + +static uint32_t get_error_code_from_lib_error_code(int lib_error_code) { + switch (lib_error_code) { + case NGHTTP2_ERR_STREAM_CLOSED: + return NGHTTP2_STREAM_CLOSED; + case NGHTTP2_ERR_HEADER_COMP: + return NGHTTP2_COMPRESSION_ERROR; + case NGHTTP2_ERR_FRAME_SIZE_ERROR: + return NGHTTP2_FRAME_SIZE_ERROR; + case NGHTTP2_ERR_FLOW_CONTROL: + return NGHTTP2_FLOW_CONTROL_ERROR; + case NGHTTP2_ERR_REFUSED_STREAM: + return NGHTTP2_REFUSED_STREAM; + case NGHTTP2_ERR_PROTO: + case NGHTTP2_ERR_HTTP_HEADER: + case NGHTTP2_ERR_HTTP_MESSAGING: + return NGHTTP2_PROTOCOL_ERROR; + default: + return NGHTTP2_INTERNAL_ERROR; + } +} + +/* + * Calls on_invalid_frame_recv_callback if it is set to |session|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_CALLBACK_FAILURE + * User defined callback function fails. + */ +static int session_call_on_invalid_frame_recv_callback(nghttp2_session *session, + nghttp2_frame *frame, + int lib_error_code) { + if (session->callbacks.on_invalid_frame_recv_callback) { + if (session->callbacks.on_invalid_frame_recv_callback( + session, frame, lib_error_code, session->user_data) != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + return 0; +} + +static int session_handle_invalid_stream2(nghttp2_session *session, + int32_t stream_id, + nghttp2_frame *frame, + int lib_error_code) { + int rv; + rv = nghttp2_session_add_rst_stream( + session, stream_id, get_error_code_from_lib_error_code(lib_error_code)); + if (rv != 0) { + return rv; + } + if (session->callbacks.on_invalid_frame_recv_callback) { + if (session->callbacks.on_invalid_frame_recv_callback( + session, frame, lib_error_code, session->user_data) != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + return 0; +} + +static int session_handle_invalid_stream(nghttp2_session *session, + nghttp2_frame *frame, + int lib_error_code) { + return session_handle_invalid_stream2(session, frame->hd.stream_id, frame, + lib_error_code); +} + +static int session_inflate_handle_invalid_stream(nghttp2_session *session, + nghttp2_frame *frame, + int lib_error_code) { + int rv; + rv = session_handle_invalid_stream(session, frame, lib_error_code); + if (nghttp2_is_fatal(rv)) { + return rv; + } + return NGHTTP2_ERR_IGN_HEADER_BLOCK; +} + +/* + * Handles invalid frame which causes connection error. + */ +static int session_handle_invalid_connection(nghttp2_session *session, + nghttp2_frame *frame, + int lib_error_code, + const char *reason) { + if (session->callbacks.on_invalid_frame_recv_callback) { + if (session->callbacks.on_invalid_frame_recv_callback( + session, frame, lib_error_code, session->user_data) != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + return nghttp2_session_terminate_session_with_reason( + session, get_error_code_from_lib_error_code(lib_error_code), reason); +} + +static int session_inflate_handle_invalid_connection(nghttp2_session *session, + nghttp2_frame *frame, + int lib_error_code, + const char *reason) { + int rv; + rv = + session_handle_invalid_connection(session, frame, lib_error_code, reason); + if (nghttp2_is_fatal(rv)) { + return rv; + } + return NGHTTP2_ERR_IGN_HEADER_BLOCK; +} + +/* + * Inflates header block in the memory pointed by |in| with |inlen| + * bytes. If this function returns NGHTTP2_ERR_PAUSE, the caller must + * call this function again, until it returns 0 or one of negative + * error code. If |call_header_cb| is zero, the on_header_callback + * are not invoked and the function never return NGHTTP2_ERR_PAUSE. If + * the given |in| is the last chunk of header block, the |final| must + * be nonzero. If header block is successfully processed (which is + * indicated by the return value 0, NGHTTP2_ERR_PAUSE or + * NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE), the number of processed + * input bytes is assigned to the |*readlen_ptr|. + * + * This function return 0 if it succeeds, or one of the negative error + * codes: + * + * NGHTTP2_ERR_CALLBACK_FAILURE + * The callback function failed. + * NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE + * The callback returns this error code, indicating that this + * stream should be RST_STREAMed. + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_PAUSE + * The callback function returned NGHTTP2_ERR_PAUSE + * NGHTTP2_ERR_HEADER_COMP + * Header decompression failed + */ +static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, + size_t *readlen_ptr, uint8_t *in, size_t inlen, + int final, int call_header_cb) { + ssize_t proclen; + int rv; + int inflate_flags; + nghttp2_hd_nv nv; + nghttp2_stream *stream; + nghttp2_stream *subject_stream; + int trailer = 0; + + *readlen_ptr = 0; + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + + if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { + subject_stream = nghttp2_session_get_stream( + session, frame->push_promise.promised_stream_id); + } else { + subject_stream = stream; + trailer = session_trailer_headers(session, stream, frame); + } + + DEBUGF("recv: decoding header block %zu bytes\n", inlen); + for (;;) { + inflate_flags = 0; + proclen = nghttp2_hd_inflate_hd_nv(&session->hd_inflater, &nv, + &inflate_flags, in, inlen, final); + if (nghttp2_is_fatal((int)proclen)) { + return (int)proclen; + } + if (proclen < 0) { + if (session->iframe.state == NGHTTP2_IB_READ_HEADER_BLOCK) { + if (subject_stream && subject_stream->state != NGHTTP2_STREAM_CLOSING) { + /* Adding RST_STREAM here is very important. It prevents + from invoking subsequent callbacks for the same stream + ID. */ + rv = nghttp2_session_add_rst_stream( + session, subject_stream->stream_id, NGHTTP2_COMPRESSION_ERROR); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + } + rv = + nghttp2_session_terminate_session(session, NGHTTP2_COMPRESSION_ERROR); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + return NGHTTP2_ERR_HEADER_COMP; + } + in += proclen; + inlen -= (size_t)proclen; + *readlen_ptr += (size_t)proclen; + + DEBUGF("recv: proclen=%zd\n", proclen); + + if (call_header_cb && (inflate_flags & NGHTTP2_HD_INFLATE_EMIT)) { + rv = 0; + if (subject_stream && session_enforce_http_messaging(session)) { + rv = nghttp2_http_on_header(session, subject_stream, frame, &nv, + trailer); + + if (rv == NGHTTP2_ERR_IGN_HTTP_HEADER) { + /* Don't overwrite rv here */ + int rv2; + + rv2 = session_call_on_invalid_header(session, frame, &nv); + if (rv2 == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + rv = NGHTTP2_ERR_HTTP_HEADER; + } else { + if (rv2 != 0) { + return rv2; + } + + /* header is ignored */ + DEBUGF("recv: HTTP ignored: type=%u, id=%d, header %.*s: %.*s\n", + frame->hd.type, frame->hd.stream_id, (int)nv.name->len, + nv.name->base, (int)nv.value->len, nv.value->base); + + rv2 = session_call_error_callback( + session, NGHTTP2_ERR_HTTP_HEADER, + "Ignoring received invalid HTTP header field: frame type: " + "%u, stream: %d, name: [%.*s], value: [%.*s]", + frame->hd.type, frame->hd.stream_id, (int)nv.name->len, + nv.name->base, (int)nv.value->len, nv.value->base); + + if (nghttp2_is_fatal(rv2)) { + return rv2; + } + } + } + + if (rv == NGHTTP2_ERR_HTTP_HEADER) { + DEBUGF("recv: HTTP error: type=%u, id=%d, header %.*s: %.*s\n", + frame->hd.type, frame->hd.stream_id, (int)nv.name->len, + nv.name->base, (int)nv.value->len, nv.value->base); + + rv = session_call_error_callback( + session, NGHTTP2_ERR_HTTP_HEADER, + "Invalid HTTP header field was received: frame type: " + "%u, stream: %d, name: [%.*s], value: [%.*s]", + frame->hd.type, frame->hd.stream_id, (int)nv.name->len, + nv.name->base, (int)nv.value->len, nv.value->base); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + rv = + session_handle_invalid_stream2(session, subject_stream->stream_id, + frame, NGHTTP2_ERR_HTTP_HEADER); + if (nghttp2_is_fatal(rv)) { + return rv; + } + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + } + } + if (rv == 0) { + rv = session_call_on_header(session, frame, &nv); + /* This handles NGHTTP2_ERR_PAUSE and + NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE as well */ + if (rv != 0) { + return rv; + } + } + } + if (inflate_flags & NGHTTP2_HD_INFLATE_FINAL) { + nghttp2_hd_inflate_end_headers(&session->hd_inflater); + break; + } + if ((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) { + break; + } + } + return 0; +} + +/* + * Call this function when HEADERS frame was completely received. + * + * This function returns 0 if it succeeds, or one of negative error + * codes: + * + * NGHTTP2_ERR_CALLBACK_FAILURE + * The callback function failed. + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +static int session_end_stream_headers_received(nghttp2_session *session, + nghttp2_frame *frame, + nghttp2_stream *stream) { + int rv; + if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) { + return 0; + } + + nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); + rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + return 0; +} + +static int session_after_header_block_received(nghttp2_session *session) { + int rv = 0; + int call_cb = 1; + nghttp2_frame *frame = &session->iframe.frame; + nghttp2_stream *stream; + + /* We don't call on_frame_recv_callback if stream has been closed + already or being closed. */ + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + if (!stream || stream->state == NGHTTP2_STREAM_CLOSING) { + return 0; + } + + if (session_enforce_http_messaging(session)) { + if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { + nghttp2_stream *subject_stream; + + subject_stream = nghttp2_session_get_stream( + session, frame->push_promise.promised_stream_id); + if (subject_stream) { + rv = nghttp2_http_on_request_headers(subject_stream, frame); + } + } else { + assert(frame->hd.type == NGHTTP2_HEADERS); + switch (frame->headers.cat) { + case NGHTTP2_HCAT_REQUEST: + rv = nghttp2_http_on_request_headers(stream, frame); + break; + case NGHTTP2_HCAT_RESPONSE: + case NGHTTP2_HCAT_PUSH_RESPONSE: + rv = nghttp2_http_on_response_headers(stream); + break; + case NGHTTP2_HCAT_HEADERS: + if (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) { + assert(!session->server); + rv = nghttp2_http_on_response_headers(stream); + } else { + rv = nghttp2_http_on_trailer_headers(stream, frame); + } + break; + default: + assert(0); + } + if (rv == 0 && (frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { + rv = nghttp2_http_on_remote_end_stream(stream); + } + } + if (rv != 0) { + int32_t stream_id; + + if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { + stream_id = frame->push_promise.promised_stream_id; + } else { + stream_id = frame->hd.stream_id; + } + + call_cb = 0; + + rv = session_handle_invalid_stream2(session, stream_id, frame, + NGHTTP2_ERR_HTTP_MESSAGING); + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + } + + if (call_cb) { + rv = session_call_on_frame_received(session, frame); + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + + if (frame->hd.type != NGHTTP2_HEADERS) { + return 0; + } + + return session_end_stream_headers_received(session, frame, stream); +} + +int nghttp2_session_on_request_headers_received(nghttp2_session *session, + nghttp2_frame *frame) { + int rv = 0; + nghttp2_stream *stream; + if (frame->hd.stream_id == 0) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: stream_id == 0"); + } + + /* If client receives idle stream from server, it is invalid + regardless stream ID is even or odd. This is because client is + not expected to receive request from server. */ + if (!session->server) { + if (session_detect_idle_stream(session, frame->hd.stream_id)) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "request HEADERS: client received request"); + } + + return NGHTTP2_ERR_IGN_HEADER_BLOCK; + } + + assert(session->server); + + if (!session_is_new_peer_stream_id(session, frame->hd.stream_id)) { + if (frame->hd.stream_id == 0 || + nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "request HEADERS: invalid stream_id"); + } + + /* RFC 7540 says if an endpoint receives a HEADERS with invalid + * stream ID (e.g, numerically smaller than previous), it MUST + * issue connection error with error code PROTOCOL_ERROR. It is a + * bit hard to detect this, since we cannot remember all streams + * we observed so far. + * + * You might imagine this is really easy. But no. HTTP/2 is + * asynchronous protocol, and usually client and server do not + * share the complete picture of open/closed stream status. For + * example, after server sends RST_STREAM for a stream, client may + * send trailer HEADERS for that stream. If naive server detects + * that, and issued connection error, then it is a bug of server + * implementation since client is not wrong if it did not get + * RST_STREAM when it issued trailer HEADERS. + * + * At the moment, we are very conservative here. We only use + * connection error if stream ID refers idle stream, or we are + * sure that stream is half-closed(remote) or closed. Otherwise + * we just ignore HEADERS for now. + */ + stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); + if (stream && (stream->shut_flags & NGHTTP2_SHUT_RD)) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed"); + } + + return NGHTTP2_ERR_IGN_HEADER_BLOCK; + } + session->last_recv_stream_id = frame->hd.stream_id; + + if (session_is_incoming_concurrent_streams_max(session)) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "request HEADERS: max concurrent streams exceeded"); + } + + if (!session_allow_incoming_new_stream(session)) { + /* We just ignore stream after GOAWAY was sent */ + return NGHTTP2_ERR_IGN_HEADER_BLOCK; + } + + if (frame->headers.pri_spec.stream_id == frame->hd.stream_id) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: depend on itself"); + } + + if (session_is_incoming_concurrent_streams_pending_max(session)) { + return session_inflate_handle_invalid_stream(session, frame, + NGHTTP2_ERR_REFUSED_STREAM); + } + + stream = nghttp2_session_open_stream( + session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, + &frame->headers.pri_spec, NGHTTP2_STREAM_OPENING, NULL); + if (!stream) { + return NGHTTP2_ERR_NOMEM; + } + + rv = nghttp2_session_adjust_closed_stream(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + session->last_proc_stream_id = session->last_recv_stream_id; + + rv = session_call_on_begin_headers(session, frame); + if (rv != 0) { + return rv; + } + return 0; +} + +int nghttp2_session_on_response_headers_received(nghttp2_session *session, + nghttp2_frame *frame, + nghttp2_stream *stream) { + int rv; + /* This function is only called if stream->state == + NGHTTP2_STREAM_OPENING and stream_id is local side initiated. */ + assert(stream->state == NGHTTP2_STREAM_OPENING && + nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)); + if (frame->hd.stream_id == 0) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, "response HEADERS: stream_id == 0"); + } + if (stream->shut_flags & NGHTTP2_SHUT_RD) { + /* half closed (remote): from the spec: + + If an endpoint receives additional frames for a stream that is + in this state it MUST respond with a stream error (Section + 5.4.2) of type STREAM_CLOSED. + + We go further, and make it connection error. + */ + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed"); + } + stream->state = NGHTTP2_STREAM_OPENED; + rv = session_call_on_begin_headers(session, frame); + if (rv != 0) { + return rv; + } + return 0; +} + +int nghttp2_session_on_push_response_headers_received(nghttp2_session *session, + nghttp2_frame *frame, + nghttp2_stream *stream) { + int rv = 0; + assert(stream->state == NGHTTP2_STREAM_RESERVED); + if (frame->hd.stream_id == 0) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "push response HEADERS: stream_id == 0"); + } + + if (session->server) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "HEADERS: no HEADERS allowed from client in reserved state"); + } + + if (session_is_incoming_concurrent_streams_max(session)) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "push response HEADERS: max concurrent streams exceeded"); + } + + if (!session_allow_incoming_new_stream(session)) { + /* We don't accept new stream after GOAWAY was sent. */ + return NGHTTP2_ERR_IGN_HEADER_BLOCK; + } + + if (session_is_incoming_concurrent_streams_pending_max(session)) { + return session_inflate_handle_invalid_stream(session, frame, + NGHTTP2_ERR_REFUSED_STREAM); + } + + nghttp2_stream_promise_fulfilled(stream); + if (!nghttp2_session_is_my_stream_id(session, stream->stream_id)) { + --session->num_incoming_reserved_streams; + } + ++session->num_incoming_streams; + rv = session_call_on_begin_headers(session, frame); + if (rv != 0) { + return rv; + } + return 0; +} + +int nghttp2_session_on_headers_received(nghttp2_session *session, + nghttp2_frame *frame, + nghttp2_stream *stream) { + int rv = 0; + if (frame->hd.stream_id == 0) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, "HEADERS: stream_id == 0"); + } + if ((stream->shut_flags & NGHTTP2_SHUT_RD)) { + /* half closed (remote): from the spec: + + If an endpoint receives additional frames for a stream that is + in this state it MUST respond with a stream error (Section + 5.4.2) of type STREAM_CLOSED. + + we go further, and make it connection error. + */ + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed"); + } + if (nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { + if (stream->state == NGHTTP2_STREAM_OPENED) { + rv = session_call_on_begin_headers(session, frame); + if (rv != 0) { + return rv; + } + return 0; + } + + return NGHTTP2_ERR_IGN_HEADER_BLOCK; + } + /* If this is remote peer initiated stream, it is OK unless it + has sent END_STREAM frame already. But if stream is in + NGHTTP2_STREAM_CLOSING, we discard the frame. This is a race + condition. */ + if (stream->state != NGHTTP2_STREAM_CLOSING) { + rv = session_call_on_begin_headers(session, frame); + if (rv != 0) { + return rv; + } + return 0; + } + return NGHTTP2_ERR_IGN_HEADER_BLOCK; +} + +static int session_process_headers_frame(nghttp2_session *session) { + int rv; + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_frame *frame = &iframe->frame; + nghttp2_stream *stream; + + rv = nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos); + + if (rv != 0) { + return nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_PROTOCOL_ERROR, "HEADERS: could not unpack"); + } + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + if (!stream) { + frame->headers.cat = NGHTTP2_HCAT_REQUEST; + return nghttp2_session_on_request_headers_received(session, frame); + } + + if (stream->state == NGHTTP2_STREAM_RESERVED) { + frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE; + return nghttp2_session_on_push_response_headers_received(session, frame, + stream); + } + + if (stream->state == NGHTTP2_STREAM_OPENING && + nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { + frame->headers.cat = NGHTTP2_HCAT_RESPONSE; + return nghttp2_session_on_response_headers_received(session, frame, stream); + } + + frame->headers.cat = NGHTTP2_HCAT_HEADERS; + return nghttp2_session_on_headers_received(session, frame, stream); +} + +int nghttp2_session_on_priority_received(nghttp2_session *session, + nghttp2_frame *frame) { + int rv; + nghttp2_stream *stream; + + if (frame->hd.stream_id == 0) { + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "PRIORITY: stream_id == 0"); + } + + if (frame->priority.pri_spec.stream_id == frame->hd.stream_id) { + return nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_PROTOCOL_ERROR, "depend on itself"); + } + + if (!session->server) { + /* Re-prioritization works only in server */ + return session_call_on_frame_received(session, frame); + } + + stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); + + if (!stream) { + /* PRIORITY against idle stream can create anchor node in + dependency tree. */ + if (!session_detect_idle_stream(session, frame->hd.stream_id)) { + return 0; + } + + stream = nghttp2_session_open_stream( + session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, + &frame->priority.pri_spec, NGHTTP2_STREAM_IDLE, NULL); + + if (stream == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + rv = nghttp2_session_adjust_idle_stream(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + } else { + rv = nghttp2_session_reprioritize_stream(session, stream, + &frame->priority.pri_spec); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + rv = nghttp2_session_adjust_idle_stream(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + + return session_call_on_frame_received(session, frame); +} + +static int session_process_priority_frame(nghttp2_session *session) { + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_frame *frame = &iframe->frame; + + nghttp2_frame_unpack_priority_payload(&frame->priority, iframe->sbuf.pos); + + return nghttp2_session_on_priority_received(session, frame); +} + +int nghttp2_session_on_rst_stream_received(nghttp2_session *session, + nghttp2_frame *frame) { + int rv; + nghttp2_stream *stream; + if (frame->hd.stream_id == 0) { + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "RST_STREAM: stream_id == 0"); + } + + if (session_detect_idle_stream(session, frame->hd.stream_id)) { + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "RST_STREAM: stream in idle"); + } + + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + if (stream) { + /* We may use stream->shut_flags for strict error checking. */ + nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); + } + + rv = session_call_on_frame_received(session, frame); + if (rv != 0) { + return rv; + } + rv = nghttp2_session_close_stream(session, frame->hd.stream_id, + frame->rst_stream.error_code); + if (nghttp2_is_fatal(rv)) { + return rv; + } + return 0; +} + +static int session_process_rst_stream_frame(nghttp2_session *session) { + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_frame *frame = &iframe->frame; + + nghttp2_frame_unpack_rst_stream_payload(&frame->rst_stream, iframe->sbuf.pos); + + return nghttp2_session_on_rst_stream_received(session, frame); +} + +static int update_remote_initial_window_size_func(nghttp2_map_entry *entry, + void *ptr) { + int rv; + nghttp2_update_window_size_arg *arg; + nghttp2_stream *stream; + + arg = (nghttp2_update_window_size_arg *)ptr; + stream = (nghttp2_stream *)entry; + + rv = nghttp2_stream_update_remote_initial_window_size( + stream, arg->new_window_size, arg->old_window_size); + if (rv != 0) { + return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, + NGHTTP2_FLOW_CONTROL_ERROR); + } + + /* If window size gets positive, push deferred DATA frame to + outbound queue. */ + if (stream->remote_window_size > 0 && + nghttp2_stream_check_deferred_by_flow_control(stream)) { + + rv = nghttp2_stream_resume_deferred_item( + stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + return 0; +} + +/* + * Updates the remote initial window size of all active streams. If + * error occurs, all streams may not be updated. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +static int +session_update_remote_initial_window_size(nghttp2_session *session, + int32_t new_initial_window_size) { + nghttp2_update_window_size_arg arg; + + arg.session = session; + arg.new_window_size = new_initial_window_size; + arg.old_window_size = (int32_t)session->remote_settings.initial_window_size; + + return nghttp2_map_each(&session->streams, + update_remote_initial_window_size_func, &arg); +} + +static int update_local_initial_window_size_func(nghttp2_map_entry *entry, + void *ptr) { + int rv; + nghttp2_update_window_size_arg *arg; + nghttp2_stream *stream; + arg = (nghttp2_update_window_size_arg *)ptr; + stream = (nghttp2_stream *)entry; + rv = nghttp2_stream_update_local_initial_window_size( + stream, arg->new_window_size, arg->old_window_size); + if (rv != 0) { + return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, + NGHTTP2_FLOW_CONTROL_ERROR); + } + if (!(arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) && + stream->window_update_queued == 0 && + nghttp2_should_send_window_update(stream->local_window_size, + stream->recv_window_size)) { + + rv = nghttp2_session_add_window_update(arg->session, NGHTTP2_FLAG_NONE, + stream->stream_id, + stream->recv_window_size); + if (rv != 0) { + return rv; + } + + stream->recv_window_size = 0; + } + return 0; +} + +/* + * Updates the local initial window size of all active streams. If + * error occurs, all streams may not be updated. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +static int +session_update_local_initial_window_size(nghttp2_session *session, + int32_t new_initial_window_size, + int32_t old_initial_window_size) { + nghttp2_update_window_size_arg arg; + arg.session = session; + arg.new_window_size = new_initial_window_size; + arg.old_window_size = old_initial_window_size; + return nghttp2_map_each(&session->streams, + update_local_initial_window_size_func, &arg); +} + +/* + * Apply SETTINGS values |iv| having |niv| elements to the local + * settings. We assumes that all values in |iv| is correct, since we + * validated them in nghttp2_session_add_settings() already. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_HEADER_COMP + * The header table size is out of range + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_session_update_local_settings(nghttp2_session *session, + nghttp2_settings_entry *iv, + size_t niv) { + int rv; + size_t i; + int32_t new_initial_window_size = -1; + uint32_t header_table_size = 0; + uint32_t min_header_table_size = UINT32_MAX; + uint8_t header_table_size_seen = 0; + /* For NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, use the value last + seen. For NGHTTP2_SETTINGS_HEADER_TABLE_SIZE, use both minimum + value and last seen value. */ + for (i = 0; i < niv; ++i) { + switch (iv[i].settings_id) { + case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: + header_table_size_seen = 1; + header_table_size = iv[i].value; + min_header_table_size = nghttp2_min(min_header_table_size, iv[i].value); + break; + case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: + new_initial_window_size = (int32_t)iv[i].value; + break; + } + } + if (header_table_size_seen) { + if (min_header_table_size < header_table_size) { + rv = nghttp2_hd_inflate_change_table_size(&session->hd_inflater, + min_header_table_size); + if (rv != 0) { + return rv; + } + } + + rv = nghttp2_hd_inflate_change_table_size(&session->hd_inflater, + header_table_size); + if (rv != 0) { + return rv; + } + } + if (new_initial_window_size != -1) { + rv = session_update_local_initial_window_size( + session, new_initial_window_size, + (int32_t)session->local_settings.initial_window_size); + if (rv != 0) { + return rv; + } + } + + for (i = 0; i < niv; ++i) { + switch (iv[i].settings_id) { + case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: + session->local_settings.header_table_size = iv[i].value; + break; + case NGHTTP2_SETTINGS_ENABLE_PUSH: + session->local_settings.enable_push = iv[i].value; + break; + case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: + session->local_settings.max_concurrent_streams = iv[i].value; + break; + case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: + session->local_settings.initial_window_size = iv[i].value; + break; + case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: + session->local_settings.max_frame_size = iv[i].value; + break; + case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: + session->local_settings.max_header_list_size = iv[i].value; + break; + } + } + + return 0; +} + +int nghttp2_session_on_settings_received(nghttp2_session *session, + nghttp2_frame *frame, int noack) { + int rv; + size_t i; + nghttp2_mem *mem; + nghttp2_inflight_settings *settings; + + mem = &session->mem; + + if (frame->hd.stream_id != 0) { + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "SETTINGS: stream_id != 0"); + } + if (frame->hd.flags & NGHTTP2_FLAG_ACK) { + if (frame->settings.niv != 0) { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_FRAME_SIZE_ERROR, + "SETTINGS: ACK and payload != 0"); + } + + settings = session->inflight_settings_head; + + if (!settings) { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, "SETTINGS: unexpected ACK"); + } + + rv = nghttp2_session_update_local_settings(session, settings->iv, + settings->niv); + + session->inflight_settings_head = settings->next; + + inflight_settings_del(settings, mem); + + if (rv != 0) { + if (nghttp2_is_fatal(rv)) { + return rv; + } + return session_handle_invalid_connection(session, frame, rv, NULL); + } + return session_call_on_frame_received(session, frame); + } + + for (i = 0; i < frame->settings.niv; ++i) { + nghttp2_settings_entry *entry = &frame->settings.iv[i]; + + switch (entry->settings_id) { + case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: + + rv = nghttp2_hd_deflate_change_table_size(&session->hd_deflater, + entry->value); + if (rv != 0) { + if (nghttp2_is_fatal(rv)) { + return rv; + } else { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_HEADER_COMP, NULL); + } + } + + session->remote_settings.header_table_size = entry->value; + + break; + case NGHTTP2_SETTINGS_ENABLE_PUSH: + + if (entry->value != 0 && entry->value != 1) { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "SETTINGS: invalid SETTINGS_ENBLE_PUSH"); + } + + if (!session->server && entry->value != 0) { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "SETTINGS: server attempted to enable push"); + } + + session->remote_settings.enable_push = entry->value; + + break; + case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: + + session->remote_settings.max_concurrent_streams = entry->value; + + break; + case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: + + /* Update the initial window size of the all active streams */ + /* Check that initial_window_size < (1u << 31) */ + if (entry->value > NGHTTP2_MAX_WINDOW_SIZE) { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_FLOW_CONTROL, + "SETTINGS: too large SETTINGS_INITIAL_WINDOW_SIZE"); + } + + rv = session_update_remote_initial_window_size(session, + (int32_t)entry->value); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + if (rv != 0) { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_FLOW_CONTROL, NULL); + } + + session->remote_settings.initial_window_size = entry->value; + + break; + case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: + + if (entry->value < NGHTTP2_MAX_FRAME_SIZE_MIN || + entry->value > NGHTTP2_MAX_FRAME_SIZE_MAX) { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "SETTINGS: invalid SETTINGS_MAX_FRAME_SIZE"); + } + + session->remote_settings.max_frame_size = entry->value; + + break; + case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: + + session->remote_settings.max_header_list_size = entry->value; + + break; + } + } + + if (!noack && !session_is_closing(session)) { + rv = nghttp2_session_add_settings(session, NGHTTP2_FLAG_ACK, NULL, 0); + + if (rv != 0) { + if (nghttp2_is_fatal(rv)) { + return rv; + } + + return session_handle_invalid_connection(session, frame, + NGHTTP2_ERR_INTERNAL, NULL); + } + } + + return session_call_on_frame_received(session, frame); +} + +static int session_process_settings_frame(nghttp2_session *session) { + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_frame *frame = &iframe->frame; + size_t i; + nghttp2_settings_entry min_header_size_entry; + + if (iframe->max_niv) { + min_header_size_entry = iframe->iv[iframe->max_niv - 1]; + + if (min_header_size_entry.value < UINT32_MAX) { + /* If we have less value, then we must have + SETTINGS_HEADER_TABLE_SIZE in i < iframe->niv */ + for (i = 0; i < iframe->niv; ++i) { + if (iframe->iv[i].settings_id == NGHTTP2_SETTINGS_HEADER_TABLE_SIZE) { + break; + } + } + + assert(i < iframe->niv); + + if (min_header_size_entry.value != iframe->iv[i].value) { + iframe->iv[iframe->niv++] = iframe->iv[i]; + iframe->iv[i] = min_header_size_entry; + } + } + } + + nghttp2_frame_unpack_settings_payload(&frame->settings, iframe->iv, + iframe->niv); + + iframe->iv = NULL; + iframe->niv = 0; + iframe->max_niv = 0; + + return nghttp2_session_on_settings_received(session, frame, 0 /* ACK */); +} + +int nghttp2_session_on_push_promise_received(nghttp2_session *session, + nghttp2_frame *frame) { + int rv; + nghttp2_stream *stream; + nghttp2_stream *promised_stream; + nghttp2_priority_spec pri_spec; + + if (frame->hd.stream_id == 0) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: stream_id == 0"); + } + if (session->server || session->local_settings.enable_push == 0) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: push disabled"); + } + + if (!nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: invalid stream_id"); + } + + if (!session_allow_incoming_new_stream(session)) { + /* We just discard PUSH_PROMISE after GOAWAY was sent */ + return NGHTTP2_ERR_IGN_HEADER_BLOCK; + } + + if (!session_is_new_peer_stream_id(session, + frame->push_promise.promised_stream_id)) { + /* The spec says if an endpoint receives a PUSH_PROMISE with + illegal stream ID is subject to a connection error of type + PROTOCOL_ERROR. */ + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "PUSH_PROMISE: invalid promised_stream_id"); + } + + if (session_detect_idle_stream(session, frame->hd.stream_id)) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: stream in idle"); + } + + session->last_recv_stream_id = frame->push_promise.promised_stream_id; + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + if (!stream || stream->state == NGHTTP2_STREAM_CLOSING || + !session->pending_enable_push || + session->num_incoming_reserved_streams >= + session->max_incoming_reserved_streams) { + /* Currently, client does not retain closed stream, so we don't + check NGHTTP2_SHUT_RD condition here. */ + + rv = nghttp2_session_add_rst_stream( + session, frame->push_promise.promised_stream_id, NGHTTP2_CANCEL); + if (rv != 0) { + return rv; + } + return NGHTTP2_ERR_IGN_HEADER_BLOCK; + } + + if (stream->shut_flags & NGHTTP2_SHUT_RD) { + return session_inflate_handle_invalid_connection( + session, frame, NGHTTP2_ERR_STREAM_CLOSED, + "PUSH_PROMISE: stream closed"); + } + + nghttp2_priority_spec_init(&pri_spec, stream->stream_id, + NGHTTP2_DEFAULT_WEIGHT, 0); + + promised_stream = nghttp2_session_open_stream( + session, frame->push_promise.promised_stream_id, NGHTTP2_STREAM_FLAG_NONE, + &pri_spec, NGHTTP2_STREAM_RESERVED, NULL); + + if (!promised_stream) { + return NGHTTP2_ERR_NOMEM; + } + + /* We don't call nghttp2_session_adjust_closed_stream(), since we + don't keep closed stream in client side */ + + session->last_proc_stream_id = session->last_recv_stream_id; + rv = session_call_on_begin_headers(session, frame); + if (rv != 0) { + return rv; + } + return 0; +} + +static int session_process_push_promise_frame(nghttp2_session *session) { + int rv; + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_frame *frame = &iframe->frame; + + rv = nghttp2_frame_unpack_push_promise_payload(&frame->push_promise, + iframe->sbuf.pos); + + if (rv != 0) { + return nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_PROTOCOL_ERROR, "PUSH_PROMISE: could not unpack"); + } + + return nghttp2_session_on_push_promise_received(session, frame); +} + +int nghttp2_session_on_ping_received(nghttp2_session *session, + nghttp2_frame *frame) { + int rv = 0; + if (frame->hd.stream_id != 0) { + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "PING: stream_id != 0"); + } + if ((session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_PING_ACK) == 0 && + (frame->hd.flags & NGHTTP2_FLAG_ACK) == 0 && + !session_is_closing(session)) { + /* Peer sent ping, so ping it back */ + rv = nghttp2_session_add_ping(session, NGHTTP2_FLAG_ACK, + frame->ping.opaque_data); + if (rv != 0) { + return rv; + } + } + return session_call_on_frame_received(session, frame); +} + +static int session_process_ping_frame(nghttp2_session *session) { + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_frame *frame = &iframe->frame; + + nghttp2_frame_unpack_ping_payload(&frame->ping, iframe->sbuf.pos); + + return nghttp2_session_on_ping_received(session, frame); +} + +int nghttp2_session_on_goaway_received(nghttp2_session *session, + nghttp2_frame *frame) { + int rv; + + if (frame->hd.stream_id != 0) { + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "GOAWAY: stream_id != 0"); + } + /* Spec says Endpoints MUST NOT increase the value they send in the + last stream identifier. */ + if ((frame->goaway.last_stream_id > 0 && + !nghttp2_session_is_my_stream_id(session, + frame->goaway.last_stream_id)) || + session->remote_last_stream_id < frame->goaway.last_stream_id) { + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "GOAWAY: invalid last_stream_id"); + } + + session->goaway_flags |= NGHTTP2_GOAWAY_RECV; + + session->remote_last_stream_id = frame->goaway.last_stream_id; + + rv = session_call_on_frame_received(session, frame); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + return session_close_stream_on_goaway(session, frame->goaway.last_stream_id, + 0); +} + +static int session_process_goaway_frame(nghttp2_session *session) { + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_frame *frame = &iframe->frame; + + nghttp2_frame_unpack_goaway_payload(&frame->goaway, iframe->sbuf.pos, + iframe->lbuf.pos, + nghttp2_buf_len(&iframe->lbuf)); + + nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0); + + return nghttp2_session_on_goaway_received(session, frame); +} + +static int +session_on_connection_window_update_received(nghttp2_session *session, + nghttp2_frame *frame) { + /* Handle connection-level flow control */ + if (frame->window_update.window_size_increment == 0) { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "WINDOW_UPDATE: window_size_increment == 0"); + } + + if (NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment < + session->remote_window_size) { + return session_handle_invalid_connection(session, frame, + NGHTTP2_ERR_FLOW_CONTROL, NULL); + } + session->remote_window_size += frame->window_update.window_size_increment; + + return session_call_on_frame_received(session, frame); +} + +static int session_on_stream_window_update_received(nghttp2_session *session, + nghttp2_frame *frame) { + int rv; + nghttp2_stream *stream; + + if (session_detect_idle_stream(session, frame->hd.stream_id)) { + return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, + "WINDOW_UPDATE to idle stream"); + } + + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + if (!stream) { + return 0; + } + if (state_reserved_remote(session, stream)) { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, "WINDOW_UPADATE to reserved stream"); + } + if (frame->window_update.window_size_increment == 0) { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "WINDOW_UPDATE: window_size_increment == 0"); + } + if (NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment < + stream->remote_window_size) { + return session_handle_invalid_stream(session, frame, + NGHTTP2_ERR_FLOW_CONTROL); + } + stream->remote_window_size += frame->window_update.window_size_increment; + + if (stream->remote_window_size > 0 && + nghttp2_stream_check_deferred_by_flow_control(stream)) { + + rv = nghttp2_stream_resume_deferred_item( + stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + return session_call_on_frame_received(session, frame); +} + +int nghttp2_session_on_window_update_received(nghttp2_session *session, + nghttp2_frame *frame) { + if (frame->hd.stream_id == 0) { + return session_on_connection_window_update_received(session, frame); + } else { + return session_on_stream_window_update_received(session, frame); + } +} + +static int session_process_window_update_frame(nghttp2_session *session) { + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_frame *frame = &iframe->frame; + + nghttp2_frame_unpack_window_update_payload(&frame->window_update, + iframe->sbuf.pos); + + return nghttp2_session_on_window_update_received(session, frame); +} + +int nghttp2_session_on_altsvc_received(nghttp2_session *session, + nghttp2_frame *frame) { + nghttp2_ext_altsvc *altsvc; + nghttp2_stream *stream; + + altsvc = frame->ext.payload; + + /* session->server case has been excluded */ + + if (frame->hd.stream_id == 0) { + if (altsvc->origin_len == 0) { + return session_call_on_invalid_frame_recv_callback(session, frame, + NGHTTP2_ERR_PROTO); + } + } else { + if (altsvc->origin_len > 0) { + return session_call_on_invalid_frame_recv_callback(session, frame, + NGHTTP2_ERR_PROTO); + } + + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + if (!stream) { + return 0; + } + + if (stream->state == NGHTTP2_STREAM_CLOSING) { + return 0; + } + } + + if (altsvc->field_value_len == 0) { + return session_call_on_invalid_frame_recv_callback(session, frame, + NGHTTP2_ERR_PROTO); + } + + return session_call_on_frame_received(session, frame); +} + +static int session_process_altsvc_frame(nghttp2_session *session) { + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_frame *frame = &iframe->frame; + + nghttp2_frame_unpack_altsvc_payload( + &frame->ext, nghttp2_get_uint16(iframe->sbuf.pos), iframe->lbuf.pos, + nghttp2_buf_len(&iframe->lbuf)); + + /* nghttp2_frame_unpack_altsvc_payload steals buffer from + iframe->lbuf */ + nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0); + + return nghttp2_session_on_altsvc_received(session, frame); +} + +static int session_process_extension_frame(nghttp2_session *session) { + int rv; + nghttp2_inbound_frame *iframe = &session->iframe; + nghttp2_frame *frame = &iframe->frame; + + rv = session_call_unpack_extension_callback(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + /* This handles the case where rv == NGHTTP2_ERR_CANCEL as well */ + if (rv != 0) { + return 0; + } + + return session_call_on_frame_received(session, frame); +} + +int nghttp2_session_on_data_received(nghttp2_session *session, + nghttp2_frame *frame) { + int rv = 0; + int call_cb = 1; + nghttp2_stream *stream; + + /* We don't call on_frame_recv_callback if stream has been closed + already or being closed. */ + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + if (!stream || stream->state == NGHTTP2_STREAM_CLOSING) { + /* This should be treated as stream error, but it results in lots + of RST_STREAM. So just ignore frame against nonexistent stream + for now. */ + return 0; + } + + if (session_enforce_http_messaging(session) && + (frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { + if (nghttp2_http_on_remote_end_stream(stream) != 0) { + call_cb = 0; + rv = nghttp2_session_add_rst_stream(session, stream->stream_id, + NGHTTP2_PROTOCOL_ERROR); + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + } + + if (call_cb) { + rv = session_call_on_frame_received(session, frame); + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + + if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { + nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); + rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + return 0; +} + +/* For errors, this function only returns FATAL error. */ +static int session_process_data_frame(nghttp2_session *session) { + int rv; + nghttp2_frame *public_data_frame = &session->iframe.frame; + rv = nghttp2_session_on_data_received(session, public_data_frame); + if (nghttp2_is_fatal(rv)) { + return rv; + } + return 0; +} + +/* + * Now we have SETTINGS synchronization, flow control error can be + * detected strictly. If DATA frame is received with length > 0 and + * current received window size + delta length is strictly larger than + * local window size, it is subject to FLOW_CONTROL_ERROR, so return + * -1. Note that local_window_size is calculated after SETTINGS ACK is + * received from peer, so peer must honor this limit. If the resulting + * recv_window_size is strictly larger than NGHTTP2_MAX_WINDOW_SIZE, + * return -1 too. + */ +static int adjust_recv_window_size(int32_t *recv_window_size_ptr, size_t delta, + int32_t local_window_size) { + if (*recv_window_size_ptr > local_window_size - (int32_t)delta || + *recv_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - (int32_t)delta) { + return -1; + } + *recv_window_size_ptr += (int32_t)delta; + return 0; +} + +/* + * Accumulates received bytes |delta_size| for stream-level flow + * control and decides whether to send WINDOW_UPDATE to that stream. + * If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not + * be sent. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +static int session_update_recv_stream_window_size(nghttp2_session *session, + nghttp2_stream *stream, + size_t delta_size, + int send_window_update) { + int rv; + rv = adjust_recv_window_size(&stream->recv_window_size, delta_size, + stream->local_window_size); + if (rv != 0) { + return nghttp2_session_add_rst_stream(session, stream->stream_id, + NGHTTP2_FLOW_CONTROL_ERROR); + } + /* We don't have to send WINDOW_UPDATE if the data received is the + last chunk in the incoming stream. */ + /* We have to use local_settings here because it is the constraint + the remote endpoint should honor. */ + if (send_window_update && + !(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) && + stream->window_update_queued == 0 && + nghttp2_should_send_window_update(stream->local_window_size, + stream->recv_window_size)) { + rv = nghttp2_session_add_window_update(session, NGHTTP2_FLAG_NONE, + stream->stream_id, + stream->recv_window_size); + if (rv != 0) { + return rv; + } + + stream->recv_window_size = 0; + } + return 0; +} + +/* + * Accumulates received bytes |delta_size| for connection-level flow + * control and decides whether to send WINDOW_UPDATE to the + * connection. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, + * WINDOW_UPDATE will not be sent. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +static int session_update_recv_connection_window_size(nghttp2_session *session, + size_t delta_size) { + int rv; + rv = adjust_recv_window_size(&session->recv_window_size, delta_size, + session->local_window_size); + if (rv != 0) { + return nghttp2_session_terminate_session(session, + NGHTTP2_FLOW_CONTROL_ERROR); + } + if (!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) && + session->window_update_queued == 0 && + nghttp2_should_send_window_update(session->local_window_size, + session->recv_window_size)) { + /* Use stream ID 0 to update connection-level flow control + window */ + rv = nghttp2_session_add_window_update(session, NGHTTP2_FLAG_NONE, 0, + session->recv_window_size); + if (rv != 0) { + return rv; + } + + session->recv_window_size = 0; + } + return 0; +} + +static int session_update_consumed_size(nghttp2_session *session, + int32_t *consumed_size_ptr, + int32_t *recv_window_size_ptr, + uint8_t window_update_queued, + int32_t stream_id, size_t delta_size, + int32_t local_window_size) { + int32_t recv_size; + int rv; + + if ((size_t)*consumed_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta_size) { + return nghttp2_session_terminate_session(session, + NGHTTP2_FLOW_CONTROL_ERROR); + } + + *consumed_size_ptr += (int32_t)delta_size; + + if (window_update_queued == 0) { + /* recv_window_size may be smaller than consumed_size, because it + may be decreased by negative value with + nghttp2_submit_window_update(). */ + recv_size = nghttp2_min(*consumed_size_ptr, *recv_window_size_ptr); + + if (nghttp2_should_send_window_update(local_window_size, recv_size)) { + rv = nghttp2_session_add_window_update(session, NGHTTP2_FLAG_NONE, + stream_id, recv_size); + + if (rv != 0) { + return rv; + } + + *recv_window_size_ptr -= recv_size; + *consumed_size_ptr -= recv_size; + } + } + + return 0; +} + +static int session_update_stream_consumed_size(nghttp2_session *session, + nghttp2_stream *stream, + size_t delta_size) { + return session_update_consumed_size( + session, &stream->consumed_size, &stream->recv_window_size, + stream->window_update_queued, stream->stream_id, delta_size, + stream->local_window_size); +} + +static int session_update_connection_consumed_size(nghttp2_session *session, + size_t delta_size) { + return session_update_consumed_size( + session, &session->consumed_size, &session->recv_window_size, + session->window_update_queued, 0, delta_size, session->local_window_size); +} + +/* + * Checks that we can receive the DATA frame for stream, which is + * indicated by |session->iframe.frame.hd.stream_id|. If it is a + * connection error situation, GOAWAY frame will be issued by this + * function. + * + * If the DATA frame is allowed, returns 0. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_IGN_PAYLOAD + * The reception of DATA frame is connection error; or should be + * ignored. + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +static int session_on_data_received_fail_fast(nghttp2_session *session) { + int rv; + nghttp2_stream *stream; + nghttp2_inbound_frame *iframe; + int32_t stream_id; + const char *failure_reason; + uint32_t error_code = NGHTTP2_PROTOCOL_ERROR; + + iframe = &session->iframe; + stream_id = iframe->frame.hd.stream_id; + + if (stream_id == 0) { + /* The spec says that if a DATA frame is received whose stream ID + is 0, the recipient MUST respond with a connection error of + type PROTOCOL_ERROR. */ + failure_reason = "DATA: stream_id == 0"; + goto fail; + } + + if (session_detect_idle_stream(session, stream_id)) { + failure_reason = "DATA: stream in idle"; + error_code = NGHTTP2_PROTOCOL_ERROR; + goto fail; + } + + stream = nghttp2_session_get_stream(session, stream_id); + if (!stream) { + stream = nghttp2_session_get_stream_raw(session, stream_id); + if (stream && (stream->shut_flags & NGHTTP2_SHUT_RD)) { + failure_reason = "DATA: stream closed"; + error_code = NGHTTP2_STREAM_CLOSED; + goto fail; + } + + return NGHTTP2_ERR_IGN_PAYLOAD; + } + if (stream->shut_flags & NGHTTP2_SHUT_RD) { + failure_reason = "DATA: stream in half-closed(remote)"; + error_code = NGHTTP2_STREAM_CLOSED; + goto fail; + } + + if (nghttp2_session_is_my_stream_id(session, stream_id)) { + if (stream->state == NGHTTP2_STREAM_CLOSING) { + return NGHTTP2_ERR_IGN_PAYLOAD; + } + if (stream->state != NGHTTP2_STREAM_OPENED) { + failure_reason = "DATA: stream not opened"; + goto fail; + } + return 0; + } + if (stream->state == NGHTTP2_STREAM_RESERVED) { + failure_reason = "DATA: stream in reserved"; + goto fail; + } + if (stream->state == NGHTTP2_STREAM_CLOSING) { + return NGHTTP2_ERR_IGN_PAYLOAD; + } + return 0; +fail: + rv = nghttp2_session_terminate_session_with_reason(session, error_code, + failure_reason); + if (nghttp2_is_fatal(rv)) { + return rv; + } + return NGHTTP2_ERR_IGN_PAYLOAD; +} + +static size_t inbound_frame_payload_readlen(nghttp2_inbound_frame *iframe, + const uint8_t *in, + const uint8_t *last) { + return nghttp2_min((size_t)(last - in), iframe->payloadleft); +} + +/* + * Resets iframe->sbuf and advance its mark pointer by |left| bytes. + */ +static void inbound_frame_set_mark(nghttp2_inbound_frame *iframe, size_t left) { + nghttp2_buf_reset(&iframe->sbuf); + iframe->sbuf.mark += left; +} + +static size_t inbound_frame_buf_read(nghttp2_inbound_frame *iframe, + const uint8_t *in, const uint8_t *last) { + size_t readlen; + + readlen = + nghttp2_min((size_t)(last - in), nghttp2_buf_mark_avail(&iframe->sbuf)); + + iframe->sbuf.last = nghttp2_cpymem(iframe->sbuf.last, in, readlen); + + return readlen; +} + +/* + * Unpacks SETTINGS entry in iframe->sbuf. + */ +static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) { + nghttp2_settings_entry iv; + nghttp2_settings_entry *min_header_table_size_entry; + size_t i; + + nghttp2_frame_unpack_settings_entry(&iv, iframe->sbuf.pos); + + switch (iv.settings_id) { + case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: + case NGHTTP2_SETTINGS_ENABLE_PUSH: + case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: + case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: + case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: + case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: + break; + default: + DEBUGF("recv: unknown settings id=0x%02x\n", iv.settings_id); + + iframe->iv[iframe->niv++] = iv; + + return; + } + + for (i = 0; i < iframe->niv; ++i) { + if (iframe->iv[i].settings_id == iv.settings_id) { + iframe->iv[i] = iv; + break; + } + } + + if (i == iframe->niv) { + iframe->iv[iframe->niv++] = iv; + } + + if (iv.settings_id == NGHTTP2_SETTINGS_HEADER_TABLE_SIZE) { + /* Keep track of minimum value of SETTINGS_HEADER_TABLE_SIZE */ + min_header_table_size_entry = &iframe->iv[iframe->max_niv - 1]; + + if (iv.value < min_header_table_size_entry->value) { + min_header_table_size_entry->value = iv.value; + } + } +} + +/* + * Checks PADDED flags and set iframe->sbuf to read them accordingly. + * If padding is set, this function returns 1. If no padding is set, + * this function returns 0. On error, returns -1. + */ +static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe, + nghttp2_frame_hd *hd) { + if (hd->flags & NGHTTP2_FLAG_PADDED) { + if (hd->length < 1) { + return -1; + } + inbound_frame_set_mark(iframe, 1); + return 1; + } + DEBUGF("recv: no padding in payload\n"); + return 0; +} + +/* + * Computes number of padding based on flags. This function returns + * the calculated length if it succeeds, or -1. + */ +static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) { + size_t padlen; + + /* 1 for Pad Length field */ + padlen = (size_t)(iframe->sbuf.pos[0] + 1); + + DEBUGF("recv: padlen=%zu\n", padlen); + + /* We cannot use iframe->frame.hd.length because of CONTINUATION */ + if (padlen - 1 > iframe->payloadleft) { + return -1; + } + + iframe->padlen = padlen; + + return (ssize_t)padlen; +} + +/* + * This function returns the effective payload length in the data of + * length |readlen| when the remaning payload is |payloadleft|. The + * |payloadleft| does not include |readlen|. If padding was started + * strictly before this data chunk, this function returns -1. + */ +static ssize_t inbound_frame_effective_readlen(nghttp2_inbound_frame *iframe, + size_t payloadleft, + size_t readlen) { + size_t trail_padlen = + nghttp2_frame_trail_padlen(&iframe->frame, iframe->padlen); + + if (trail_padlen > payloadleft) { + size_t padlen; + padlen = trail_padlen - payloadleft; + if (readlen < padlen) { + return -1; + } + return (ssize_t)(readlen - padlen); + } + return (ssize_t)(readlen); +} + +ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, + size_t inlen) { + const uint8_t *first = in, *last = in + inlen; + nghttp2_inbound_frame *iframe = &session->iframe; + size_t readlen; + ssize_t padlen; + int rv; + int busy = 0; + nghttp2_frame_hd cont_hd; + nghttp2_stream *stream; + size_t pri_fieldlen; + nghttp2_mem *mem; + + mem = &session->mem; + + /* We may have idle streams more than we expect (e.g., + nghttp2_session_change_stream_priority() or + nghttp2_session_create_idle_stream()). Adjust them here. */ + rv = nghttp2_session_adjust_idle_stream(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + if (!nghttp2_session_want_read(session)) { + return (ssize_t)inlen; + } + + for (;;) { + switch (iframe->state) { + case NGHTTP2_IB_READ_CLIENT_MAGIC: + readlen = nghttp2_min(inlen, iframe->payloadleft); + + if (memcmp(NGHTTP2_CLIENT_MAGIC + NGHTTP2_CLIENT_MAGIC_LEN - + iframe->payloadleft, + in, readlen) != 0) { + return NGHTTP2_ERR_BAD_CLIENT_MAGIC; + } + + iframe->payloadleft -= readlen; + in += readlen; + + if (iframe->payloadleft == 0) { + session_inbound_frame_reset(session); + iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS; + } + + break; + case NGHTTP2_IB_READ_FIRST_SETTINGS: + DEBUGF("recv: [IB_READ_FIRST_SETTINGS]\n"); + + readlen = inbound_frame_buf_read(iframe, in, last); + in += readlen; + + if (nghttp2_buf_mark_avail(&iframe->sbuf)) { + return in - first; + } + + if (iframe->sbuf.pos[3] != NGHTTP2_SETTINGS || + (iframe->sbuf.pos[4] & NGHTTP2_FLAG_ACK)) { + + iframe->state = NGHTTP2_IB_IGN_ALL; + + rv = session_call_error_callback( + session, NGHTTP2_ERR_SETTINGS_EXPECTED, + "Remote peer returned unexpected data while we expected " + "SETTINGS frame. Perhaps, peer does not support HTTP/2 " + "properly."); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + rv = nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_PROTOCOL_ERROR, "SETTINGS expected"); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + return (ssize_t)inlen; + } + + iframe->state = NGHTTP2_IB_READ_HEAD; + + /* Fall through */ + case NGHTTP2_IB_READ_HEAD: { + int on_begin_frame_called = 0; + + DEBUGF("recv: [IB_READ_HEAD]\n"); + + readlen = inbound_frame_buf_read(iframe, in, last); + in += readlen; + + if (nghttp2_buf_mark_avail(&iframe->sbuf)) { + return in - first; + } + + nghttp2_frame_unpack_frame_hd(&iframe->frame.hd, iframe->sbuf.pos); + iframe->payloadleft = iframe->frame.hd.length; + + DEBUGF("recv: payloadlen=%zu, type=%u, flags=0x%02x, stream_id=%d\n", + iframe->frame.hd.length, iframe->frame.hd.type, + iframe->frame.hd.flags, iframe->frame.hd.stream_id); + + if (iframe->frame.hd.length > session->local_settings.max_frame_size) { + DEBUGF("recv: length is too large %zu > %u\n", iframe->frame.hd.length, + session->local_settings.max_frame_size); + + busy = 1; + + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + + rv = nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_FRAME_SIZE_ERROR, "too large frame size"); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + break; + } + + switch (iframe->frame.hd.type) { + case NGHTTP2_DATA: { + DEBUGF("recv: DATA\n"); + + iframe->frame.hd.flags &= + (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PADDED); + /* Check stream is open. If it is not open or closing, + ignore payload. */ + busy = 1; + + rv = session_on_data_received_fail_fast(session); + if (rv == NGHTTP2_ERR_IGN_PAYLOAD) { + DEBUGF("recv: DATA not allowed stream_id=%d\n", + iframe->frame.hd.stream_id); + iframe->state = NGHTTP2_IB_IGN_DATA; + break; + } + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); + if (rv < 0) { + iframe->state = NGHTTP2_IB_IGN_DATA; + rv = nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_PROTOCOL_ERROR, + "DATA: insufficient padding space"); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + break; + } + + if (rv == 1) { + iframe->state = NGHTTP2_IB_READ_PAD_DATA; + break; + } + + iframe->state = NGHTTP2_IB_READ_DATA; + break; + } + case NGHTTP2_HEADERS: + + DEBUGF("recv: HEADERS\n"); + + iframe->frame.hd.flags &= + (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | + NGHTTP2_FLAG_PADDED | NGHTTP2_FLAG_PRIORITY); + + rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); + if (rv < 0) { + busy = 1; + + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + + rv = nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_PROTOCOL_ERROR, + "HEADERS: insufficient padding space"); + if (nghttp2_is_fatal(rv)) { + return rv; + } + break; + } + + if (rv == 1) { + iframe->state = NGHTTP2_IB_READ_NBYTE; + break; + } + + pri_fieldlen = nghttp2_frame_priority_len(iframe->frame.hd.flags); + + if (pri_fieldlen > 0) { + if (iframe->payloadleft < pri_fieldlen) { + busy = 1; + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + break; + } + + iframe->state = NGHTTP2_IB_READ_NBYTE; + + inbound_frame_set_mark(iframe, pri_fieldlen); + + break; + } + + /* Call on_begin_frame_callback here because + session_process_headers_frame() may call + on_begin_headers_callback */ + rv = session_call_on_begin_frame(session, &iframe->frame.hd); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + on_begin_frame_called = 1; + + rv = session_process_headers_frame(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + busy = 1; + + if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + rv = nghttp2_session_add_rst_stream( + session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR); + if (nghttp2_is_fatal(rv)) { + return rv; + } + iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; + break; + } + + if (rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { + iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; + break; + } + + iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; + + break; + case NGHTTP2_PRIORITY: + DEBUGF("recv: PRIORITY\n"); + + iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; + + if (iframe->payloadleft != NGHTTP2_PRIORITY_SPECLEN) { + busy = 1; + + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + + break; + } + + iframe->state = NGHTTP2_IB_READ_NBYTE; + + inbound_frame_set_mark(iframe, NGHTTP2_PRIORITY_SPECLEN); + + break; + case NGHTTP2_RST_STREAM: + case NGHTTP2_WINDOW_UPDATE: +#ifdef DEBUGBUILD + switch (iframe->frame.hd.type) { + case NGHTTP2_RST_STREAM: + DEBUGF("recv: RST_STREAM\n"); + break; + case NGHTTP2_WINDOW_UPDATE: + DEBUGF("recv: WINDOW_UPDATE\n"); + break; + } +#endif /* DEBUGBUILD */ + + iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; + + if (iframe->payloadleft != 4) { + busy = 1; + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + break; + } + + iframe->state = NGHTTP2_IB_READ_NBYTE; + + inbound_frame_set_mark(iframe, 4); + + break; + case NGHTTP2_SETTINGS: + DEBUGF("recv: SETTINGS\n"); + + iframe->frame.hd.flags &= NGHTTP2_FLAG_ACK; + + if ((iframe->frame.hd.length % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) || + ((iframe->frame.hd.flags & NGHTTP2_FLAG_ACK) && + iframe->payloadleft > 0)) { + busy = 1; + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + break; + } + + iframe->state = NGHTTP2_IB_READ_SETTINGS; + + if (iframe->payloadleft) { + nghttp2_settings_entry *min_header_table_size_entry; + + /* We allocate iv with additional one entry, to store the + minimum header table size. */ + iframe->max_niv = + iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1; + + iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) * + iframe->max_niv); + + if (!iframe->iv) { + return NGHTTP2_ERR_NOMEM; + } + + min_header_table_size_entry = &iframe->iv[iframe->max_niv - 1]; + min_header_table_size_entry->settings_id = + NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; + min_header_table_size_entry->value = UINT32_MAX; + + inbound_frame_set_mark(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH); + break; + } + + busy = 1; + + inbound_frame_set_mark(iframe, 0); + + break; + case NGHTTP2_PUSH_PROMISE: + DEBUGF("recv: PUSH_PROMISE\n"); + + iframe->frame.hd.flags &= + (NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PADDED); + + rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); + if (rv < 0) { + busy = 1; + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + rv = nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_PROTOCOL_ERROR, + "PUSH_PROMISE: insufficient padding space"); + if (nghttp2_is_fatal(rv)) { + return rv; + } + break; + } + + if (rv == 1) { + iframe->state = NGHTTP2_IB_READ_NBYTE; + break; + } + + if (iframe->payloadleft < 4) { + busy = 1; + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + break; + } + + iframe->state = NGHTTP2_IB_READ_NBYTE; + + inbound_frame_set_mark(iframe, 4); + + break; + case NGHTTP2_PING: + DEBUGF("recv: PING\n"); + + iframe->frame.hd.flags &= NGHTTP2_FLAG_ACK; + + if (iframe->payloadleft != 8) { + busy = 1; + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + break; + } + + iframe->state = NGHTTP2_IB_READ_NBYTE; + inbound_frame_set_mark(iframe, 8); + + break; + case NGHTTP2_GOAWAY: + DEBUGF("recv: GOAWAY\n"); + + iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; + + if (iframe->payloadleft < 8) { + busy = 1; + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + break; + } + + iframe->state = NGHTTP2_IB_READ_NBYTE; + inbound_frame_set_mark(iframe, 8); + + break; + case NGHTTP2_CONTINUATION: + DEBUGF("recv: unexpected CONTINUATION\n"); + + /* Receiving CONTINUATION in this state are subject to + connection error of type PROTOCOL_ERROR */ + rv = nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_PROTOCOL_ERROR, "CONTINUATION: unexpected"); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + busy = 1; + + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + + break; + default: + DEBUGF("recv: extension frame\n"); + + if (check_ext_type_set(session->user_recv_ext_types, + iframe->frame.hd.type)) { + if (!session->callbacks.unpack_extension_callback) { + /* Silently ignore unknown frame type. */ + + busy = 1; + + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + + break; + } + + busy = 1; + + iframe->state = NGHTTP2_IB_READ_EXTENSION_PAYLOAD; + + break; + } else { + switch (iframe->frame.hd.type) { + case NGHTTP2_ALTSVC: + if ((session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ALTSVC) == + 0) { + busy = 1; + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + break; + } + + DEBUGF("recv: ALTSVC\n"); + + iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; + iframe->frame.ext.payload = &iframe->ext_frame_payload.altsvc; + + if (session->server) { + busy = 1; + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + break; + } + + if (iframe->payloadleft < 2) { + busy = 1; + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + break; + } + + busy = 1; + + iframe->state = NGHTTP2_IB_READ_NBYTE; + inbound_frame_set_mark(iframe, 2); + + break; + default: + busy = 1; + + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + + break; + } + } + } + + if (!on_begin_frame_called) { + switch (iframe->state) { + case NGHTTP2_IB_IGN_HEADER_BLOCK: + case NGHTTP2_IB_IGN_PAYLOAD: + case NGHTTP2_IB_FRAME_SIZE_ERROR: + case NGHTTP2_IB_IGN_DATA: + break; + default: + rv = session_call_on_begin_frame(session, &iframe->frame.hd); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + } + + break; + } + case NGHTTP2_IB_READ_NBYTE: + DEBUGF("recv: [IB_READ_NBYTE]\n"); + + readlen = inbound_frame_buf_read(iframe, in, last); + in += readlen; + iframe->payloadleft -= readlen; + + DEBUGF("recv: readlen=%zu, payloadleft=%zu, left=%zd\n", readlen, + iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf)); + + if (nghttp2_buf_mark_avail(&iframe->sbuf)) { + return in - first; + } + + switch (iframe->frame.hd.type) { + case NGHTTP2_HEADERS: + if (iframe->padlen == 0 && + (iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) { + padlen = inbound_frame_compute_pad(iframe); + if (padlen < 0) { + busy = 1; + rv = nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_PROTOCOL_ERROR, "HEADERS: invalid padding"); + if (nghttp2_is_fatal(rv)) { + return rv; + } + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + break; + } + iframe->frame.headers.padlen = (size_t)padlen; + + pri_fieldlen = nghttp2_frame_priority_len(iframe->frame.hd.flags); + + if (pri_fieldlen > 0) { + if (iframe->payloadleft < pri_fieldlen) { + busy = 1; + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + break; + } + iframe->state = NGHTTP2_IB_READ_NBYTE; + inbound_frame_set_mark(iframe, pri_fieldlen); + break; + } else { + /* Truncate buffers used for padding spec */ + inbound_frame_set_mark(iframe, 0); + } + } + + rv = session_process_headers_frame(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + busy = 1; + + if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + rv = nghttp2_session_add_rst_stream( + session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR); + if (nghttp2_is_fatal(rv)) { + return rv; + } + iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; + break; + } + + if (rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { + iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; + break; + } + + iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; + + break; + case NGHTTP2_PRIORITY: + rv = session_process_priority_frame(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + session_inbound_frame_reset(session); + + break; + case NGHTTP2_RST_STREAM: + rv = session_process_rst_stream_frame(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + session_inbound_frame_reset(session); + + break; + case NGHTTP2_PUSH_PROMISE: + if (iframe->padlen == 0 && + (iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) { + padlen = inbound_frame_compute_pad(iframe); + if (padlen < 0) { + busy = 1; + rv = nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_PROTOCOL_ERROR, + "PUSH_PROMISE: invalid padding"); + if (nghttp2_is_fatal(rv)) { + return rv; + } + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + break; + } + + iframe->frame.push_promise.padlen = (size_t)padlen; + + if (iframe->payloadleft < 4) { + busy = 1; + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + break; + } + + iframe->state = NGHTTP2_IB_READ_NBYTE; + + inbound_frame_set_mark(iframe, 4); + + break; + } + + rv = session_process_push_promise_frame(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + busy = 1; + + if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + rv = nghttp2_session_add_rst_stream( + session, iframe->frame.push_promise.promised_stream_id, + NGHTTP2_INTERNAL_ERROR); + if (nghttp2_is_fatal(rv)) { + return rv; + } + iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; + break; + } + + if (rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { + iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; + break; + } + + iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; + + break; + case NGHTTP2_PING: + rv = session_process_ping_frame(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + session_inbound_frame_reset(session); + + break; + case NGHTTP2_GOAWAY: { + size_t debuglen; + + /* 8 is Last-stream-ID + Error Code */ + debuglen = iframe->frame.hd.length - 8; + + if (debuglen > 0) { + iframe->raw_lbuf = nghttp2_mem_malloc(mem, debuglen); + + if (iframe->raw_lbuf == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_buf_wrap_init(&iframe->lbuf, iframe->raw_lbuf, debuglen); + } + + busy = 1; + + iframe->state = NGHTTP2_IB_READ_GOAWAY_DEBUG; + + break; + } + case NGHTTP2_WINDOW_UPDATE: + rv = session_process_window_update_frame(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + session_inbound_frame_reset(session); + + break; + case NGHTTP2_ALTSVC: { + size_t origin_len; + + origin_len = nghttp2_get_uint16(iframe->sbuf.pos); + + DEBUGF("recv: origin_len=%zu\n", origin_len); + + if (origin_len > iframe->payloadleft) { + busy = 1; + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + break; + } + + if (iframe->frame.hd.length > 2) { + iframe->raw_lbuf = + nghttp2_mem_malloc(mem, iframe->frame.hd.length - 2); + + if (iframe->raw_lbuf == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_buf_wrap_init(&iframe->lbuf, iframe->raw_lbuf, + iframe->frame.hd.length); + } + + busy = 1; + + iframe->state = NGHTTP2_IB_READ_ALTSVC_PAYLOAD; + + break; + } + default: + /* This is unknown frame */ + session_inbound_frame_reset(session); + + break; + } + break; + case NGHTTP2_IB_READ_HEADER_BLOCK: + case NGHTTP2_IB_IGN_HEADER_BLOCK: { + ssize_t data_readlen; + size_t trail_padlen; + int final; +#ifdef DEBUGBUILD + if (iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { + DEBUGF("recv: [IB_READ_HEADER_BLOCK]\n"); + } else { + DEBUGF("recv: [IB_IGN_HEADER_BLOCK]\n"); + } +#endif /* DEBUGBUILD */ + + readlen = inbound_frame_payload_readlen(iframe, in, last); + + DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, + iframe->payloadleft - readlen); + + data_readlen = inbound_frame_effective_readlen( + iframe, iframe->payloadleft - readlen, readlen); + trail_padlen = nghttp2_frame_trail_padlen(&iframe->frame, iframe->padlen); + + final = (iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) && + iframe->payloadleft - (size_t)data_readlen == trail_padlen; + + if (data_readlen > 0 || (data_readlen == 0 && final)) { + size_t hd_proclen = 0; + + DEBUGF("recv: block final=%d\n", final); + + rv = + inflate_header_block(session, &iframe->frame, &hd_proclen, + (uint8_t *)in, (size_t)data_readlen, final, + iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + if (rv == NGHTTP2_ERR_PAUSE) { + in += hd_proclen; + iframe->payloadleft -= hd_proclen; + + return in - first; + } + + if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + /* The application says no more headers. We decompress the + rest of the header block but not invoke on_header_callback + and on_frame_recv_callback. */ + in += hd_proclen; + iframe->payloadleft -= hd_proclen; + + /* Use promised stream ID for PUSH_PROMISE */ + rv = nghttp2_session_add_rst_stream( + session, + iframe->frame.hd.type == NGHTTP2_PUSH_PROMISE + ? iframe->frame.push_promise.promised_stream_id + : iframe->frame.hd.stream_id, + NGHTTP2_INTERNAL_ERROR); + if (nghttp2_is_fatal(rv)) { + return rv; + } + busy = 1; + iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; + break; + } + + in += readlen; + iframe->payloadleft -= readlen; + + if (rv == NGHTTP2_ERR_HEADER_COMP) { + /* GOAWAY is already issued */ + if (iframe->payloadleft == 0) { + session_inbound_frame_reset(session); + } else { + busy = 1; + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + } + break; + } + } else { + in += readlen; + iframe->payloadleft -= readlen; + } + + if (iframe->payloadleft) { + break; + } + + if ((iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) { + + inbound_frame_set_mark(iframe, NGHTTP2_FRAME_HDLEN); + + iframe->padlen = 0; + + if (iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { + iframe->state = NGHTTP2_IB_EXPECT_CONTINUATION; + } else { + iframe->state = NGHTTP2_IB_IGN_CONTINUATION; + } + } else { + if (iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { + rv = session_after_header_block_received(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + session_inbound_frame_reset(session); + } + break; + } + case NGHTTP2_IB_IGN_PAYLOAD: + DEBUGF("recv: [IB_IGN_PAYLOAD]\n"); + + readlen = inbound_frame_payload_readlen(iframe, in, last); + iframe->payloadleft -= readlen; + in += readlen; + + DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, + iframe->payloadleft); + + if (iframe->payloadleft) { + break; + } + + switch (iframe->frame.hd.type) { + case NGHTTP2_HEADERS: + case NGHTTP2_PUSH_PROMISE: + case NGHTTP2_CONTINUATION: + /* Mark inflater bad so that we won't perform further decoding */ + session->hd_inflater.ctx.bad = 1; + break; + default: + break; + } + + session_inbound_frame_reset(session); + + break; + case NGHTTP2_IB_FRAME_SIZE_ERROR: + DEBUGF("recv: [IB_FRAME_SIZE_ERROR]\n"); + + rv = session_handle_frame_size_error(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + busy = 1; + + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + + break; + case NGHTTP2_IB_READ_SETTINGS: + DEBUGF("recv: [IB_READ_SETTINGS]\n"); + + readlen = inbound_frame_buf_read(iframe, in, last); + iframe->payloadleft -= readlen; + in += readlen; + + DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, + iframe->payloadleft); + + if (nghttp2_buf_mark_avail(&iframe->sbuf)) { + break; + } + + if (readlen > 0) { + inbound_frame_set_settings_entry(iframe); + } + if (iframe->payloadleft) { + inbound_frame_set_mark(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH); + break; + } + + rv = session_process_settings_frame(session); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + session_inbound_frame_reset(session); + + break; + case NGHTTP2_IB_READ_GOAWAY_DEBUG: + DEBUGF("recv: [IB_READ_GOAWAY_DEBUG]\n"); + + readlen = inbound_frame_payload_readlen(iframe, in, last); + + if (readlen > 0) { + iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen); + + iframe->payloadleft -= readlen; + in += readlen; + } + + DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, + iframe->payloadleft); + + if (iframe->payloadleft) { + assert(nghttp2_buf_avail(&iframe->lbuf) > 0); + + break; + } + + rv = session_process_goaway_frame(session); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + session_inbound_frame_reset(session); + + break; + case NGHTTP2_IB_EXPECT_CONTINUATION: + case NGHTTP2_IB_IGN_CONTINUATION: +#ifdef DEBUGBUILD + if (iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { + fprintf(stderr, "recv: [IB_EXPECT_CONTINUATION]\n"); + } else { + fprintf(stderr, "recv: [IB_IGN_CONTINUATION]\n"); + } +#endif /* DEBUGBUILD */ + + readlen = inbound_frame_buf_read(iframe, in, last); + in += readlen; + + if (nghttp2_buf_mark_avail(&iframe->sbuf)) { + return in - first; + } + + nghttp2_frame_unpack_frame_hd(&cont_hd, iframe->sbuf.pos); + iframe->payloadleft = cont_hd.length; + + DEBUGF("recv: payloadlen=%zu, type=%u, flags=0x%02x, stream_id=%d\n", + cont_hd.length, cont_hd.type, cont_hd.flags, cont_hd.stream_id); + + if (cont_hd.type != NGHTTP2_CONTINUATION || + cont_hd.stream_id != iframe->frame.hd.stream_id) { + DEBUGF("recv: expected stream_id=%d, type=%d, but got stream_id=%d, " + "type=%u\n", + iframe->frame.hd.stream_id, NGHTTP2_CONTINUATION, + cont_hd.stream_id, cont_hd.type); + rv = nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_PROTOCOL_ERROR, + "unexpected non-CONTINUATION frame or stream_id is invalid"); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + busy = 1; + + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + + break; + } + + /* CONTINUATION won't bear NGHTTP2_PADDED flag */ + + iframe->frame.hd.flags = (uint8_t)( + iframe->frame.hd.flags | (cont_hd.flags & NGHTTP2_FLAG_END_HEADERS)); + iframe->frame.hd.length += cont_hd.length; + + busy = 1; + + if (iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { + iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; + + rv = session_call_on_begin_frame(session, &cont_hd); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + } else { + iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; + } + + break; + case NGHTTP2_IB_READ_PAD_DATA: + DEBUGF("recv: [IB_READ_PAD_DATA]\n"); + + readlen = inbound_frame_buf_read(iframe, in, last); + in += readlen; + iframe->payloadleft -= readlen; + + DEBUGF("recv: readlen=%zu, payloadleft=%zu, left=%zu\n", readlen, + iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf)); + + if (nghttp2_buf_mark_avail(&iframe->sbuf)) { + return in - first; + } + + /* Pad Length field is subject to flow control */ + rv = session_update_recv_connection_window_size(session, readlen); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + /* Pad Length field is consumed immediately */ + rv = + nghttp2_session_consume(session, iframe->frame.hd.stream_id, readlen); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id); + if (stream) { + rv = session_update_recv_stream_window_size( + session, stream, readlen, + iframe->payloadleft || + (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0); + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + + busy = 1; + + padlen = inbound_frame_compute_pad(iframe); + if (padlen < 0) { + rv = nghttp2_session_terminate_session_with_reason( + session, NGHTTP2_PROTOCOL_ERROR, "DATA: invalid padding"); + if (nghttp2_is_fatal(rv)) { + return rv; + } + iframe->state = NGHTTP2_IB_IGN_DATA; + break; + } + + iframe->frame.data.padlen = (size_t)padlen; + + iframe->state = NGHTTP2_IB_READ_DATA; + + break; + case NGHTTP2_IB_READ_DATA: + stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id); + + if (!stream) { + busy = 1; + iframe->state = NGHTTP2_IB_IGN_DATA; + break; + } + + DEBUGF("recv: [IB_READ_DATA]\n"); + + readlen = inbound_frame_payload_readlen(iframe, in, last); + iframe->payloadleft -= readlen; + in += readlen; + + DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, + iframe->payloadleft); + + if (readlen > 0) { + ssize_t data_readlen; + + rv = session_update_recv_connection_window_size(session, readlen); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + rv = session_update_recv_stream_window_size( + session, stream, readlen, + iframe->payloadleft || + (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + data_readlen = inbound_frame_effective_readlen( + iframe, iframe->payloadleft, readlen); + + if (data_readlen == -1) { + /* everything is padding */ + data_readlen = 0; + } + + padlen = (ssize_t)readlen - data_readlen; + + if (padlen > 0) { + /* Padding is considered as "consumed" immediately */ + rv = nghttp2_session_consume(session, iframe->frame.hd.stream_id, + (size_t)padlen); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + + DEBUGF("recv: data_readlen=%zd\n", data_readlen); + + if (data_readlen > 0) { + if (session_enforce_http_messaging(session)) { + if (nghttp2_http_on_data_chunk(stream, (size_t)data_readlen) != 0) { + if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { + /* Consume all data for connection immediately here */ + rv = session_update_connection_consumed_size( + session, (size_t)data_readlen); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + + rv = nghttp2_session_add_rst_stream( + session, iframe->frame.hd.stream_id, NGHTTP2_PROTOCOL_ERROR); + if (nghttp2_is_fatal(rv)) { + return rv; + } + busy = 1; + iframe->state = NGHTTP2_IB_IGN_DATA; + break; + } + } + if (session->callbacks.on_data_chunk_recv_callback) { + rv = session->callbacks.on_data_chunk_recv_callback( + session, iframe->frame.hd.flags, iframe->frame.hd.stream_id, + in - readlen, (size_t)data_readlen, session->user_data); + if (rv == NGHTTP2_ERR_PAUSE) { + return in - first; + } + + if (nghttp2_is_fatal(rv)) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + } + } + + if (iframe->payloadleft) { + break; + } + + rv = session_process_data_frame(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + session_inbound_frame_reset(session); + + break; + case NGHTTP2_IB_IGN_DATA: + DEBUGF("recv: [IB_IGN_DATA]\n"); + + readlen = inbound_frame_payload_readlen(iframe, in, last); + iframe->payloadleft -= readlen; + in += readlen; + + DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, + iframe->payloadleft); + + if (readlen > 0) { + /* Update connection-level flow control window for ignored + DATA frame too */ + rv = session_update_recv_connection_window_size(session, readlen); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { + + /* Ignored DATA is considered as "consumed" immediately. */ + rv = session_update_connection_consumed_size(session, readlen); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + } + } + + if (iframe->payloadleft) { + break; + } + + session_inbound_frame_reset(session); + + break; + case NGHTTP2_IB_IGN_ALL: + return (ssize_t)inlen; + case NGHTTP2_IB_READ_EXTENSION_PAYLOAD: + DEBUGF("recv: [IB_READ_EXTENSION_PAYLOAD]\n"); + + readlen = inbound_frame_payload_readlen(iframe, in, last); + iframe->payloadleft -= readlen; + in += readlen; + + DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, + iframe->payloadleft); + + if (readlen > 0) { + rv = session_call_on_extension_chunk_recv_callback( + session, in - readlen, readlen); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + if (rv != 0) { + busy = 1; + + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + + break; + } + } + + if (iframe->payloadleft > 0) { + break; + } + + rv = session_process_extension_frame(session); + if (nghttp2_is_fatal(rv)) { + return rv; + } + + session_inbound_frame_reset(session); + + break; + case NGHTTP2_IB_READ_ALTSVC_PAYLOAD: + DEBUGF("recv: [IB_READ_ALTSVC_PAYLOAD]\n"); + + readlen = inbound_frame_payload_readlen(iframe, in, last); + + if (readlen > 0) { + iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen); + + iframe->payloadleft -= readlen; + in += readlen; + } + + DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, + iframe->payloadleft); + + if (iframe->payloadleft) { + assert(nghttp2_buf_avail(&iframe->lbuf) > 0); + + break; + } + + rv = session_process_altsvc_frame(session); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + session_inbound_frame_reset(session); + + break; + } + + if (!busy && in == last) { + break; + } + + busy = 0; + } + + assert(in == last); + + return in - first; +} + +int nghttp2_session_recv(nghttp2_session *session) { + uint8_t buf[NGHTTP2_INBOUND_BUFFER_LENGTH]; + while (1) { + ssize_t readlen; + readlen = session_recv(session, buf, sizeof(buf)); + if (readlen > 0) { + ssize_t proclen = nghttp2_session_mem_recv(session, buf, (size_t)readlen); + if (proclen < 0) { + return (int)proclen; + } + assert(proclen == readlen); + } else if (readlen == 0 || readlen == NGHTTP2_ERR_WOULDBLOCK) { + return 0; + } else if (readlen == NGHTTP2_ERR_EOF) { + return NGHTTP2_ERR_EOF; + } else if (readlen < 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } +} + +/* + * Returns the number of active streams, which includes streams in + * reserved state. + */ +static size_t session_get_num_active_streams(nghttp2_session *session) { + return nghttp2_map_size(&session->streams) - session->num_closed_streams - + session->num_idle_streams; +} + +int nghttp2_session_want_read(nghttp2_session *session) { + size_t num_active_streams; + + /* If this flag is set, we don't want to read. The application + should drop the connection. */ + if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_SENT) { + return 0; + } + + num_active_streams = session_get_num_active_streams(session); + + /* Unless termination GOAWAY is sent or received, we always want to + read incoming frames. */ + + if (num_active_streams > 0) { + return 1; + } + + /* If there is no active streams and GOAWAY has been sent or + received, we are done with this session. */ + return (session->goaway_flags & + (NGHTTP2_GOAWAY_SENT | NGHTTP2_GOAWAY_RECV)) == 0; +} + +int nghttp2_session_want_write(nghttp2_session *session) { + /* If these flag is set, we don't want to write any data. The + application should drop the connection. */ + if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_SENT) { + return 0; + } + + /* + * Unless termination GOAWAY is sent or received, we want to write + * frames if there is pending ones. If pending frame is request/push + * response HEADERS and concurrent stream limit is reached, we don't + * want to write them. + */ + return session->aob.item || nghttp2_outbound_queue_top(&session->ob_urgent) || + nghttp2_outbound_queue_top(&session->ob_reg) || + (!nghttp2_pq_empty(&session->root.obq) && + session->remote_window_size > 0) || + (nghttp2_outbound_queue_top(&session->ob_syn) && + !session_is_outgoing_concurrent_streams_max(session)); +} + +int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags, + const uint8_t *opaque_data) { + int rv; + nghttp2_outbound_item *item; + nghttp2_frame *frame; + nghttp2_mem *mem; + + mem = &session->mem; + + if ((flags & NGHTTP2_FLAG_ACK) && + session->obq_flood_counter_ >= NGHTTP2_MAX_OBQ_FLOOD_ITEM) { + return NGHTTP2_ERR_FLOODED; + } + + item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); + if (item == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_outbound_item_init(item); + + frame = &item->frame; + + nghttp2_frame_ping_init(&frame->ping, flags, opaque_data); + + rv = nghttp2_session_add_item(session, item); + + if (rv != 0) { + nghttp2_frame_ping_free(&frame->ping); + nghttp2_mem_free(mem, item); + return rv; + } + + if (flags & NGHTTP2_FLAG_ACK) { + ++session->obq_flood_counter_; + } + + return 0; +} + +int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id, + uint32_t error_code, const uint8_t *opaque_data, + size_t opaque_data_len, uint8_t aux_flags) { + int rv; + nghttp2_outbound_item *item; + nghttp2_frame *frame; + uint8_t *opaque_data_copy = NULL; + nghttp2_goaway_aux_data *aux_data; + nghttp2_mem *mem; + + mem = &session->mem; + + if (nghttp2_session_is_my_stream_id(session, last_stream_id)) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + if (opaque_data_len) { + if (opaque_data_len + 8 > NGHTTP2_MAX_PAYLOADLEN) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + opaque_data_copy = nghttp2_mem_malloc(mem, opaque_data_len); + if (opaque_data_copy == NULL) { + return NGHTTP2_ERR_NOMEM; + } + memcpy(opaque_data_copy, opaque_data, opaque_data_len); + } + + item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); + if (item == NULL) { + nghttp2_mem_free(mem, opaque_data_copy); + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_outbound_item_init(item); + + frame = &item->frame; + + /* last_stream_id must not be increased from the value previously + sent */ + last_stream_id = nghttp2_min(last_stream_id, session->local_last_stream_id); + + nghttp2_frame_goaway_init(&frame->goaway, last_stream_id, error_code, + opaque_data_copy, opaque_data_len); + + aux_data = &item->aux_data.goaway; + aux_data->flags = aux_flags; + + rv = nghttp2_session_add_item(session, item); + if (rv != 0) { + nghttp2_frame_goaway_free(&frame->goaway, mem); + nghttp2_mem_free(mem, item); + return rv; + } + return 0; +} + +int nghttp2_session_add_window_update(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + int32_t window_size_increment) { + int rv; + nghttp2_outbound_item *item; + nghttp2_frame *frame; + nghttp2_mem *mem; + + mem = &session->mem; + item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); + if (item == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_outbound_item_init(item); + + frame = &item->frame; + + nghttp2_frame_window_update_init(&frame->window_update, flags, stream_id, + window_size_increment); + + rv = nghttp2_session_add_item(session, item); + + if (rv != 0) { + nghttp2_frame_window_update_free(&frame->window_update); + nghttp2_mem_free(mem, item); + return rv; + } + return 0; +} + +static void +session_append_inflight_settings(nghttp2_session *session, + nghttp2_inflight_settings *settings) { + nghttp2_inflight_settings **i; + + for (i = &session->inflight_settings_head; *i; i = &(*i)->next) + ; + + *i = settings; +} + +int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags, + const nghttp2_settings_entry *iv, size_t niv) { + nghttp2_outbound_item *item; + nghttp2_frame *frame; + nghttp2_settings_entry *iv_copy; + size_t i; + int rv; + nghttp2_mem *mem; + nghttp2_inflight_settings *inflight_settings = NULL; + + mem = &session->mem; + + if (flags & NGHTTP2_FLAG_ACK) { + if (niv != 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + if (session->obq_flood_counter_ >= NGHTTP2_MAX_OBQ_FLOOD_ITEM) { + return NGHTTP2_ERR_FLOODED; + } + } + + if (!nghttp2_iv_check(iv, niv)) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); + if (item == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + if (niv > 0) { + iv_copy = nghttp2_frame_iv_copy(iv, niv, mem); + if (iv_copy == NULL) { + nghttp2_mem_free(mem, item); + return NGHTTP2_ERR_NOMEM; + } + } else { + iv_copy = NULL; + } + + if ((flags & NGHTTP2_FLAG_ACK) == 0) { + rv = inflight_settings_new(&inflight_settings, iv, niv, mem); + if (rv != 0) { + assert(nghttp2_is_fatal(rv)); + nghttp2_mem_free(mem, iv_copy); + nghttp2_mem_free(mem, item); + return rv; + } + } + + nghttp2_outbound_item_init(item); + + frame = &item->frame; + + nghttp2_frame_settings_init(&frame->settings, flags, iv_copy, niv); + rv = nghttp2_session_add_item(session, item); + if (rv != 0) { + /* The only expected error is fatal one */ + assert(nghttp2_is_fatal(rv)); + + inflight_settings_del(inflight_settings, mem); + + nghttp2_frame_settings_free(&frame->settings, mem); + nghttp2_mem_free(mem, item); + + return rv; + } + + if (flags & NGHTTP2_FLAG_ACK) { + ++session->obq_flood_counter_; + } else { + session_append_inflight_settings(session, inflight_settings); + } + + /* Extract NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS and ENABLE_PUSH + here. We use it to refuse the incoming stream and PUSH_PROMISE + with RST_STREAM. */ + + for (i = niv; i > 0; --i) { + if (iv[i - 1].settings_id == NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS) { + session->pending_local_max_concurrent_stream = iv[i - 1].value; + break; + } + } + + for (i = niv; i > 0; --i) { + if (iv[i - 1].settings_id == NGHTTP2_SETTINGS_ENABLE_PUSH) { + session->pending_enable_push = (uint8_t)iv[i - 1].value; + break; + } + } + + return 0; +} + +int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs, + size_t datamax, nghttp2_frame *frame, + nghttp2_data_aux_data *aux_data, + nghttp2_stream *stream) { + int rv; + uint32_t data_flags; + ssize_t payloadlen; + ssize_t padded_payloadlen; + nghttp2_buf *buf; + size_t max_payloadlen; + + assert(bufs->head == bufs->cur); + + buf = &bufs->cur->buf; + + if (session->callbacks.read_length_callback) { + + payloadlen = session->callbacks.read_length_callback( + session, frame->hd.type, stream->stream_id, session->remote_window_size, + stream->remote_window_size, session->remote_settings.max_frame_size, + session->user_data); + + DEBUGF("send: read_length_callback=%zd\n", payloadlen); + + payloadlen = nghttp2_session_enforce_flow_control_limits(session, stream, + payloadlen); + + DEBUGF("send: read_length_callback after flow control=%zd\n", payloadlen); + + if (payloadlen <= 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + if ((size_t)payloadlen > nghttp2_buf_avail(buf)) { + /* Resize the current buffer(s). The reason why we do +1 for + buffer size is for possible padding field. */ + rv = nghttp2_bufs_realloc(&session->aob.framebufs, + (size_t)(NGHTTP2_FRAME_HDLEN + 1 + payloadlen)); + + if (rv != 0) { + DEBUGF("send: realloc buffer failed rv=%d", rv); + /* If reallocation failed, old buffers are still in tact. So + use safe limit. */ + payloadlen = (ssize_t)datamax; + + DEBUGF("send: use safe limit payloadlen=%zd", payloadlen); + } else { + assert(&session->aob.framebufs == bufs); + + buf = &bufs->cur->buf; + } + } + datamax = (size_t)payloadlen; + } + + /* Current max DATA length is less then buffer chunk size */ + assert(nghttp2_buf_avail(buf) >= datamax); + + data_flags = NGHTTP2_DATA_FLAG_NONE; + payloadlen = aux_data->data_prd.read_callback( + session, frame->hd.stream_id, buf->pos, datamax, &data_flags, + &aux_data->data_prd.source, session->user_data); + + if (payloadlen == NGHTTP2_ERR_DEFERRED || + payloadlen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE || + payloadlen == NGHTTP2_ERR_PAUSE) { + DEBUGF("send: DATA postponed due to %s\n", + nghttp2_strerror((int)payloadlen)); + + return (int)payloadlen; + } + + if (payloadlen < 0 || datamax < (size_t)payloadlen) { + /* This is the error code when callback is failed. */ + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + buf->last = buf->pos + payloadlen; + buf->pos -= NGHTTP2_FRAME_HDLEN; + + /* Clear flags, because this may contain previous flags of previous + DATA */ + frame->hd.flags = NGHTTP2_FLAG_NONE; + + if (data_flags & NGHTTP2_DATA_FLAG_EOF) { + aux_data->eof = 1; + /* If NGHTTP2_DATA_FLAG_NO_END_STREAM is set, don't set + NGHTTP2_FLAG_END_STREAM */ + if ((aux_data->flags & NGHTTP2_FLAG_END_STREAM) && + (data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM) == 0) { + frame->hd.flags |= NGHTTP2_FLAG_END_STREAM; + } + } + + if (data_flags & NGHTTP2_DATA_FLAG_NO_COPY) { + if (session->callbacks.send_data_callback == NULL) { + DEBUGF("NGHTTP2_DATA_FLAG_NO_COPY requires send_data_callback set\n"); + + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + aux_data->no_copy = 1; + } + + frame->hd.length = (size_t)payloadlen; + frame->data.padlen = 0; + + max_payloadlen = nghttp2_min(datamax, frame->hd.length + NGHTTP2_MAX_PADLEN); + + padded_payloadlen = + session_call_select_padding(session, frame, max_payloadlen); + + if (nghttp2_is_fatal((int)padded_payloadlen)) { + return (int)padded_payloadlen; + } + + frame->data.padlen = (size_t)(padded_payloadlen - payloadlen); + + nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); + + rv = nghttp2_frame_add_pad(bufs, &frame->hd, frame->data.padlen, + aux_data->no_copy); + if (rv != 0) { + return rv; + } + + reschedule_stream(stream); + + if (frame->hd.length == 0 && (data_flags & NGHTTP2_DATA_FLAG_EOF) && + (data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM)) { + /* DATA payload length is 0, and DATA frame does not bear + END_STREAM. In this case, there is no point to send 0 length + DATA frame. */ + return NGHTTP2_ERR_CANCEL; + } + + return 0; +} + +void *nghttp2_session_get_stream_user_data(nghttp2_session *session, + int32_t stream_id) { + nghttp2_stream *stream; + stream = nghttp2_session_get_stream(session, stream_id); + if (stream) { + return stream->stream_user_data; + } else { + return NULL; + } +} + +int nghttp2_session_set_stream_user_data(nghttp2_session *session, + int32_t stream_id, + void *stream_user_data) { + nghttp2_stream *stream; + stream = nghttp2_session_get_stream(session, stream_id); + if (!stream) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + stream->stream_user_data = stream_user_data; + return 0; +} + +int nghttp2_session_resume_data(nghttp2_session *session, int32_t stream_id) { + int rv; + nghttp2_stream *stream; + stream = nghttp2_session_get_stream(session, stream_id); + if (stream == NULL || !nghttp2_stream_check_deferred_item(stream)) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + rv = nghttp2_stream_resume_deferred_item(stream, + NGHTTP2_STREAM_FLAG_DEFERRED_USER); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + return 0; +} + +size_t nghttp2_session_get_outbound_queue_size(nghttp2_session *session) { + return nghttp2_outbound_queue_size(&session->ob_urgent) + + nghttp2_outbound_queue_size(&session->ob_reg) + + nghttp2_outbound_queue_size(&session->ob_syn); + /* TODO account for item attached to stream */ +} + +int32_t +nghttp2_session_get_stream_effective_recv_data_length(nghttp2_session *session, + int32_t stream_id) { + nghttp2_stream *stream; + stream = nghttp2_session_get_stream(session, stream_id); + if (stream == NULL) { + return -1; + } + return stream->recv_window_size < 0 ? 0 : stream->recv_window_size; +} + +int32_t +nghttp2_session_get_stream_effective_local_window_size(nghttp2_session *session, + int32_t stream_id) { + nghttp2_stream *stream; + stream = nghttp2_session_get_stream(session, stream_id); + if (stream == NULL) { + return -1; + } + return stream->local_window_size; +} + +int32_t nghttp2_session_get_stream_local_window_size(nghttp2_session *session, + int32_t stream_id) { + nghttp2_stream *stream; + int32_t size; + stream = nghttp2_session_get_stream(session, stream_id); + if (stream == NULL) { + return -1; + } + + size = stream->local_window_size - stream->recv_window_size; + + /* size could be negative if local endpoint reduced + SETTINGS_INITIAL_WINDOW_SIZE */ + if (size < 0) { + return 0; + } + + return size; +} + +int32_t +nghttp2_session_get_effective_recv_data_length(nghttp2_session *session) { + return session->recv_window_size < 0 ? 0 : session->recv_window_size; +} + +int32_t +nghttp2_session_get_effective_local_window_size(nghttp2_session *session) { + return session->local_window_size; +} + +int32_t nghttp2_session_get_local_window_size(nghttp2_session *session) { + return session->local_window_size - session->recv_window_size; +} + +int32_t nghttp2_session_get_stream_remote_window_size(nghttp2_session *session, + int32_t stream_id) { + nghttp2_stream *stream; + + stream = nghttp2_session_get_stream(session, stream_id); + if (stream == NULL) { + return -1; + } + + /* stream->remote_window_size can be negative when + SETTINGS_INITIAL_WINDOW_SIZE is changed. */ + return nghttp2_max(0, stream->remote_window_size); +} + +int32_t nghttp2_session_get_remote_window_size(nghttp2_session *session) { + return session->remote_window_size; +} + +uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session, + nghttp2_settings_id id) { + switch (id) { + case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: + return session->remote_settings.header_table_size; + case NGHTTP2_SETTINGS_ENABLE_PUSH: + return session->remote_settings.enable_push; + case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: + return session->remote_settings.max_concurrent_streams; + case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: + return session->remote_settings.initial_window_size; + case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: + return session->remote_settings.max_frame_size; + case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: + return session->remote_settings.max_header_list_size; + } + + assert(0); + abort(); /* if NDEBUG is set */ +} + +uint32_t nghttp2_session_get_local_settings(nghttp2_session *session, + nghttp2_settings_id id) { + switch (id) { + case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: + return session->local_settings.header_table_size; + case NGHTTP2_SETTINGS_ENABLE_PUSH: + return session->local_settings.enable_push; + case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: + return session->local_settings.max_concurrent_streams; + case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: + return session->local_settings.initial_window_size; + case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: + return session->local_settings.max_frame_size; + case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: + return session->local_settings.max_header_list_size; + } + + assert(0); + abort(); /* if NDEBUG is set */ +} + +static int nghttp2_session_upgrade_internal(nghttp2_session *session, + const uint8_t *settings_payload, + size_t settings_payloadlen, + void *stream_user_data) { + nghttp2_stream *stream; + nghttp2_frame frame; + nghttp2_settings_entry *iv; + size_t niv; + int rv; + nghttp2_priority_spec pri_spec; + nghttp2_mem *mem; + + mem = &session->mem; + + if ((!session->server && session->next_stream_id != 1) || + (session->server && session->last_recv_stream_id >= 1)) { + return NGHTTP2_ERR_PROTO; + } + if (settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + rv = nghttp2_frame_unpack_settings_payload2(&iv, &niv, settings_payload, + settings_payloadlen, mem); + if (rv != 0) { + return rv; + } + + if (session->server) { + nghttp2_frame_hd_init(&frame.hd, settings_payloadlen, NGHTTP2_SETTINGS, + NGHTTP2_FLAG_NONE, 0); + frame.settings.iv = iv; + frame.settings.niv = niv; + rv = nghttp2_session_on_settings_received(session, &frame, 1 /* No ACK */); + } else { + rv = nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, niv); + } + nghttp2_mem_free(mem, iv); + if (rv != 0) { + return rv; + } + + nghttp2_priority_spec_default_init(&pri_spec); + + stream = nghttp2_session_open_stream( + session, 1, NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_OPENING, + session->server ? NULL : stream_user_data); + if (stream == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + /* We don't call nghttp2_session_adjust_closed_stream(), since this + should be the first stream open. */ + + if (session->server) { + nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); + session->last_recv_stream_id = 1; + session->last_proc_stream_id = 1; + } else { + nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); + session->last_sent_stream_id = 1; + session->next_stream_id += 2; + } + return 0; +} + +int nghttp2_session_upgrade(nghttp2_session *session, + const uint8_t *settings_payload, + size_t settings_payloadlen, + void *stream_user_data) { + int rv; + nghttp2_stream *stream; + + rv = nghttp2_session_upgrade_internal(session, settings_payload, + settings_payloadlen, stream_user_data); + if (rv != 0) { + return rv; + } + + stream = nghttp2_session_get_stream(session, 1); + assert(stream); + + /* We have no information about request header fields when Upgrade + was happened. So we don't know the request method here. If + request method is HEAD, we have a trouble because we may have + nonzero content-length header field in response headers, and we + will going to check it against the actual DATA frames, but we may + get mismatch because HEAD response body must be empty. Because + of this reason, nghttp2_session_upgrade() was deprecated in favor + of nghttp2_session_upgrade2(), which has |head_request| parameter + to indicate that request method is HEAD or not. */ + stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND; + return 0; +} + +int nghttp2_session_upgrade2(nghttp2_session *session, + const uint8_t *settings_payload, + size_t settings_payloadlen, int head_request, + void *stream_user_data) { + int rv; + nghttp2_stream *stream; + + rv = nghttp2_session_upgrade_internal(session, settings_payload, + settings_payloadlen, stream_user_data); + if (rv != 0) { + return rv; + } + + stream = nghttp2_session_get_stream(session, 1); + assert(stream); + + if (head_request) { + stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD; + } + + return 0; +} + +int nghttp2_session_get_stream_local_close(nghttp2_session *session, + int32_t stream_id) { + nghttp2_stream *stream; + + stream = nghttp2_session_get_stream(session, stream_id); + + if (!stream) { + return -1; + } + + return (stream->shut_flags & NGHTTP2_SHUT_WR) != 0; +} + +int nghttp2_session_get_stream_remote_close(nghttp2_session *session, + int32_t stream_id) { + nghttp2_stream *stream; + + stream = nghttp2_session_get_stream(session, stream_id); + + if (!stream) { + return -1; + } + + return (stream->shut_flags & NGHTTP2_SHUT_RD) != 0; +} + +int nghttp2_session_consume(nghttp2_session *session, int32_t stream_id, + size_t size) { + int rv; + nghttp2_stream *stream; + + if (stream_id == 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + if (!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) { + return NGHTTP2_ERR_INVALID_STATE; + } + + rv = session_update_connection_consumed_size(session, size); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + stream = nghttp2_session_get_stream(session, stream_id); + + if (!stream) { + return 0; + } + + rv = session_update_stream_consumed_size(session, stream, size); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + return 0; +} + +int nghttp2_session_consume_connection(nghttp2_session *session, size_t size) { + int rv; + + if (!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) { + return NGHTTP2_ERR_INVALID_STATE; + } + + rv = session_update_connection_consumed_size(session, size); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + return 0; +} + +int nghttp2_session_consume_stream(nghttp2_session *session, int32_t stream_id, + size_t size) { + int rv; + nghttp2_stream *stream; + + if (stream_id == 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + if (!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) { + return NGHTTP2_ERR_INVALID_STATE; + } + + stream = nghttp2_session_get_stream(session, stream_id); + + if (!stream) { + return 0; + } + + rv = session_update_stream_consumed_size(session, stream, size); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + return 0; +} + +int nghttp2_session_set_next_stream_id(nghttp2_session *session, + int32_t next_stream_id) { + if (next_stream_id <= 0 || + session->next_stream_id > (uint32_t)next_stream_id) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + if (session->server) { + if (next_stream_id % 2) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + } else if (next_stream_id % 2 == 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + session->next_stream_id = (uint32_t)next_stream_id; + return 0; +} + +uint32_t nghttp2_session_get_next_stream_id(nghttp2_session *session) { + return session->next_stream_id; +} + +int32_t nghttp2_session_get_last_proc_stream_id(nghttp2_session *session) { + return session->last_proc_stream_id; +} + +nghttp2_stream *nghttp2_session_find_stream(nghttp2_session *session, + int32_t stream_id) { + if (stream_id == 0) { + return &session->root; + } + + return nghttp2_session_get_stream_raw(session, stream_id); +} + +nghttp2_stream *nghttp2_session_get_root_stream(nghttp2_session *session) { + return &session->root; +} + +int nghttp2_session_check_server_session(nghttp2_session *session) { + return session->server; +} + +int nghttp2_session_change_stream_priority( + nghttp2_session *session, int32_t stream_id, + const nghttp2_priority_spec *pri_spec) { + int rv; + nghttp2_stream *stream; + nghttp2_priority_spec pri_spec_copy; + + if (stream_id == 0 || stream_id == pri_spec->stream_id) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + stream = nghttp2_session_get_stream_raw(session, stream_id); + if (!stream) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + pri_spec_copy = *pri_spec; + nghttp2_priority_spec_normalize_weight(&pri_spec_copy); + + rv = nghttp2_session_reprioritize_stream(session, stream, &pri_spec_copy); + + if (nghttp2_is_fatal(rv)) { + return rv; + } + + /* We don't intentionally call nghttp2_session_adjust_idle_stream() + so that idle stream created by this function, and existing ones + are kept for application. We will adjust number of idle stream + in nghttp2_session_mem_send or nghttp2_session_mem_recv is + called. */ + return 0; +} + +int nghttp2_session_create_idle_stream(nghttp2_session *session, + int32_t stream_id, + const nghttp2_priority_spec *pri_spec) { + nghttp2_stream *stream; + nghttp2_priority_spec pri_spec_copy; + + if (stream_id == 0 || stream_id == pri_spec->stream_id || + !session_detect_idle_stream(session, stream_id)) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + stream = nghttp2_session_get_stream_raw(session, stream_id); + if (stream) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + pri_spec_copy = *pri_spec; + nghttp2_priority_spec_normalize_weight(&pri_spec_copy); + + stream = + nghttp2_session_open_stream(session, stream_id, NGHTTP2_STREAM_FLAG_NONE, + &pri_spec_copy, NGHTTP2_STREAM_IDLE, NULL); + if (!stream) { + return NGHTTP2_ERR_NOMEM; + } + + /* We don't intentionally call nghttp2_session_adjust_idle_stream() + so that idle stream created by this function, and existing ones + are kept for application. We will adjust number of idle stream + in nghttp2_session_mem_send or nghttp2_session_mem_recv is + called. */ + return 0; +} + +size_t +nghttp2_session_get_hd_inflate_dynamic_table_size(nghttp2_session *session) { + return nghttp2_hd_inflate_get_dynamic_table_size(&session->hd_inflater); +} + +size_t +nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session) { + return nghttp2_hd_deflate_get_dynamic_table_size(&session->hd_deflater); +} + +void nghttp2_session_set_user_data(nghttp2_session *session, void *user_data) { + session->user_data = user_data; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_session.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_session.h new file mode 100644 index 00000000..c67781f8 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_session.h @@ -0,0 +1,860 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_SESSION_H +#define NGHTTP2_SESSION_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" +#include "nghttp2_map.h" +#include "nghttp2_frame.h" +#include "nghttp2_hd.h" +#include "nghttp2_stream.h" +#include "nghttp2_outbound_item.h" +#include "nghttp2_int.h" +#include "nghttp2_buf.h" +#include "nghttp2_callbacks.h" +#include "nghttp2_mem.h" + +/* The global variable for tests where we want to disable strict + preface handling. */ +extern int nghttp2_enable_strict_preface; + +/* + * Option flags. + */ +typedef enum { + NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0, + NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1, + NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2, + NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3, + NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4 +} nghttp2_optmask; + +/* + * bitmask for built-in type to enable the default handling for that + * type of the frame. + */ +typedef enum { + NGHTTP2_TYPEMASK_NONE = 0, + NGHTTP2_TYPEMASK_ALTSVC = 1 << 0 +} nghttp2_typemask; + +typedef enum { + NGHTTP2_OB_POP_ITEM, + NGHTTP2_OB_SEND_DATA, + NGHTTP2_OB_SEND_NO_COPY, + NGHTTP2_OB_SEND_CLIENT_MAGIC +} nghttp2_outbound_state; + +typedef struct { + nghttp2_outbound_item *item; + nghttp2_bufs framebufs; + nghttp2_outbound_state state; +} nghttp2_active_outbound_item; + +/* Buffer length for inbound raw byte stream used in + nghttp2_session_recv(). */ +#define NGHTTP2_INBOUND_BUFFER_LENGTH HTTP2_RECV_BUFFER_LENGHT + +/* The default maximum number of incoming reserved streams */ +#define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200 + +/* Even if we have less SETTINGS_MAX_CONCURRENT_STREAMS than this + number, we keep NGHTTP2_MIN_IDLE_STREAMS streams in idle state */ +#define NGHTTP2_MIN_IDLE_STREAMS 16 + +/* The maximum number of items in outbound queue, which is considered + as flooding caused by peer. All frames are not considered here. + We only consider PING + ACK and SETTINGS + ACK. This is because + they both are response to the frame initiated by peer and peer can + send as many of them as they want. If peer does not read network, + response frames are stacked up, which leads to memory exhaustion. + The value selected here is arbitrary, but safe value and if we have + these frames in this number, it is considered suspicious. */ +#define NGHTTP2_MAX_OBQ_FLOOD_ITEM 10000 + +/* The default value of maximum number of concurrent streams. */ +#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu + +/* Internal state when receiving incoming frame */ +typedef enum { + /* Receiving frame header */ + NGHTTP2_IB_READ_CLIENT_MAGIC, + NGHTTP2_IB_READ_FIRST_SETTINGS, + NGHTTP2_IB_READ_HEAD, + NGHTTP2_IB_READ_NBYTE, + NGHTTP2_IB_READ_HEADER_BLOCK, + NGHTTP2_IB_IGN_HEADER_BLOCK, + NGHTTP2_IB_IGN_PAYLOAD, + NGHTTP2_IB_FRAME_SIZE_ERROR, + NGHTTP2_IB_READ_SETTINGS, + NGHTTP2_IB_READ_GOAWAY_DEBUG, + NGHTTP2_IB_EXPECT_CONTINUATION, + NGHTTP2_IB_IGN_CONTINUATION, + NGHTTP2_IB_READ_PAD_DATA, + NGHTTP2_IB_READ_DATA, + NGHTTP2_IB_IGN_DATA, + NGHTTP2_IB_IGN_ALL, + NGHTTP2_IB_READ_ALTSVC_PAYLOAD, + NGHTTP2_IB_READ_EXTENSION_PAYLOAD +} nghttp2_inbound_state; + +typedef struct { + nghttp2_frame frame; + /* Storage for extension frame payload. frame->ext.payload points + to this structure to avoid frequent memory allocation. */ + nghttp2_ext_frame_payload ext_frame_payload; + /* The received SETTINGS entry. For the standard settings entries, + we only keep the last seen value. For + SETTINGS_HEADER_TABLE_SIZE, we also keep minimum value in the + last index. */ + nghttp2_settings_entry *iv; + /* buffer pointers to small buffer, raw_sbuf */ + nghttp2_buf sbuf; + /* buffer pointers to large buffer, raw_lbuf */ + nghttp2_buf lbuf; + /* Large buffer, malloced on demand */ + uint8_t *raw_lbuf; + /* The number of entry filled in |iv| */ + size_t niv; + /* The number of entries |iv| can store. */ + size_t max_niv; + /* How many bytes we still need to receive for current frame */ + size_t payloadleft; + /* padding length for the current frame */ + size_t padlen; + nghttp2_inbound_state state; + /* Small buffer. Currently the largest contiguous chunk to buffer + is frame header. We buffer part of payload, but they are smaller + than frame header. */ + uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN]; +} nghttp2_inbound_frame; + +typedef struct { + uint32_t header_table_size; + uint32_t enable_push; + uint32_t max_concurrent_streams; + uint32_t initial_window_size; + uint32_t max_frame_size; + uint32_t max_header_list_size; +} nghttp2_settings_storage; + +typedef enum { + NGHTTP2_GOAWAY_NONE = 0, + /* Flag means that connection should be terminated after sending GOAWAY. */ + NGHTTP2_GOAWAY_TERM_ON_SEND = 0x1, + /* Flag means GOAWAY to terminate session has been sent */ + NGHTTP2_GOAWAY_TERM_SENT = 0x2, + /* Flag means GOAWAY was sent */ + NGHTTP2_GOAWAY_SENT = 0x4, + /* Flag means GOAWAY was received */ + NGHTTP2_GOAWAY_RECV = 0x8 +} nghttp2_goaway_flag; + +/* nghttp2_inflight_settings stores the SETTINGS entries which local + endpoint has sent to the remote endpoint, and has not received ACK + yet. */ +struct nghttp2_inflight_settings { + struct nghttp2_inflight_settings *next; + nghttp2_settings_entry *iv; + size_t niv; +}; + +typedef struct nghttp2_inflight_settings nghttp2_inflight_settings; + +struct nghttp2_session { + nghttp2_map /* */ streams; + /* root of dependency tree*/ + nghttp2_stream root; + /* Queue for outbound urgent frames (PING and SETTINGS) */ + nghttp2_outbound_queue ob_urgent; + /* Queue for non-DATA frames */ + nghttp2_outbound_queue ob_reg; + /* Queue for outbound stream-creating HEADERS (request or push + response) frame, which are subject to + SETTINGS_MAX_CONCURRENT_STREAMS limit. */ + nghttp2_outbound_queue ob_syn; + nghttp2_active_outbound_item aob; + nghttp2_inbound_frame iframe; + nghttp2_hd_deflater hd_deflater; + nghttp2_hd_inflater hd_inflater; + nghttp2_session_callbacks callbacks; + /* Memory allocator */ + nghttp2_mem mem; + /* Base value when we schedule next DATA frame write. This is + updated when one frame was written. */ + uint64_t last_cycle; + void *user_data; + /* Points to the latest incoming closed stream. NULL if there is no + closed stream. Only used when session is initialized as + server. */ + nghttp2_stream *closed_stream_head; + /* Points to the oldest incoming closed stream. NULL if there is no + closed stream. Only used when session is initialized as + server. */ + nghttp2_stream *closed_stream_tail; + /* Points to the latest idle stream. NULL if there is no idle + stream. Only used when session is initialized as server .*/ + nghttp2_stream *idle_stream_head; + /* Points to the oldest idle stream. NULL if there is no idle + stream. Only used when session is initialized as erver. */ + nghttp2_stream *idle_stream_tail; + /* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not + considered as in-flight. */ + nghttp2_inflight_settings *inflight_settings_head; + /* The number of outgoing streams. This will be capped by + remote_settings.max_concurrent_streams. */ + size_t num_outgoing_streams; + /* The number of incoming streams. This will be capped by + local_settings.max_concurrent_streams. */ + size_t num_incoming_streams; + /* The number of incoming reserved streams. This is the number of + streams in reserved (remote) state. RFC 7540 does not limit this + number. nghttp2 offers + nghttp2_option_set_max_reserved_remote_streams() to achieve this. + If it is used, num_incoming_streams is capped by + max_incoming_reserved_streams. Client application should + consider to set this because without that server can send + arbitrary number of PUSH_PROMISE, and exhaust client's memory. */ + size_t num_incoming_reserved_streams; + /* The maximum number of incoming reserved streams (reserved + (remote) state). RST_STREAM will be sent for the pushed stream + which exceeds this limit. */ + size_t max_incoming_reserved_streams; + /* The number of closed streams still kept in |streams| hash. The + closed streams can be accessed through single linked list + |closed_stream_head|. The current implementation only keeps + incoming streams and session is initialized as server. */ + size_t num_closed_streams; + /* The number of idle streams kept in |streams| hash. The idle + streams can be accessed through doubly linked list + |idle_stream_head|. The current implementation only keeps idle + streams if session is initialized as server. */ + size_t num_idle_streams; + /* The number of bytes allocated for nvbuf */ + size_t nvbuflen; + /* Counter for detecting flooding in outbound queue */ + size_t obq_flood_counter_; + /* The maximum length of header block to send. Calculated by the + same way as nghttp2_hd_deflate_bound() does. */ + size_t max_send_header_block_length; + /* Next Stream ID. Made unsigned int to detect >= (1 << 31). */ + uint32_t next_stream_id; + /* The last stream ID this session initiated. For client session, + this is the last stream ID it has sent. For server session, it + is the last promised stream ID sent in PUSH_PROMISE. */ + int32_t last_sent_stream_id; + /* The largest stream ID received so far */ + int32_t last_recv_stream_id; + /* The largest stream ID which has been processed in some way. This + value will be used as last-stream-id when sending GOAWAY + frame. */ + int32_t last_proc_stream_id; + /* Counter of unique ID of PING. Wraps when it exceeds + NGHTTP2_MAX_UNIQUE_ID */ + uint32_t next_unique_id; + /* This is the last-stream-ID we have sent in GOAWAY */ + int32_t local_last_stream_id; + /* This is the value in GOAWAY frame received from remote endpoint. */ + int32_t remote_last_stream_id; + /* Current sender window size. This value is computed against the + current initial window size of remote endpoint. */ + int32_t remote_window_size; + /* Keep track of the number of bytes received without + WINDOW_UPDATE. This could be negative after submitting negative + value to WINDOW_UPDATE. */ + int32_t recv_window_size; + /* The number of bytes consumed by the application and now is + subject to WINDOW_UPDATE. This is only used when auto + WINDOW_UPDATE is turned off. */ + int32_t consumed_size; + /* The amount of recv_window_size cut using submitting negative + value to WINDOW_UPDATE */ + int32_t recv_reduction; + /* window size for local flow control. It is initially set to + NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE and could be + increased/decreased by submitting WINDOW_UPDATE. See + nghttp2_submit_window_update(). */ + int32_t local_window_size; + /* Settings value received from the remote endpoint. We just use ID + as index. The index = 0 is unused. */ + nghttp2_settings_storage remote_settings; + /* Settings value of the local endpoint. */ + nghttp2_settings_storage local_settings; + /* Option flags. This is bitwise-OR of 0 or more of nghttp2_optmask. */ + uint32_t opt_flags; + /* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this + to refuse the incoming stream if it exceeds this value. */ + uint32_t pending_local_max_concurrent_stream; + /* The bitwise OR of zero or more of nghttp2_typemask to indicate + that the default handling of extension frame is enabled. */ + uint32_t builtin_recv_ext_types; + /* Unacked local ENABLE_PUSH value. We use this to refuse + PUSH_PROMISE before SETTINGS ACK is received. */ + uint8_t pending_enable_push; + /* Nonzero if the session is server side. */ + uint8_t server; + /* Flags indicating GOAWAY is sent and/or received. The flags are + composed by bitwise OR-ing nghttp2_goaway_flag. */ + uint8_t goaway_flags; + /* This flag is used to reduce excessive queuing of WINDOW_UPDATE to + this session. The nonzero does not necessarily mean + WINDOW_UPDATE is not queued. */ + uint8_t window_update_queued; + /* Bitfield of extension frame types that application is willing to + receive. To designate the bit of given frame type i, use + user_recv_ext_types[i / 8] & (1 << (i & 0x7)). First 10 frame + types are standard frame types and not used in this bitfield. If + bit is set, it indicates that incoming frame with that type is + passed to user defined callbacks, otherwise they are ignored. */ + uint8_t user_recv_ext_types[32]; +}; + +/* Struct used when updating initial window size of each active + stream. */ +typedef struct { + nghttp2_session *session; + int32_t new_window_size, old_window_size; +} nghttp2_update_window_size_arg; + +typedef struct { + nghttp2_session *session; + /* linked list of streams to close */ + nghttp2_stream *head; + int32_t last_stream_id; + /* nonzero if GOAWAY is sent to peer, which means we are going to + close incoming streams. zero if GOAWAY is received from peer and + we are going to close outgoing streams. */ + int incoming; +} nghttp2_close_stream_on_goaway_arg; + +/* TODO stream timeout etc */ + +/* + * Returns nonzero value if |stream_id| is initiated by local + * endpoint. + */ +int nghttp2_session_is_my_stream_id(nghttp2_session *session, + int32_t stream_id); + +/* + * Adds |item| to the outbound queue in |session|. When this function + * succeeds, it takes ownership of |item|. So caller must not free it + * on success. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_STREAM_CLOSED + * Stream already closed (DATA and PUSH_PROMISE frame only) + */ +int nghttp2_session_add_item(nghttp2_session *session, + nghttp2_outbound_item *item); + +/* + * Adds RST_STREAM frame for the stream |stream_id| with the error + * code |error_code|. This is a convenient function built on top of + * nghttp2_session_add_frame() to add RST_STREAM easily. + * + * This function simply returns 0 without adding RST_STREAM frame if + * given stream is in NGHTTP2_STREAM_CLOSING state, because multiple + * RST_STREAM for a stream is redundant. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id, + uint32_t error_code); + +/* + * Adds PING frame. This is a convenient functin built on top of + * nghttp2_session_add_frame() to add PING easily. + * + * If the |opaque_data| is not NULL, it must point to 8 bytes memory + * region of data. The data pointed by |opaque_data| is copied. It can + * be NULL. In this case, 8 bytes NULL is used. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_FLOODED + * There are too many items in outbound queue; this only happens + * if NGHTTP2_FLAG_ACK is set in |flags| + */ +int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags, + const uint8_t *opaque_data); + +/* + * Adds GOAWAY frame with the last-stream-ID |last_stream_id| and the + * error code |error_code|. This is a convenient function built on top + * of nghttp2_session_add_frame() to add GOAWAY easily. The + * |aux_flags| are bitwise-OR of one or more of + * nghttp2_goaway_aux_flag. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_INVALID_ARGUMENT + * The |opaque_data_len| is too large. + */ +int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id, + uint32_t error_code, const uint8_t *opaque_data, + size_t opaque_data_len, uint8_t aux_flags); + +/* + * Adds WINDOW_UPDATE frame with stream ID |stream_id| and + * window-size-increment |window_size_increment|. This is a convenient + * function built on top of nghttp2_session_add_frame() to add + * WINDOW_UPDATE easily. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_session_add_window_update(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + int32_t window_size_increment); + +/* + * Adds SETTINGS frame. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_FLOODED + * There are too many items in outbound queue; this only happens + * if NGHTTP2_FLAG_ACK is set in |flags| + */ +int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags, + const nghttp2_settings_entry *iv, size_t niv); + +/* + * Creates new stream in |session| with stream ID |stream_id|, + * priority |pri_spec| and flags |flags|. The |flags| is bitwise OR + * of nghttp2_stream_flag. Since this function is called when initial + * HEADERS is sent or received, these flags are taken from it. The + * state of stream is set to |initial_state|. The |stream_user_data| + * is a pointer to the arbitrary user supplied data to be associated + * to this stream. + * + * If |initial_state| is NGHTTP2_STREAM_RESERVED, this function sets + * NGHTTP2_STREAM_FLAG_PUSH flag set. + * + * This function returns a pointer to created new stream object, or + * NULL. + * + * This function adjusts neither the number of closed streams or idle + * streams. The caller should manually call + * nghttp2_session_adjust_closed_stream() or + * nghttp2_session_adjust_idle_stream() respectively. + */ +nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, + int32_t stream_id, uint8_t flags, + nghttp2_priority_spec *pri_spec, + nghttp2_stream_state initial_state, + void *stream_user_data); + +/* + * Closes stream whose stream ID is |stream_id|. The reason of closure + * is indicated by the |error_code|. When closing the stream, + * on_stream_close_callback will be called. + * + * If the session is initialized as server and |stream| is incoming + * stream, stream is just marked closed and this function calls + * nghttp2_session_keep_closed_stream() with |stream|. Otherwise, + * |stream| will be deleted from memory. + * + * This function returns 0 if it succeeds, or one the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + * NGHTTP2_ERR_INVALID_ARGUMENT + * The specified stream does not exist. + * NGHTTP2_ERR_CALLBACK_FAILURE + * The callback function failed. + */ +int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, + uint32_t error_code); + +/* + * Deletes |stream| from memory. After this function returns, stream + * cannot be accessed. + * + * This function returns 0 if it succeeds, or one the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_session_destroy_stream(nghttp2_session *session, + nghttp2_stream *stream); + +/* + * Tries to keep incoming closed stream |stream|. Due to the + * limitation of maximum number of streams in memory, |stream| is not + * closed and just deleted from memory (see + * nghttp2_session_destroy_stream). + */ +void nghttp2_session_keep_closed_stream(nghttp2_session *session, + nghttp2_stream *stream); + +/* + * Appends |stream| to linked list |session->idle_stream_head|. We + * apply fixed limit for list size. To fit into that limit, one or + * more oldest streams are removed from list as necessary. + */ +void nghttp2_session_keep_idle_stream(nghttp2_session *session, + nghttp2_stream *stream); + +/* + * Detaches |stream| from idle streams linked list. + */ +void nghttp2_session_detach_idle_stream(nghttp2_session *session, + nghttp2_stream *stream); + +/* + * Deletes closed stream to ensure that number of incoming streams + * including active and closed is in the maximum number of allowed + * stream. + * + * This function returns 0 if it succeeds, or one the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_session_adjust_closed_stream(nghttp2_session *session); + +/* + * Deletes idle stream to ensure that number of idle streams is in + * certain limit. + * + * This function returns 0 if it succeeds, or one the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_session_adjust_idle_stream(nghttp2_session *session); + +/* + * If further receptions and transmissions over the stream |stream_id| + * are disallowed, close the stream with error code NGHTTP2_NO_ERROR. + * + * This function returns 0 if it + * succeeds, or one of the following negative error codes: + * + * NGHTTP2_ERR_INVALID_ARGUMENT + * The specified stream does not exist. + */ +int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session, + nghttp2_stream *stream); + +int nghttp2_session_on_request_headers_received(nghttp2_session *session, + nghttp2_frame *frame); + +int nghttp2_session_on_response_headers_received(nghttp2_session *session, + nghttp2_frame *frame, + nghttp2_stream *stream); + +int nghttp2_session_on_push_response_headers_received(nghttp2_session *session, + nghttp2_frame *frame, + nghttp2_stream *stream); + +/* + * Called when HEADERS is received, assuming |frame| is properly + * initialized. This function does first validate received frame and + * then open stream and call callback functions. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_IGN_HEADER_BLOCK + * Frame was rejected and header block must be decoded but + * result must be ignored. + * NGHTTP2_ERR_CALLBACK_FAILURE + * The read_callback failed + */ +int nghttp2_session_on_headers_received(nghttp2_session *session, + nghttp2_frame *frame, + nghttp2_stream *stream); + +/* + * Called when PRIORITY is received, assuming |frame| is properly + * initialized. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_CALLBACK_FAILURE + * The read_callback failed + */ +int nghttp2_session_on_priority_received(nghttp2_session *session, + nghttp2_frame *frame); + +/* + * Called when RST_STREAM is received, assuming |frame| is properly + * initialized. + * + * This function returns 0 if it succeeds, or one the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + * NGHTTP2_ERR_CALLBACK_FAILURE + * The read_callback failed + */ +int nghttp2_session_on_rst_stream_received(nghttp2_session *session, + nghttp2_frame *frame); + +/* + * Called when SETTINGS is received, assuming |frame| is properly + * initialized. If |noack| is non-zero, SETTINGS with ACK will not be + * submitted. If |frame| has NGHTTP2_FLAG_ACK flag set, no SETTINGS + * with ACK will not be submitted regardless of |noack|. + * + * This function returns 0 if it succeeds, or one the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + * NGHTTP2_ERR_CALLBACK_FAILURE + * The read_callback failed + * NGHTTP2_ERR_FLOODED + * There are too many items in outbound queue, and this is most + * likely caused by misbehaviour of peer. + */ +int nghttp2_session_on_settings_received(nghttp2_session *session, + nghttp2_frame *frame, int noack); + +/* + * Called when PUSH_PROMISE is received, assuming |frame| is properly + * initialized. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_IGN_HEADER_BLOCK + * Frame was rejected and header block must be decoded but + * result must be ignored. + * NGHTTP2_ERR_CALLBACK_FAILURE + * The read_callback failed + */ +int nghttp2_session_on_push_promise_received(nghttp2_session *session, + nghttp2_frame *frame); + +/* + * Called when PING is received, assuming |frame| is properly + * initialized. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_CALLBACK_FAILURE + * The callback function failed. + * NGHTTP2_ERR_FLOODED + * There are too many items in outbound queue, and this is most + * likely caused by misbehaviour of peer. + */ +int nghttp2_session_on_ping_received(nghttp2_session *session, + nghttp2_frame *frame); + +/* + * Called when GOAWAY is received, assuming |frame| is properly + * initialized. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_CALLBACK_FAILURE + * The callback function failed. + */ +int nghttp2_session_on_goaway_received(nghttp2_session *session, + nghttp2_frame *frame); + +/* + * Called when WINDOW_UPDATE is received, assuming |frame| is properly + * initialized. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_CALLBACK_FAILURE + * The callback function failed. + */ +int nghttp2_session_on_window_update_received(nghttp2_session *session, + nghttp2_frame *frame); + +/* + * Called when ALTSVC is received, assuming |frame| is properly + * initialized. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_CALLBACK_FAILURE + * The callback function failed. + */ +int nghttp2_session_on_altsvc_received(nghttp2_session *session, + nghttp2_frame *frame); + +/* + * Called when DATA is received, assuming |frame| is properly + * initialized. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_CALLBACK_FAILURE + * The callback function failed. + */ +int nghttp2_session_on_data_received(nghttp2_session *session, + nghttp2_frame *frame); + +/* + * Returns nghttp2_stream* object whose stream ID is |stream_id|. It + * could be NULL if such stream does not exist. This function returns + * NULL if stream is marked as closed. + */ +nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session, + int32_t stream_id); + +/* + * This function behaves like nghttp2_session_get_stream(), but it + * returns stream object even if it is marked as closed or in + * NGHTTP2_STREAM_IDLE state. + */ +nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session, + int32_t stream_id); + +/* + * Packs DATA frame |frame| in wire frame format and stores it in + * |bufs|. Payload will be read using |aux_data->data_prd|. The + * length of payload is at most |datamax| bytes. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_DEFERRED + * The DATA frame is postponed. + * NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE + * The read_callback failed (stream error). + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_CALLBACK_FAILURE + * The read_callback failed (session error). + */ +int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs, + size_t datamax, nghttp2_frame *frame, + nghttp2_data_aux_data *aux_data, + nghttp2_stream *stream); + +/* + * Pops and returns next item to send. If there is no such item, + * returns NULL. This function takes into account max concurrent + * streams. That means if session->ob_syn has item and max concurrent + * streams is reached, the even if other queues contain items, then + * this function returns NULL. + */ +nghttp2_outbound_item * +nghttp2_session_pop_next_ob_item(nghttp2_session *session); + +/* + * Returns next item to send. If there is no such item, this function + * returns NULL. This function takes into account max concurrent + * streams. That means if session->ob_syn has item and max concurrent + * streams is reached, the even if other queues contain items, then + * this function returns NULL. + */ +nghttp2_outbound_item * +nghttp2_session_get_next_ob_item(nghttp2_session *session); + +/* + * Updates local settings with the |iv|. The number of elements in the + * array pointed by the |iv| is given by the |niv|. This function + * assumes that the all settings_id member in |iv| are in range 1 to + * NGHTTP2_SETTINGS_MAX, inclusive. + * + * While updating individual stream's local window size, if the window + * size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE, + * RST_STREAM is issued against such a stream. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_session_update_local_settings(nghttp2_session *session, + nghttp2_settings_entry *iv, + size_t niv); + +/* + * Re-prioritize |stream|. The new priority specification is + * |pri_spec|. Caller must ensure that stream->hd.stream_id != + * pri_spec->stream_id. + * + * This function does not adjust the number of idle streams. The + * caller should call nghttp2_session_adjust_idle_stream() later. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_session_reprioritize_stream(nghttp2_session *session, + nghttp2_stream *stream, + const nghttp2_priority_spec *pri_spec); + +/* + * Terminates current |session| with the |error_code|. The |reason| + * is NULL-terminated debug string. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_INVALID_ARGUMENT + * The |reason| is too long. + */ +int nghttp2_session_terminate_session_with_reason(nghttp2_session *session, + uint32_t error_code, + const char *reason); + +#endif /* NGHTTP2_SESSION_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_stream.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_stream.c new file mode 100644 index 00000000..e3d2b1e4 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_stream.c @@ -0,0 +1,985 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_stream.h" + +#include +#include + +#include "nghttp2_session.h" +#include "nghttp2_helper.h" +#include "nghttp2_debug.h" + +/* Maximum distance between any two stream's cycle in the same + prirority queue. Imagine stream A's cycle is A, and stream B's + cycle is B, and A < B. The cycle is unsigned 32 bit integer, it + may get overflow. Because of how we calculate the next cycle + value, if B - A is less than or equals to + NGHTTP2_MAX_CYCLE_DISTANCE, A and B are in the same scale, in other + words, B is really greater than or equal to A. Otherwise, A is a + result of overflow, and it is actually A > B if we consider that + fact. */ +#define NGHTTP2_MAX_CYCLE_DISTANCE (16384 * 256 + 255) + +static int stream_less(const void *lhsx, const void *rhsx) { + const nghttp2_stream *lhs, *rhs; + + lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry); + rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry); + + if (lhs->cycle == rhs->cycle) { + return lhs->seq < rhs->seq; + } + + if (lhs->cycle < rhs->cycle) { + return rhs->cycle - lhs->cycle <= NGHTTP2_MAX_CYCLE_DISTANCE; + } + + return lhs->cycle - rhs->cycle > NGHTTP2_MAX_CYCLE_DISTANCE; +} + +void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, + uint8_t flags, nghttp2_stream_state initial_state, + int32_t weight, int32_t remote_initial_window_size, + int32_t local_initial_window_size, + void *stream_user_data, nghttp2_mem *mem) { + nghttp2_map_entry_init(&stream->map_entry, (key_type)stream_id); + nghttp2_pq_init(&stream->obq, stream_less, mem); + + stream->stream_id = stream_id; + stream->flags = flags; + stream->state = initial_state; + stream->shut_flags = NGHTTP2_SHUT_NONE; + stream->stream_user_data = stream_user_data; + stream->item = NULL; + stream->remote_window_size = remote_initial_window_size; + stream->local_window_size = local_initial_window_size; + stream->recv_window_size = 0; + stream->consumed_size = 0; + stream->recv_reduction = 0; + stream->window_update_queued = 0; + + stream->dep_prev = NULL; + stream->dep_next = NULL; + stream->sib_prev = NULL; + stream->sib_next = NULL; + + stream->closed_prev = NULL; + stream->closed_next = NULL; + + stream->weight = weight; + stream->sum_dep_weight = 0; + + stream->http_flags = NGHTTP2_HTTP_FLAG_NONE; + stream->content_length = -1; + stream->recv_content_length = 0; + stream->status_code = -1; + + stream->queued = 0; + stream->descendant_last_cycle = 0; + stream->cycle = 0; + stream->pending_penalty = 0; + stream->descendant_next_seq = 0; + stream->seq = 0; + stream->last_writelen = 0; +} + +void nghttp2_stream_free(nghttp2_stream *stream) { + nghttp2_pq_free(&stream->obq); + /* We don't free stream->item. If it is assigned to aob, then + active_outbound_item_reset() will delete it. Otherwise, + nghttp2_stream_close() or session_del() will delete it. */ +} + +void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) { + stream->shut_flags = (uint8_t)(stream->shut_flags | flag); +} + +/* + * Returns nonzero if |stream| is active. This function does not take + * into account its descendants. + */ +static int stream_active(nghttp2_stream *stream) { + return stream->item && + (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0; +} + +/* + * Returns nonzero if |stream| or one of its descendants is active + */ +static int stream_subtree_active(nghttp2_stream *stream) { + return stream_active(stream) || !nghttp2_pq_empty(&stream->obq); +} + +/* + * Returns next cycle for |stream|. + */ +static void stream_next_cycle(nghttp2_stream *stream, uint32_t last_cycle) { + uint32_t penalty; + + penalty = (uint32_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT + + stream->pending_penalty; + + stream->cycle = last_cycle + penalty / (uint32_t)stream->weight; + stream->pending_penalty = penalty % (uint32_t)stream->weight; +} + +static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) { + int rv; + + for (; dep_stream && !stream->queued; + stream = dep_stream, dep_stream = dep_stream->dep_prev) { + stream_next_cycle(stream, dep_stream->descendant_last_cycle); + stream->seq = dep_stream->descendant_next_seq++; + + DEBUGF("stream: stream=%d obq push cycle=%d\n", stream->stream_id, + stream->cycle); + + DEBUGF("stream: push stream %d to stream %d\n", stream->stream_id, + dep_stream->stream_id); + + rv = nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); + if (rv != 0) { + return rv; + } + stream->queued = 1; + } + + return 0; +} + +/* + * Removes |stream| from parent's obq. If removal of |stream| makes + * parent's obq empty, and parent is not active, then parent is also + * removed. This process is repeated recursively. + */ +static void stream_obq_remove(nghttp2_stream *stream) { + nghttp2_stream *dep_stream; + + dep_stream = stream->dep_prev; + + if (!stream->queued) { + return; + } + + for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) { + DEBUGF("stream: remove stream %d from stream %d\n", stream->stream_id, + dep_stream->stream_id); + + nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); + + assert(stream->queued); + + stream->queued = 0; + stream->cycle = 0; + stream->pending_penalty = 0; + stream->descendant_last_cycle = 0; + stream->last_writelen = 0; + + if (stream_subtree_active(dep_stream)) { + return; + } + } +} + +/* + * Moves |stream| from |src|'s obq to |dest|'s obq. Removal from + * |src|'s obq is just done calling nghttp2_pq_remove(), so it does + * not recursively remove |src| and ancestors, like + * stream_obq_remove(). + */ +static int stream_obq_move(nghttp2_stream *dest, nghttp2_stream *src, + nghttp2_stream *stream) { + if (!stream->queued) { + return 0; + } + + DEBUGF("stream: remove stream %d from stream %d (move)\n", stream->stream_id, + src->stream_id); + + nghttp2_pq_remove(&src->obq, &stream->pq_entry); + stream->queued = 0; + + return stream_obq_push(dest, stream); +} + +void nghttp2_stream_reschedule(nghttp2_stream *stream) { + nghttp2_stream *dep_stream; + + assert(stream->queued); + + dep_stream = stream->dep_prev; + + for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) { + nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); + + stream_next_cycle(stream, dep_stream->descendant_last_cycle); + stream->seq = dep_stream->descendant_next_seq++; + + nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); + + DEBUGF("stream: stream=%d obq resched cycle=%d\n", stream->stream_id, + stream->cycle); + + dep_stream->last_writelen = stream->last_writelen; + } +} + +void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) { + nghttp2_stream *dep_stream; + uint32_t last_cycle; + int32_t old_weight; + uint32_t wlen_penalty; + + if (stream->weight == weight) { + return; + } + + old_weight = stream->weight; + stream->weight = weight; + + dep_stream = stream->dep_prev; + + if (!dep_stream) { + return; + } + + dep_stream->sum_dep_weight += weight - old_weight; + + if (!stream->queued) { + return; + } + + nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); + + wlen_penalty = (uint32_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT; + + /* Compute old stream->pending_penalty we used to calculate + stream->cycle */ + stream->pending_penalty = + (uint32_t)((stream->pending_penalty + (uint32_t)old_weight - + (wlen_penalty % (uint32_t)old_weight)) % + (uint32_t)old_weight); + + last_cycle = stream->cycle - + (wlen_penalty + stream->pending_penalty) / (uint32_t)old_weight; + + /* Now we have old stream->pending_penalty and new stream->weight in + place */ + stream_next_cycle(stream, last_cycle); + + if (stream->cycle < dep_stream->descendant_last_cycle && + (dep_stream->descendant_last_cycle - stream->cycle) <= + NGHTTP2_MAX_CYCLE_DISTANCE) { + stream->cycle = dep_stream->descendant_last_cycle; + } + + /* Continue to use same stream->seq */ + + nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); + + DEBUGF("stream: stream=%d obq resched cycle=%d\n", stream->stream_id, + stream->cycle); +} + +static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) { + for (; stream->sib_next; stream = stream->sib_next) + ; + + return stream; +} + +int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, + int32_t weight) { + weight = stream->weight * weight / stream->sum_dep_weight; + + return nghttp2_max(1, weight); +} + +#ifdef STREAM_DEP_DEBUG + +static void ensure_inactive(nghttp2_stream *stream) { + nghttp2_stream *si; + + if (stream->queued) { + fprintf(stderr, "stream(%p)=%d, stream->queued = 1; want 0\n", stream, + stream->stream_id); + assert(0); + } + + if (stream_active(stream)) { + fprintf(stderr, "stream(%p)=%d, stream_active(stream) = 1; want 0\n", + stream, stream->stream_id); + assert(0); + } + + if (!nghttp2_pq_empty(&stream->obq)) { + fprintf(stderr, "stream(%p)=%d, nghttp2_pq_size() = %zu; want 0\n", stream, + stream->stream_id, nghttp2_pq_size(&stream->obq)); + assert(0); + } + + for (si = stream->dep_next; si; si = si->sib_next) { + ensure_inactive(si); + } +} + +static void check_queued(nghttp2_stream *stream) { + nghttp2_stream *si; + int queued; + + if (stream->queued) { + if (!stream_subtree_active(stream)) { + fprintf(stderr, + "stream(%p)=%d, stream->queued == 1, but " + "stream_active() == %d and nghttp2_pq_size(&stream->obq) = %zu\n", + stream, stream->stream_id, stream_active(stream), + nghttp2_pq_size(&stream->obq)); + assert(0); + } + if (!stream_active(stream)) { + queued = 0; + for (si = stream->dep_next; si; si = si->sib_next) { + if (si->queued) { + ++queued; + } + } + if (queued == 0) { + fprintf(stderr, + "stream(%p)=%d, stream->queued == 1, and " + "!stream_active(), but no descendants is queued\n", + stream, stream->stream_id); + assert(0); + } + } + + for (si = stream->dep_next; si; si = si->sib_next) { + check_queued(si); + } + } else { + if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) { + fprintf(stderr, + "stream(%p) = %d, stream->queued == 0, but " + "stream_active(stream) == %d and " + "nghttp2_pq_size(&stream->obq) = %zu\n", + stream, stream->stream_id, stream_active(stream), + nghttp2_pq_size(&stream->obq)); + assert(0); + } + for (si = stream->dep_next; si; si = si->sib_next) { + ensure_inactive(si); + } + } +} + +static void check_sum_dep(nghttp2_stream *stream) { + nghttp2_stream *si; + int32_t n = 0; + for (si = stream->dep_next; si; si = si->sib_next) { + n += si->weight; + } + if (n != stream->sum_dep_weight) { + fprintf(stderr, "stream(%p)=%d, sum_dep_weight = %d; want %d\n", stream, + stream->stream_id, n, stream->sum_dep_weight); + assert(0); + } + for (si = stream->dep_next; si; si = si->sib_next) { + check_sum_dep(si); + } +} + +static void check_dep_prev(nghttp2_stream *stream) { + nghttp2_stream *si; + for (si = stream->dep_next; si; si = si->sib_next) { + if (si->dep_prev != stream) { + fprintf(stderr, "si->dep_prev = %p; want %p\n", si->dep_prev, stream); + assert(0); + } + check_dep_prev(si); + } +} + +#endif /* STREAM_DEP_DEBUG */ + +#ifdef STREAM_DEP_DEBUG +static void validate_tree(nghttp2_stream *stream) { + nghttp2_stream *si; + + if (!stream) { + return; + } + + for (; stream->dep_prev; stream = stream->dep_prev) + ; + + assert(stream->stream_id == 0); + assert(!stream->queued); + + fprintf(stderr, "checking...\n"); + if (nghttp2_pq_empty(&stream->obq)) { + fprintf(stderr, "root obq empty\n"); + for (si = stream->dep_next; si; si = si->sib_next) { + ensure_inactive(si); + } + } else { + for (si = stream->dep_next; si; si = si->sib_next) { + check_queued(si); + } + } + + check_sum_dep(stream); + check_dep_prev(stream); +} +#else /* !STREAM_DEP_DEBUG */ +static void validate_tree(nghttp2_stream *stream) { (void)stream; } +#endif /* !STREAM_DEP_DEBUG*/ + +static int stream_update_dep_on_attach_item(nghttp2_stream *stream) { + int rv; + + rv = stream_obq_push(stream->dep_prev, stream); + if (rv != 0) { + return rv; + } + + validate_tree(stream); + return 0; +} + +static int stream_update_dep_on_detach_item(nghttp2_stream *stream) { + if (nghttp2_pq_empty(&stream->obq)) { + stream_obq_remove(stream); + } + + validate_tree(stream); + + return 0; +} + +int nghttp2_stream_attach_item(nghttp2_stream *stream, + nghttp2_outbound_item *item) { + int rv; + + assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0); + assert(stream->item == NULL); + + DEBUGF("stream: stream=%d attach item=%p\n", stream->stream_id, item); + + stream->item = item; + + rv = stream_update_dep_on_attach_item(stream); + if (rv != 0) { + /* This may relave stream->queued == 1, but stream->item == NULL. + But only consequence of this error is fatal one, and session + destruction. In that execution path, these inconsistency does + not matter. */ + stream->item = NULL; + return rv; + } + + return 0; +} + +int nghttp2_stream_detach_item(nghttp2_stream *stream) { + DEBUGF("stream: stream=%d detach item=%p\n", stream->stream_id, stream->item); + + stream->item = NULL; + stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL); + + return stream_update_dep_on_detach_item(stream); +} + +int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) { + assert(stream->item); + + DEBUGF("stream: stream=%d defer item=%p cause=%02x\n", stream->stream_id, + stream->item, flags); + + stream->flags |= flags; + + return stream_update_dep_on_detach_item(stream); +} + +int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) { + assert(stream->item); + + DEBUGF("stream: stream=%d resume item=%p flags=%02x\n", stream->stream_id, + stream->item, flags); + + stream->flags = (uint8_t)(stream->flags & ~flags); + + if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) { + return 0; + } + + return stream_update_dep_on_attach_item(stream); +} + +int nghttp2_stream_check_deferred_item(nghttp2_stream *stream) { + return stream->item && (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL); +} + +int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream) { + return stream->item && + (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); +} + +static int update_initial_window_size(int32_t *window_size_ptr, + int32_t new_initial_window_size, + int32_t old_initial_window_size) { + int64_t new_window_size = (int64_t)(*window_size_ptr) + + new_initial_window_size - old_initial_window_size; + if (INT32_MIN > new_window_size || + new_window_size > NGHTTP2_MAX_WINDOW_SIZE) { + return -1; + } + *window_size_ptr = (int32_t)new_window_size; + return 0; +} + +int nghttp2_stream_update_remote_initial_window_size( + nghttp2_stream *stream, int32_t new_initial_window_size, + int32_t old_initial_window_size) { + return update_initial_window_size(&stream->remote_window_size, + new_initial_window_size, + old_initial_window_size); +} + +int nghttp2_stream_update_local_initial_window_size( + nghttp2_stream *stream, int32_t new_initial_window_size, + int32_t old_initial_window_size) { + return update_initial_window_size(&stream->local_window_size, + new_initial_window_size, + old_initial_window_size); +} + +void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) { + stream->state = NGHTTP2_STREAM_OPENED; + stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH); +} + +int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream, + nghttp2_stream *target) { + for (; stream; stream = stream->dep_prev) { + if (stream == target) { + return 1; + } + } + return 0; +} + +int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, + nghttp2_stream *stream) { + nghttp2_stream *si; + int rv; + + DEBUGF("stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream, + dep_stream->stream_id, stream, stream->stream_id); + + stream->sum_dep_weight = dep_stream->sum_dep_weight; + dep_stream->sum_dep_weight = stream->weight; + + if (dep_stream->dep_next) { + for (si = dep_stream->dep_next; si; si = si->sib_next) { + si->dep_prev = stream; + if (si->queued) { + rv = stream_obq_move(stream, dep_stream, si); + if (rv != 0) { + return rv; + } + } + } + + if (stream_subtree_active(stream)) { + rv = stream_obq_push(dep_stream, stream); + if (rv != 0) { + return rv; + } + } + + stream->dep_next = dep_stream->dep_next; + } + + dep_stream->dep_next = stream; + stream->dep_prev = dep_stream; + + validate_tree(stream); + + return 0; +} + +static void set_dep_prev(nghttp2_stream *stream, nghttp2_stream *dep) { + for (; stream; stream = stream->sib_next) { + stream->dep_prev = dep; + } +} + +static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) { + dep_stream->dep_next = stream; + if (stream) { + stream->dep_prev = dep_stream; + } +} + +static void link_sib(nghttp2_stream *a, nghttp2_stream *b) { + a->sib_next = b; + if (b) { + b->sib_prev = a; + } +} + +static void insert_link_dep(nghttp2_stream *dep_stream, + nghttp2_stream *stream) { + nghttp2_stream *sib_next; + + assert(stream->sib_prev == NULL); + + sib_next = dep_stream->dep_next; + + link_sib(stream, sib_next); + + link_dep(dep_stream, stream); +} + +static void unlink_sib(nghttp2_stream *stream) { + nghttp2_stream *prev, *next, *dep_next; + + prev = stream->sib_prev; + dep_next = stream->dep_next; + + assert(prev); + + if (dep_next) { + /* + * prev--stream(--sib_next--...) + * | + * dep_next + */ + + link_sib(prev, dep_next); + + set_dep_prev(dep_next, stream->dep_prev); + + if (stream->sib_next) { + link_sib(stream_last_sib(dep_next), stream->sib_next); + } + } else { + /* + * prev--stream(--sib_next--...) + */ + next = stream->sib_next; + + prev->sib_next = next; + + if (next) { + next->sib_prev = prev; + } + } +} + +static void unlink_dep(nghttp2_stream *stream) { + nghttp2_stream *prev, *next, *dep_next; + + prev = stream->dep_prev; + dep_next = stream->dep_next; + + assert(prev); + + if (dep_next) { + /* + * prev + * | + * stream(--sib_next--...) + * | + * dep_next + */ + link_dep(prev, dep_next); + + set_dep_prev(dep_next, stream->dep_prev); + + if (stream->sib_next) { + link_sib(stream_last_sib(dep_next), stream->sib_next); + } + + } else if (stream->sib_next) { + /* + * prev + * | + * stream--sib_next + */ + next = stream->sib_next; + + next->sib_prev = NULL; + + link_dep(prev, next); + } else { + prev->dep_next = NULL; + } +} + +void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, + nghttp2_stream *stream) { + DEBUGF("stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream, + dep_stream->stream_id, stream, stream->stream_id); + + dep_stream->sum_dep_weight += stream->weight; + + if (dep_stream->dep_next == NULL) { + link_dep(dep_stream, stream); + } else { + insert_link_dep(dep_stream, stream); + } + + validate_tree(stream); +} + +int nghttp2_stream_dep_remove(nghttp2_stream *stream) { + nghttp2_stream *dep_prev, *si; + int32_t sum_dep_weight_delta; + int rv; + + DEBUGF("stream: dep_remove stream(%p)=%d\n", stream, stream->stream_id); + + /* Distribute weight of |stream| to direct descendants */ + sum_dep_weight_delta = -stream->weight; + + for (si = stream->dep_next; si; si = si->sib_next) { + si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight); + + sum_dep_weight_delta += si->weight; + + if (si->queued) { + rv = stream_obq_move(stream->dep_prev, stream, si); + if (rv != 0) { + return rv; + } + } + } + + assert(stream->dep_prev); + + dep_prev = stream->dep_prev; + + dep_prev->sum_dep_weight += sum_dep_weight_delta; + + if (stream->queued) { + stream_obq_remove(stream); + } + + if (stream->sib_prev) { + unlink_sib(stream); + } else { + unlink_dep(stream); + } + + stream->sum_dep_weight = 0; + + stream->dep_prev = NULL; + stream->dep_next = NULL; + stream->sib_prev = NULL; + stream->sib_next = NULL; + + validate_tree(dep_prev); + + return 0; +} + +int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, + nghttp2_stream *stream) { + nghttp2_stream *last_sib; + nghttp2_stream *dep_next; + nghttp2_stream *si; + int rv; + + DEBUGF("stream: dep_insert_subtree dep_stream(%p)=%d stream(%p)=%d\n", + dep_stream, dep_stream->stream_id, stream, stream->stream_id); + + stream->sum_dep_weight += dep_stream->sum_dep_weight; + dep_stream->sum_dep_weight = stream->weight; + + if (dep_stream->dep_next) { + dep_next = dep_stream->dep_next; + + link_dep(dep_stream, stream); + + if (stream->dep_next) { + last_sib = stream_last_sib(stream->dep_next); + + link_sib(last_sib, dep_next); + } else { + link_dep(stream, dep_next); + } + + for (si = dep_next; si; si = si->sib_next) { + si->dep_prev = stream; + if (si->queued) { + rv = stream_obq_move(stream, dep_stream, si); + if (rv != 0) { + return rv; + } + } + } + } else { + link_dep(dep_stream, stream); + } + + if (stream_subtree_active(stream)) { + rv = stream_obq_push(dep_stream, stream); + if (rv != 0) { + return rv; + } + } + + validate_tree(dep_stream); + + return 0; +} + +int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, + nghttp2_stream *stream) { + int rv; + + DEBUGF("stream: dep_add_subtree dep_stream(%p)=%d stream(%p)=%d\n", + dep_stream, dep_stream->stream_id, stream, stream->stream_id); + + dep_stream->sum_dep_weight += stream->weight; + + if (dep_stream->dep_next) { + insert_link_dep(dep_stream, stream); + } else { + link_dep(dep_stream, stream); + } + + if (stream_subtree_active(stream)) { + rv = stream_obq_push(dep_stream, stream); + if (rv != 0) { + return rv; + } + } + + validate_tree(dep_stream); + + return 0; +} + +void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) { + nghttp2_stream *next, *dep_prev; + + DEBUGF("stream: dep_remove_subtree stream(%p)=%d\n", stream, + stream->stream_id); + + assert(stream->dep_prev); + + dep_prev = stream->dep_prev; + + if (stream->sib_prev) { + link_sib(stream->sib_prev, stream->sib_next); + } else { + next = stream->sib_next; + + link_dep(dep_prev, next); + + if (next) { + next->sib_prev = NULL; + } + } + + dep_prev->sum_dep_weight -= stream->weight; + + if (stream->queued) { + stream_obq_remove(stream); + } + + validate_tree(dep_prev); + + stream->sib_prev = NULL; + stream->sib_next = NULL; + stream->dep_prev = NULL; +} + +int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) { + return stream->dep_prev || stream->dep_next || stream->sib_prev || + stream->sib_next; +} + +nghttp2_outbound_item * +nghttp2_stream_next_outbound_item(nghttp2_stream *stream) { + nghttp2_pq_entry *ent; + nghttp2_stream *si; + + for (;;) { + if (stream_active(stream)) { + /* Update ascendant's descendant_last_cycle here, so that we can + assure that new stream is scheduled based on it. */ + for (si = stream; si->dep_prev; si = si->dep_prev) { + si->dep_prev->descendant_last_cycle = si->cycle; + } + return stream->item; + } + ent = nghttp2_pq_top(&stream->obq); + if (!ent) { + return NULL; + } + stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry); + } +} + +nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) { + if (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) { + return NGHTTP2_STREAM_STATE_CLOSED; + } + + if (stream->flags & NGHTTP2_STREAM_FLAG_PUSH) { + if (stream->shut_flags & NGHTTP2_SHUT_RD) { + return NGHTTP2_STREAM_STATE_RESERVED_LOCAL; + } + + if (stream->shut_flags & NGHTTP2_SHUT_WR) { + return NGHTTP2_STREAM_STATE_RESERVED_REMOTE; + } + } + + if (stream->shut_flags & NGHTTP2_SHUT_RD) { + return NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE; + } + + if (stream->shut_flags & NGHTTP2_SHUT_WR) { + return NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL; + } + + if (stream->state == NGHTTP2_STREAM_IDLE) { + return NGHTTP2_STREAM_STATE_IDLE; + } + + return NGHTTP2_STREAM_STATE_OPEN; +} + +nghttp2_stream *nghttp2_stream_get_parent(nghttp2_stream *stream) { + return stream->dep_prev; +} + +nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream) { + return stream->sib_next; +} + +nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream) { + return stream->sib_prev; +} + +nghttp2_stream *nghttp2_stream_get_first_child(nghttp2_stream *stream) { + return stream->dep_next; +} + +int32_t nghttp2_stream_get_weight(nghttp2_stream *stream) { + return stream->weight; +} + +int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream) { + return stream->sum_dep_weight; +} + +int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream) { + return stream->stream_id; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_stream.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_stream.h new file mode 100644 index 00000000..7ff69281 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_stream.h @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_STREAM_H +#define NGHTTP2_STREAM_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" +#include "nghttp2_outbound_item.h" +#include "nghttp2_map.h" +#include "nghttp2_pq.h" +#include "nghttp2_int.h" + +/* + * If local peer is stream initiator: + * NGHTTP2_STREAM_OPENING : upon sending request HEADERS + * NGHTTP2_STREAM_OPENED : upon receiving response HEADERS + * NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM + * + * If remote peer is stream initiator: + * NGHTTP2_STREAM_OPENING : upon receiving request HEADERS + * NGHTTP2_STREAM_OPENED : upon sending response HEADERS + * NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM + */ +typedef enum { + /* Initial state */ + NGHTTP2_STREAM_INITIAL, + /* For stream initiator: request HEADERS has been sent, but response + HEADERS has not been received yet. For receiver: request HEADERS + has been received, but it does not send response HEADERS yet. */ + NGHTTP2_STREAM_OPENING, + /* For stream initiator: response HEADERS is received. For receiver: + response HEADERS is sent. */ + NGHTTP2_STREAM_OPENED, + /* RST_STREAM is received, but somehow we need to keep stream in + memory. */ + NGHTTP2_STREAM_CLOSING, + /* PUSH_PROMISE is received or sent */ + NGHTTP2_STREAM_RESERVED, + /* Stream is created in this state if it is used as anchor in + dependency tree. */ + NGHTTP2_STREAM_IDLE +} nghttp2_stream_state; + +typedef enum { + NGHTTP2_SHUT_NONE = 0, + /* Indicates further receptions will be disallowed. */ + NGHTTP2_SHUT_RD = 0x01, + /* Indicates further transmissions will be disallowed. */ + NGHTTP2_SHUT_WR = 0x02, + /* Indicates both further receptions and transmissions will be + disallowed. */ + NGHTTP2_SHUT_RDWR = NGHTTP2_SHUT_RD | NGHTTP2_SHUT_WR +} nghttp2_shut_flag; + +typedef enum { + NGHTTP2_STREAM_FLAG_NONE = 0, + /* Indicates that this stream is pushed stream and not opened + yet. */ + NGHTTP2_STREAM_FLAG_PUSH = 0x01, + /* Indicates that this stream was closed */ + NGHTTP2_STREAM_FLAG_CLOSED = 0x02, + /* Indicates the item is deferred due to flow control. */ + NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL = 0x04, + /* Indicates the item is deferred by user callback */ + NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08, + /* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and + NGHTTP2_STREAM_FLAG_DEFERRED_USER. */ + NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c + +} nghttp2_stream_flag; + +/* HTTP related flags to enforce HTTP semantics */ +typedef enum { + NGHTTP2_HTTP_FLAG_NONE = 0, + /* header field seen so far */ + NGHTTP2_HTTP_FLAG__AUTHORITY = 1, + NGHTTP2_HTTP_FLAG__PATH = 1 << 1, + NGHTTP2_HTTP_FLAG__METHOD = 1 << 2, + NGHTTP2_HTTP_FLAG__SCHEME = 1 << 3, + /* host is not pseudo header, but we require either host or + :authority */ + NGHTTP2_HTTP_FLAG_HOST = 1 << 4, + NGHTTP2_HTTP_FLAG__STATUS = 1 << 5, + /* required header fields for HTTP request except for CONNECT + method. */ + NGHTTP2_HTTP_FLAG_REQ_HEADERS = NGHTTP2_HTTP_FLAG__METHOD | + NGHTTP2_HTTP_FLAG__PATH | + NGHTTP2_HTTP_FLAG__SCHEME, + NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED = 1 << 6, + /* HTTP method flags */ + NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7, + NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8, + NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9, + NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND = 1 << 10, + NGHTTP2_HTTP_FLAG_METH_ALL = NGHTTP2_HTTP_FLAG_METH_CONNECT | + NGHTTP2_HTTP_FLAG_METH_HEAD | + NGHTTP2_HTTP_FLAG_METH_OPTIONS | + NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND, + /* :path category */ + /* path starts with "/" */ + NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 11, + /* path "*" */ + NGHTTP2_HTTP_FLAG_PATH_ASTERISK = 1 << 12, + /* scheme */ + /* "http" or "https" scheme */ + NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 13, + /* set if final response is expected */ + NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14 +} nghttp2_http_flag; + +struct nghttp2_stream { + /* Intrusive Map */ + nghttp2_map_entry map_entry; + /* Entry for dep_prev->obq */ + nghttp2_pq_entry pq_entry; + /* Priority Queue storing direct descendant (nghttp2_stream). Only + streams which itself has some data to send, or has a descendant + which has some data to sent. */ + nghttp2_pq obq; + /* Content-Length of request/response body. -1 if unknown. */ + int64_t content_length; + /* Received body so far */ + int64_t recv_content_length; + /* Base last_cycle for direct descendent streams. */ + uint32_t descendant_last_cycle; + /* Next scheduled time to sent item */ + uint32_t cycle; + /* Next seq used for direct descendant streams */ + uint64_t descendant_next_seq; + /* Secondary key for prioritization to break a tie for cycle. This + value is monotonically increased for single parent stream. */ + uint64_t seq; + /* pointers to form dependency tree. If multiple streams depend on + a stream, only one stream (left most) has non-NULL dep_prev which + points to the stream it depends on. The remaining streams are + linked using sib_prev and sib_next. The stream which has + non-NULL dep_prev always NULL sib_prev. The right most stream + has NULL sib_next. If this stream is a root of dependency tree, + dep_prev and sib_prev are NULL. */ + nghttp2_stream *dep_prev, *dep_next; + nghttp2_stream *sib_prev, *sib_next; + /* When stream is kept after closure, it may be kept in doubly + linked list pointed by nghttp2_session closed_stream_head. + closed_next points to the next stream object if it is the element + of the list. */ + nghttp2_stream *closed_prev, *closed_next; + /* The arbitrary data provided by user for this stream. */ + void *stream_user_data; + /* Item to send */ + nghttp2_outbound_item *item; + /* Last written length of frame payload */ + size_t last_writelen; + /* stream ID */ + int32_t stream_id; + /* Current remote window size. This value is computed against the + current initial window size of remote endpoint. */ + int32_t remote_window_size; + /* Keep track of the number of bytes received without + WINDOW_UPDATE. This could be negative after submitting negative + value to WINDOW_UPDATE */ + int32_t recv_window_size; + /* The number of bytes consumed by the application and now is + subject to WINDOW_UPDATE. This is only used when auto + WINDOW_UPDATE is turned off. */ + int32_t consumed_size; + /* The amount of recv_window_size cut using submitting negative + value to WINDOW_UPDATE */ + int32_t recv_reduction; + /* window size for local flow control. It is initially set to + NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by + submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */ + int32_t local_window_size; + /* weight of this stream */ + int32_t weight; + /* This is unpaid penalty (offset) when calculating cycle. */ + uint32_t pending_penalty; + /* sum of weight of direct descendants */ + int32_t sum_dep_weight; + nghttp2_stream_state state; + /* status code from remote server */ + int16_t status_code; + /* Bitwise OR of zero or more nghttp2_http_flag values */ + uint16_t http_flags; + /* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */ + uint8_t flags; + /* Bitwise OR of zero or more nghttp2_shut_flag values */ + uint8_t shut_flags; + /* Nonzero if this stream has been queued to stream pointed by + dep_prev. We maintain the invariant that if a stream is queued, + then its ancestors, except for root, are also queued. This + invariant may break in fatal error condition. */ + uint8_t queued; + /* This flag is used to reduce excessive queuing of WINDOW_UPDATE to + this stream. The nonzero does not necessarily mean WINDOW_UPDATE + is not queued. */ + uint8_t window_update_queued; +}; + +void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, + uint8_t flags, nghttp2_stream_state initial_state, + int32_t weight, int32_t remote_initial_window_size, + int32_t local_initial_window_size, + void *stream_user_data, nghttp2_mem *mem); + +void nghttp2_stream_free(nghttp2_stream *stream); + +/* + * Disallow either further receptions or transmissions, or both. + * |flag| is bitwise OR of one or more of nghttp2_shut_flag. + */ +void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag); + +/* + * Defer |stream->item|. We won't call this function in the situation + * where |stream->item| == NULL. The |flags| is bitwise OR of zero or + * more of NGHTTP2_STREAM_FLAG_DEFERRED_USER and + * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL. The |flags| indicates + * the reason of this action. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags); + +/* + * Put back deferred data in this stream to active state. The |flags| + * are one or more of bitwise OR of the following values: + * NGHTTP2_STREAM_FLAG_DEFERRED_USER and + * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are + * cleared if they are set. So even if this function is called, if + * one of flag is still set, data does not become active. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags); + +/* + * Returns nonzero if item is deferred by whatever reason. + */ +int nghttp2_stream_check_deferred_item(nghttp2_stream *stream); + +/* + * Returns nonzero if item is deferred by flow control. + */ +int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream); + +/* + * Updates the remote window size with the new value + * |new_initial_window_size|. The |old_initial_window_size| is used to + * calculate the current window size. + * + * This function returns 0 if it succeeds or -1. The failure is due to + * overflow. + */ +int nghttp2_stream_update_remote_initial_window_size( + nghttp2_stream *stream, int32_t new_initial_window_size, + int32_t old_initial_window_size); + +/* + * Updates the local window size with the new value + * |new_initial_window_size|. The |old_initial_window_size| is used to + * calculate the current window size. + * + * This function returns 0 if it succeeds or -1. The failure is due to + * overflow. + */ +int nghttp2_stream_update_local_initial_window_size( + nghttp2_stream *stream, int32_t new_initial_window_size, + int32_t old_initial_window_size); + +/* + * Call this function if promised stream |stream| is replied with + * HEADERS. This function makes the state of the |stream| to + * NGHTTP2_STREAM_OPENED. + */ +void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream); + +/* + * Returns nonzero if |target| is an ancestor of |stream|. + */ +int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream, + nghttp2_stream *target); + +/* + * Computes distributed weight of a stream of the |weight| under the + * |stream| if |stream| is removed from a dependency tree. + */ +int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, + int32_t weight); + +/* + * Makes the |stream| depend on the |dep_stream|. This dependency is + * exclusive. All existing direct descendants of |dep_stream| become + * the descendants of the |stream|. This function assumes + * |stream->item| is NULL. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, + nghttp2_stream *stream); + +/* + * Makes the |stream| depend on the |dep_stream|. This dependency is + * not exclusive. This function assumes |stream->item| is NULL. + */ +void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream); + +/* + * Removes the |stream| from the current dependency tree. This + * function assumes |stream->item| is NULL. + */ +int nghttp2_stream_dep_remove(nghttp2_stream *stream); + +/* + * Attaches |item| to |stream|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_stream_attach_item(nghttp2_stream *stream, + nghttp2_outbound_item *item); + +/* + * Detaches |stream->item|. This function does not free + * |stream->item|. The caller must free it. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_stream_detach_item(nghttp2_stream *stream); + +/* + * Makes the |stream| depend on the |dep_stream|. This dependency is + * exclusive. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, + nghttp2_stream *stream); + +/* + * Makes the |stream| depend on the |dep_stream|. This dependency is + * not exclusive. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, + nghttp2_stream *stream); + +/* + * Removes subtree whose root stream is |stream|. The + * effective_weight of streams in removed subtree is not updated. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory + */ +void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream); + +/* + * Returns nonzero if |stream| is in any dependency tree. + */ +int nghttp2_stream_in_dep_tree(nghttp2_stream *stream); + +/* + * Schedules transmission of |stream|'s item, assuming stream->item is + * attached, and stream->last_writelen was updated. + */ +void nghttp2_stream_reschedule(nghttp2_stream *stream); + +/* + * Changes |stream|'s weight to |weight|. If |stream| is queued, it + * will be rescheduled based on new weight. + */ +void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight); + +/* + * Returns a stream which has highest priority, updating + * descendant_last_cycle of selected stream's ancestors. + */ +nghttp2_outbound_item * +nghttp2_stream_next_outbound_item(nghttp2_stream *stream); + +#endif /* NGHTTP2_STREAM */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_submit.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_submit.c new file mode 100644 index 00000000..dedf86e8 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_submit.c @@ -0,0 +1,712 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#include "nghttp2_submit.h" + +#include +#include + +#include "nghttp2_session.h" +#include "nghttp2_frame.h" +#include "nghttp2_helper.h" +#include "nghttp2_priority_spec.h" + +/* + * Detects the dependency error, that is stream attempted to depend on + * itself. If |stream_id| is -1, we use session->next_stream_id as + * stream ID. + * + * This function returns 0 if it succeeds, or one of the following + * error codes: + * + * NGHTTP2_ERR_INVALID_ARGUMENT + * Stream attempted to depend on itself. + */ +static int detect_self_dependency(nghttp2_session *session, int32_t stream_id, + const nghttp2_priority_spec *pri_spec) { + assert(pri_spec); + + if (stream_id == -1) { + if ((int32_t)session->next_stream_id == pri_spec->stream_id) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + return 0; + } + + if (stream_id == pri_spec->stream_id) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + return 0; +} + +/* This function takes ownership of |nva_copy|. Regardless of the + return value, the caller must not free |nva_copy| after this + function returns. */ +static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + const nghttp2_priority_spec *pri_spec, + nghttp2_nv *nva_copy, size_t nvlen, + const nghttp2_data_provider *data_prd, + void *stream_user_data) { + int rv; + uint8_t flags_copy; + nghttp2_outbound_item *item = NULL; + nghttp2_frame *frame = NULL; + nghttp2_headers_category hcat; + nghttp2_mem *mem; + + mem = &session->mem; + + item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); + if (item == NULL) { + rv = NGHTTP2_ERR_NOMEM; + goto fail; + } + + nghttp2_outbound_item_init(item); + + if (data_prd != NULL && data_prd->read_callback != NULL) { + item->aux_data.headers.data_prd = *data_prd; + } + + item->aux_data.headers.stream_user_data = stream_user_data; + + flags_copy = + (uint8_t)((flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) | + NGHTTP2_FLAG_END_HEADERS); + + if (stream_id == -1) { + if (session->next_stream_id > INT32_MAX) { + rv = NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE; + goto fail; + } + + stream_id = (int32_t)session->next_stream_id; + session->next_stream_id += 2; + + hcat = NGHTTP2_HCAT_REQUEST; + } else { + /* More specific categorization will be done later. */ + hcat = NGHTTP2_HCAT_HEADERS; + } + + frame = &item->frame; + + nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, hcat, + pri_spec, nva_copy, nvlen); + + rv = nghttp2_session_add_item(session, item); + + if (rv != 0) { + nghttp2_frame_headers_free(&frame->headers, mem); + goto fail2; + } + + if (hcat == NGHTTP2_HCAT_REQUEST) { + return stream_id; + } + + return 0; + +fail: + /* nghttp2_frame_headers_init() takes ownership of nva_copy. */ + nghttp2_nv_array_del(nva_copy, mem); +fail2: + nghttp2_mem_free(mem, item); + + return rv; +} + +static int32_t submit_headers_shared_nva(nghttp2_session *session, + uint8_t flags, int32_t stream_id, + const nghttp2_priority_spec *pri_spec, + const nghttp2_nv *nva, size_t nvlen, + const nghttp2_data_provider *data_prd, + void *stream_user_data) { + int rv; + nghttp2_nv *nva_copy; + nghttp2_priority_spec copy_pri_spec; + nghttp2_mem *mem; + + mem = &session->mem; + + if (pri_spec) { + copy_pri_spec = *pri_spec; + nghttp2_priority_spec_normalize_weight(©_pri_spec); + } else { + nghttp2_priority_spec_default_init(©_pri_spec); + } + + rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem); + if (rv < 0) { + return rv; + } + + return submit_headers_shared(session, flags, stream_id, ©_pri_spec, + nva_copy, nvlen, data_prd, stream_user_data); +} + +int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id, + const nghttp2_nv *nva, size_t nvlen) { + if (stream_id <= 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + return (int)submit_headers_shared_nva(session, NGHTTP2_FLAG_END_STREAM, + stream_id, NULL, nva, nvlen, NULL, + NULL); +} + +int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + const nghttp2_priority_spec *pri_spec, + const nghttp2_nv *nva, size_t nvlen, + void *stream_user_data) { + int rv; + + if (stream_id == -1) { + if (session->server) { + return NGHTTP2_ERR_PROTO; + } + } else if (stream_id <= 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + flags &= NGHTTP2_FLAG_END_STREAM; + + if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) { + rv = detect_self_dependency(session, stream_id, pri_spec); + if (rv != 0) { + return rv; + } + + flags |= NGHTTP2_FLAG_PRIORITY; + } else { + pri_spec = NULL; + } + + return submit_headers_shared_nva(session, flags, stream_id, pri_spec, nva, + nvlen, NULL, stream_user_data); +} + +int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags, + const uint8_t *opaque_data) { + flags &= NGHTTP2_FLAG_ACK; + return nghttp2_session_add_ping(session, flags, opaque_data); +} + +int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + const nghttp2_priority_spec *pri_spec) { + int rv; + nghttp2_outbound_item *item; + nghttp2_frame *frame; + nghttp2_priority_spec copy_pri_spec; + nghttp2_mem *mem; + (void)flags; + + mem = &session->mem; + + if (stream_id == 0 || pri_spec == NULL) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + if (stream_id == pri_spec->stream_id) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + copy_pri_spec = *pri_spec; + + nghttp2_priority_spec_normalize_weight(©_pri_spec); + + item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); + + if (item == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_outbound_item_init(item); + + frame = &item->frame; + + nghttp2_frame_priority_init(&frame->priority, stream_id, ©_pri_spec); + + rv = nghttp2_session_add_item(session, item); + + if (rv != 0) { + nghttp2_frame_priority_free(&frame->priority); + nghttp2_mem_free(mem, item); + + return rv; + } + + return 0; +} + +int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags, + int32_t stream_id, uint32_t error_code) { + (void)flags; + + if (stream_id == 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + return nghttp2_session_add_rst_stream(session, stream_id, error_code); +} + +int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags, + int32_t last_stream_id, uint32_t error_code, + const uint8_t *opaque_data, size_t opaque_data_len) { + (void)flags; + + if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) { + return 0; + } + return nghttp2_session_add_goaway(session, last_stream_id, error_code, + opaque_data, opaque_data_len, + NGHTTP2_GOAWAY_AUX_NONE); +} + +int nghttp2_submit_shutdown_notice(nghttp2_session *session) { + if (!session->server) { + return NGHTTP2_ERR_INVALID_STATE; + } + if (session->goaway_flags) { + return 0; + } + return nghttp2_session_add_goaway(session, (1u << 31) - 1, NGHTTP2_NO_ERROR, + NULL, 0, + NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE); +} + +int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags, + const nghttp2_settings_entry *iv, size_t niv) { + (void)flags; + return nghttp2_session_add_settings(session, NGHTTP2_FLAG_NONE, iv, niv); +} + +int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags, + int32_t stream_id, const nghttp2_nv *nva, + size_t nvlen, + void *promised_stream_user_data) { + nghttp2_outbound_item *item; + nghttp2_frame *frame; + nghttp2_nv *nva_copy; + uint8_t flags_copy; + int32_t promised_stream_id; + int rv; + nghttp2_mem *mem; + (void)flags; + + mem = &session->mem; + + if (stream_id <= 0 || nghttp2_session_is_my_stream_id(session, stream_id)) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + if (!session->server) { + return NGHTTP2_ERR_PROTO; + } + + /* All 32bit signed stream IDs are spent. */ + if (session->next_stream_id > INT32_MAX) { + return NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE; + } + + item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); + if (item == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_outbound_item_init(item); + + item->aux_data.headers.stream_user_data = promised_stream_user_data; + + frame = &item->frame; + + rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem); + if (rv < 0) { + nghttp2_mem_free(mem, item); + return rv; + } + + flags_copy = NGHTTP2_FLAG_END_HEADERS; + + promised_stream_id = (int32_t)session->next_stream_id; + session->next_stream_id += 2; + + nghttp2_frame_push_promise_init(&frame->push_promise, flags_copy, stream_id, + promised_stream_id, nva_copy, nvlen); + + rv = nghttp2_session_add_item(session, item); + + if (rv != 0) { + nghttp2_frame_push_promise_free(&frame->push_promise, mem); + nghttp2_mem_free(mem, item); + + return rv; + } + + return promised_stream_id; +} + +int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + int32_t window_size_increment) { + int rv; + nghttp2_stream *stream = 0; + (void)flags; + + if (window_size_increment == 0) { + return 0; + } + if (stream_id == 0) { + rv = nghttp2_adjust_local_window_size( + &session->local_window_size, &session->recv_window_size, + &session->recv_reduction, &window_size_increment); + if (rv != 0) { + return rv; + } + } else { + stream = nghttp2_session_get_stream(session, stream_id); + if (!stream) { + return 0; + } + + rv = nghttp2_adjust_local_window_size( + &stream->local_window_size, &stream->recv_window_size, + &stream->recv_reduction, &window_size_increment); + if (rv != 0) { + return rv; + } + } + + if (window_size_increment > 0) { + if (stream_id == 0) { + session->consumed_size = + nghttp2_max(0, session->consumed_size - window_size_increment); + } else { + stream->consumed_size = + nghttp2_max(0, stream->consumed_size - window_size_increment); + } + + return nghttp2_session_add_window_update(session, 0, stream_id, + window_size_increment); + } + return 0; +} + +int nghttp2_session_set_local_window_size(nghttp2_session *session, + uint8_t flags, int32_t stream_id, + int32_t window_size) { + int32_t window_size_increment; + nghttp2_stream *stream; + int rv; + (void)flags; + + if (window_size < 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + if (stream_id == 0) { + window_size_increment = window_size - session->local_window_size; + + if (window_size_increment == 0) { + return 0; + } + + if (window_size_increment < 0) { + return nghttp2_adjust_local_window_size( + &session->local_window_size, &session->recv_window_size, + &session->recv_reduction, &window_size_increment); + } + + rv = nghttp2_increase_local_window_size( + &session->local_window_size, &session->recv_window_size, + &session->recv_reduction, &window_size_increment); + + if (rv != 0) { + return rv; + } + } else { + stream = nghttp2_session_get_stream(session, stream_id); + + if (stream == NULL) { + return 0; + } + + window_size_increment = window_size - stream->local_window_size; + + if (window_size_increment == 0) { + return 0; + } + + if (window_size_increment < 0) { + return nghttp2_adjust_local_window_size( + &stream->local_window_size, &stream->recv_window_size, + &stream->recv_reduction, &window_size_increment); + } + + rv = nghttp2_increase_local_window_size( + &stream->local_window_size, &stream->recv_window_size, + &stream->recv_reduction, &window_size_increment); + + if (rv != 0) { + return rv; + } + } + + if (window_size_increment > 0) { + return nghttp2_session_add_window_update(session, 0, stream_id, + window_size_increment); + } + + return 0; +} + +int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags, + int32_t stream_id, const uint8_t *origin, + size_t origin_len, const uint8_t *field_value, + size_t field_value_len) { + nghttp2_mem *mem; + uint8_t *buf, *p; + uint8_t *origin_copy; + uint8_t *field_value_copy; + nghttp2_outbound_item *item; + nghttp2_frame *frame; + nghttp2_ext_altsvc *altsvc; + int rv; + (void)flags; + + mem = &session->mem; + + if (!session->server) { + return NGHTTP2_ERR_INVALID_STATE; + } + + if (2 + origin_len + field_value_len > NGHTTP2_MAX_PAYLOADLEN) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + if (stream_id == 0) { + if (origin_len == 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + } else if (origin_len != 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + buf = nghttp2_mem_malloc(mem, origin_len + field_value_len + 2); + if (buf == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + p = buf; + + origin_copy = p; + if (origin_len) { + p = nghttp2_cpymem(p, origin, origin_len); + } + *p++ = '\0'; + + field_value_copy = p; + if (field_value_len) { + p = nghttp2_cpymem(p, field_value, field_value_len); + } + *p++ = '\0'; + + item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); + if (item == NULL) { + rv = NGHTTP2_ERR_NOMEM; + goto fail_item_malloc; + } + + nghttp2_outbound_item_init(item); + + item->aux_data.ext.builtin = 1; + + altsvc = &item->ext_frame_payload.altsvc; + + frame = &item->frame; + frame->ext.payload = altsvc; + + nghttp2_frame_altsvc_init(&frame->ext, stream_id, origin_copy, origin_len, + field_value_copy, field_value_len); + + rv = nghttp2_session_add_item(session, item); + if (rv != 0) { + nghttp2_frame_altsvc_free(&frame->ext, mem); + nghttp2_mem_free(mem, item); + + return rv; + } + + return 0; + +fail_item_malloc: + nghttp2_mem_free(mem, buf); + + return rv; +} + +static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec, + const nghttp2_data_provider *data_prd) { + uint8_t flags = NGHTTP2_FLAG_NONE; + if (data_prd == NULL || data_prd->read_callback == NULL) { + flags |= NGHTTP2_FLAG_END_STREAM; + } + + if (pri_spec) { + flags |= NGHTTP2_FLAG_PRIORITY; + } + + return flags; +} + +int32_t nghttp2_submit_request(nghttp2_session *session, + const nghttp2_priority_spec *pri_spec, + const nghttp2_nv *nva, size_t nvlen, + const nghttp2_data_provider *data_prd, + void *stream_user_data) { + uint8_t flags; + int rv; + + if (session->server) { + return NGHTTP2_ERR_PROTO; + } + + if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) { + rv = detect_self_dependency(session, -1, pri_spec); + if (rv != 0) { + return rv; + } + } else { + pri_spec = NULL; + } + + flags = set_request_flags(pri_spec, data_prd); + + return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen, + data_prd, stream_user_data); +} + +static uint8_t set_response_flags(const nghttp2_data_provider *data_prd) { + uint8_t flags = NGHTTP2_FLAG_NONE; + if (data_prd == NULL || data_prd->read_callback == NULL) { + flags |= NGHTTP2_FLAG_END_STREAM; + } + return flags; +} + +int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, + const nghttp2_nv *nva, size_t nvlen, + const nghttp2_data_provider *data_prd) { + uint8_t flags; + + if (stream_id <= 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + if (!session->server) { + return NGHTTP2_ERR_PROTO; + } + + flags = set_response_flags(data_prd); + return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen, + data_prd, NULL); +} + +int nghttp2_submit_data(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + const nghttp2_data_provider *data_prd) { + int rv; + nghttp2_outbound_item *item; + nghttp2_frame *frame; + nghttp2_data_aux_data *aux_data; + uint8_t nflags = flags & NGHTTP2_FLAG_END_STREAM; + nghttp2_mem *mem; + + mem = &session->mem; + + if (stream_id == 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); + if (item == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_outbound_item_init(item); + + frame = &item->frame; + aux_data = &item->aux_data.data; + aux_data->data_prd = *data_prd; + aux_data->eof = 0; + aux_data->flags = nflags; + + /* flags are sent on transmission */ + nghttp2_frame_data_init(&frame->data, NGHTTP2_FLAG_NONE, stream_id); + + rv = nghttp2_session_add_item(session, item); + if (rv != 0) { + nghttp2_frame_data_free(&frame->data); + nghttp2_mem_free(mem, item); + return rv; + } + return 0; +} + +ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen, + const nghttp2_settings_entry *iv, + size_t niv) { + if (!nghttp2_iv_check(iv, niv)) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + if (buflen < (niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH)) { + return NGHTTP2_ERR_INSUFF_BUFSIZE; + } + + return (ssize_t)nghttp2_frame_pack_settings_payload(buf, iv, niv); +} + +int nghttp2_submit_extension(nghttp2_session *session, uint8_t type, + uint8_t flags, int32_t stream_id, void *payload) { + int rv; + nghttp2_outbound_item *item; + nghttp2_frame *frame; + nghttp2_mem *mem; + + mem = &session->mem; + + if (type <= NGHTTP2_CONTINUATION) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + if (!session->callbacks.pack_extension_callback) { + return NGHTTP2_ERR_INVALID_STATE; + } + + item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); + if (item == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_outbound_item_init(item); + + frame = &item->frame; + nghttp2_frame_extension_init(&frame->ext, type, flags, stream_id, payload); + + rv = nghttp2_session_add_item(session, item); + if (rv != 0) { + nghttp2_frame_extension_free(&frame->ext); + nghttp2_mem_free(mem, item); + return rv; + } + + return 0; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_submit.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_submit.h new file mode 100644 index 00000000..4d35029a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_submit.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2_SUBMIT_H +#define NGHTTP2_SUBMIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +#endif /* NGHTTP2_SUBMIT_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_version.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_version.c new file mode 100644 index 00000000..1b21d39c --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2_version.c @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "nghttp2.h" + +static nghttp2_info version = {NGHTTP2_VERSION_AGE, NGHTTP2_VERSION_NUM, + NGHTTP2_VERSION, NGHTTP2_PROTO_VERSION_ID}; + +nghttp2_info *nghttp2_version(int least_version) { + if (least_version > NGHTTP2_VERSION_NUM) + return NULL; + return &version; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2ver.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2ver.h new file mode 100644 index 00000000..28ededcd --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/external_libs/nghttp2/nghttp2ver.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015-2018 Alibaba Group Holding Limited + */ + + +#ifndef NGHTTP2VER_H +#define NGHTTP2VER_H + +/** + * @macro + * Version number of the nghttp2 library release + */ +#define NGHTTP2_VERSION "nghttp2" + +/** + * @macro + * Numerical representation of the version number of the nghttp2 library + * release. This is a 24 bit number with 8 bits for major number, 8 bits + * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. + */ +#define NGHTTP2_VERSION_NUM 0x013190 + +#endif /* NGHTTP2VER_H */ diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_awss.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_awss.c new file mode 100644 index 00000000..4c8f9c8a --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_awss.c @@ -0,0 +1,268 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include + +#include "infra_defs.h" +#include "iot_import_awss.h" +#include "dev_bind_wrapper.h" + +#include "esp_log.h" +#include "esp_wifi.h" +#ifdef CONFIG_IDF_TARGET_ESP8266 +#include "esp_task_wdt.h" +#endif + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static awss_recv_80211_frame_cb_t s_sniffer_cb; + +static const char *TAG = "awss"; + +static void HAL_Awss_Monitor_callback(void *recv_buf, wifi_promiscuous_pkt_type_t type) +{ + int with_fcs = 0; + int link_type = AWSS_LINK_TYPE_NONE; + uint16_t len = 0; + wifi_promiscuous_pkt_t *pkt = (wifi_promiscuous_pkt_t *)recv_buf; + int8_t rssi; + + if (type != WIFI_PKT_DATA && type != WIFI_PKT_MGMT) { + return; + } + + rssi = pkt->rx_ctrl.rssi; + +#ifdef CONFIG_IDF_TARGET_ESP8266 + uint8_t total_num = 1; + uint16_t seq_buf; + len = pkt->rx_ctrl.sig_mode ? pkt->rx_ctrl.HT_length : pkt->rx_ctrl.legacy_length; + + esp_task_wdt_reset(); + + if (pkt->rx_ctrl.aggregation) { + total_num = pkt->rx_ctrl.ampdu_cnt; + } + + for (uint8_t count = 0; count < total_num; count++) { + if (total_num > 1) { + len = *(uint16_t *)(pkt->payload + 40 + 2 * count); + } + + if (type == WIFI_PKT_MISC && pkt->rx_ctrl.aggregation == 1) { + len -= 4; + } + + if (s_sniffer_cb) { + s_sniffer_cb((char *)pkt->payload, len - 4, link_type, with_fcs, rssi); + } + + if (total_num > 1) { + seq_buf = *(uint16_t *)(pkt->payload + 22) >> 4; + seq_buf++; + *(uint16_t *)(pkt->payload + 22) = (seq_buf << 4) | (*(uint16_t *)(pkt->payload + 22) & 0xF); + } + } + +#else + + if (s_sniffer_cb) { + len = pkt->rx_ctrl.sig_len; + s_sniffer_cb((char *)pkt->payload, len - 4, link_type, with_fcs, rssi); + } + +#endif +} + +void HAL_Awss_Open_Monitor(_IN_ awss_recv_80211_frame_cb_t cb) +{ + if (!cb) { + return; + } + + s_sniffer_cb = cb; + + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_start()); + ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true)); + ESP_ERROR_CHECK(esp_wifi_set_channel(6, 0)); + ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(HAL_Awss_Monitor_callback)); + +#ifdef CONFIG_IDF_TARGET_ESP8266 + extern void esp_wifi_set_promiscuous_data_len(uint32_t); + esp_wifi_set_promiscuous_data_len(512); +#endif + + ESP_LOGI(TAG, "Open monitor mode"); +} + +void HAL_Awss_Close_Monitor(void) +{ + if (!s_sniffer_cb) { + return; + } + + ESP_ERROR_CHECK(esp_wifi_set_promiscuous(false)); + ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(NULL)); + + s_sniffer_cb = NULL; + + ESP_LOGI(TAG, "Close monitor mode"); + +} + +int HAL_Awss_Connect_Ap( + _IN_ uint32_t connection_timeout_ms, + _IN_ char ssid[HAL_MAX_SSID_LEN], + _IN_ char passwd[HAL_MAX_PASSWD_LEN], + _IN_OPT_ enum AWSS_AUTH_TYPE auth, + _IN_OPT_ enum AWSS_ENC_TYPE encry, + _IN_OPT_ uint8_t bssid[ETH_ALEN], + _IN_OPT_ uint8_t channel) +{ + uint32_t connect_ms = 0; + wifi_config_t wifi_config = { 0 }; + + if (ssid) { + memcpy(wifi_config.sta.ssid, ssid, HAL_MAX_SSID_LEN - 1); + } + + if (passwd) { + memcpy(wifi_config.sta.password, passwd, HAL_MAX_PASSWD_LEN - 1); + } + + if (bssid != NULL && strlen((char *)bssid)) { + memcpy(wifi_config.sta.bssid, bssid, ETH_ALEN); + wifi_config.sta.bssid_set = false; + } + + wifi_config.sta.channel = channel; + + ESP_LOGI(TAG, "ssid: %s, password: %s, channel: %d", + wifi_config.sta.ssid, "******", channel); + + ESP_LOGD(TAG, "password: %s", wifi_config.sta.password); + + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); + ESP_ERROR_CHECK(esp_wifi_start()); + ESP_ERROR_CHECK(esp_wifi_connect()); + + while (connect_ms < connection_timeout_ms) { + if (HAL_Sys_Net_Is_Ready() == 1) { + ESP_LOGI(TAG, "AP connected"); + return SUCCESS_RETURN; + } else { + ESP_LOGI(TAG, "Connecting AP"); + vTaskDelay(500 / portTICK_PERIOD_MS); + connect_ms += 500; + } + } + + return FAIL_RETURN; + +} + +int HAL_Awss_Get_Channelscan_Interval_Ms(void) +{ + return CONFIG_AWSS_CHANNELSCAN_INTERVAL_MS; +} + +int HAL_Awss_Get_Timeout_Interval_Ms(void) +{ + return CONFIG_AWSS_TIMEOUT_INTERVAL_MS; +} + +int HAL_Awss_Open_Ap(const char *ssid, const char *passwd, int beacon_interval, int hide) +{ + if (!ssid || !passwd) { + ESP_LOGI(TAG, "ssid or passwd is NULL"); + return FAIL_RETURN; + } + + wifi_config_t wifi_config = { + .ap = { + .max_connection = 5, + .beacon_interval = beacon_interval, + .ssid_hidden = hide, + }, + }; +#ifdef CONFIG_HAL_USE_CUSTOMER_AP_SSID + uint8_t ssid_kv[32] = {0}; + int len_kv = 32; + #define AP_SSID_KEY CONFIG_AP_SSID_KEY + int ret = HAL_Kv_Get(AP_SSID_KEY, ssid_kv, &len_kv); + if (ret == ESP_OK) { + memcpy(wifi_config.ap.ssid, ssid_kv, len_kv); + wifi_config.ap.ssid_len = len_kv; + } else { + ESP_LOGI(TAG, "Can't get customer softap ssid, so use default"); + strncpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); + wifi_config.ap.ssid_len = strlen(ssid); + } +#else + strncpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); + wifi_config.ap.ssid_len = strlen(ssid); +#endif + if (strlen(passwd) == 0) { + memset(wifi_config.ap.password, 0, sizeof(wifi_config.ap.password)); + wifi_config.ap.authmode = WIFI_AUTH_OPEN; + } else { + strncpy((char *) wifi_config.ap.password, passwd, sizeof(wifi_config.ap.password)); + wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK; + } + ESP_LOGI(TAG, "ssid: %s", (char *) wifi_config.ap.ssid); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); + ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config)); + ESP_ERROR_CHECK(esp_wifi_start()); + + return SUCCESS_RETURN; +} + +int HAL_Awss_Close_Ap(void) +{ + wifi_mode_t mode; + ESP_ERROR_CHECK(esp_wifi_get_mode(&mode)); + if (mode == WIFI_MODE_AP) { + ESP_ERROR_CHECK(esp_wifi_stop()); + } + return SUCCESS_RETURN; +} + +void HAL_Awss_Switch_Channel(char primary_channel, char secondary_channel, uint8_t bssid[ETH_ALEN]) +{ + if (esp_wifi_set_channel(primary_channel, secondary_channel) != ESP_OK) { + ESP_LOGW(TAG, "HAL_Awss_Switch_Channel primary %d, second %d", primary_channel, secondary_channel); + } +} + +int HAL_Awss_Get_Encrypt_Type() { + return 3; +} + +int HAL_Awss_Get_Conn_Encrypt_Type() { + return 3; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_crypto.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_crypto.c new file mode 100644 index 00000000..b6b25027 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_crypto.c @@ -0,0 +1,219 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "infra_compat.h" + +#include +#include +#include + +#include "sdkconfig.h" + +#ifdef CONFIG_IDF_TARGET_ESP8266 +#include "esp_aes.h" +#else +#include "mbedtls/aes.h" +#endif + +#define AES_BLOCK_SIZE 16 + +typedef struct { +#ifdef CONFIG_IDF_TARGET_ESP8266 + esp_aes_t ctx; +#else + mbedtls_aes_context ctx; +#endif + uint8_t iv[16]; + uint8_t key[16]; +} platform_aes_t; + +int HAL_Aes128_Cbc_Decrypt( + p_HAL_Aes128_t aes, + const void *src, + size_t blockNum, + void *dst) +{ + int i = 0; + int ret = -1; + platform_aes_t *p_aes128 = (platform_aes_t *)aes; + + if (!aes || !src || !dst) { + return ret; + } + + for (i = 0; i < blockNum; ++i) { +#ifdef CONFIG_IDF_TARGET_ESP8266 + ret = esp_aes_decrypt_cbc(&p_aes128->ctx, src, AES_BLOCK_SIZE, dst, AES_BLOCK_SIZE, p_aes128->iv); +#else + ret = mbedtls_aes_crypt_cbc(&p_aes128->ctx, MBEDTLS_AES_DECRYPT, AES_BLOCK_SIZE, + p_aes128->iv, src, dst); +#endif + src += 16; + dst += 16; + } + + return ret; +} + +int HAL_Aes128_Cbc_Encrypt( + p_HAL_Aes128_t aes, + const void *src, + size_t blockNum, + void *dst) +{ + int i = 0; + int ret = ret; + platform_aes_t *p_aes128 = (platform_aes_t *)aes; + + if (!aes || !src || !dst) { + return -1; + } + + for (i = 0; i < blockNum; ++i) { +#ifdef CONFIG_IDF_TARGET_ESP8266 + ret = esp_aes_encrypt_cbc(&p_aes128->ctx, src, AES_BLOCK_SIZE, dst, AES_BLOCK_SIZE, p_aes128->iv); +#else + ret = mbedtls_aes_crypt_cbc(&p_aes128->ctx, MBEDTLS_AES_ENCRYPT, AES_BLOCK_SIZE, + p_aes128->iv, src, dst); +#endif + src += 16; + dst += 16; + } + + return ret; +} + +DLL_HAL_API int HAL_Aes128_Cfb_Decrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t length, + _OU_ void *dst) +{ + size_t offset = 0; + int ret = -1; + platform_aes_t *p_aes128 = (platform_aes_t *)aes; + + if (!aes || !src || !dst) { + return ret; + } + +#ifdef CONFIG_IDF_TARGET_ESP8266 + ret = esp_aes_set_encrypt_key(&p_aes128->ctx, p_aes128->key, 128); + ret = esp_aes_decrypt_cfb128(&p_aes128->ctx, src, length, dst, length, p_aes128->iv, &offset); +#else + ret = mbedtls_aes_setkey_enc(&p_aes128->ctx, p_aes128->key, 128); + ret = mbedtls_aes_crypt_cfb128(&p_aes128->ctx, MBEDTLS_AES_DECRYPT, length, + &offset, p_aes128->iv, src, dst); +#endif + + return ret; +} + +DLL_HAL_API int HAL_Aes128_Cfb_Encrypt( + _IN_ p_HAL_Aes128_t aes, + _IN_ const void *src, + _IN_ size_t length, + _OU_ void *dst) +{ + size_t offset = 0; + int ret = -1; + platform_aes_t *p_aes128 = (platform_aes_t *)aes; + + if (!aes || !src || !dst) { + return ret; + } + +#ifdef CONFIG_IDF_TARGET_ESP8266 + ret = esp_aes_encrypt_cfb128(&p_aes128->ctx, src, length, dst, length, p_aes128->iv, &offset); +#else + ret = mbedtls_aes_crypt_cfb128(&p_aes128->ctx, MBEDTLS_AES_ENCRYPT, length, + &offset, p_aes128->iv, src, dst); +#endif + return ret; +} + +int HAL_Aes128_Destroy(p_HAL_Aes128_t aes) +{ + if (!aes) { + return -1; + } + +#ifdef CONFIG_IDF_TARGET_ESP8266 + // esp_aes_free(&((platform_aes_t *)aes)->ctx); +#else + mbedtls_aes_free(&((platform_aes_t *)aes)->ctx); +#endif + free(aes); + + return 0; +} + +p_HAL_Aes128_t HAL_Aes128_Init( + const uint8_t *key, + const uint8_t *iv, + AES_DIR_t dir) +{ + int ret = 0; + platform_aes_t *p_aes128 = NULL; + + if (!key || !iv) { + return p_aes128; + } + + p_aes128 = (platform_aes_t *)calloc(1, sizeof(platform_aes_t)); + + if (!p_aes128) { + return p_aes128; + } + +#ifdef CONFIG_IDF_TARGET_ESP8266 + // esp_aes_init(&p_aes128->ctx); +#else + mbedtls_aes_init(&p_aes128->ctx); +#endif + + if (dir == HAL_AES_ENCRYPTION) { +#ifdef CONFIG_IDF_TARGET_ESP8266 + ret = esp_aes_set_encrypt_key(&p_aes128->ctx, key, 128); +#else + ret = mbedtls_aes_setkey_enc(&p_aes128->ctx, key, 128); +#endif + } else { +#ifdef CONFIG_IDF_TARGET_ESP8266 + ret = esp_aes_set_decrypt_key(&p_aes128->ctx, key, 128); +#else + ret = mbedtls_aes_setkey_dec(&p_aes128->ctx, key, 128); +#endif + } + + if (ret == 0) { + memcpy(p_aes128->iv, iv, 16); + memcpy(p_aes128->key, key, 16); + } else { + free(p_aes128); + p_aes128 = NULL; + } + + return (p_HAL_Aes128_t *)p_aes128; +} \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_kv.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_kv.c new file mode 100644 index 00000000..357e1d8e --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_kv.c @@ -0,0 +1,174 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include +#include "nvs_flash.h" +#include "nvs.h" + +#include "esp_err.h" +#include "esp_log.h" + +#define NVS_PARTITION_NAME "nvs" +#define NVS_KV "iotkit-kv" + +static const char *TAG = "wrapper_kv"; + +static bool s_kv_init_flag; + +esp_err_t HAL_Kv_Init(void) +{ + esp_err_t ret = ESP_OK; + + do { + if (s_kv_init_flag == false) { + ret = nvs_flash_init_partition(NVS_PARTITION_NAME); + + if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase_partition(NVS_PARTITION_NAME)); + ret = nvs_flash_init_partition(NVS_PARTITION_NAME); + } else if (ret != ESP_OK) { + ESP_LOGE(TAG, "NVS Flash init %s failed!", NVS_PARTITION_NAME); + break; + } + + s_kv_init_flag = true; + } + } while (0); + + return ret; +} + +int HAL_Kv_Del(const char *key) +{ + nvs_handle handle; + esp_err_t ret; + + char key_name[16] = {0}; + + if (key == NULL) { + ESP_LOGE(TAG, "HAL_Kv_Del Null key"); + return ESP_FAIL; + } + + if (HAL_Kv_Init() != ESP_OK) { + return ESP_FAIL; + } + + ret = nvs_open_from_partition(NVS_PARTITION_NAME, NVS_KV, NVS_READWRITE, &handle); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "nvs open %s failed with %x", NVS_KV, ret); + return ESP_FAIL; + } + + /*max key name is 15UL*/ + memcpy(key_name, key, sizeof(key_name) - 1); + + ret = nvs_erase_key(handle, key_name); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "nvs erase key %s failed with %x", key_name, ret); + } else { + nvs_commit(handle); + } + + nvs_close(handle); + + return ret; +} + +int HAL_Kv_Get(const char *key, void *val, int *buffer_len) +{ + nvs_handle handle; + esp_err_t ret; + + char key_name[16] = {0}; + + if (key == NULL || val == NULL || buffer_len == NULL) { + ESP_LOGE(TAG, "HAL_Kv_Get Null params"); + return ESP_FAIL; + } + + if (HAL_Kv_Init() != ESP_OK) { + return ESP_FAIL; + } + + ret = nvs_open_from_partition(NVS_PARTITION_NAME, NVS_KV, NVS_READONLY, &handle); + + if (ret != ESP_OK) { + ESP_LOGW(TAG, "nvs open %s failed with %x", NVS_KV, ret); + return ESP_FAIL; + } + /*max key name is 15UL*/ + memcpy(key_name, key, sizeof(key_name) - 1); + + ret = nvs_get_blob(handle, key_name, val, (size_t *) buffer_len); + + if (ret != ESP_OK) { + ESP_LOGW(TAG, "nvs get blob %s failed with %x", key_name, ret); + } + + nvs_close(handle); + + return ret; +} + +int HAL_Kv_Set(const char *key, const void *val, int len, int sync) +{ + nvs_handle handle; + esp_err_t ret; + + char key_name[16] = {0}; + + if (key == NULL || val == NULL || len <= 0) { + ESP_LOGE(TAG, "HAL_Kv_Set NULL params"); + return ESP_FAIL; + } + + if (HAL_Kv_Init() != ESP_OK) { + return ESP_FAIL; + } + + ret = nvs_open_from_partition(NVS_PARTITION_NAME, NVS_KV, NVS_READWRITE, &handle); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "nvs open %s failed with %x", NVS_KV, ret); + return ESP_FAIL; + } + /*max key name is 15UL*/ + memcpy(key_name, key, sizeof(key_name) - 1); + ESP_LOGE(TAG, "Set %s blob value", key_name); + ret = nvs_set_blob(handle, key_name, val, len); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "nvs erase key %s failed with %x", key_name, ret); + } else { + nvs_commit(handle); + } + + nvs_close(handle); + + return ret; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_os.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_os.c new file mode 100644 index 00000000..2cf11159 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_os.c @@ -0,0 +1,322 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "wrappers_defs.h" +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/timers.h" + +#include "pthread.h" +#include "esp_wifi.h" +#include "esp_log.h" + +static const char *TAG = "os"; + +#ifdef CONFIG_IDF_TARGET_ESP8266 +#if __has_include("esp_idf_version.h") +#include "esp_idf_version.h" +#else +/** Major version number (X.x.x) */ +#define ESP_IDF_VERSION_MAJOR 3 +/** Minor version number (x.X.x) */ +#define ESP_IDF_VERSION_MINOR 2 +/** Patch version number (x.x.X) */ +#define ESP_IDF_VERSION_PATCH 0 +#define ESP_IDF_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch)) +#define ESP_IDF_VERSION ESP_IDF_VERSION_VAL(ESP_IDF_VERSION_MAJOR, \ + ESP_IDF_VERSION_MINOR, \ + ESP_IDF_VERSION_PATCH) +#endif + +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(3, 3, 0) +// notes: pthread_exit has already defined on ESP-IDF +void pthread_exit(void *value_ptr) +{ + ESP_LOGE(TAG, "%s: esp82666 not supported!", __FUNCTION__); +} +#endif +#endif + +static long long os_time_get(void) +{ + struct timeval tv; + long long ms; + gettimeofday(&tv, NULL); + ms = tv.tv_sec * 1000LL + tv.tv_usec / 1000; + return ms; +} + +static long long delta_time = 0; + +void HAL_UTC_Set(long long ms) +{ + delta_time = ms - os_time_get(); +} + +long long HAL_UTC_Get(void) +{ + return delta_time + os_time_get(); +} + +/** + * @brief Create a mutex. + * + * @retval NULL : Initialize mutex failed. + * @retval NOT_NULL : The mutex handle. + * @see None. + * @note None. + */ +void *HAL_MutexCreate(void) +{ + return (void *)xSemaphoreCreateMutex(); +} + +/** + * @brief Destroy the specified mutex object, it will release related resource. + * + * @param [in] mutex @n The specified mutex. + * @return None. + * @see None. + * @note None. + */ +void HAL_MutexDestroy(void *mutex) +{ + if (mutex) { + vSemaphoreDelete((SemaphoreHandle_t)mutex); + } +} + +/** + * @brief Waits until the specified mutex is in the signaled state. + * + * @param [in] mutex @n the specified mutex. + * @return None. + * @see None. + * @note None. + */ +void HAL_MutexLock(void *mutex) +{ + if (mutex) { + xSemaphoreTake((SemaphoreHandle_t)mutex, portMAX_DELAY); + } +} + +/** + * @brief Releases ownership of the specified mutex object.. + * + * @param [in] mutex @n the specified mutex. + * @return None. + * @see None. + * @note None. + */ +void HAL_MutexUnlock(void *mutex) +{ + if (mutex) { + xSemaphoreGive((SemaphoreHandle_t)mutex); + } +} + +/** + * @brief create a semaphore + * + * @return semaphore handle. + * @see None. + * @note The recommended value of maximum count of the semaphore is 255. + */ +void *HAL_SemaphoreCreate(void) +{ + return (void *)xSemaphoreCreateCounting(CONFIG_HAL_SEM_MAX_COUNT, CONFIG_HAL_SEM_INIT_COUNT); +} + +/** + * @brief destory a semaphore + * + * @param[in] sem @n the specified sem. + * @return None. + * @see None. + * @note None. + */ +void HAL_SemaphoreDestroy(void *sem) +{ + if (sem) { + vSemaphoreDelete((SemaphoreHandle_t)sem); + } +} + +/** + * @brief signal thread wait on a semaphore + * + * @param[in] sem @n the specified semaphore. + * @return None. + * @see None. + * @note None. + */ +void HAL_SemaphorePost(void *sem) +{ + if (sem) { + xSemaphoreGive((SemaphoreHandle_t)sem); + } +} + +/** + * @brief wait on a semaphore + * + * @param[in] sem @n the specified semaphore. + * @param[in] timeout_ms @n timeout interval in millisecond. + If timeout_ms is PLATFORM_WAIT_INFINITE, the function will return only when the semaphore is signaled. + * @return + @verbatim + = 0: The state of the specified object is signaled. + = -1: The time-out interval elapsed, and the object's state is nonsignaled. + @endverbatim + * @see None. + * @note None. + */ +int HAL_SemaphoreWait(void *sem, uint32_t timeout_ms) +{ + if (pdPASS == xSemaphoreTake((SemaphoreHandle_t)sem, timeout_ms)) { + return SUCCESS_RETURN; + } + + return FAIL_RETURN; +} + +/** + * @brief create a thread + * + * @param[out] thread_handle @n The new thread handle, memory allocated before thread created and return it, free it after thread joined or exit. + * @param[in] start_routine @n A pointer to the application-defined function to be executed by the thread. + This pointer represents the starting address of the thread. + * @param[in] arg @n A pointer to a variable to be passed to the start_routine. + * @param[in] hal_os_thread_param @n A pointer to stack params. + * @param[out] stack_used @n if platform used stack buffer, set stack_used to 1, otherwise set it to 0. + * @return + @verbatim + = 0: on success. + = -1: error occur. + @endverbatim + * @see None. + * @note None. + */ +int HAL_ThreadCreate( + void **thread_handle, + void *(*work_routine)(void *), + void *arg, + hal_os_thread_param_t *hal_os_thread_param, + int *stack_used) +{ + int ret = -1; + pthread_attr_t attr = {0}; + + if (!thread_handle || !work_routine || + !hal_os_thread_param || !stack_used) { + return NULL_VALUE_ERROR; + } + + *stack_used = 0; + printf("task name is %s\n", hal_os_thread_param->name); + + if (hal_os_thread_param->stack_size == 0) { + ret = pthread_create((pthread_t *)thread_handle, NULL, work_routine, arg); + } else { + attr.stacksize = hal_os_thread_param->stack_size; + ret = pthread_create((pthread_t *)thread_handle, &attr, work_routine, arg); + } + return ret; + +} + +void HAL_ThreadDelete(void *thread_handle) +{ + if (NULL == thread_handle) { + pthread_exit(0); + } else { + /*main thread delete child thread*/ + pthread_cancel((pthread_t) thread_handle); + pthread_join((pthread_t) thread_handle, 0); + } + +} + +void HAL_ThreadDetach(void *thread_handle) +{ + pthread_detach((pthread_t)thread_handle); +} + +void *HAL_Timer_Create(const char *name, void (*func)(void *), void *user_data) +{ + TimerHandle_t timer_handle = NULL; + timer_handle = xTimerCreate(name, portMAX_DELAY, pdFALSE, NULL, (TimerCallbackFunction_t)func); + + return (void *)timer_handle; +} + +int HAL_Timer_Delete(void *timer) +{ + if (!timer) { + return FAIL_RETURN; + } + + if (pdTRUE == xTimerDelete((TimerHandle_t)timer, portMAX_DELAY)) { + return SUCCESS_RETURN; + } + + return FAIL_RETURN; +} + +int HAL_Timer_Start(void *timer, int ms) +{ + if (!timer) { + return FAIL_RETURN; + } + + uint32_t ticks = ms / portTICK_PERIOD_MS; + if (ticks == 0) { + ticks = 1; + } + + if (xTimerChangePeriod(timer, ticks, portMAX_DELAY) != pdTRUE) { + return FAIL_RETURN; + } + if (xTimerStart((TimerHandle_t)timer, portMAX_DELAY) != pdTRUE) { + return FAIL_RETURN; + } + + return SUCCESS_RETURN; +} + +int HAL_Timer_Stop(void *timer) +{ + if (!timer) { + return FAIL_RETURN; + } + + if (pdTRUE == xTimerStop((TimerHandle_t)timer, portMAX_DELAY)) { + return SUCCESS_RETURN; + } + + return FAIL_RETURN; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_ota.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_ota.c new file mode 100644 index 00000000..c07fc672 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_ota.c @@ -0,0 +1,416 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "infra_types.h" +#include "infra_defs.h" +#include "string.h" +#include "esp_log.h" +#include "esp_ota_ops.h" +#include "mbedtls/sha256.h" +#include "mbedtls/md5.h" +#include "mbedtls/bignum.h" +#include "mbedtls/rsa.h" +#include "ota_wrapper.h" + +typedef struct { + const esp_partition_t *partition; + esp_ota_handle_t handle; + esp_err_t write_err; +} hal_ota_t; + +static hal_ota_t *s_ota_handle; +static uint8_t security_ota = 0; +static const char *TAG = "ota"; + +void HAL_Firmware_Persistence_Start(void) +{ + if (s_ota_handle) { + ESP_LOGE(TAG, "OTA is running..."); + return; + } + + do { + esp_err_t err; + esp_ota_handle_t update_handle = 0; + const esp_partition_t *update_partition = NULL; + + ESP_LOGI(TAG, "Starting OTA..."); + update_partition = esp_ota_get_next_update_partition(NULL); + + if (update_partition == NULL) { + ESP_LOGE(TAG, "Passive OTA partition not found"); + break; + } + + ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", + update_partition->subtype, update_partition->address); + + err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ota_begin failed, error=0x%x", err); + break; + } + + ESP_LOGI(TAG, "esp_ota_begin succeeded"); + ESP_LOGI(TAG, "Please Wait. This may take time"); + + s_ota_handle = (hal_ota_t *)HAL_Malloc(sizeof(hal_ota_t)); + + if (!s_ota_handle) { + ESP_LOGE(TAG, "No space for ota handle"); + break;; + } + + s_ota_handle->partition = update_partition; + s_ota_handle->handle = update_handle; + } while (0); +} + +int HAL_Firmware_Persistence_Stop(void) +{ + if (!s_ota_handle) { + ESP_LOGE(TAG, "OTA doesn't start"); + return NULL_VALUE_ERROR; + } + + bool err_flag = true; + + do { + esp_err_t err = esp_ota_end(s_ota_handle->handle); + + if (s_ota_handle->write_err != ESP_OK) { + ESP_LOGE(TAG, "esp_ota_write failed! err=0x%x", s_ota_handle->write_err); + break; + } else if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ota_end failed! err=0x%x. Image is invalid", err); + break; + } + + err = esp_ota_set_boot_partition(s_ota_handle->partition); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ota_set_boot_partition failed! err=0x%x", err); + break; + } + + ESP_LOGI(TAG, "esp_ota_set_boot_partition succeeded"); + + err_flag = false; + } while (0); + + HAL_Free(s_ota_handle); + s_ota_handle = NULL; + + return err_flag ? FAIL_RETURN : SUCCESS_RETURN; +} + +int HAL_Firmware_Persistence_Write(char *buffer, uint32_t length) +{ + if (!s_ota_handle) { + ESP_LOGE(TAG, "OTA doesn't start"); + return NULL_VALUE_ERROR; + } + + s_ota_handle->write_err = esp_ota_write(s_ota_handle->handle, (const void *) buffer, length); + + if (s_ota_handle->write_err != ESP_OK) { + ESP_LOGE(TAG, "esp_ota_write failed, err=0x%x", s_ota_handle->write_err); + return FAIL_RETURN; + } + + return length; +} + +/* RSA Public Key:User needs sign in alibaba cloud to get and replace them. */ +const __attribute__((section(".rodata_custom_desc"))) unsigned char ota_pubn_buf[256] = {0xB3, 0x6F, 0xEE, 0x07, 0x2D, 0xB9, 0x5B, 0x11, 0x6E, 0x13, 0x6C, 0xA1, 0x00, 0xAA, 0xAE, 0xB8, 0xC4, 0x2D, 0xB7, 0xF9, 0x4D, 0xEC, 0xC2, 0x82, 0x8A, 0x88, 0x57, 0xAF, 0xEB, 0xFB, 0x74, 0xE4, 0xE0, 0x44, 0xAE, 0xDC, 0x63, 0xEF, 0x85, 0xBC, 0xBE, 0x70, 0x62, 0xC0, 0x1F, 0x06, 0x79, 0x7A, 0x10, 0xCD, 0x94, 0x07, 0x57, 0x65, 0xE4, 0xD2, 0x1F, 0x51, 0x02, 0x87, 0x37, 0x0B, 0x2F, 0xC3, 0x0B, 0xB6, 0x93, 0x7F, 0xBD, 0x5A, 0x35, 0x1A, 0x67, 0xC0, 0xD0, 0x40, 0x48, 0x61, 0x58, 0x34, 0x83, 0x7D, 0x43, 0x82, 0xE8, 0xF8, 0x91, 0xC4, 0x1F, 0x40, 0x98, 0xF4, 0xE0, 0x5A, 0xED, 0x3C, 0x0D, 0x95, 0xBD, 0x24, 0x5F, 0xA3, 0x77, 0xD9, 0xDE, 0x4F, 0x6B, 0xE8, 0x76, 0xCB, 0xB0, 0xE2, 0x18, 0x27, 0xB9, 0x32, 0x19, 0x99, 0x6E, 0xED, 0x2D, 0x18, 0x0A, 0x8A, 0x19, 0xE6, 0x1B, 0x78, 0x9B, 0x70, 0xB6, 0xD7, 0x44, 0x7E, 0xF7, 0x91, 0xDC, 0x94, 0x72, 0xE7, 0x32, 0xE8, 0xDB, 0x51, 0x38, 0x86, 0xC6, 0xBE, 0xEA, 0x82, 0xAE, 0xDF, 0x4B, 0x7F, 0x40, 0xB7, 0x08, 0xDC, 0x67, 0xE8, 0xE6, 0xD3, 0x8F, 0xCC, 0x4A, 0xC9, 0x1F, 0xF3, 0xCC, 0x33, 0xCC, 0xB5, 0xBA, 0x8C, 0xD5, 0x06, 0x63, 0xCB, 0x98, 0x9B, 0xF2, 0xCB, 0xD0, 0x7C, 0xBC, 0xD6, 0x31, 0x53, 0xAE, 0x71, 0xEF, 0xD0, 0xFD, 0x42, 0x8F, 0xC6, 0x19, 0x17, 0x28, 0xE7, 0x52, 0xC6, 0xC1, 0xA4, 0xB4, 0x45, 0x58, 0xC3, 0xDF, 0x0C, 0x2F, 0xB4, 0x8E, 0x81, 0x66, 0x3F, 0x4A, 0xDF, 0x10, 0xB0, 0x0F, 0xF4, 0xDC, 0xF6, 0x80, 0x18, 0xED, 0xFB, 0x1F, 0x32, 0x65, 0xB0, 0x57, 0x95, 0x0C, 0x53, 0xF6, 0x1F, 0xDC, 0xCE, 0x73, 0x59, 0xD8, 0xC9, 0xE6, 0x95, 0x63, 0x4B, 0x0B, 0x1B, 0xB6, 0x76, 0x8B, 0x65, 0xD5, 0x3D}; +static const unsigned char ota_pube_buf[3] = {0x01, 0x00, 0x01}; + +static int ota_rsa_pubkey_verify(const unsigned char *pubkey_n, + const unsigned char *pubkey_e, + unsigned int pubkey_n_size, + unsigned int pubkey_e_size, + const unsigned char *dig, + unsigned int dig_size, + const unsigned char *sig, + unsigned int sig_size) +{ + int ret = 0; + mbedtls_rsa_context ctx; + + if (pubkey_n == NULL || pubkey_n == NULL || dig == NULL || sig == NULL) { + ret = -1; + goto EXIT; + } + + mbedtls_rsa_init(&ctx, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256); + ret = mbedtls_mpi_read_binary(&ctx.N, pubkey_n, pubkey_n_size); + if (0 != ret) { + goto EXIT; + } + ret = mbedtls_mpi_read_binary(&ctx.E, pubkey_e, pubkey_e_size); + if (0 != ret) { + goto EXIT; + } + ctx.len = pubkey_n_size; + ret = mbedtls_rsa_check_pubkey(&ctx); + if (0 != ret) { + goto EXIT; + } + ret = mbedtls_rsa_pkcs1_verify(&ctx, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256,(unsigned int)0, (const unsigned char *)dig, (const unsigned char *)sig); + if (0 != ret) { + goto EXIT; + } +EXIT: + if(ret != 0) { + ESP_LOGE(TAG, "rsa verify ret: 0x%x", ret); + } + mbedtls_rsa_free(&ctx); + return ret; +} + +static int ota_str2hex(const char *src, char *dest, unsigned int dest_len) +{ + int i, n = 0; + int ret = -1; + if((src != NULL) && (dest != NULL) && (strlen(src) % 2 == 0) && (dest_len >= strlen(src) / 2)) { + ret = 0; + for(i = 0; src[i]; i += 2) { + if(src[i] >= 'A' && src[i] <= 'F') { + dest[n] = src[i] - 'A' + 10; + } + else { + dest[n] = src[i] - '0'; + } + if(src[i + 1] >= 'A' && src[i + 1] <= 'F') { + dest[n] = (dest[n] << 4) | (src[i + 1] - 'A' + 10); + } + else { + dest[n] = (dest[n] << 4) | (src[i + 1] - '0'); + } + ++n; + } + } + return ret; +} + +static int ota_to_capital(char *value, int len) +{ + int i = 0; + int ret = -1; + if ((value != NULL) && (len > 0)) { + ret = 0; + for (; i < len; i++) { + if (*(value + i) >= 'a' && *(value + i) <= 'z') { + *(value + i) -= 'a' - 'A'; + } + } + } + return ret; +} + +/*base64*/ +static const unsigned char base64_dec_map[128] = +{ + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, + 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 127, 127, 127, 127, 127 +}; + +static int ota_base64_decode(const unsigned char *src, unsigned int slen, unsigned char *dst, unsigned int *dlen) +{ + unsigned int i, n; + unsigned int j, x; + unsigned char *p; + + for( i = n = j = 0; i < slen; i++ ) + { + if( ( slen - i ) >= 2 && + src[i] == '\r' && src[i + 1] == '\n' ) + continue; + + if( src[i] == '\n' ) + continue; + + if( src[i] == '=' && ++j > 2 ) + return -1; + + if( src[i] > 127 || base64_dec_map[src[i]] == 127 ) + return -1; + + if( base64_dec_map[src[i]] < 64 && j != 0 ) + return -1; + + n++; + } + + if( n == 0 ) + return 0; + + n = ( ( n * 6 ) + 7 ) >> 3; + n -= j; + + if( dst == 0 || *dlen < n ) + { + *dlen = n; + return -2; + } + + for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) + { + if( *src == '\r' || *src == '\n' ) + continue; + + j -= ( base64_dec_map[*src] == 64 ); + x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F ); + + if( ++n == 4 ) + { + n = 0; + if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); + if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); + if( j > 2 ) *p++ = (unsigned char)( x ); + } + } + + *dlen = p - dst; + + return 0; +} + +static int ota_hash_create(const char *signMethod, const unsigned char *src, unsigned char *dst) +{ + if (!signMethod || !src || !dst) { + ESP_LOGE(TAG, "%s: input parameter invalid", __FUNCTION__); + return FAIL_RETURN; + } + + if (!strncmp(signMethod, "SHA256", strlen("SHA256"))) { + mbedtls_sha256_context ctx; + mbedtls_sha256_init(&ctx); + mbedtls_sha256_starts_ret(&ctx, 0); + mbedtls_sha256_update_ret(&ctx, src, 32); + mbedtls_sha256_finish_ret(&ctx, dst); + mbedtls_sha256_free( &ctx ); + } else if (!strncmp(signMethod, "Md5", strlen("Md5"))) { + mbedtls_md5_context ctx; + mbedtls_md5_init(&ctx); + mbedtls_md5_starts_ret(&ctx); + mbedtls_md5_update_ret(&ctx, src, 16); + mbedtls_md5_finish_ret(&ctx, dst); + mbedtls_md5_free( &ctx ); + } else { + ESP_LOGE(TAG, "%s: Not SHA256 and Md5", __FUNCTION__); + return FAIL_RETURN; + } + return SUCCESS_RETURN; +} + +int HAL_OTA_Security_check(const char *digest, const char *sign, const char *signMethod) +{ + if (!digest || !sign || !signMethod) { + ESP_LOGE(TAG, "%s: input parameter invalid", __FUNCTION__); + return FAIL_RETURN; + } + + ESP_LOGI(TAG, "digest is %s, sign is %s, signMethod is %s\n", digest, sign, signMethod); + + if (strncmp(signMethod, "SHA256", strlen("SHA256"))) { //only check signmethod is SHA256 + ESP_LOGI(TAG, "signMethod is %s, regard sign success", signMethod); + return SUCCESS_RETURN; + } + + int ret = FAIL_RETURN; + char sign_hash[66] = {0}; + unsigned char hash[32] = {0}; + unsigned char hash_ctx[32] = {0}; + + unsigned int digest_len = 256; + unsigned char *digest_decode = calloc(1, digest_len + 1); + + if (!digest_decode) { + ESP_LOGE(TAG, "%s: calloc digest_decode fail", __FUNCTION__); + return FAIL_RETURN; + } + + strncpy(sign_hash, sign, strlen(sign) + 1); + sign_hash[strlen(sign)] = '\0'; + ota_to_capital(sign_hash, strlen(sign_hash)); + ota_str2hex(sign_hash, (char *)hash, sizeof(hash)); + + ota_base64_decode((unsigned char *)digest, strlen(digest), digest_decode, &digest_len); + + ota_hash_create(signMethod, hash, hash_ctx); + + ret = ota_rsa_pubkey_verify(ota_pubn_buf, ota_pube_buf, sizeof(ota_pubn_buf), sizeof(ota_pube_buf), hash_ctx, 32, digest_decode, 256); + + if (ret == 0) { + ESP_LOGI(TAG, "check security success"); + ret = SUCCESS_RETURN; + } + + free(digest_decode); + digest_decode = NULL; + + return ret; +} + +int HAL_Firmware_Check_Rsa_Key(char *buffer, uint32_t length) +{ + if (!security_ota) { + return SUCCESS_RETURN; + } + + if (!s_ota_handle) { + ESP_LOGE(TAG, "OTA doesn't start"); + return NULL_VALUE_ERROR; + } +#ifdef CONFIG_IDF_TARGET_ESP8266 + uint8_t *p = (uint8_t *)buffer + 16; +#else + uint8_t *p = (uint8_t *)buffer + 288; +#endif + if (memcmp(p, ota_pubn_buf, 256)) { + ESP_LOGI(TAG, "check firmware key fail"); + return FAIL_RETURN; + } else { + ESP_LOGI(TAG, "check firmware key success"); + return SUCCESS_RETURN; + } +} + +void HAL_Firmware_Need_Check_Security_Ota(uint8_t flag) +{ + security_ota = flag; +} \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_product.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_product.c new file mode 100644 index 00000000..1216aaf4 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_product.c @@ -0,0 +1,222 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include + +#include "infra_defs.h" + +#include "esp_err.h" +#include "esp_log.h" + +#include "nvs_flash.h" +#include "nvs.h" + +#define MFG_PARTITION_NAME "fctry" +#define NVS_PRODUCT "aliyun-key" + +static const char *TAG = "wrapper_product"; + +static bool s_part_init_flag; + +static esp_err_t HAL_ProductParam_init(void) +{ + esp_err_t ret = ESP_OK; + + do { + if (s_part_init_flag == false) { + if ((ret = nvs_flash_init_partition(MFG_PARTITION_NAME)) != ESP_OK) { + ESP_LOGE(TAG, "NVS Flash init %s failed, Please check that you have flashed fctry partition!!!", MFG_PARTITION_NAME); + break; + } + + s_part_init_flag = true; + } + } while (0); + + return ret; +} + +static int HAL_GetProductParam(char *param_name, const char *param_name_str) +{ + esp_err_t ret; + size_t read_len = 0; + nvs_handle handle; + + do { + if (HAL_ProductParam_init() != ESP_OK) { + break; + } + + if (param_name == NULL) { + ESP_LOGE(TAG, "%s param %s NULL", __func__, param_name); + break; + } + + ret = nvs_open_from_partition(MFG_PARTITION_NAME, NVS_PRODUCT, NVS_READONLY, &handle); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "%s nvs_open failed with %x", __func__, ret); + break; + } + + ret = nvs_get_str(handle, param_name_str, NULL, (size_t *)&read_len); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "%s nvs_get_str get %s failed with %x", __func__, param_name_str, ret); + break; + } + + ret = nvs_get_str(handle, param_name_str, param_name, (size_t *)&read_len); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "%s nvs_get_str get %s failed with %x", __func__, param_name_str, ret); + } else { + ESP_LOGV(TAG, "%s %s %s", __func__, param_name_str, param_name); + } + + nvs_close(handle); + } while (0); + + return read_len; +} +/** + * @brief Get device name from user's system persistent storage + * + * @param [ou] device_name: array to store device name, max length is IOTX_DEVICE_NAME_LEN + * @return the actual length of device name + */ +int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN + 1]) +{ + return HAL_GetProductParam(device_name, "DeviceName"); +} + +/** + * @brief Get device secret from user's system persistent storage + * + * @param [ou] device_secret: array to store device secret, max length is IOTX_DEVICE_SECRET_LEN + * @return the actual length of device secret + */ +int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN + 1]) +{ + return HAL_GetProductParam(device_secret, "DeviceSecret"); +} + +/** + * @brief Get product key from user's system persistent storage + * + * @param [ou] product_key: array to store product key, max length is IOTX_PRODUCT_KEY_LEN + * @return the actual length of product key + */ +int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN + 1]) +{ + return HAL_GetProductParam(product_key, "ProductKey"); +} + +int HAL_GetProductSecret(char product_secret[IOTX_PRODUCT_SECRET_LEN + 1]) +{ + return HAL_GetProductParam(product_secret, "ProductSecret"); +} + +/** + * @brief Get firmware version + * + * @param [ou] version: array to store firmware version, max length is IOTX_FIRMWARE_VER_LEN + * @return the actual length of firmware version + */ +int HAL_GetFirmwareVersion(char *version) +{ + if (!version) { + ESP_LOGE(TAG, "%s version is NULL", __func__); + return 0; + } + + memset(version, 0, IOTX_FIRMWARE_VER_LEN); + int len = strlen(CONFIG_LINKKIT_FIRMWARE_VERSION); + if (len > IOTX_FIRMWARE_VER_LEN) { + len = 0; + } else { + memcpy(version, CONFIG_LINKKIT_FIRMWARE_VERSION, len); + } + + return len; +} + +static int HAL_SetProductParam(char *param_name, const char *param_name_str) +{ + esp_err_t ret; + size_t write_len = 0; + nvs_handle handle; + + do { + if (HAL_ProductParam_init() != ESP_OK) { + break; + } + + if (param_name == NULL) { + ESP_LOGE(TAG, "%s param %s NULL", __func__, param_name); + break; + } + + ret = nvs_open_from_partition(MFG_PARTITION_NAME, NVS_PRODUCT, NVS_READWRITE, &handle); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "%s nvs_open failed with %x", __func__, ret); + break; + } + + ret = nvs_set_str(handle, param_name_str, param_name); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "%s nvs_set_str set %s failed with %x", __func__, param_name_str, ret); + } else { + write_len = strlen(param_name); + ESP_LOGV(TAG, "%s %s %s", __func__, param_name_str, param_name); + } + + nvs_close(handle); + } while (0); + + return write_len; +} + +int HAL_SetDeviceName(char *device_name) +{ + return HAL_SetProductParam(device_name, "DeviceName"); +} + +int HAL_SetDeviceSecret(char *device_secret) +{ + return HAL_SetProductParam(device_secret, "DeviceSecret"); +} + +int HAL_SetProductKey(char *product_key) +{ + return HAL_SetProductParam(product_key, "ProductKey"); +} + +int HAL_SetProductSecret(char *product_secret) +{ + return HAL_SetProductParam(product_secret, "ProductSecret"); +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_system.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_system.c new file mode 100644 index 00000000..e8f3671f --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_system.c @@ -0,0 +1,210 @@ + +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "infra_types.h" + +#include +#include +#include +#include +#include + +#include "esp_timer.h" +#include "esp_system.h" + +#include "tcpip_adapter.h" + +extern int HAL_Fclose(void *stream) +{ + return (int)1; +} + +extern void *HAL_Fopen(const char *path, const char *mode) +{ + return (void*)1; +} + +extern uint32_t HAL_Fread(void *buff, uint32_t size, uint32_t count, void *stream) +{ + return (uint32_t)1; +} + +extern int HAL_Fseek(void *stream, long offset, int framewhere) +{ + return (int)1; +} + +extern long HAL_Ftell(void *stream) +{ + return (long)1; +} + +extern uint32_t HAL_Fwrite(const void *ptr, uint32_t size, uint32_t count, void *stream) +{ + return (uint32_t)1; +} + +/** + * @brief Allocates a block of size bytes of memory, returning a pointer to the beginning of the block. + * + * @param [in] size @n specify block size in bytes. + * @return A pointer to the beginning of the block. + * @see None. + * @note Block value is indeterminate. + */ +void *HAL_Malloc(uint32_t size) +{ + return calloc(1,size); +} + +/** + * @brief Deallocate memory block + * + * @param[in] ptr @n Pointer to a memory block previously allocated with platform_malloc. + * @return None. + * @see None. + * @note None. + */ +void HAL_Free(void *ptr) +{ + free(ptr); +} + +extern void *HAL_Realloc(void *ptr, uint32_t size) +{ + return realloc(ptr, size); +} + + +/** + * @brief Writes formatted data to stream. + * + * @param [in] fmt: @n String that contains the text to be written, it can optionally contain embedded format specifiers + that specifies how subsequent arguments are converted for output. + * @param [in] ...: @n the variable argument list, for formatted and inserted in the resulting string replacing their respective specifiers. + * @return None. + * @see None. + * @note None. + */ +void HAL_Printf(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + + fflush(stdout); +} + +/** + * @brief Writes formatted data to string. + * + * @param [out] str: @n String that holds written text. + * @param [in] len: @n Maximum length of character will be written + * @param [in] fmt: @n Format that contains the text to be written, it can optionally contain embedded format specifiers + that specifies how subsequent arguments are converted for output. + * @param [in] ...: @n the variable argument list, for formatted and inserted in the resulting string replacing their respective specifiers. + * @return bytes of character successfully written into string. + * @see None. + * @note None. + */ +int HAL_Snprintf(char *str, const int len, const char *fmt, ...) +{ + va_list args; + int rc; + + va_start(args, fmt); + rc = vsnprintf(str, len, fmt, args); + va_end(args); + + return rc; +} + +int HAL_Vsnprintf(char *str, const int len, const char *format, va_list ap) +{ + return vsnprintf(str, len, format, ap); +} + +uint32_t HAL_Random(uint32_t region) +{ + return (region != 0) ? (esp_random() % region) : 0; +} + +void HAL_Srandom(uint32_t seed) +{ + return; +} + +void HAL_Reboot() +{ + esp_restart(); +} + +/** + * @brief Sleep thread itself. + * + * @param [in] ms @n the time interval for which execution is to be suspended, in milliseconds. + * @return None. + * @see None. + * @note None. + */ +void HAL_SleepMs(uint32_t ms) +{ + usleep(1000 * ms); +} + +/** + * @brief Retrieves the number of milliseconds that have elapsed since the system was boot. + * + * @return the number of milliseconds. + * @see None. + * @note None. + */ +uint64_t HAL_UptimeMs(void) +{ + return (esp_timer_get_time()/1000); +} + +/** + * @brief check system network is ready(get ip address) or not. + * + * @param None. + * @return 0, net is not ready; 1, net is ready. + * @see None. + * @note None. + */ +int HAL_Sys_Net_Is_Ready() +{ + tcpip_adapter_ip_info_t local_ip; + + esp_err_t ret = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &local_ip); + + if ((ESP_OK == ret) && (local_ip.ip.addr != INADDR_ANY)) { + return 1; + } + + return 0; +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_tcp.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_tcp.c new file mode 100644 index 00000000..8f9d87b8 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_tcp.c @@ -0,0 +1,257 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include +#include +#include + +#include "infra_types.h" +#include "wrappers_defs.h" + +#include "esp_system.h" +#include "esp_log.h" + +static const char *TAG = "iot_import_tcp"; + +uint64_t HAL_UptimeMs(void); + +static uint64_t _esp_get_time_ms(void) +{ + return HAL_UptimeMs(); +} + +static uint64_t _esp_time_left(uint64_t t_end, uint64_t t_now) +{ + uint64_t t_left; + + if (t_end > t_now) { + t_left = t_end - t_now; + } else { + t_left = 0; + } + + return t_left; +} + +uintptr_t HAL_TCP_Establish(const char *host, uint16_t port) +{ + struct addrinfo hints; + struct addrinfo *addrInfoList = NULL; + struct addrinfo *cur = NULL; + int fd = 0; + int rc = 0; + char service[6]; + int sockopt = 1; + memset(&hints, 0, sizeof(hints)); + + ESP_LOGI(TAG, "establish tcp connection with server(host=%s port=%u)", host, port); + + hints.ai_family = AF_INET; /* only IPv4 */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + sprintf(service, "%u", port); + + if ((rc = getaddrinfo(host, service, &hints, &addrInfoList)) != 0) { + ESP_LOGE(TAG, "getaddrinfo error"); + return -1; + } + + for (cur = addrInfoList; cur != NULL; cur = cur->ai_next) { + if (cur->ai_family != AF_INET) { + ESP_LOGE(TAG, "socket type error"); + rc = -1; + continue; + } + + fd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol); + if (fd < 0) { + ESP_LOGE(TAG, "create socket error"); + rc = -1; + continue; + } + + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,&sockopt, sizeof(sockopt)); + setsockopt(fd, SOL_SOCKET, SO_REUSEPORT,&sockopt, sizeof(sockopt)); + + if (connect(fd, cur->ai_addr, cur->ai_addrlen) == 0) { + rc = fd; + break; + } + + close(fd); + ESP_LOGE(TAG, "connect error"); + rc = -1; + } + + if (-1 == rc) { + ESP_LOGI(TAG, "fail to establish tcp"); + } else { + ESP_LOGI(TAG, "success to establish tcp, fd=%d", rc); + } + freeaddrinfo(addrInfoList); + return (uintptr_t)rc; +} + +int HAL_TCP_Destroy(uintptr_t fd) +{ + int rc; + + /* Shutdown both send and receive operations. */ + rc = shutdown((int) fd, 2); + if (0 != rc) { + ESP_LOGE(TAG, "shutdown error"); + return -1; + } + + rc = close((int) fd); + if (0 != rc) { + ESP_LOGE(TAG, "closesocket error"); + return -1; + } + + return 0; +} + +int32_t HAL_TCP_Write(uintptr_t fd, const char *buf, uint32_t len, uint32_t timeout_ms) +{ + int ret; + uint32_t len_sent; + uint64_t t_end, t_left; + fd_set sets; + + t_end = _esp_get_time_ms() + timeout_ms; + len_sent = 0; + ret = 1; /* send one time if timeout_ms is value 0 */ + + do { + t_left = _esp_time_left(t_end, _esp_get_time_ms()); + + if (0 != t_left) { + struct timeval timeout; + + FD_ZERO(&sets); + FD_SET(fd, &sets); + + timeout.tv_sec = t_left / 1000; + timeout.tv_usec = (t_left % 1000) * 1000; + + ret = select(fd + 1, NULL, &sets, NULL, &timeout); + if (ret > 0) { + if (0 == FD_ISSET(fd, &sets)) { + ESP_LOGI(TAG, "Should NOT arrive"); + /* If timeout in next loop, it will not sent any data */ + ret = 0; + continue; + } + } else if (0 == ret) { + ESP_LOGI(TAG, "select-write timeout %d", (int)fd); + break; + } else { + if (EINTR == errno) { + ESP_LOGI(TAG, "EINTR be caught"); + continue; + } + + ESP_LOGE(TAG, "select-write fail"); + break; + } + } + + if (ret > 0) { + ret = send(fd, buf + len_sent, len - len_sent, 0); + if (ret > 0) { + len_sent += ret; + } else if (0 == ret) { + ESP_LOGI(TAG, "No data be sent"); + } else { + if (EINTR == errno) { + ESP_LOGI(TAG, "EINTR be caught"); + continue; + } + + ESP_LOGE(TAG, "send fail"); + break; + } + } + } while ((len_sent < len) && (_esp_time_left(t_end, _esp_get_time_ms()) > 0)); + + return len_sent; +} + +int32_t HAL_TCP_Read(uintptr_t fd, char *buf, uint32_t len, uint32_t timeout_ms) +{ + int ret, err_code; + uint32_t len_recv; + uint64_t t_end, t_left; + fd_set sets; + struct timeval timeout; + + t_end = _esp_get_time_ms() + timeout_ms; + len_recv = 0; + err_code = 0; + + do { + t_left = _esp_time_left(t_end, _esp_get_time_ms()); + if (0 == t_left) { + break; + } + FD_ZERO(&sets); + FD_SET(fd, &sets); + + timeout.tv_sec = t_left / 1000; + timeout.tv_usec = (t_left % 1000) * 1000; + + ret = select(fd + 1, &sets, NULL, NULL, &timeout); + if (ret > 0) { + ret = recv(fd, buf + len_recv, len - len_recv, 0); + if (ret > 0) { + len_recv += ret; + } else if (0 == ret) { + ESP_LOGE(TAG, "connection is closed"); + err_code = -1; + break; + } else { + if (EINTR == errno) { + ESP_LOGI(TAG, "EINTR be caught"); + continue; + } + ESP_LOGE(TAG, "recv fail"); + err_code = -2; + break; + } + } else if (0 == ret) { + break; + } else { + ESP_LOGE(TAG, "select-recv fail"); + err_code = -2; + break; + } + } while ((len_recv < len)); + + /* priority to return data bytes if any data be received from TCP connection. */ + /* It will get error code on next calling */ + return (0 != len_recv) ? len_recv : err_code; +} + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_tls.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_tls.c new file mode 100644 index 00000000..eeb5c314 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_tls.c @@ -0,0 +1,289 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include + +#include "infra_types.h" +#include "wrappers_defs.h" + +#include "esp_tls.h" +#include "esp_system.h" +#include "esp_log.h" + +static const char *TAG = "iot_import_tls"; + +/** + * @brief Set malloc/free function. + * + * @param [in] hooks: @n Specify malloc/free function you want to use + * + * @retval DTLS_SUCCESS : Success. + @retval other : Fail. + * @see None. + * @note None. + */ +DLL_HAL_API int HAL_DTLSHooks_set(dtls_hooks_t *hooks) +{ + return (int)1; +} + +/** + * @brief Establish a DSSL connection. + * + * @param [in] p_options: @n Specify paramter of DTLS + @verbatim + p_host : @n Specify the hostname(IP) of the DSSL server + port : @n Specify the DSSL port of DSSL server + p_ca_cert_pem : @n Specify the root certificate which is PEM format. + @endverbatim + * @return DSSL handle. + * @see None. + * @note None. + */ +DLL_HAL_API DTLSContext *HAL_DTLSSession_create(coap_dtls_options_t *p_options) +{ + return (DTLSContext *)1; +} + +/** + * @brief Destroy the specific DSSL connection. + * + * @param[in] context: @n Handle of the specific connection. + * + * @return The result of free dtls session + * @retval DTLS_SUCCESS : Read success. + * @retval DTLS_INVALID_PARAM : Invalid parameter. + * @retval DTLS_INVALID_CA_CERTIFICATE : Invalid CA Certificate. + * @retval DTLS_HANDSHAKE_IN_PROGRESS : Handshake in progress. + * @retval DTLS_HANDSHAKE_FAILED : Handshake failed. + * @retval DTLS_FATAL_ALERT_MESSAGE : Recv peer fatal alert message. + * @retval DTLS_PEER_CLOSE_NOTIFY : The DTLS session was closed by peer. + * @retval DTLS_SESSION_CREATE_FAILED : Create session fail. + * @retval DTLS_READ_DATA_FAILED : Read data fail. + */ +DLL_HAL_API unsigned int HAL_DTLSSession_free(DTLSContext *context) +{ + return (unsigned)1; +} + +/** + * @brief Read data from the specific DSSL connection with timeout parameter. + * The API will return immediately if len be received from the specific DSSL connection. + * + * @param [in] context @n A descriptor identifying a DSSL connection. + * @param [in] p_data @n A pointer to a buffer to receive incoming data. + * @param [in] p_datalen @n The length, in bytes, of the data pointed to by the 'p_data' parameter. + * @param [in] timeout_ms @n Specify the timeout value in millisecond. In other words, the API block 'timeout_ms' millisecond maximumly. + * @return The result of read data from DSSL connection + * @retval DTLS_SUCCESS : Read success. + * @retval DTLS_FATAL_ALERT_MESSAGE : Recv peer fatal alert message. + * @retval DTLS_PEER_CLOSE_NOTIFY : The DTLS session was closed by peer. + * @retval DTLS_READ_DATA_FAILED : Read data fail. + * @see None. + */ +DLL_HAL_API unsigned int HAL_DTLSSession_read(DTLSContext *context, + unsigned char *p_data, + unsigned int *p_datalen, + unsigned int timeout_ms) +{ + return (unsigned)1; +} + +/** + * @brief Write data into the specific DSSL connection. + * + * @param [in] context @n A descriptor identifying a connection. + * @param [in] p_data @n A pointer to a buffer containing the data to be transmitted. + * @param [in] p_datalen @n The length, in bytes, of the data pointed to by the 'p_data' parameter. + * @retval DTLS_SUCCESS : Success. + @retval other : Fail. + * @see None. + */ +DLL_HAL_API unsigned int HAL_DTLSSession_write(DTLSContext *context, + const unsigned char *p_data, + unsigned int *p_datalen) +{ + return (unsigned)1; +} + +extern void *HAL_Malloc(uint32_t size); +extern void HAL_Free(void *ptr); + +static ssl_hooks_t g_ssl_hooks = { HAL_Malloc, HAL_Free}; + +int32_t HAL_SSL_Destroy(uintptr_t handle) +{ + struct esp_tls *tls = (struct esp_tls *)handle; + + if (!tls) { + return ESP_FAIL; + } + + esp_tls_conn_delete(tls); + + return ESP_OK; +} + +uintptr_t HAL_SSL_Establish(const char *host, uint16_t port, const char *ca_crt, uint32_t ca_crt_len) +{ + esp_tls_cfg_t cfg = { + .cacert_pem_buf = (const unsigned char *)ca_crt, + .cacert_pem_bytes = ca_crt_len, + .timeout_ms = CONFIG_TLS_ESTABLISH_TIMEOUT_MS, + }; + +#ifdef CONFIG_IDF_TARGET_ESP8266 +#if ESP_IDF_VERSION >= 0x30300 + esp_set_cpu_freq(ESP_CPU_FREQ_160M); +#else + rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M); +#endif +#endif + struct esp_tls *tls = esp_tls_conn_new(host, strlen(host), port, &cfg); + +#ifdef CONFIG_IDF_TARGET_ESP8266 +#if ESP_IDF_VERSION >= 0x30300 + esp_set_cpu_freq(ESP_CPU_FREQ_80M); +#else + rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M); +#endif +#endif + + return (uintptr_t)tls; +} + +int HAL_SSLHooks_set(ssl_hooks_t *hooks) +{ + if (hooks == NULL || hooks->malloc == NULL || hooks->free == NULL) { + return ESP_FAIL; + } + + g_ssl_hooks.malloc = hooks->malloc; + g_ssl_hooks.free = hooks->free; + + return ESP_OK; +} + +static void HAL_utils_ms_to_timeval(int timeout_ms, struct timeval *tv) +{ + tv->tv_sec = timeout_ms / 1000; + tv->tv_usec = (timeout_ms - (tv->tv_sec * 1000)) * 1000; +} + +static int ssl_poll_read(esp_tls_t *tls, int timeout_ms) +{ + int ret = -1; + fd_set readset; + fd_set errset; + FD_ZERO(&readset); + FD_ZERO(&errset); + FD_SET(tls->sockfd, &readset); + FD_SET(tls->sockfd, &errset); + struct timeval timeout; + HAL_utils_ms_to_timeval(timeout_ms, &timeout); + ret = select(tls->sockfd + 1, &readset, NULL, &errset, &timeout); + if (ret > 0 && FD_ISSET(tls->sockfd, &errset)) { + int sock_errno = 0; + uint32_t optlen = sizeof(sock_errno); + getsockopt(tls->sockfd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen); + ESP_LOGE(TAG, "ssl_poll_read select error %d, errno = %s, fd = %d", sock_errno, strerror(sock_errno), tls->sockfd); + ret = -1; + } + return ret; +} + +int HAL_SSL_Read(uintptr_t handle, char *buf, int len, int timeout_ms) +{ + int poll, ret; + struct esp_tls *tls = (struct esp_tls *)handle; + + if (tls == NULL) { + ESP_LOGE(TAG, "HAL_SSL_Read, handle == NULL"); + return NULL_VALUE_ERROR; + } + + if (esp_tls_get_bytes_avail(tls) <= 0) { + if ((poll = ssl_poll_read(tls, timeout_ms)) <= 0) { + return poll; + } + } + + ret = esp_tls_conn_read(tls, (void *)buf, len); + + if (ret < 0) { + ESP_LOGE(TAG, "esp_tls_conn_read error, errno:%s", strerror(errno)); + } + if (ret == 0) { + ret = -1; + } + + return ret; +} + +static int ssl_poll_write(esp_tls_t *tls, int timeout_ms) +{ + int ret = -1; + fd_set writeset; + fd_set errset; + FD_ZERO(&writeset); + FD_ZERO(&errset); + FD_SET(tls->sockfd, &writeset); + FD_SET(tls->sockfd, &errset); + struct timeval timeout; + HAL_utils_ms_to_timeval(timeout_ms, &timeout); + ret = select(tls->sockfd + 1, NULL, &writeset, &errset, &timeout); + if (ret > 0 && FD_ISSET(tls->sockfd, &errset)) { + int sock_errno = 0; + uint32_t optlen = sizeof(sock_errno); + getsockopt(tls->sockfd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen); + ESP_LOGE(TAG, "ssl_poll_write select error %d, errno = %s, fd = %d", sock_errno, strerror(sock_errno), tls->sockfd); + ret = -1; + } + return ret; +} + +int HAL_SSL_Write(uintptr_t handle, const char *buf, int len, int timeout_ms) +{ + int poll, ret; + struct esp_tls *tls = (struct esp_tls *)handle; + + if (tls == NULL) { + ESP_LOGE(TAG, "HAL_SSL_Write, handle == NULL"); + return NULL_VALUE_ERROR; + } + + if ((poll = ssl_poll_write(tls, timeout_ms)) <= 0) { + ESP_LOGE(TAG, "ssl_poll_write return %d, timeout is %d", poll, timeout_ms); + return poll; + } + + ret = esp_tls_conn_write(tls, (const void *) buf, len); + + if (ret < 0) { + ESP_LOGE(TAG, "esp_tls_conn_write error, errno=%s", strerror(errno)); + } + + return ret; +} \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_udp.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_udp.c new file mode 100644 index 00000000..63fbda35 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_udp.c @@ -0,0 +1,422 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "infra_compat.h" +#include "wrappers_defs.h" + +#include + +#include +#include +#include +#include + +#include + +#include "esp_log.h" + +static const char *TAG = "udp"; + +static int hal_net_errno(int fd) +{ + int sock_errno = 0; + u32_t optlen = sizeof(sock_errno); + + getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen); + + return sock_errno; +} + + +int HAL_UDP_close_without_connect(intptr_t sockfd) +{ + return close((int)sockfd); +} + +intptr_t HAL_UDP_create(char *host, unsigned short port) +{ +#define NETWORK_ADDR_LEN (16) + + int rc = -1; + long socket_id = -1; + char port_ptr[6] = {0}; + struct addrinfo hints; + char addr[NETWORK_ADDR_LEN] = {0}; + struct addrinfo *res, *ainfo; + struct sockaddr_in *sa = NULL; + + if (NULL == host) { + return (-1); + } + + sprintf(port_ptr, "%u", port); + memset((char *)&hints, 0x00, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; + hints.ai_family = AF_INET; + hints.ai_protocol = IPPROTO_UDP; + + rc = getaddrinfo(host, port_ptr, &hints, &res); + + if (0 != rc) { + ESP_LOGE(TAG, "getaddrinfo error"); + return (-1); + } + + for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) { + if (AF_INET == ainfo->ai_family) { + sa = (struct sockaddr_in *)ainfo->ai_addr; + inet_ntop(AF_INET, &sa->sin_addr, addr, NETWORK_ADDR_LEN); + fprintf(stderr, "The host IP %s, port is %d\r\n", addr, ntohs(sa->sin_port)); + + socket_id = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); + + if (socket_id < 0) { + ESP_LOGE(TAG, "create socket error"); + continue; + } + + if (0 == connect(socket_id, ainfo->ai_addr, ainfo->ai_addrlen)) { + break; + } + + close(socket_id); + } + } + + freeaddrinfo(res); + + return socket_id; + +#undef NETWORK_ADDR_LEN + +} + +intptr_t HAL_UDP_create_without_connect(const char *host, unsigned short port) +{ + struct sockaddr_in addr; + int sockfd; + int opt_val = 1; + struct hostent *hp; + struct in_addr in; + uint32_t ip; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + + if (sockfd < 0) { + ESP_LOGE(TAG, "socket"); + return -1; + } + + if (0 == port) { + return (intptr_t)sockfd; + } + + memset(&addr, 0, sizeof(struct sockaddr_in)); + + if (0 != setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val))) { + ESP_LOGE(TAG, "setsockopt"); + close(sockfd); + return -1; + } + + + if (0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt_val, sizeof(opt_val))) { + ESP_LOGE(TAG, "setsockopt"); + close(sockfd); + return -1; + } + + if (NULL == host) { + addr.sin_addr.s_addr = htonl(INADDR_ANY); + } else { + if (inet_aton(host, &in)) { + ip = *(uint32_t *)∈ + } else { + hp = gethostbyname(host); + + if (!hp) { + ESP_LOGE(TAG, "can't resolute the host address \n"); + close(sockfd); + return -1; + } + + ip = *(uint32_t *)(hp->h_addr); + } + + addr.sin_addr.s_addr = ip; + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + if (-1 == bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) { + close(sockfd); + return -1; + } + + ESP_LOGI(TAG, "success to establish udp, fd=%d", sockfd); + + return (intptr_t)sockfd; + +} + + +int HAL_UDP_joinmulticast(intptr_t sockfd, + char *p_group) +{ + int err = -1; + int socket_id = -1; + + if (NULL == p_group) { + return -1; + } + + /*set loopback*/ + int loop = 0; + socket_id = (int)sockfd; + err = setsockopt(socket_id, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); + + if (err < 0) { + ESP_LOGE(TAG, "setsockopt"); + return err; + } + + struct ip_mreq mreq; + + mreq.imr_multiaddr.s_addr = inet_addr(p_group); + + mreq.imr_interface.s_addr = htonl(INADDR_ANY); /*default networt interface*/ + + /*join to the multicast group*/ + err = setsockopt(socket_id, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); + + if (err < 0) { + ESP_LOGE(TAG, "setsockopt"); + return err; + } + + return 0; + +} + +/** + * @brief Read data from the specific UDP connection by blocked + * + * @param [in] p_socket @n A descriptor identifying a UDP connection. + * @param [in] p_data @n A pointer to a buffer to receive incoming data. + * @param [out] datalen @n The length, in bytes, of the data pointed to by the 'p_data' parameter. + * @return + * + * @retval < 0 : UDP connect error occur. + * @retval = 0 : End of file. + * @retval > 0 : The number of byte read. + * @see None. + */ +int HAL_UDP_read(intptr_t p_socket, + unsigned char *p_data, + unsigned int datalen) +{ + long socket_id = -1; + int count = -1; + + if (NULL == p_data || 0 == p_socket) { + return -1; + } + + socket_id = (long)p_socket; + count = (int)read(socket_id, p_data, datalen); + + return count; +} + + +int HAL_UDP_readTimeout(intptr_t p_socket, + unsigned char *p_data, + unsigned int datalen, + unsigned int timeout) +{ + int ret; + struct timeval tv; + fd_set read_fds; + long socket_id = -1; + + if (0 == p_socket || NULL == p_data) { + return -1; + } + + socket_id = (long)p_socket; + + if (socket_id < 0) { + return -1; + } + + FD_ZERO(&read_fds); + FD_SET(socket_id, &read_fds); + + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + ret = select(socket_id + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv); + + /* Zero fds ready means we timed out */ + if (ret == 0) { + return -2; /* receive timeout */ + } + + if (ret < 0) { + if (hal_net_errno(socket_id) == EINTR) { + return -3; /* want read */ + } + + return -4; /* receive failed */ + } + + /* This call will not block */ + return HAL_UDP_read(p_socket, p_data, datalen); + +} + + +int HAL_UDP_recvfrom(intptr_t sockfd, + NetworkAddr *p_remote, + unsigned char *p_data, + unsigned int datalen, + unsigned int timeout_ms) +{ + //printf("==========HAL_UDP_recvfromtimeout_ms :%d============\n",timeout_ms); + int ret; + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + fd_set read_fds; + struct timeval timeout = {timeout_ms / 1000, (timeout_ms % 1000) * 1000}; + + FD_ZERO(&read_fds); + FD_SET(sockfd, &read_fds); + + ret = select(sockfd + 1, &read_fds, NULL, NULL, &timeout); + + if (ret == 0) { + return 0; /* receive timeout */ + } + + if (ret < 0) { + if (hal_net_errno(sockfd) == EINTR) { + return -3; /* want read */ + } + + return -4; /* receive failed */ + } + + ret = recvfrom(sockfd, p_data, datalen, 0, (struct sockaddr *)&addr, &addr_len); + + if (ret > 0) { + if (NULL != p_remote) { + p_remote->port = ntohs(addr.sin_port); + + strcpy((char *)p_remote->addr, inet_ntoa(addr.sin_addr)); + } + + return ret; + } + + return -1; + +} + + +int HAL_UDP_sendto(intptr_t sockfd, + const NetworkAddr *p_remote, + const unsigned char *p_data, + unsigned int datalen, + unsigned int timeout_ms) +{ + int ret; + uint32_t ip; + struct in_addr in; + struct hostent *hp; + struct sockaddr_in addr; + fd_set write_fds; + struct timeval timeout = {timeout_ms / 1000, (timeout_ms % 1000) * 1000}; + + if (inet_aton((char *)p_remote->addr, &in)) { + ip = *(uint32_t *)∈ + } else { + hp = gethostbyname((char *)p_remote->addr); + + if (!hp) { + ESP_LOGE(TAG, "can't resolute the host address \n"); + return -1; + } + + ip = *(uint32_t *)(hp->h_addr); + } + + FD_ZERO(&write_fds); + FD_SET(sockfd, &write_fds); + + ret = select(sockfd + 1, NULL, &write_fds, NULL, &timeout); + + if (ret == 0) { + return 0; /* write timeout */ + } + + if (ret < 0) { + if (hal_net_errno(sockfd) == EINTR) { + return -3; /* want write */ + } + + return -4; /* write failed */ + } + + addr.sin_addr.s_addr = ip; + addr.sin_family = AF_INET; + addr.sin_port = htons(p_remote->port); + + ret = sendto(sockfd, p_data, datalen, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + + if (ret < 0) { + ESP_LOGE(TAG, "sendto"); + } + + return (ret) > 0 ? ret : -1; + +} + + +int HAL_UDP_write(intptr_t p_socket, + const unsigned char *p_data, + unsigned int datalen) +{ + int rc = -1; + long socket_id = -1; + + socket_id = (long)p_socket; + rc = send(socket_id, (char *)p_data, (int)datalen, 0); + + if (-1 == rc) { + return -1; + } + + return rc; +} \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_wifi.c b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_wifi.c new file mode 100644 index 00000000..a7777647 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrapper_wifi.c @@ -0,0 +1,206 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include + +#include "iot_import_awss.h" + +#include "esp_log.h" +#include "esp_wifi.h" + +static const char *TAG = "wifi"; + +static awss_wifi_mgmt_frame_cb_t s_awss_mgmt_frame_cb = NULL; +static uint8_t s_esp_oui[3] = { 0 }; + +typedef void (*wifi_sta_rx_probe_req_t)(const uint8_t *frame, int len, int rssi); +extern esp_err_t esp_wifi_set_sta_rx_probe_req(wifi_sta_rx_probe_req_t cb); +extern void *HAL_Malloc(uint32_t size); +extern void *HAL_Realloc(void *ptr, uint32_t size); +extern void HAL_Free(void *ptr); + +static void wifi_sta_rx_probe_req(const uint8_t *frame, int len, int rssi) +{ + //Notice: The number must be sync to function awss_init_enrollee_info logic to decode data format + //42 = ZC_PROBE_LEN - FCS_SIZE; + vendor_ie_data_t *awss_ie_info = (vendor_ie_data_t *)(frame + 42); + // vendor_oui is {0xD8, 0x96, 0xE0} + if (awss_ie_info->element_id == WIFI_VENDOR_IE_ELEMENT_ID && awss_ie_info->length != 0 && !memcmp(awss_ie_info->vendor_oui, s_esp_oui, 3)) { + if (awss_ie_info->vendor_oui_type == 171) { // 171 = WLAN_OUI_TYPE_ENROLLEE + ESP_LOGW(TAG, "frame is no support, awss_ie_info->type: %d", awss_ie_info->vendor_oui_type); + return; + } + if (s_awss_mgmt_frame_cb) { + s_awss_mgmt_frame_cb((uint8_t *)awss_ie_info, awss_ie_info->length + 2, rssi, 1); + } + } +} + +int HAL_Wifi_Enable_Mgmt_Frame_Filter( + _IN_ uint32_t filter_mask, + _IN_OPT_ uint8_t vendor_oui[3], + _IN_ awss_wifi_mgmt_frame_cb_t callback) +{ + if (!callback || filter_mask != (FRAME_PROBE_REQ_MASK | FRAME_BEACON_MASK)) { + return NULL_VALUE_ERROR; + } + + s_awss_mgmt_frame_cb = callback; + memcpy(s_esp_oui, vendor_oui, sizeof(s_esp_oui)); + esp_err_t ret = esp_wifi_set_sta_rx_probe_req(wifi_sta_rx_probe_req); + + return ret == ESP_OK ? SUCCESS_RETURN : FAIL_RETURN; +} + +int HAL_Wifi_Get_Ap_Info(char ssid[HAL_MAX_SSID_LEN], char passwd[HAL_MAX_PASSWD_LEN], uint8_t bssid[ETH_ALEN]) +{ + esp_err_t ret = ESP_FAIL; + wifi_ap_record_t ap_info; + + do { + memset(&ap_info, 0, sizeof(wifi_ap_record_t)); + ret = esp_wifi_sta_get_ap_info(&ap_info); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Get AP info fail, err=0x%x", ret); + break; + } + + if (ssid) { + memcpy(ssid, ap_info.ssid, HAL_MAX_SSID_LEN); + } + + if (bssid) { + memcpy(bssid, ap_info.bssid, ETH_ALEN); + } + + if (ap_info.authmode != WIFI_AUTH_OPEN && passwd) { + wifi_config_t wifi_cfg; + if (esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_cfg) == ESP_OK) { + if (wifi_cfg.sta.password) { + memcpy(passwd, wifi_cfg.sta.password, HAL_MAX_PASSWD_LEN); + } + } + + } + } while (0); + + return (ret == ESP_OK) ? SUCCESS_RETURN : FAIL_RETURN; +} + +uint32_t HAL_Wifi_Get_IP(char ip_str[NETWORK_ADDR_LEN], const char *ifname) +{ + esp_err_t ret = 0; + tcpip_adapter_ip_info_t info; + wifi_mode_t mode; + + ret = esp_wifi_get_mode(&mode); + + if (ret != ESP_OK) { + return 0; + } + + ret = tcpip_adapter_get_ip_info((mode == WIFI_MODE_STA) ? TCPIP_ADAPTER_IF_STA : TCPIP_ADAPTER_IF_AP, &info); + + if (ret != ESP_OK) { + return 0; + } + + memcpy(ip_str, inet_ntoa(info.ip.addr), NETWORK_ADDR_LEN); + + return info.ip.addr; +} + +char *HAL_Wifi_Get_Mac(char mac_str[HAL_MAC_LEN]) +{ + esp_err_t ret = 0; + uint8_t mac[6] = {0}; + wifi_mode_t mode; + + ret = esp_wifi_get_mode(&mode); + + if (ret != ESP_OK) { + return NULL; + } + + ret = esp_wifi_get_mac((mode == WIFI_MODE_AP) ? WIFI_MODE_AP - 1 : WIFI_MODE_STA - 1, mac); + + if (ret != ESP_OK) { + return NULL; + } + + snprintf(mac_str, HAL_MAC_LEN, MACSTR, MAC2STR(mac)); + return (char *)mac_str; +} + +int HAL_Wifi_Scan(awss_wifi_scan_result_cb_t cb) +{ + esp_err_t ret = ESP_OK; + uint16_t wifi_ap_num = 0; + wifi_ap_record_t *ap_info = NULL; + wifi_scan_config_t scan_config = { + .show_hidden = 0, + .scan_type = 0, + .scan_time = { + .passive = 0, + .active = { + .min = 100, + .max = 200 + } + } + }; + + ret = esp_wifi_scan_start(&scan_config, true); + ret |= esp_wifi_scan_get_ap_num(&wifi_ap_num); + if (wifi_ap_num) { + ap_info = (wifi_ap_record_t *)HAL_Malloc(sizeof(wifi_ap_record_t) * wifi_ap_num); + ret |= esp_wifi_scan_get_ap_records(&wifi_ap_num, ap_info); + if (ret == ESP_OK && cb) { + for (int i = 0; i < wifi_ap_num; ++i) { + cb((char *)ap_info[i].ssid, (uint8_t *)ap_info[i].bssid, ap_info[i].authmode, AWSS_ENC_TYPE_INVALID, + ap_info[i].primary, ap_info[i].rssi, 1); + } + } + HAL_Free(ap_info); + } + + esp_wifi_scan_stop(); + + return (ret == ESP_OK) ? SUCCESS_RETURN : FAIL_RETURN; +} + +int HAL_Wifi_Send_80211_Raw_Frame(_IN_ enum HAL_Awss_Frame_Type type, + _IN_ uint8_t *buffer, _IN_ int len) +{ + esp_err_t ret = ESP_OK; + + if (!buffer) { + return NULL_VALUE_ERROR; + } + + ret = esp_wifi_80211_tx(ESP_IF_WIFI_STA, buffer, len, true); + + return (ret == ESP_OK) ? SUCCESS_RETURN : FAIL_RETURN; +} \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrappers_defs.h b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrappers_defs.h new file mode 100644 index 00000000..1ed0d0ad --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/esp-aliyun/wrappers/wrappers_defs.h @@ -0,0 +1,58 @@ +#ifndef _WRAPPERS_DEFS_H_ +#define _WRAPPERS_DEFS_H_ + +#include "infra_types.h" +#include "infra_defs.h" + +#define PLATFORM_WAIT_INFINITE (~0) + +typedef struct { + void *(*malloc)(uint32_t size); + void (*free)(void *ptr); +} ssl_hooks_t; + +typedef enum { + os_thread_priority_idle = -3, /* priority: idle (lowest) */ + os_thread_priority_low = -2, /* priority: low */ + os_thread_priority_belowNormal = -1, /* priority: below normal */ + os_thread_priority_normal = 0, /* priority: normal (default) */ + os_thread_priority_aboveNormal = 1, /* priority: above normal */ + os_thread_priority_high = 2, /* priority: high */ + os_thread_priority_realtime = 3, /* priority: realtime (highest) */ + os_thread_priority_error = 0x84, /* system cannot determine priority or thread has illegal priority */ +} hal_os_thread_priority_t; + +typedef struct _hal_os_thread { + hal_os_thread_priority_t priority; /*initial thread priority */ + void *stack_addr; /* thread stack address malloced by caller, use system stack by . */ + int stack_size; /* stack size requirements in bytes; 0 is default stack size */ + int detach_state; /* 0: not detached state; otherwise: detached state. */ + char *name; /* thread name. */ +} hal_os_thread_param_t; + +#define DTLS_ERROR_BASE (1<<24) +#define DTLS_SUCCESS (0) +#define DTLS_INVALID_PARAM (DTLS_ERROR_BASE | 1) +#define DTLS_INVALID_CA_CERTIFICATE (DTLS_ERROR_BASE | 2) +#define DTLS_HANDSHAKE_IN_PROGRESS (DTLS_ERROR_BASE | 3) +#define DTLS_HANDSHAKE_FAILED (DTLS_ERROR_BASE | 4) +#define DTLS_FATAL_ALERT_MESSAGE (DTLS_ERROR_BASE | 5) +#define DTLS_PEER_CLOSE_NOTIFY (DTLS_ERROR_BASE | 6) +#define DTLS_SESSION_CREATE_FAILED (DTLS_ERROR_BASE | 7) +#define DTLS_READ_DATA_FAILED (DTLS_ERROR_BASE | 8) + +typedef struct { + void *(*malloc)(uint32_t size); + void (*free)(void *ptr); +} dtls_hooks_t; + +typedef struct { + unsigned char *p_ca_cert_pem; + char *p_host; + unsigned short port; +} coap_dtls_options_t; + +typedef void DTLSContext; + +#endif + diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/main/CMakeLists.txt b/sdk/ESP-IDF/esp_fastbee_aliyun/main/CMakeLists.txt new file mode 100644 index 00000000..62f663ae --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/main/CMakeLists.txt @@ -0,0 +1,9 @@ +set(COMPONENT_ADD_INCLUDEDIRS ".") + +# Edit following two lines to set component requirements (see docs) +set(COMPONENT_REQUIRES ) +set(COMPONENT_PRIV_REQUIRES ) + +set(COMPONENT_SRCS ./app_main.c) + +register_component() diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/main/Kconfig.projbuild b/sdk/ESP-IDF/esp_fastbee_aliyun/main/Kconfig.projbuild new file mode 100644 index 00000000..71df7dee --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/main/Kconfig.projbuild @@ -0,0 +1,65 @@ +menu "WIFI Configuration" + + config ESP_WIFI_SSID + string "WiFi SSID" + default "myssid" + help + SSID (network name) for the example to connect to. + + config ESP_WIFI_PASSWORD + string "WiFi Password" + default "mypassword" + help + WiFi password (WPA or WPA2) for the example to use. + +endmenu + +menu "Platform Configuration" + choice ESP_MQTT_PLATFORM + prompt "The platform connected by mqtt" + default ESP_MQTT_PLATFORM_FASTBEE + help + The platform connected by mqtt. + config ESP_MQTT_PLATFORM_ALIYUN + bool "aliyun" + config ESP_MQTT_PLATFORM_FASTBEE + bool "fastbee" + endchoice + + config ESP_MQTT_PLATFORM_FASTBEE_URL + string "MQTT URL" + default "fastbee.cn:1883" + help + MQTT URL. + + config ESP_MQTT_PLATFORM_FASTBEE_USERNAME + string "MQTT Username" + default "FastBee" + help + MQTT Username. + + config ESP_MQTT_PLATFORM_FASTBEE_PASSWORD + string "MQTT Password" + default "P63653937TRQ8F27" + help + MQTT Password. + + config ESP_MQTT_PLATFORM_FASTBEE_USERID + string "Platform user ID" + default "1" + help + Platform user ID. + + config ESP_MQTT_PLATFORM_FASTBEE_PRODICTID + string "Platform product ID" + default "588" + help + Platform product ID. + + config ESP_MQTT_PLATFORM_FASTBEE_DEVICESN + string "Platform device serial number" + default "D1FJTWOT3HIB" + help + Platform device serial number + +endmenu diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/main/app_main.c b/sdk/ESP-IDF/esp_fastbee_aliyun/main/app_main.c new file mode 100644 index 00000000..124ec308 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/main/app_main.c @@ -0,0 +1,223 @@ +/* + * ESPRSSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_err.h" +#include "esp_event.h" +#include "esp_log.h" + +#include "infra_compat.h" +#include "linkkit_solo.h" +#include "factory_restore.h" +#include "lightbulb.h" +#include "fastbee.h" +#include "conn_mgr.h" + +static const char *TAG = "app main"; + +static bool linkkit_started = false; +static bool fastbee_started = false; + +static esp_err_t wifi_event_handle(void *ctx, system_event_t *event) +{ + switch (event->event_id) { + case SYSTEM_EVENT_STA_GOT_IP: +#ifdef CONFIG_ESP_MQTT_PLATFORM_ALIYUN + if (linkkit_started == false) { + wifi_config_t wifi_config = {0}; + if (conn_mgr_get_wifi_config(&wifi_config) == ESP_OK && + strcmp((char *)(wifi_config.sta.ssid), HOTSPOT_AP) && + strcmp((char *)(wifi_config.sta.ssid), ROUTER_AP)) { + xTaskCreate((void (*)(void *))linkkit_main, "lightbulb", 10240, NULL, 5, NULL); + linkkit_started = true; + } + } +#endif +#ifdef CONFIG_ESP_MQTT_PLATFORM_FASTBEE + if (fastbee_started == false) { + wifi_config_t wifi_config = {0}; + if (conn_mgr_get_wifi_config(&wifi_config) == ESP_OK && + strcmp((char *)(wifi_config.sta.ssid), HOTSPOT_AP) && + strcmp((char *)(wifi_config.sta.ssid), ROUTER_AP)) { + xTaskCreate((void (*)(void *))fastbee_main, "lightbulb", 10240, NULL, 5, NULL); + fastbee_started = true; + } + } +#endif + break; + + default: + break; + } + + return ESP_OK; +} + +static void linkkit_event_monitor(int event) +{ + switch (event) { + case IOTX_AWSS_START: // AWSS start without enbale, just supports device discover + // operate led to indicate user + ESP_LOGI(TAG, "IOTX_AWSS_START"); + break; + + case IOTX_AWSS_ENABLE: // AWSS enable, AWSS doesn't parse awss packet until AWSS is enabled. + ESP_LOGI(TAG, "IOTX_AWSS_ENABLE"); + // operate led to indicate user + break; + + case IOTX_AWSS_LOCK_CHAN: // AWSS lock channel(Got AWSS sync packet) + ESP_LOGI(TAG, "IOTX_AWSS_LOCK_CHAN"); + // operate led to indicate user + break; + + case IOTX_AWSS_PASSWD_ERR: // AWSS decrypt passwd error + ESP_LOGE(TAG, "IOTX_AWSS_PASSWD_ERR"); + // operate led to indicate user + break; + + case IOTX_AWSS_GOT_SSID_PASSWD: + ESP_LOGI(TAG, "IOTX_AWSS_GOT_SSID_PASSWD"); + // operate led to indicate user + break; + + case IOTX_AWSS_CONNECT_ADHA: // AWSS try to connnect adha (device + // discover, router solution) + ESP_LOGI(TAG, "IOTX_AWSS_CONNECT_ADHA"); + // operate led to indicate user + break; + + case IOTX_AWSS_CONNECT_ADHA_FAIL: // AWSS fails to connect adha + ESP_LOGE(TAG, "IOTX_AWSS_CONNECT_ADHA_FAIL"); + // operate led to indicate user + break; + + case IOTX_AWSS_CONNECT_AHA: // AWSS try to connect aha (AP solution) + ESP_LOGI(TAG, "IOTX_AWSS_CONNECT_AHA"); + // operate led to indicate user + break; + + case IOTX_AWSS_CONNECT_AHA_FAIL: // AWSS fails to connect aha + ESP_LOGE(TAG, "IOTX_AWSS_CONNECT_AHA_FAIL"); + // operate led to indicate user + break; + + case IOTX_AWSS_SETUP_NOTIFY: // AWSS sends out device setup information + // (AP and router solution) + ESP_LOGI(TAG, "IOTX_AWSS_SETUP_NOTIFY"); + // operate led to indicate user + break; + + case IOTX_AWSS_CONNECT_ROUTER: // AWSS try to connect destination router + ESP_LOGI(TAG, "IOTX_AWSS_CONNECT_ROUTER"); + // operate led to indicate user + break; + + case IOTX_AWSS_CONNECT_ROUTER_FAIL: // AWSS fails to connect destination + // router. + ESP_LOGE(TAG, "IOTX_AWSS_CONNECT_ROUTER_FAIL"); + // operate led to indicate user + break; + + case IOTX_AWSS_GOT_IP: // AWSS connects destination successfully and got + // ip address + ESP_LOGI(TAG, "IOTX_AWSS_GOT_IP"); + // operate led to indicate user + break; + + case IOTX_AWSS_SUC_NOTIFY: // AWSS sends out success notify (AWSS + // sucess) + ESP_LOGI(TAG, "IOTX_AWSS_SUC_NOTIFY"); + // operate led to indicate user + break; + + case IOTX_AWSS_BIND_NOTIFY: // AWSS sends out bind notify information to + // support bind between user and device + ESP_LOGI(TAG, "IOTX_AWSS_BIND_NOTIFY"); + // operate led to indicate user + break; + + case IOTX_AWSS_ENABLE_TIMEOUT: // AWSS enable timeout + // user needs to enable awss again to support get ssid & passwd of router + ESP_LOGW(TAG, "IOTX_AWSS_ENALBE_TIMEOUT"); + // operate led to indicate user + break; + + case IOTX_CONN_CLOUD: // Device try to connect cloud + ESP_LOGI(TAG, "IOTX_CONN_CLOUD"); + // operate led to indicate user + break; + + case IOTX_CONN_CLOUD_FAIL: // Device fails to connect cloud, refer to + // net_sockets.h for error code + ESP_LOGE(TAG, "IOTX_CONN_CLOUD_FAIL"); + // operate led to indicate user + break; + + case IOTX_CONN_CLOUD_SUC: // Device connects cloud successfully + ESP_LOGI(TAG, "IOTX_CONN_CLOUD_SUC"); + // operate led to indicate user + break; + + case IOTX_RESET: // Linkkit reset success (just got reset response from + // cloud without any other operation) + ESP_LOGI(TAG, "IOTX_RESET"); + // operate led to indicate user + break; + + default: + break; + } +} + +static void start_conn_mgr() +{ + iotx_event_regist_cb(linkkit_event_monitor); // awss callback + conn_mgr_start(); + + vTaskDelete(NULL); +} + +void app_main() +{ + factory_restore_init(); + + lightbulb_init(); + + conn_mgr_init(); + conn_mgr_register_wifi_event(wifi_event_handle); + //conn_mgr_init_wifi_config(); + + IOT_SetLogLevel(IOT_LOG_INFO); + +#ifdef CONFIG_USE_SOFTAP_CONFIG + conn_mgr_set_sc_mode(CONN_SOFTAP_MODE); +#else + conn_mgr_set_sc_mode(CONN_SC_ZERO_MODE); +#endif + xTaskCreate((void (*)(void *))start_conn_mgr, "conn_mgr", 3072, NULL, 5, NULL); +} diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/main/component.mk b/sdk/ESP-IDF/esp_fastbee_aliyun/main/component.mk new file mode 100644 index 00000000..e69de29b diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/partitions_esp32.csv b/sdk/ESP-IDF/esp_fastbee_aliyun/partitions_esp32.csv new file mode 100644 index 00000000..787847de --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/partitions_esp32.csv @@ -0,0 +1,8 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, , 0x4000, +otadata, data, ota, , 0x2000, +phy_init, data, phy, , 0x1000, +ota_0, app, ota_0, , 1M, +ota_1, app, ota_1, , 1M, +fctry, data, nvs, , 0x4000 diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/partitions_esp32s2.csv b/sdk/ESP-IDF/esp_fastbee_aliyun/partitions_esp32s2.csv new file mode 100644 index 00000000..787847de --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/partitions_esp32s2.csv @@ -0,0 +1,8 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, , 0x4000, +otadata, data, ota, , 0x2000, +phy_init, data, phy, , 0x1000, +ota_0, app, ota_0, , 1M, +ota_1, app, ota_1, , 1M, +fctry, data, nvs, , 0x4000 diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/partitions_esp32s3.csv b/sdk/ESP-IDF/esp_fastbee_aliyun/partitions_esp32s3.csv new file mode 100644 index 00000000..787847de --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/partitions_esp32s3.csv @@ -0,0 +1,8 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, , 0x4000, +otadata, data, ota, , 0x2000, +phy_init, data, phy, , 0x1000, +ota_0, app, ota_0, , 1M, +ota_1, app, ota_1, , 1M, +fctry, data, nvs, , 0x4000 diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/partitions_esp8266.csv b/sdk/ESP-IDF/esp_fastbee_aliyun/partitions_esp8266.csv new file mode 100644 index 00000000..4837cd47 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/partitions_esp8266.csv @@ -0,0 +1,8 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, 0x9000, 0x4000 +otadata, data, ota, 0xd000, 0x2000 +phy_init, data, phy, 0xf000, 0x1000 +ota_0, 0, ota_0, 0x10000, 0xF0000 +fctry, data, nvs, 0x100000,0x4000 +ota_1, 0, ota_1, 0x110000,0xF0000 diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig new file mode 100644 index 00000000..6cb3deb7 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig @@ -0,0 +1,1569 @@ +# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) Project Configuration +# +CONFIG_IDF_CMAKE=y +CONFIG_IDF_TARGET_ARCH_XTENSA=y +CONFIG_IDF_TARGET="esp32s3" +CONFIG_IDF_TARGET_ESP32S3=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0009 + +# +# SDK tool configuration +# +CONFIG_SDK_TOOLPREFIX="xtensa-esp32s3-elf-" +# CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set +# end of SDK tool configuration + +# +# Build type +# +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +CONFIG_APP_BUILD_GENERATE_BINARIES=y +CONFIG_APP_BUILD_BOOTLOADER=y +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# end of Build type + +# +# Application manager +# +CONFIG_APP_COMPILE_TIME_DATE=y +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 +# end of Application manager + +# +# Bootloader config +# +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0 +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set +CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y +# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set +CONFIG_BOOTLOADER_LOG_LEVEL=3 + +# +# Serial Flash Configurations +# +# CONFIG_BOOTLOADER_FLASH_DC_AWARE is not set +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y +# end of Serial Flash Configurations + +CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y +# CONFIG_BOOTLOADER_FACTORY_RESET is not set +# CONFIG_BOOTLOADER_APP_TEST is not set +CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y +CONFIG_BOOTLOADER_WDT_ENABLE=y +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 +# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +# end of Bootloader config + +# +# Security features +# +CONFIG_SECURE_BOOT_SUPPORTS_RSA=y +CONFIG_SECURE_TARGET_HAS_SECURE_ROM_DL_MODE=y +# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set +# CONFIG_SECURE_BOOT is not set +# CONFIG_SECURE_FLASH_ENC_ENABLED is not set +# end of Security features + +# +# Boot ROM Behavior +# +CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y +# CONFIG_BOOT_ROM_LOG_ALWAYS_OFF is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW is not set +# end of Boot ROM Behavior + +# +# Serial flasher config +# +CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200 +# CONFIG_ESPTOOLPY_NO_STUB is not set +# CONFIG_ESPTOOLPY_OCT_FLASH is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +CONFIG_ESPTOOLPY_S3_STR=y +# CONFIG_ESPTOOLPY_FLASHFREQ_120M is not set +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +CONFIG_ESPTOOLPY_FLASHFREQ="80m" +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" +CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER="hard_reset" +# CONFIG_ESPTOOLPY_MONITOR_BAUD_CONSOLE is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set +CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y +# CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set +CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200 +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# +# CONFIG_PARTITION_TABLE_SINGLE_APP is not set +# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32s3.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_esp32s3.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# WIFI Configuration +# +CONFIG_ESP_WIFI_SSID="myssid" +CONFIG_ESP_WIFI_PASSWORD="mypassword" +# end of WIFI Configuration + +# +# Platform Configuration +# +# CONFIG_ESP_MQTT_PLATFORM_ALIYUN is not set +CONFIG_ESP_MQTT_PLATFORM_FASTBEE=y +CONFIG_ESP_MQTT_PLATFORM_FASTBEE_URL="fastbee.cn:1883" +CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERNAME="FastBee" +CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PASSWORD="P63653937TRQ8F27" +CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERID="1" +CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PRODICTID="588" +CONFIG_ESP_MQTT_PLATFORM_FASTBEE_DEVICESN="D1FJTWOT3HIB" +# end of Platform Configuration + +# +# [Aliyun]Factory restore +# +CONFIG_FACTORY_QUICK_REBOOT_TIMEOUT=6 +CONFIG_FACTORY_QUICK_REBOOT_MAX_TIMES=5 +# end of [Aliyun]Factory restore + +# +# Compiler options +# +CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y +# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set +# CONFIG_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +# CONFIG_COMPILER_CXX_EXCEPTIONS is not set +# CONFIG_COMPILER_CXX_RTTI is not set +CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y +# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set +# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set +# CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +# end of Compiler options + +# +# Component config +# + +# +# Application Level Tracing +# +# CONFIG_APPTRACE_DEST_JTAG is not set +CONFIG_APPTRACE_DEST_NONE=y +CONFIG_APPTRACE_LOCK_ENABLE=y +# end of Application Level Tracing + +# +# ESP-ASIO +# +# CONFIG_ASIO_SSL_SUPPORT is not set +# end of ESP-ASIO + +# +# Bluetooth +# +# CONFIG_BT_ENABLED is not set +# end of Bluetooth + +# +# CoAP Configuration +# +CONFIG_COAP_MBEDTLS_PSK=y +# CONFIG_COAP_MBEDTLS_PKI is not set +# CONFIG_COAP_MBEDTLS_DEBUG is not set +CONFIG_COAP_LOG_DEFAULT_LEVEL=0 +# end of CoAP Configuration + +# +# Driver configurations +# + +# +# ADC configuration +# +# CONFIG_ADC_FORCE_XPD_FSM is not set +CONFIG_ADC_DISABLE_DAC=y +# CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3 is not set +# end of ADC configuration + +# +# MCPWM configuration +# +# CONFIG_MCPWM_ISR_IN_IRAM is not set +# end of MCPWM configuration + +# +# SPI configuration +# +# CONFIG_SPI_MASTER_IN_IRAM is not set +CONFIG_SPI_MASTER_ISR_IN_IRAM=y +# CONFIG_SPI_SLAVE_IN_IRAM is not set +CONFIG_SPI_SLAVE_ISR_IN_IRAM=y +# end of SPI configuration + +# +# TWAI configuration +# +# CONFIG_TWAI_ISR_IN_IRAM is not set +# CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM is not set +# end of TWAI configuration + +# +# UART configuration +# +# CONFIG_UART_ISR_IN_IRAM is not set +# end of UART configuration + +# +# GDMA Configuration +# +# CONFIG_GDMA_CTRL_FUNC_IN_IRAM is not set +# CONFIG_GDMA_ISR_IRAM_SAFE is not set +# end of GDMA Configuration +# end of Driver configurations + +# +# eFuse Bit Manager +# +# CONFIG_EFUSE_CUSTOM_TABLE is not set +# CONFIG_EFUSE_VIRTUAL is not set +CONFIG_EFUSE_MAX_BLK_LEN=256 +# end of eFuse Bit Manager + +# +# ESP-TLS +# +CONFIG_ESP_TLS_USING_MBEDTLS=y +CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y +# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER is not set +# CONFIG_ESP_TLS_PSK_VERIFICATION is not set +# CONFIG_ESP_TLS_INSECURE is not set +# end of ESP-TLS + +# +# ESP32S3-Specific +# +CONFIG_ESP32S3_REV_MIN_0=y +# CONFIG_ESP32S3_REV_MIN_1 is not set +# CONFIG_ESP32S3_REV_MIN_2 is not set +CONFIG_ESP32S3_REV_MIN_FULL=0 +CONFIG_ESP_REV_MIN_FULL=0 +CONFIG_ESP32S3_REV_MAX_FULL_STR_OPT=y +CONFIG_ESP32S3_REV_MAX_FULL=99 +CONFIG_ESP_REV_MAX_FULL=99 +# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_80 is not set +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160=y +# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240 is not set +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=160 + +# +# Cache config +# +CONFIG_ESP32S3_INSTRUCTION_CACHE_16KB=y +# CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB is not set +CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE=0x4000 +# CONFIG_ESP32S3_INSTRUCTION_CACHE_4WAYS is not set +CONFIG_ESP32S3_INSTRUCTION_CACHE_8WAYS=y +CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS=8 +# CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_16B is not set +CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_32B=y +CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE=32 +# CONFIG_ESP32S3_INSTRUCTION_CACHE_WRAP is not set +# CONFIG_ESP32S3_DATA_CACHE_16KB is not set +CONFIG_ESP32S3_DATA_CACHE_32KB=y +# CONFIG_ESP32S3_DATA_CACHE_64KB is not set +CONFIG_ESP32S3_DATA_CACHE_SIZE=0x8000 +# CONFIG_ESP32S3_DATA_CACHE_4WAYS is not set +CONFIG_ESP32S3_DATA_CACHE_8WAYS=y +CONFIG_ESP32S3_DCACHE_ASSOCIATED_WAYS=8 +# CONFIG_ESP32S3_DATA_CACHE_LINE_16B is not set +CONFIG_ESP32S3_DATA_CACHE_LINE_32B=y +# CONFIG_ESP32S3_DATA_CACHE_LINE_64B is not set +CONFIG_ESP32S3_DATA_CACHE_LINE_SIZE=32 +# CONFIG_ESP32S3_DATA_CACHE_WRAP is not set +# end of Cache config + +# CONFIG_ESP32S3_SPIRAM_SUPPORT is not set +# CONFIG_ESP32S3_TRAX is not set +CONFIG_ESP32S3_TRACEMEM_RESERVE_DRAM=0x0 +# CONFIG_ESP32S3_ULP_COPROC_ENABLED is not set +CONFIG_ESP32S3_ULP_COPROC_RESERVE_MEM=0 +CONFIG_ESP32S3_DEBUG_OCDAWARE=y +CONFIG_ESP32S3_BROWNOUT_DET=y +CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_7=y +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_1 is not set +CONFIG_ESP32S3_BROWNOUT_DET_LVL=7 +CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC_FRC1=y +# CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC is not set +# CONFIG_ESP32S3_TIME_SYSCALL_USE_FRC1 is not set +# CONFIG_ESP32S3_TIME_SYSCALL_USE_NONE is not set +CONFIG_ESP32S3_RTC_CLK_SRC_INT_RC=y +# CONFIG_ESP32S3_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_ESP32S3_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_ESP32S3_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_ESP32S3_RTC_CLK_CAL_CYCLES=1024 +CONFIG_ESP32S3_DEEP_SLEEP_WAKEUP_DELAY=2000 +# CONFIG_ESP32S3_NO_BLOBS is not set +# CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM is not set +# CONFIG_ESP32S3_USE_FIXED_STATIC_RAM_SIZE is not set +# end of ESP32S3-Specific + +# +# ADC-Calibration +# +# end of ADC-Calibration + +# +# Common ESP-related +# +CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +# end of Common ESP-related + +# +# Ethernet +# +CONFIG_ETH_ENABLED=y +CONFIG_ETH_USE_SPI_ETHERNET=y +# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set +# CONFIG_ETH_SPI_ETHERNET_W5500 is not set +# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set +# CONFIG_ETH_USE_OPENETH is not set +# end of Ethernet + +# +# Event Loop Library +# +# CONFIG_ESP_EVENT_LOOP_PROFILING is not set +CONFIG_ESP_EVENT_POST_FROM_ISR=y +CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y +# end of Event Loop Library + +# +# GDB Stub +# +# end of GDB Stub + +# +# ESP HTTP client +# +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y +# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set +CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH=y +# end of ESP HTTP client + +# +# HTTP Server +# +CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_URI_LEN=512 +CONFIG_HTTPD_ERR_RESP_NO_DELAY=y +CONFIG_HTTPD_PURGE_BUF_LEN=32 +# CONFIG_HTTPD_LOG_PURGE_DATA is not set +# CONFIG_HTTPD_WS_SUPPORT is not set +# end of HTTP Server + +# +# ESP HTTPS OTA +# +# CONFIG_OTA_ALLOW_HTTP is not set +# end of ESP HTTPS OTA + +# +# ESP HTTPS server +# +# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set +# end of ESP HTTPS server + +# +# Hardware Settings +# + +# +# MAC Config +# +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +# CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES_TWO is not set +CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES=4 +# end of MAC Config + +# +# Sleep Config +# +# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set +CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y +CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y +CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU=y +CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y +# end of Sleep Config + +# +# RTC Clock Config +# +CONFIG_RTC_CLOCK_BBPLL_POWER_ON_WITH_USB=y +# end of RTC Clock Config +# end of Hardware Settings + +# +# IPC (Inter-Processor Call) +# +CONFIG_ESP_IPC_TASK_STACK_SIZE=1536 +CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y +CONFIG_ESP_IPC_ISR_ENABLE=y +# end of IPC (Inter-Processor Call) + +# +# LCD and Touch Panel +# + +# +# LCD Touch Drivers are maintained in the IDF Component Registry +# + +# +# LCD Peripheral Configuration +# +CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32 +# CONFIG_LCD_RGB_ISR_IRAM_SAFE is not set +# end of LCD Peripheral Configuration +# end of LCD and Touch Panel + +# +# ESP NETIF Adapter +# +CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 +CONFIG_ESP_NETIF_TCPIP_LWIP=y +# CONFIG_ESP_NETIF_LOOPBACK is not set +CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y +# end of ESP NETIF Adapter + +# +# PHY +# +CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP_PHY_MAX_TX_POWER=20 +# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set +CONFIG_ESP_PHY_ENABLE_USB=y +CONFIG_ESP_PHY_RF_CAL_PARTIAL=y +# CONFIG_ESP_PHY_RF_CAL_NONE is not set +# CONFIG_ESP_PHY_RF_CAL_FULL is not set +CONFIG_ESP_PHY_CALIBRATION_MODE=0 +# end of PHY + +# +# Power Management +# +# CONFIG_PM_ENABLE is not set +CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y +CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP=y +# end of Power Management + +# +# ESP Ringbuf +# +# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH is not set +# end of ESP Ringbuf + +# +# ESP System Settings +# +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set +# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set +CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y +CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y + +# +# Memory protection +# +# end of Memory protection + +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set +# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_USB_CDC is not set +# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_NONE is not set +# CONFIG_ESP_CONSOLE_SECONDARY_NONE is not set +CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y +CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_MULTIPLE_UART=y +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_INT_WDT=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 +CONFIG_ESP_INT_WDT_CHECK_CPU1=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_ESP_TASK_WDT_PANIC is not set +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y +CONFIG_ESP_SYSTEM_BBPLL_RECALIB=y +# end of ESP System Settings + +# +# High resolution timer (esp_timer) +# +# CONFIG_ESP_TIMER_PROFILING is not set +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 +# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set +CONFIG_ESP_TIMER_IMPL_SYSTIMER=y +# end of High resolution timer (esp_timer) + +# +# Wi-Fi +# +CONFIG_ESP32_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +CONFIG_ESP_WIFI_STATIC_RX_MGMT_BUFFER=y +# CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUFFER is not set +CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF=0 +CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF=5 +# CONFIG_ESP32_WIFI_CSI_ENABLED is not set +CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP32_WIFI_TX_BA_WIN=6 +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +CONFIG_ESP32_WIFI_NVS_ENABLED=y +CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y +# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set +CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP32_WIFI_IRAM_OPT=y +CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y +# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set +# CONFIG_ESP_WIFI_FTM_ENABLE is not set +# CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set +# CONFIG_ESP_WIFI_GCMP_SUPPORT is not set +# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set +CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 +# end of Wi-Fi + +# +# Core dump +# +# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set +CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y +# end of Core dump + +# +# FAT Filesystem support +# +# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set +CONFIG_FATFS_CODEPAGE_437=y +# CONFIG_FATFS_CODEPAGE_720 is not set +# CONFIG_FATFS_CODEPAGE_737 is not set +# CONFIG_FATFS_CODEPAGE_771 is not set +# CONFIG_FATFS_CODEPAGE_775 is not set +# CONFIG_FATFS_CODEPAGE_850 is not set +# CONFIG_FATFS_CODEPAGE_852 is not set +# CONFIG_FATFS_CODEPAGE_855 is not set +# CONFIG_FATFS_CODEPAGE_857 is not set +# CONFIG_FATFS_CODEPAGE_860 is not set +# CONFIG_FATFS_CODEPAGE_861 is not set +# CONFIG_FATFS_CODEPAGE_862 is not set +# CONFIG_FATFS_CODEPAGE_863 is not set +# CONFIG_FATFS_CODEPAGE_864 is not set +# CONFIG_FATFS_CODEPAGE_865 is not set +# CONFIG_FATFS_CODEPAGE_866 is not set +# CONFIG_FATFS_CODEPAGE_869 is not set +# CONFIG_FATFS_CODEPAGE_932 is not set +# CONFIG_FATFS_CODEPAGE_936 is not set +# CONFIG_FATFS_CODEPAGE_949 is not set +# CONFIG_FATFS_CODEPAGE_950 is not set +CONFIG_FATFS_CODEPAGE=437 +CONFIG_FATFS_LFN_NONE=y +# CONFIG_FATFS_LFN_HEAP is not set +# CONFIG_FATFS_LFN_STACK is not set +CONFIG_FATFS_FS_LOCK=0 +CONFIG_FATFS_TIMEOUT_MS=10000 +CONFIG_FATFS_PER_FILE_CACHE=y +# CONFIG_FATFS_USE_FASTSEEK is not set +# end of FAT Filesystem support + +# +# Modbus configuration +# +CONFIG_FMB_COMM_MODE_TCP_EN=y +CONFIG_FMB_TCP_PORT_DEFAULT=502 +CONFIG_FMB_TCP_PORT_MAX_CONN=5 +CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20 +CONFIG_FMB_COMM_MODE_RTU_EN=y +CONFIG_FMB_COMM_MODE_ASCII_EN=y +CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150 +CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200 +CONFIG_FMB_QUEUE_LENGTH=20 +CONFIG_FMB_PORT_TASK_STACK_SIZE=4096 +CONFIG_FMB_SERIAL_BUF_SIZE=256 +CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8 +CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000 +CONFIG_FMB_PORT_TASK_PRIO=10 +# CONFIG_FMB_PORT_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_FMB_PORT_TASK_AFFINITY_CPU0=y +# CONFIG_FMB_PORT_TASK_AFFINITY_CPU1 is not set +CONFIG_FMB_PORT_TASK_AFFINITY=0x0 +CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT=y +CONFIG_FMB_CONTROLLER_SLAVE_ID=0x00112233 +CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20 +CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 +CONFIG_FMB_CONTROLLER_STACK_SIZE=4096 +CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20 +# CONFIG_FMB_TIMER_PORT_ENABLED is not set +# CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD is not set +# end of Modbus configuration + +# +# FreeRTOS +# +# CONFIG_FREERTOS_UNICORE is not set +CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y +CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y +# CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set +CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y +CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 +CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y +# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set +# CONFIG_FREERTOS_ASSERT_DISABLE is not set +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +CONFIG_FREERTOS_ISR_STACKSIZE=1536 +# CONFIG_FREERTOS_LEGACY_HOOKS is not set +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set +CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3072 +CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 +# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set +# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y +# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y +# CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH is not set +# end of FreeRTOS + +# +# Hardware Abstraction Layer (HAL) and Low Level (LL) +# +CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y +# CONFIG_HAL_ASSERTION_DISABLE is not set +# CONFIG_HAL_ASSERTION_SILIENT is not set +# CONFIG_HAL_ASSERTION_ENABLE is not set +CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 +# end of Hardware Abstraction Layer (HAL) and Low Level (LL) + +# +# Heap memory debugging +# +CONFIG_HEAP_POISONING_DISABLED=y +# CONFIG_HEAP_POISONING_LIGHT is not set +# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set +CONFIG_HEAP_TRACING_OFF=y +# CONFIG_HEAP_TRACING_STANDALONE is not set +# CONFIG_HEAP_TRACING_TOHOST is not set +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +# end of Heap memory debugging + +# +# jsmn +# +# CONFIG_JSMN_PARENT_LINKS is not set +# CONFIG_JSMN_STRICT is not set +# end of jsmn + +# +# libsodium +# +# end of libsodium + +# +# Log output +# +# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set +# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=3 +CONFIG_LOG_COLORS=y +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Log output + +# +# LWIP +# +CONFIG_LWIP_LOCAL_HOSTNAME="espressif" +# CONFIG_LWIP_NETIF_API is not set +CONFIG_LWIP_TCPIP_TASK_PRIO=18 +# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set +# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +# CONFIG_LWIP_L2_TO_L3_COPY is not set +# CONFIG_LWIP_IRAM_OPTIMIZATION is not set +CONFIG_LWIP_TIMERS_ONDEMAND=y +CONFIG_LWIP_MAX_SOCKETS=10 +# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set +# CONFIG_LWIP_SO_LINGER is not set +CONFIG_LWIP_SO_REUSE=y +CONFIG_LWIP_SO_REUSE_RXTOALL=y +# CONFIG_LWIP_SO_RCVBUF is not set +# CONFIG_LWIP_NETBUF_RECVINFO is not set +CONFIG_LWIP_IP_DEFAULT_TTL=64 +CONFIG_LWIP_IP4_FRAG=y +CONFIG_LWIP_IP6_FRAG=y +# CONFIG_LWIP_IP4_REASSEMBLY is not set +# CONFIG_LWIP_IP6_REASSEMBLY is not set +# CONFIG_LWIP_IP_FORWARD is not set +# CONFIG_LWIP_STATS is not set +# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set +CONFIG_LWIP_ESP_GRATUITOUS_ARP=y +CONFIG_LWIP_GARP_TMR_INTERVAL=60 +CONFIG_LWIP_ESP_MLDV6_REPORT=y +CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 +CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y +# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set +CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y +# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set +CONFIG_LWIP_DHCP_OPTIONS_LEN=68 +CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1 + +# +# DHCP server +# +CONFIG_LWIP_DHCPS=y +CONFIG_LWIP_DHCPS_LEASE_UNIT=60 +CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 +# end of DHCP server + +# CONFIG_LWIP_AUTOIP is not set +CONFIG_LWIP_IPV6=y +# CONFIG_LWIP_IPV6_AUTOCONFIG is not set +CONFIG_LWIP_IPV6_NUM_ADDRESSES=3 +# CONFIG_LWIP_IPV6_FORWARD is not set +# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=y +CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 + +# +# TCP +# +CONFIG_LWIP_MAX_ACTIVE_TCP=16 +CONFIG_LWIP_MAX_LISTENING_TCP=16 +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y +CONFIG_LWIP_TCP_MAXRTX=12 +CONFIG_LWIP_TCP_SYNMAXRTX=12 +CONFIG_LWIP_TCP_MSS=1440 +CONFIG_LWIP_TCP_TMR_INTERVAL=250 +CONFIG_LWIP_TCP_MSL=60000 +CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000 +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5760 +CONFIG_LWIP_TCP_WND_DEFAULT=5760 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 +CONFIG_LWIP_TCP_QUEUE_OOSEQ=y +CONFIG_LWIP_TCP_OOSEQ_TIMEOUT=6 +CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4 +# CONFIG_LWIP_TCP_SACK_OUT is not set +# CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set +CONFIG_LWIP_TCP_OVERSIZE_MSS=y +# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set +CONFIG_LWIP_TCP_RTO_TIME=1500 +# end of TCP + +# +# UDP +# +CONFIG_LWIP_MAX_UDP_PCBS=16 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 +# end of UDP + +# +# Checksums +# +# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set +# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set +CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y +# end of Checksums + +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_LWIP_PPP_SUPPORT is not set +CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 +CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 +# CONFIG_LWIP_SLIP_SUPPORT is not set + +# +# ICMP +# +CONFIG_LWIP_ICMP=y +# CONFIG_LWIP_MULTICAST_PING is not set +# CONFIG_LWIP_BROADCAST_PING is not set +# end of ICMP + +# +# LWIP RAW API +# +CONFIG_LWIP_MAX_RAW_PCBS=16 +# end of LWIP RAW API + +# +# SNTP +# +CONFIG_LWIP_SNTP_MAX_SERVERS=1 +# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set +CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 +# end of SNTP + +# +# DNS +# +CONFIG_LWIP_DNS_MAX_SERVERS=3 +# CONFIG_LWIP_FALLBACK_DNS_SERVER_SUPPORT is not set +# end of DNS + +CONFIG_LWIP_ESP_LWIP_ASSERT=y + +# +# Hooks +# +# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set +CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y +# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y +# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set +CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y +# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set +# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set +CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set +# end of Hooks + +# CONFIG_LWIP_DEBUG is not set +# end of LWIP + +# +# mbedTLS +# +CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set +# CONFIG_MBEDTLS_DEBUG is not set + +# +# mbedTLS v2.28.x related +# +# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set +# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set +# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set +CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y +# end of mbedTLS v2.28.x related + +# +# Certificate Bundle +# +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 +# end of Certificate Bundle + +# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set +# CONFIG_MBEDTLS_CMAC_C is not set +CONFIG_MBEDTLS_HARDWARE_AES=y +CONFIG_MBEDTLS_AES_USE_INTERRUPT=y +CONFIG_MBEDTLS_HARDWARE_MPI=y +CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_ROM_MD5=y +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set +CONFIG_MBEDTLS_HAVE_TIME=y +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +CONFIG_MBEDTLS_SHA512_C=y +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set +# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set +# CONFIG_MBEDTLS_TLS_DISABLED is not set +CONFIG_MBEDTLS_TLS_SERVER=y +CONFIG_MBEDTLS_TLS_CLIENT=y +CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Key Exchange Methods +# +# CONFIG_MBEDTLS_PSK_MODES is not set +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y +# end of TLS Key Exchange Methods + +CONFIG_MBEDTLS_SSL_RENEGOTIATION=y +# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set +CONFIG_MBEDTLS_SSL_PROTO_TLS1=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set +# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set +CONFIG_MBEDTLS_SSL_ALPN=y +CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +CONFIG_MBEDTLS_X509_CHECK_KEY_USAGE=y +CONFIG_MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE=y +CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y + +# +# Symmetric Ciphers +# +CONFIG_MBEDTLS_AES_C=y +# CONFIG_MBEDTLS_CAMELLIA_C is not set +# CONFIG_MBEDTLS_DES_C is not set +CONFIG_MBEDTLS_RC4_DISABLED=y +# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set +# CONFIG_MBEDTLS_RC4_ENABLED is not set +# CONFIG_MBEDTLS_BLOWFISH_C is not set +# CONFIG_MBEDTLS_XTEA_C is not set +CONFIG_MBEDTLS_CCM_C=y +CONFIG_MBEDTLS_GCM_C=y +# CONFIG_MBEDTLS_NIST_KW_C is not set +# end of Symmetric Ciphers + +# CONFIG_MBEDTLS_RIPEMD160_C is not set + +# +# Certificates +# +CONFIG_MBEDTLS_PEM_PARSE_C=y +CONFIG_MBEDTLS_PEM_WRITE_C=y +CONFIG_MBEDTLS_X509_CRL_PARSE_C=y +CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# end of Certificates + +CONFIG_MBEDTLS_ECP_C=y +CONFIG_MBEDTLS_ECDH_C=y +CONFIG_MBEDTLS_ECDSA_C=y +# CONFIG_MBEDTLS_ECJPAKE_C is not set +CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y +CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +# CONFIG_MBEDTLS_POLY1305_C is not set +# CONFIG_MBEDTLS_CHACHA20_C is not set +# CONFIG_MBEDTLS_HKDF_C is not set +# CONFIG_MBEDTLS_THREADING_C is not set +# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set +# CONFIG_MBEDTLS_SECURITY_RISKS is not set +# end of mbedTLS + +# +# mDNS +# +CONFIG_MDNS_MAX_SERVICES=10 +CONFIG_MDNS_TASK_PRIORITY=1 +CONFIG_MDNS_TASK_STACK_SIZE=4096 +# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_MDNS_TASK_AFFINITY_CPU0=y +# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set +CONFIG_MDNS_TASK_AFFINITY=0x0 +CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000 +# CONFIG_MDNS_STRICT_MODE is not set +CONFIG_MDNS_TIMER_PERIOD_MS=100 +# CONFIG_MDNS_NETWORKING_SOCKET is not set +CONFIG_MDNS_MULTIPLE_INSTANCE=y +# end of mDNS + +# +# ESP-MQTT Configurations +# +CONFIG_MQTT_PROTOCOL_311=y +CONFIG_MQTT_TRANSPORT_SSL=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y +# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set +# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set +# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set +# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set +# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set +# CONFIG_MQTT_CUSTOM_OUTBOX is not set +# end of ESP-MQTT Configurations + +# +# Newlib +# +CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set +CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y +# CONFIG_NEWLIB_NANO_FORMAT is not set +# end of Newlib + +# +# NVS +# +# CONFIG_NVS_ASSERT_ERROR_CHECK is not set +# end of NVS + +# +# OpenSSL +# +# CONFIG_OPENSSL_DEBUG is not set +CONFIG_OPENSSL_ERROR_STACK=y +# CONFIG_OPENSSL_ASSERT_DO_NOTHING is not set +CONFIG_OPENSSL_ASSERT_EXIT=y +# end of OpenSSL + +# +# OpenThread +# +# CONFIG_OPENTHREAD_ENABLED is not set +# end of OpenThread + +# +# PThreads +# +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_PTHREAD_STACK_MIN=768 +CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y +# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set +# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set +CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# Main Flash configuration +# + +# +# Optional and Experimental Features (READ DOCS FIRST) +# + +# +# Features here require specific hardware (READ DOCS FIRST!) +# +# CONFIG_SPI_FLASH_HPM_ENA is not set +CONFIG_SPI_FLASH_HPM_AUTO=y +# CONFIG_SPI_FLASH_HPM_DIS is not set +CONFIG_SPI_FLASH_HPM_ON=y +CONFIG_SPI_FLASH_HPM_DC_AUTO=y +# CONFIG_SPI_FLASH_HPM_DC_DISABLE is not set +# end of Optional and Experimental Features (READ DOCS FIRST) +# end of Main Flash configuration + +# +# SPI Flash driver +# +# CONFIG_SPI_FLASH_VERIFY_WRITE is not set +# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y +# CONFIG_SPI_FLASH_ROM_IMPL is not set +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set +# CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set +# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set +# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set + +# +# Auto-detect flash chips +# +CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP=y +# end of Auto-detect flash chips + +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver + +# +# SPIFFS Configuration +# +CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# +CONFIG_SPIFFS_CACHE=y +CONFIG_SPIFFS_CACHE_WR=y +# CONFIG_SPIFFS_CACHE_STATS is not set +# end of SPIFFS Cache Configuration + +CONFIG_SPIFFS_PAGE_CHECK=y +CONFIG_SPIFFS_GC_MAX_RUNS=10 +# CONFIG_SPIFFS_GC_STATS is not set +CONFIG_SPIFFS_PAGE_SIZE=256 +CONFIG_SPIFFS_OBJ_NAME_LEN=32 +# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set +CONFIG_SPIFFS_USE_MAGIC=y +CONFIG_SPIFFS_USE_MAGIC_LENGTH=y +CONFIG_SPIFFS_META_LENGTH=4 +CONFIG_SPIFFS_USE_MTIME=y + +# +# Debug Configuration +# +# CONFIG_SPIFFS_DBG is not set +# CONFIG_SPIFFS_API_DBG is not set +# CONFIG_SPIFFS_GC_DBG is not set +# CONFIG_SPIFFS_CACHE_DBG is not set +# CONFIG_SPIFFS_CHECK_DBG is not set +# CONFIG_SPIFFS_TEST_VISUALISATION is not set +# end of Debug Configuration +# end of SPIFFS Configuration + +# +# TCP Transport +# + +# +# Websocket +# +CONFIG_WS_TRANSPORT=y +CONFIG_WS_BUFFER_SIZE=1024 +# end of Websocket +# end of TCP Transport + +# +# TinyUSB Stack +# +# CONFIG_TINYUSB is not set +# end of TinyUSB Stack + +# +# Unity unit testing library +# +CONFIG_UNITY_ENABLE_FLOAT=y +CONFIG_UNITY_ENABLE_DOUBLE=y +# CONFIG_UNITY_ENABLE_64BIT is not set +# CONFIG_UNITY_ENABLE_COLOR is not set +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y +# CONFIG_UNITY_ENABLE_FIXTURE is not set +# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set +# end of Unity unit testing library + +# +# USB-OTG +# +CONFIG_USB_OTG_SUPPORTED=y +CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE=256 +CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED=y +# CONFIG_USB_HOST_HW_BUFFER_BIAS_IN is not set +# CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT is not set + +# +# Root Hub configuration +# +CONFIG_USB_HOST_DEBOUNCE_DELAY_MS=250 +CONFIG_USB_HOST_RESET_HOLD_MS=30 +CONFIG_USB_HOST_RESET_RECOVERY_MS=30 +CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS=10 +# end of Root Hub configuration +# end of USB-OTG + +# +# Virtual file system +# +CONFIG_VFS_SUPPORT_IO=y +CONFIG_VFS_SUPPORT_DIR=y +CONFIG_VFS_SUPPORT_SELECT=y +CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_VFS_SUPPORT_TERMIOS=y + +# +# Host File System I/O (Semihosting) +# +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# end of Host File System I/O (Semihosting) +# end of Virtual file system + +# +# Wear Levelling +# +# CONFIG_WL_SECTOR_SIZE_512 is not set +CONFIG_WL_SECTOR_SIZE_4096=y +CONFIG_WL_SECTOR_SIZE=4096 +# end of Wear Levelling + +# +# Wi-Fi Provisioning Manager +# +CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set +# end of Wi-Fi Provisioning Manager + +# +# Supplicant +# +CONFIG_WPA_MBEDTLS_CRYPTO=y +# CONFIG_WPA_WAPI_PSK is not set +# CONFIG_WPA_SUITE_B_192 is not set +# CONFIG_WPA_DEBUG_PRINT is not set +# CONFIG_WPA_TESTING_OPTIONS is not set +# CONFIG_WPA_WPS_STRICT is not set +# CONFIG_WPA_11KV_SUPPORT is not set +# CONFIG_WPA_MBO_SUPPORT is not set +# CONFIG_WPA_DPP_SUPPORT is not set +# end of Supplicant + +# +# iotkit embedded +# + +# +# Aliyun linkkit device version +# +CONFIG_LINKKIT_FIRMWARE_VERSION="0.0.1" +# end of Aliyun linkkit device version + +# +# Aliyun linkkit awss config +# +CONFIG_AWSS_ENCRYPT_TYPE=3 +CONFIG_AWSS_CONN_ENCRYPT_TYPE=4 +CONFIG_AWSS_TIMEOUT_INTERVAL_MS=180000 +CONFIG_AWSS_CHANNELSCAN_INTERVAL_MS=200 +# end of Aliyun linkkit awss config + +# +# Aliyun linkkit network config +# +# CONFIG_SUPPORT_TCP is not set +CONFIG_TCP_ESTABLISH_TIMEOUT_MS=10000 +CONFIG_TLS_ESTABLISH_TIMEOUT_MS=10000 +# end of Aliyun linkkit network config + +# +# Aliyun linkkit device model config +# +# CONFIG_DEVICE_MODEL_GATEWAY is not set +# end of Aliyun linkkit device model config + +# +# Aliyun linkkit local control +# +# CONFIG_DEVICE_ALCS_ENABLE is not set +# end of Aliyun linkkit local control + +# +# Aliyun linkkit security OTA +# +# CONFIG_SUPPORT_SECURITY_OTA is not set +# end of Aliyun linkkit security OTA + +# +# Aliyun linkkit dynamic register +# +CONFIG_DYNAMIC_REGISTER=y +# end of Aliyun linkkit dynamic register + +# +# Aliyun linkkit mqtt config +# +CONFIG_MQTT_DIRECT=y +# end of Aliyun linkkit mqtt config + +CONFIG_HAL_SEM_MAX_COUNT=255 +CONFIG_HAL_SEM_INIT_COUNT=0 +CONFIG_HAL_TLS_HANDSHAKE_TIMEOUT=180 +# CONFIG_HAL_USE_CUSTOMER_AP_SSID is not set +CONFIG_AP_SSID_KEY="apssid" +# CONFIG_USE_SOFTAP_CONFIG is not set +# end of iotkit embedded +# end of Component config + +# +# Compatibility options +# +# CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set +# end of Compatibility options + +# Deprecated options for backward compatibility +CONFIG_TOOLPREFIX="xtensa-esp32s3-elf-" +# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set +CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y +# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL=3 +# CONFIG_APP_ROLLBACK_ENABLE is not set +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +# CONFIG_FLASHMODE_QIO is not set +# CONFIG_FLASHMODE_QOUT is not set +CONFIG_FLASHMODE_DIO=y +# CONFIG_FLASHMODE_DOUT is not set +# CONFIG_MONITOR_BAUD_9600B is not set +# CONFIG_MONITOR_BAUD_57600B is not set +CONFIG_MONITOR_BAUD_115200B=y +# CONFIG_MONITOR_BAUD_230400B is not set +# CONFIG_MONITOR_BAUD_921600B is not set +# CONFIG_MONITOR_BAUD_2MB is not set +# CONFIG_MONITOR_BAUD_OTHER is not set +CONFIG_MONITOR_BAUD_OTHER_VAL=115200 +CONFIG_MONITOR_BAUD=115200 +CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_CXX_EXCEPTIONS is not set +CONFIG_STACK_CHECK_NONE=y +# CONFIG_STACK_CHECK_NORM is not set +# CONFIG_STACK_CHECK_STRONG is not set +# CONFIG_STACK_CHECK_ALL is not set +# CONFIG_WARN_WRITE_STRINGS is not set +# CONFIG_DISABLE_GCC8_WARNINGS is not set +# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +CONFIG_ESP32_APPTRACE_DEST_NONE=y +CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y +CONFIG_ADC2_DISABLE_DAC=y +# CONFIG_EVENT_LOOP_PROFILING is not set +CONFIG_POST_EVENTS_FROM_ISR=y +CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +# CONFIG_ESP_SYSTEM_PD_FLASH is not set +CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND=y +CONFIG_IPC_TASK_STACK_SIZE=1536 +CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP32_PHY_MAX_TX_POWER=20 +# CONFIG_ESP32_REDUCE_PHY_TX_POWER is not set +CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y +# CONFIG_ESP32S2_PANIC_PRINT_HALT is not set +CONFIG_ESP32S2_PANIC_PRINT_REBOOT=y +# CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP32S2_PANIC_GDBSTUB is not set +CONFIG_ESP32S2_ALLOW_RTC_FAST_MEM_AS_HEAP=y +CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_INT_WDT=y +CONFIG_INT_WDT_TIMEOUT_MS=300 +CONFIG_INT_WDT_CHECK_CPU1=y +CONFIG_TASK_WDT=y +# CONFIG_TASK_WDT_PANIC is not set +CONFIG_TASK_WDT_TIMEOUT_S=5 +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set +CONFIG_TIMER_TASK_STACK_SIZE=3584 +# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y +CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150 +CONFIG_MB_MASTER_DELAY_MS_CONVERT=200 +CONFIG_MB_QUEUE_LENGTH=20 +CONFIG_MB_SERIAL_TASK_STACK_SIZE=4096 +CONFIG_MB_SERIAL_BUF_SIZE=256 +CONFIG_MB_SERIAL_TASK_PRIO=10 +CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT=y +CONFIG_MB_CONTROLLER_SLAVE_ID=0x00112233 +CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20 +CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 +CONFIG_MB_CONTROLLER_STACK_SIZE=4096 +CONFIG_MB_EVENT_QUEUE_TIMEOUT=20 +# CONFIG_MB_TIMER_PORT_ENABLED is not set +# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set +CONFIG_TIMER_TASK_PRIORITY=1 +CONFIG_TIMER_TASK_STACK_DEPTH=3072 +CONFIG_TIMER_QUEUE_LENGTH=10 +# CONFIG_L2_TO_L3_COPY is not set +# CONFIG_USE_ONLY_LWIP_SELECT is not set +CONFIG_ESP_GRATUITOUS_ARP=y +CONFIG_GARP_TMR_INTERVAL=60 +CONFIG_TCPIP_RECVMBOX_SIZE=32 +CONFIG_TCP_MAXRTX=12 +CONFIG_TCP_SYNMAXRTX=12 +CONFIG_TCP_MSS=1440 +CONFIG_TCP_MSL=60000 +CONFIG_TCP_SND_BUF_DEFAULT=5760 +CONFIG_TCP_WND_DEFAULT=5760 +CONFIG_TCP_RECVMBOX_SIZE=6 +CONFIG_TCP_QUEUE_OOSEQ=y +# CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set +CONFIG_TCP_OVERSIZE_MSS=y +# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_TCP_OVERSIZE_DISABLE is not set +CONFIG_UDP_RECVMBOX_SIZE=6 +CONFIG_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_PPP_SUPPORT is not set +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_ESP32_PTHREAD_STACK_MIN=768 +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set +# CONFIG_USB_ENABLED is not set +CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_SUPPORT_TERMIOS=y +CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# End of deprecated options diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig.defaults b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig.defaults new file mode 100644 index 00000000..153ff678 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_ESPTOOLPY_BAUD_921600B=y +CONFIG_TIMER_TASK_STACK_DEPTH=3072 diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig.defaults.esp32s2 b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig.defaults.esp32s2 new file mode 100644 index 00000000..367b3498 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig.defaults.esp32s2 @@ -0,0 +1,3 @@ +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32s2.csv" diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig.defaults.esp32s3 b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig.defaults.esp32s3 new file mode 100644 index 00000000..7256fc56 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig.defaults.esp32s3 @@ -0,0 +1,3 @@ +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32s3.csv" diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig.old b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig.old new file mode 100644 index 00000000..ac2a4d16 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig.old @@ -0,0 +1,1605 @@ +# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) Project Configuration +# +CONFIG_IDF_CMAKE=y +CONFIG_IDF_TARGET_ARCH_XTENSA=y +CONFIG_IDF_TARGET="esp32s3" +CONFIG_IDF_TARGET_ESP32S3=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0009 + +# +# SDK tool configuration +# +CONFIG_SDK_TOOLPREFIX="xtensa-esp32s3-elf-" +# CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set +# end of SDK tool configuration + +# +# Build type +# +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +CONFIG_APP_BUILD_GENERATE_BINARIES=y +CONFIG_APP_BUILD_BOOTLOADER=y +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# end of Build type + +# +# Application manager +# +CONFIG_APP_COMPILE_TIME_DATE=y +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 +# end of Application manager + +# +# Bootloader config +# +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0 +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set +CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y +# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set +CONFIG_BOOTLOADER_LOG_LEVEL=3 + +# +# Serial Flash Configurations +# +# CONFIG_BOOTLOADER_FLASH_DC_AWARE is not set +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y +# end of Serial Flash Configurations + +CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y +# CONFIG_BOOTLOADER_FACTORY_RESET is not set +# CONFIG_BOOTLOADER_APP_TEST is not set +CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y +CONFIG_BOOTLOADER_WDT_ENABLE=y +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 +# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +# end of Bootloader config + +# +# Security features +# +CONFIG_SECURE_BOOT_SUPPORTS_RSA=y +CONFIG_SECURE_TARGET_HAS_SECURE_ROM_DL_MODE=y +# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set +# CONFIG_SECURE_BOOT is not set +# CONFIG_SECURE_FLASH_ENC_ENABLED is not set +# end of Security features + +# +# Boot ROM Behavior +# +CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y +# CONFIG_BOOT_ROM_LOG_ALWAYS_OFF is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW is not set +# end of Boot ROM Behavior + +# +# Serial flasher config +# +CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200 +# CONFIG_ESPTOOLPY_NO_STUB is not set +# CONFIG_ESPTOOLPY_OCT_FLASH is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +CONFIG_ESPTOOLPY_S3_STR=y +# CONFIG_ESPTOOLPY_FLASHFREQ_120M is not set +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +CONFIG_ESPTOOLPY_FLASHFREQ="80m" +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" +CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER="hard_reset" +# CONFIG_ESPTOOLPY_MONITOR_BAUD_CONSOLE is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set +CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y +# CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set +CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200 +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# +# CONFIG_PARTITION_TABLE_SINGLE_APP is not set +# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32s3.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_esp32s3.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# WIFI Configuration +# +CONFIG_ESP_WIFI_SSID="myssid" +CONFIG_ESP_WIFI_PASSWORD="mypassword" +# end of WIFI Configuration + +# +# Platform Configuration +# +# CONFIG_ESP_MQTT_PLATFORM_ALIYUN is not set +CONFIG_ESP_MQTT_PLATFORM_FASTBEE=y +CONFIG_ESP_MQTT_PLATFORM_FASTBEE_URL="fastbee.cn:1883" +CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERNAME="FastBee" +CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PASSWORD="P63653937TRQ8F27" +CONFIG_ESP_MQTT_PLATFORM_FASTBEE_USERID="1" +CONFIG_ESP_MQTT_PLATFORM_FASTBEE_PRODICTID="588" +CONFIG_ESP_MQTT_PLATFORM_FASTBEE_DEVICESN="D1FJTWOT3HIB" +# end of Platform Configuration + +# +# Example Connection Configuration +# +CONFIG_EXAMPLE_GPIO_RANGE_MIN=0 +CONFIG_EXAMPLE_GPIO_RANGE_MAX=48 +CONFIG_EXAMPLE_CONNECT_WIFI=y +CONFIG_EXAMPLE_WIFI_SSID="myssid" +CONFIG_EXAMPLE_WIFI_PASSWORD="mypassword" +# CONFIG_EXAMPLE_WIFI_SCAN_METHOD_FAST is not set +CONFIG_EXAMPLE_WIFI_SCAN_METHOD_ALL_CHANNEL=y + +# +# WiFi Scan threshold +# +CONFIG_EXAMPLE_WIFI_SCAN_RSSI_THRESHOLD=-127 +CONFIG_EXAMPLE_WIFI_AUTH_OPEN=y +# CONFIG_EXAMPLE_WIFI_AUTH_WEP is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WPA_PSK is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WPA2_PSK is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WPA_WPA2_PSK is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WPA2_ENTERPRISE is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WPA3_PSK is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WPA2_WPA3_PSK is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WAPI_PSK is not set +# end of WiFi Scan threshold + +CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SIGNAL=y +# CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SECURITY is not set +# CONFIG_EXAMPLE_CONNECT_ETHERNET is not set +CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK=y +# CONFIG_EXAMPLE_CONNECT_IPV6_PREF_GLOBAL is not set +# CONFIG_EXAMPLE_CONNECT_IPV6_PREF_SITE_LOCAL is not set +# CONFIG_EXAMPLE_CONNECT_IPV6_PREF_UNIQUE_LOCAL is not set +# end of Example Connection Configuration + +# +# [Aliyun]Factory restore +# +CONFIG_FACTORY_QUICK_REBOOT_TIMEOUT=6 +CONFIG_FACTORY_QUICK_REBOOT_MAX_TIMES=5 +# end of [Aliyun]Factory restore + +# +# Compiler options +# +CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y +# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set +# CONFIG_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +# CONFIG_COMPILER_CXX_EXCEPTIONS is not set +# CONFIG_COMPILER_CXX_RTTI is not set +CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y +# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set +# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set +# CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +# end of Compiler options + +# +# Component config +# + +# +# Application Level Tracing +# +# CONFIG_APPTRACE_DEST_JTAG is not set +CONFIG_APPTRACE_DEST_NONE=y +CONFIG_APPTRACE_LOCK_ENABLE=y +# end of Application Level Tracing + +# +# ESP-ASIO +# +# CONFIG_ASIO_SSL_SUPPORT is not set +# end of ESP-ASIO + +# +# Bluetooth +# +# CONFIG_BT_ENABLED is not set +# end of Bluetooth + +# +# CoAP Configuration +# +CONFIG_COAP_MBEDTLS_PSK=y +# CONFIG_COAP_MBEDTLS_PKI is not set +# CONFIG_COAP_MBEDTLS_DEBUG is not set +CONFIG_COAP_LOG_DEFAULT_LEVEL=0 +# end of CoAP Configuration + +# +# Driver configurations +# + +# +# ADC configuration +# +# CONFIG_ADC_FORCE_XPD_FSM is not set +CONFIG_ADC_DISABLE_DAC=y +# CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3 is not set +# end of ADC configuration + +# +# MCPWM configuration +# +# CONFIG_MCPWM_ISR_IN_IRAM is not set +# end of MCPWM configuration + +# +# SPI configuration +# +# CONFIG_SPI_MASTER_IN_IRAM is not set +CONFIG_SPI_MASTER_ISR_IN_IRAM=y +# CONFIG_SPI_SLAVE_IN_IRAM is not set +CONFIG_SPI_SLAVE_ISR_IN_IRAM=y +# end of SPI configuration + +# +# TWAI configuration +# +# CONFIG_TWAI_ISR_IN_IRAM is not set +# CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM is not set +# end of TWAI configuration + +# +# UART configuration +# +# CONFIG_UART_ISR_IN_IRAM is not set +# end of UART configuration + +# +# GDMA Configuration +# +# CONFIG_GDMA_CTRL_FUNC_IN_IRAM is not set +# CONFIG_GDMA_ISR_IRAM_SAFE is not set +# end of GDMA Configuration +# end of Driver configurations + +# +# eFuse Bit Manager +# +# CONFIG_EFUSE_CUSTOM_TABLE is not set +# CONFIG_EFUSE_VIRTUAL is not set +CONFIG_EFUSE_MAX_BLK_LEN=256 +# end of eFuse Bit Manager + +# +# ESP-TLS +# +CONFIG_ESP_TLS_USING_MBEDTLS=y +CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y +# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER is not set +# CONFIG_ESP_TLS_PSK_VERIFICATION is not set +# CONFIG_ESP_TLS_INSECURE is not set +# end of ESP-TLS + +# +# ESP32S3-Specific +# +CONFIG_ESP32S3_REV_MIN_0=y +# CONFIG_ESP32S3_REV_MIN_1 is not set +# CONFIG_ESP32S3_REV_MIN_2 is not set +CONFIG_ESP32S3_REV_MIN_FULL=0 +CONFIG_ESP_REV_MIN_FULL=0 +CONFIG_ESP32S3_REV_MAX_FULL_STR_OPT=y +CONFIG_ESP32S3_REV_MAX_FULL=99 +CONFIG_ESP_REV_MAX_FULL=99 +# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_80 is not set +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160=y +# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240 is not set +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=160 + +# +# Cache config +# +CONFIG_ESP32S3_INSTRUCTION_CACHE_16KB=y +# CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB is not set +CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE=0x4000 +# CONFIG_ESP32S3_INSTRUCTION_CACHE_4WAYS is not set +CONFIG_ESP32S3_INSTRUCTION_CACHE_8WAYS=y +CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS=8 +# CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_16B is not set +CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_32B=y +CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE=32 +# CONFIG_ESP32S3_INSTRUCTION_CACHE_WRAP is not set +# CONFIG_ESP32S3_DATA_CACHE_16KB is not set +CONFIG_ESP32S3_DATA_CACHE_32KB=y +# CONFIG_ESP32S3_DATA_CACHE_64KB is not set +CONFIG_ESP32S3_DATA_CACHE_SIZE=0x8000 +# CONFIG_ESP32S3_DATA_CACHE_4WAYS is not set +CONFIG_ESP32S3_DATA_CACHE_8WAYS=y +CONFIG_ESP32S3_DCACHE_ASSOCIATED_WAYS=8 +# CONFIG_ESP32S3_DATA_CACHE_LINE_16B is not set +CONFIG_ESP32S3_DATA_CACHE_LINE_32B=y +# CONFIG_ESP32S3_DATA_CACHE_LINE_64B is not set +CONFIG_ESP32S3_DATA_CACHE_LINE_SIZE=32 +# CONFIG_ESP32S3_DATA_CACHE_WRAP is not set +# end of Cache config + +# CONFIG_ESP32S3_SPIRAM_SUPPORT is not set +# CONFIG_ESP32S3_TRAX is not set +CONFIG_ESP32S3_TRACEMEM_RESERVE_DRAM=0x0 +# CONFIG_ESP32S3_ULP_COPROC_ENABLED is not set +CONFIG_ESP32S3_ULP_COPROC_RESERVE_MEM=0 +CONFIG_ESP32S3_DEBUG_OCDAWARE=y +CONFIG_ESP32S3_BROWNOUT_DET=y +CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_7=y +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_1 is not set +CONFIG_ESP32S3_BROWNOUT_DET_LVL=7 +CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC_FRC1=y +# CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC is not set +# CONFIG_ESP32S3_TIME_SYSCALL_USE_FRC1 is not set +# CONFIG_ESP32S3_TIME_SYSCALL_USE_NONE is not set +CONFIG_ESP32S3_RTC_CLK_SRC_INT_RC=y +# CONFIG_ESP32S3_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_ESP32S3_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_ESP32S3_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_ESP32S3_RTC_CLK_CAL_CYCLES=1024 +CONFIG_ESP32S3_DEEP_SLEEP_WAKEUP_DELAY=2000 +# CONFIG_ESP32S3_NO_BLOBS is not set +# CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM is not set +# CONFIG_ESP32S3_USE_FIXED_STATIC_RAM_SIZE is not set +# end of ESP32S3-Specific + +# +# ADC-Calibration +# +# end of ADC-Calibration + +# +# Common ESP-related +# +CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +# end of Common ESP-related + +# +# Ethernet +# +CONFIG_ETH_ENABLED=y +CONFIG_ETH_USE_SPI_ETHERNET=y +# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set +# CONFIG_ETH_SPI_ETHERNET_W5500 is not set +# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set +# CONFIG_ETH_USE_OPENETH is not set +# end of Ethernet + +# +# Event Loop Library +# +# CONFIG_ESP_EVENT_LOOP_PROFILING is not set +CONFIG_ESP_EVENT_POST_FROM_ISR=y +CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y +# end of Event Loop Library + +# +# GDB Stub +# +# end of GDB Stub + +# +# ESP HTTP client +# +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y +# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set +CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH=y +# end of ESP HTTP client + +# +# HTTP Server +# +CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_URI_LEN=512 +CONFIG_HTTPD_ERR_RESP_NO_DELAY=y +CONFIG_HTTPD_PURGE_BUF_LEN=32 +# CONFIG_HTTPD_LOG_PURGE_DATA is not set +# CONFIG_HTTPD_WS_SUPPORT is not set +# end of HTTP Server + +# +# ESP HTTPS OTA +# +# CONFIG_OTA_ALLOW_HTTP is not set +# end of ESP HTTPS OTA + +# +# ESP HTTPS server +# +# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set +# end of ESP HTTPS server + +# +# Hardware Settings +# + +# +# MAC Config +# +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +# CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES_TWO is not set +CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES=4 +# end of MAC Config + +# +# Sleep Config +# +# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set +CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y +CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y +CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU=y +CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y +# end of Sleep Config + +# +# RTC Clock Config +# +CONFIG_RTC_CLOCK_BBPLL_POWER_ON_WITH_USB=y +# end of RTC Clock Config +# end of Hardware Settings + +# +# IPC (Inter-Processor Call) +# +CONFIG_ESP_IPC_TASK_STACK_SIZE=1536 +CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y +CONFIG_ESP_IPC_ISR_ENABLE=y +# end of IPC (Inter-Processor Call) + +# +# LCD and Touch Panel +# + +# +# LCD Touch Drivers are maintained in the IDF Component Registry +# + +# +# LCD Peripheral Configuration +# +CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32 +# CONFIG_LCD_RGB_ISR_IRAM_SAFE is not set +# end of LCD Peripheral Configuration +# end of LCD and Touch Panel + +# +# ESP NETIF Adapter +# +CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 +CONFIG_ESP_NETIF_TCPIP_LWIP=y +# CONFIG_ESP_NETIF_LOOPBACK is not set +CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y +# end of ESP NETIF Adapter + +# +# PHY +# +CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP_PHY_MAX_TX_POWER=20 +# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set +CONFIG_ESP_PHY_ENABLE_USB=y +CONFIG_ESP_PHY_RF_CAL_PARTIAL=y +# CONFIG_ESP_PHY_RF_CAL_NONE is not set +# CONFIG_ESP_PHY_RF_CAL_FULL is not set +CONFIG_ESP_PHY_CALIBRATION_MODE=0 +# end of PHY + +# +# Power Management +# +# CONFIG_PM_ENABLE is not set +CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y +CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP=y +# end of Power Management + +# +# ESP Ringbuf +# +# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH is not set +# end of ESP Ringbuf + +# +# ESP System Settings +# +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set +# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set +CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y +CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y + +# +# Memory protection +# +# end of Memory protection + +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set +# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_USB_CDC is not set +# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_NONE is not set +# CONFIG_ESP_CONSOLE_SECONDARY_NONE is not set +CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y +CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_MULTIPLE_UART=y +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_INT_WDT=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 +CONFIG_ESP_INT_WDT_CHECK_CPU1=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_ESP_TASK_WDT_PANIC is not set +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y +CONFIG_ESP_SYSTEM_BBPLL_RECALIB=y +# end of ESP System Settings + +# +# High resolution timer (esp_timer) +# +# CONFIG_ESP_TIMER_PROFILING is not set +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 +# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set +CONFIG_ESP_TIMER_IMPL_SYSTIMER=y +# end of High resolution timer (esp_timer) + +# +# Wi-Fi +# +CONFIG_ESP32_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +CONFIG_ESP_WIFI_STATIC_RX_MGMT_BUFFER=y +# CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUFFER is not set +CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF=0 +CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF=5 +# CONFIG_ESP32_WIFI_CSI_ENABLED is not set +CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP32_WIFI_TX_BA_WIN=6 +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +CONFIG_ESP32_WIFI_NVS_ENABLED=y +CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y +# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set +CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP32_WIFI_IRAM_OPT=y +CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y +# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set +# CONFIG_ESP_WIFI_FTM_ENABLE is not set +# CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set +# CONFIG_ESP_WIFI_GCMP_SUPPORT is not set +# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set +CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 +# end of Wi-Fi + +# +# Core dump +# +# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set +CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y +# end of Core dump + +# +# FAT Filesystem support +# +# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set +CONFIG_FATFS_CODEPAGE_437=y +# CONFIG_FATFS_CODEPAGE_720 is not set +# CONFIG_FATFS_CODEPAGE_737 is not set +# CONFIG_FATFS_CODEPAGE_771 is not set +# CONFIG_FATFS_CODEPAGE_775 is not set +# CONFIG_FATFS_CODEPAGE_850 is not set +# CONFIG_FATFS_CODEPAGE_852 is not set +# CONFIG_FATFS_CODEPAGE_855 is not set +# CONFIG_FATFS_CODEPAGE_857 is not set +# CONFIG_FATFS_CODEPAGE_860 is not set +# CONFIG_FATFS_CODEPAGE_861 is not set +# CONFIG_FATFS_CODEPAGE_862 is not set +# CONFIG_FATFS_CODEPAGE_863 is not set +# CONFIG_FATFS_CODEPAGE_864 is not set +# CONFIG_FATFS_CODEPAGE_865 is not set +# CONFIG_FATFS_CODEPAGE_866 is not set +# CONFIG_FATFS_CODEPAGE_869 is not set +# CONFIG_FATFS_CODEPAGE_932 is not set +# CONFIG_FATFS_CODEPAGE_936 is not set +# CONFIG_FATFS_CODEPAGE_949 is not set +# CONFIG_FATFS_CODEPAGE_950 is not set +CONFIG_FATFS_CODEPAGE=437 +CONFIG_FATFS_LFN_NONE=y +# CONFIG_FATFS_LFN_HEAP is not set +# CONFIG_FATFS_LFN_STACK is not set +CONFIG_FATFS_FS_LOCK=0 +CONFIG_FATFS_TIMEOUT_MS=10000 +CONFIG_FATFS_PER_FILE_CACHE=y +# CONFIG_FATFS_USE_FASTSEEK is not set +# end of FAT Filesystem support + +# +# Modbus configuration +# +CONFIG_FMB_COMM_MODE_TCP_EN=y +CONFIG_FMB_TCP_PORT_DEFAULT=502 +CONFIG_FMB_TCP_PORT_MAX_CONN=5 +CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20 +CONFIG_FMB_COMM_MODE_RTU_EN=y +CONFIG_FMB_COMM_MODE_ASCII_EN=y +CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150 +CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200 +CONFIG_FMB_QUEUE_LENGTH=20 +CONFIG_FMB_PORT_TASK_STACK_SIZE=4096 +CONFIG_FMB_SERIAL_BUF_SIZE=256 +CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8 +CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000 +CONFIG_FMB_PORT_TASK_PRIO=10 +# CONFIG_FMB_PORT_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_FMB_PORT_TASK_AFFINITY_CPU0=y +# CONFIG_FMB_PORT_TASK_AFFINITY_CPU1 is not set +CONFIG_FMB_PORT_TASK_AFFINITY=0x0 +CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT=y +CONFIG_FMB_CONTROLLER_SLAVE_ID=0x00112233 +CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20 +CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 +CONFIG_FMB_CONTROLLER_STACK_SIZE=4096 +CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20 +# CONFIG_FMB_TIMER_PORT_ENABLED is not set +# CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD is not set +# end of Modbus configuration + +# +# FreeRTOS +# +# CONFIG_FREERTOS_UNICORE is not set +CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y +CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y +# CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set +CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y +CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 +CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y +# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set +# CONFIG_FREERTOS_ASSERT_DISABLE is not set +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +CONFIG_FREERTOS_ISR_STACKSIZE=1536 +# CONFIG_FREERTOS_LEGACY_HOOKS is not set +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set +CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3072 +CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 +# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set +# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y +# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y +# CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH is not set +# end of FreeRTOS + +# +# Hardware Abstraction Layer (HAL) and Low Level (LL) +# +CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y +# CONFIG_HAL_ASSERTION_DISABLE is not set +# CONFIG_HAL_ASSERTION_SILIENT is not set +# CONFIG_HAL_ASSERTION_ENABLE is not set +CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 +# end of Hardware Abstraction Layer (HAL) and Low Level (LL) + +# +# Heap memory debugging +# +CONFIG_HEAP_POISONING_DISABLED=y +# CONFIG_HEAP_POISONING_LIGHT is not set +# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set +CONFIG_HEAP_TRACING_OFF=y +# CONFIG_HEAP_TRACING_STANDALONE is not set +# CONFIG_HEAP_TRACING_TOHOST is not set +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +# end of Heap memory debugging + +# +# jsmn +# +# CONFIG_JSMN_PARENT_LINKS is not set +# CONFIG_JSMN_STRICT is not set +# end of jsmn + +# +# libsodium +# +# end of libsodium + +# +# Log output +# +# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set +# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=3 +CONFIG_LOG_COLORS=y +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Log output + +# +# LWIP +# +CONFIG_LWIP_LOCAL_HOSTNAME="espressif" +# CONFIG_LWIP_NETIF_API is not set +CONFIG_LWIP_TCPIP_TASK_PRIO=18 +# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set +# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +# CONFIG_LWIP_L2_TO_L3_COPY is not set +# CONFIG_LWIP_IRAM_OPTIMIZATION is not set +CONFIG_LWIP_TIMERS_ONDEMAND=y +CONFIG_LWIP_MAX_SOCKETS=10 +# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set +# CONFIG_LWIP_SO_LINGER is not set +CONFIG_LWIP_SO_REUSE=y +CONFIG_LWIP_SO_REUSE_RXTOALL=y +# CONFIG_LWIP_SO_RCVBUF is not set +# CONFIG_LWIP_NETBUF_RECVINFO is not set +CONFIG_LWIP_IP_DEFAULT_TTL=64 +CONFIG_LWIP_IP4_FRAG=y +CONFIG_LWIP_IP6_FRAG=y +# CONFIG_LWIP_IP4_REASSEMBLY is not set +# CONFIG_LWIP_IP6_REASSEMBLY is not set +# CONFIG_LWIP_IP_FORWARD is not set +# CONFIG_LWIP_STATS is not set +# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set +CONFIG_LWIP_ESP_GRATUITOUS_ARP=y +CONFIG_LWIP_GARP_TMR_INTERVAL=60 +CONFIG_LWIP_ESP_MLDV6_REPORT=y +CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 +CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y +# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set +CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y +# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set +CONFIG_LWIP_DHCP_OPTIONS_LEN=68 +CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1 + +# +# DHCP server +# +CONFIG_LWIP_DHCPS=y +CONFIG_LWIP_DHCPS_LEASE_UNIT=60 +CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 +# end of DHCP server + +# CONFIG_LWIP_AUTOIP is not set +CONFIG_LWIP_IPV6=y +# CONFIG_LWIP_IPV6_AUTOCONFIG is not set +CONFIG_LWIP_IPV6_NUM_ADDRESSES=3 +# CONFIG_LWIP_IPV6_FORWARD is not set +# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=y +CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 + +# +# TCP +# +CONFIG_LWIP_MAX_ACTIVE_TCP=16 +CONFIG_LWIP_MAX_LISTENING_TCP=16 +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y +CONFIG_LWIP_TCP_MAXRTX=12 +CONFIG_LWIP_TCP_SYNMAXRTX=12 +CONFIG_LWIP_TCP_MSS=1440 +CONFIG_LWIP_TCP_TMR_INTERVAL=250 +CONFIG_LWIP_TCP_MSL=60000 +CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000 +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5760 +CONFIG_LWIP_TCP_WND_DEFAULT=5760 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 +CONFIG_LWIP_TCP_QUEUE_OOSEQ=y +CONFIG_LWIP_TCP_OOSEQ_TIMEOUT=6 +CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4 +# CONFIG_LWIP_TCP_SACK_OUT is not set +# CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set +CONFIG_LWIP_TCP_OVERSIZE_MSS=y +# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set +CONFIG_LWIP_TCP_RTO_TIME=1500 +# end of TCP + +# +# UDP +# +CONFIG_LWIP_MAX_UDP_PCBS=16 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 +# end of UDP + +# +# Checksums +# +# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set +# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set +CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y +# end of Checksums + +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_LWIP_PPP_SUPPORT is not set +CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 +CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 +# CONFIG_LWIP_SLIP_SUPPORT is not set + +# +# ICMP +# +CONFIG_LWIP_ICMP=y +# CONFIG_LWIP_MULTICAST_PING is not set +# CONFIG_LWIP_BROADCAST_PING is not set +# end of ICMP + +# +# LWIP RAW API +# +CONFIG_LWIP_MAX_RAW_PCBS=16 +# end of LWIP RAW API + +# +# SNTP +# +CONFIG_LWIP_SNTP_MAX_SERVERS=1 +# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set +CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 +# end of SNTP + +# +# DNS +# +CONFIG_LWIP_DNS_MAX_SERVERS=3 +# CONFIG_LWIP_FALLBACK_DNS_SERVER_SUPPORT is not set +# end of DNS + +CONFIG_LWIP_ESP_LWIP_ASSERT=y + +# +# Hooks +# +# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set +CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y +# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y +# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set +CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y +# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set +# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set +CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set +# end of Hooks + +# CONFIG_LWIP_DEBUG is not set +# end of LWIP + +# +# mbedTLS +# +CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set +# CONFIG_MBEDTLS_DEBUG is not set + +# +# mbedTLS v2.28.x related +# +# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set +# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set +# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set +CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y +# end of mbedTLS v2.28.x related + +# +# Certificate Bundle +# +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 +# end of Certificate Bundle + +# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set +# CONFIG_MBEDTLS_CMAC_C is not set +CONFIG_MBEDTLS_HARDWARE_AES=y +CONFIG_MBEDTLS_AES_USE_INTERRUPT=y +CONFIG_MBEDTLS_HARDWARE_MPI=y +CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_ROM_MD5=y +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set +CONFIG_MBEDTLS_HAVE_TIME=y +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +CONFIG_MBEDTLS_SHA512_C=y +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set +# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set +# CONFIG_MBEDTLS_TLS_DISABLED is not set +CONFIG_MBEDTLS_TLS_SERVER=y +CONFIG_MBEDTLS_TLS_CLIENT=y +CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Key Exchange Methods +# +# CONFIG_MBEDTLS_PSK_MODES is not set +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y +# end of TLS Key Exchange Methods + +CONFIG_MBEDTLS_SSL_RENEGOTIATION=y +# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set +CONFIG_MBEDTLS_SSL_PROTO_TLS1=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set +# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set +CONFIG_MBEDTLS_SSL_ALPN=y +CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +CONFIG_MBEDTLS_X509_CHECK_KEY_USAGE=y +CONFIG_MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE=y +CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y + +# +# Symmetric Ciphers +# +CONFIG_MBEDTLS_AES_C=y +# CONFIG_MBEDTLS_CAMELLIA_C is not set +# CONFIG_MBEDTLS_DES_C is not set +CONFIG_MBEDTLS_RC4_DISABLED=y +# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set +# CONFIG_MBEDTLS_RC4_ENABLED is not set +# CONFIG_MBEDTLS_BLOWFISH_C is not set +# CONFIG_MBEDTLS_XTEA_C is not set +CONFIG_MBEDTLS_CCM_C=y +CONFIG_MBEDTLS_GCM_C=y +# CONFIG_MBEDTLS_NIST_KW_C is not set +# end of Symmetric Ciphers + +# CONFIG_MBEDTLS_RIPEMD160_C is not set + +# +# Certificates +# +CONFIG_MBEDTLS_PEM_PARSE_C=y +CONFIG_MBEDTLS_PEM_WRITE_C=y +CONFIG_MBEDTLS_X509_CRL_PARSE_C=y +CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# end of Certificates + +CONFIG_MBEDTLS_ECP_C=y +CONFIG_MBEDTLS_ECDH_C=y +CONFIG_MBEDTLS_ECDSA_C=y +# CONFIG_MBEDTLS_ECJPAKE_C is not set +CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y +CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +# CONFIG_MBEDTLS_POLY1305_C is not set +# CONFIG_MBEDTLS_CHACHA20_C is not set +# CONFIG_MBEDTLS_HKDF_C is not set +# CONFIG_MBEDTLS_THREADING_C is not set +# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set +# CONFIG_MBEDTLS_SECURITY_RISKS is not set +# end of mbedTLS + +# +# mDNS +# +CONFIG_MDNS_MAX_SERVICES=10 +CONFIG_MDNS_TASK_PRIORITY=1 +CONFIG_MDNS_TASK_STACK_SIZE=4096 +# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_MDNS_TASK_AFFINITY_CPU0=y +# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set +CONFIG_MDNS_TASK_AFFINITY=0x0 +CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000 +# CONFIG_MDNS_STRICT_MODE is not set +CONFIG_MDNS_TIMER_PERIOD_MS=100 +# CONFIG_MDNS_NETWORKING_SOCKET is not set +CONFIG_MDNS_MULTIPLE_INSTANCE=y +# end of mDNS + +# +# ESP-MQTT Configurations +# +CONFIG_MQTT_PROTOCOL_311=y +CONFIG_MQTT_TRANSPORT_SSL=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y +# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set +# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set +# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set +# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set +# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set +# CONFIG_MQTT_CUSTOM_OUTBOX is not set +# end of ESP-MQTT Configurations + +# +# Newlib +# +CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set +CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y +# CONFIG_NEWLIB_NANO_FORMAT is not set +# end of Newlib + +# +# NVS +# +# CONFIG_NVS_ASSERT_ERROR_CHECK is not set +# end of NVS + +# +# OpenSSL +# +# CONFIG_OPENSSL_DEBUG is not set +CONFIG_OPENSSL_ERROR_STACK=y +# CONFIG_OPENSSL_ASSERT_DO_NOTHING is not set +CONFIG_OPENSSL_ASSERT_EXIT=y +# end of OpenSSL + +# +# OpenThread +# +# CONFIG_OPENTHREAD_ENABLED is not set +# end of OpenThread + +# +# PThreads +# +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_PTHREAD_STACK_MIN=768 +CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y +# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set +# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set +CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# Main Flash configuration +# + +# +# Optional and Experimental Features (READ DOCS FIRST) +# + +# +# Features here require specific hardware (READ DOCS FIRST!) +# +# CONFIG_SPI_FLASH_HPM_ENA is not set +CONFIG_SPI_FLASH_HPM_AUTO=y +# CONFIG_SPI_FLASH_HPM_DIS is not set +CONFIG_SPI_FLASH_HPM_ON=y +CONFIG_SPI_FLASH_HPM_DC_AUTO=y +# CONFIG_SPI_FLASH_HPM_DC_DISABLE is not set +# end of Optional and Experimental Features (READ DOCS FIRST) +# end of Main Flash configuration + +# +# SPI Flash driver +# +# CONFIG_SPI_FLASH_VERIFY_WRITE is not set +# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y +# CONFIG_SPI_FLASH_ROM_IMPL is not set +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set +# CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set +# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set +# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set + +# +# Auto-detect flash chips +# +CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP=y +# end of Auto-detect flash chips + +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver + +# +# SPIFFS Configuration +# +CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# +CONFIG_SPIFFS_CACHE=y +CONFIG_SPIFFS_CACHE_WR=y +# CONFIG_SPIFFS_CACHE_STATS is not set +# end of SPIFFS Cache Configuration + +CONFIG_SPIFFS_PAGE_CHECK=y +CONFIG_SPIFFS_GC_MAX_RUNS=10 +# CONFIG_SPIFFS_GC_STATS is not set +CONFIG_SPIFFS_PAGE_SIZE=256 +CONFIG_SPIFFS_OBJ_NAME_LEN=32 +# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set +CONFIG_SPIFFS_USE_MAGIC=y +CONFIG_SPIFFS_USE_MAGIC_LENGTH=y +CONFIG_SPIFFS_META_LENGTH=4 +CONFIG_SPIFFS_USE_MTIME=y + +# +# Debug Configuration +# +# CONFIG_SPIFFS_DBG is not set +# CONFIG_SPIFFS_API_DBG is not set +# CONFIG_SPIFFS_GC_DBG is not set +# CONFIG_SPIFFS_CACHE_DBG is not set +# CONFIG_SPIFFS_CHECK_DBG is not set +# CONFIG_SPIFFS_TEST_VISUALISATION is not set +# end of Debug Configuration +# end of SPIFFS Configuration + +# +# TCP Transport +# + +# +# Websocket +# +CONFIG_WS_TRANSPORT=y +CONFIG_WS_BUFFER_SIZE=1024 +# end of Websocket +# end of TCP Transport + +# +# TinyUSB Stack +# +# CONFIG_TINYUSB is not set +# end of TinyUSB Stack + +# +# Unity unit testing library +# +CONFIG_UNITY_ENABLE_FLOAT=y +CONFIG_UNITY_ENABLE_DOUBLE=y +# CONFIG_UNITY_ENABLE_64BIT is not set +# CONFIG_UNITY_ENABLE_COLOR is not set +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y +# CONFIG_UNITY_ENABLE_FIXTURE is not set +# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set +# end of Unity unit testing library + +# +# USB-OTG +# +CONFIG_USB_OTG_SUPPORTED=y +CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE=256 +CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED=y +# CONFIG_USB_HOST_HW_BUFFER_BIAS_IN is not set +# CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT is not set + +# +# Root Hub configuration +# +CONFIG_USB_HOST_DEBOUNCE_DELAY_MS=250 +CONFIG_USB_HOST_RESET_HOLD_MS=30 +CONFIG_USB_HOST_RESET_RECOVERY_MS=30 +CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS=10 +# end of Root Hub configuration +# end of USB-OTG + +# +# Virtual file system +# +CONFIG_VFS_SUPPORT_IO=y +CONFIG_VFS_SUPPORT_DIR=y +CONFIG_VFS_SUPPORT_SELECT=y +CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_VFS_SUPPORT_TERMIOS=y + +# +# Host File System I/O (Semihosting) +# +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# end of Host File System I/O (Semihosting) +# end of Virtual file system + +# +# Wear Levelling +# +# CONFIG_WL_SECTOR_SIZE_512 is not set +CONFIG_WL_SECTOR_SIZE_4096=y +CONFIG_WL_SECTOR_SIZE=4096 +# end of Wear Levelling + +# +# Wi-Fi Provisioning Manager +# +CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set +# end of Wi-Fi Provisioning Manager + +# +# Supplicant +# +CONFIG_WPA_MBEDTLS_CRYPTO=y +# CONFIG_WPA_WAPI_PSK is not set +# CONFIG_WPA_SUITE_B_192 is not set +# CONFIG_WPA_DEBUG_PRINT is not set +# CONFIG_WPA_TESTING_OPTIONS is not set +# CONFIG_WPA_WPS_STRICT is not set +# CONFIG_WPA_11KV_SUPPORT is not set +# CONFIG_WPA_MBO_SUPPORT is not set +# CONFIG_WPA_DPP_SUPPORT is not set +# end of Supplicant + +# +# iotkit embedded +# + +# +# Aliyun linkkit device version +# +CONFIG_LINKKIT_FIRMWARE_VERSION="0.0.1" +# end of Aliyun linkkit device version + +# +# Aliyun linkkit awss config +# +CONFIG_AWSS_ENCRYPT_TYPE=3 +CONFIG_AWSS_CONN_ENCRYPT_TYPE=4 +CONFIG_AWSS_TIMEOUT_INTERVAL_MS=180000 +CONFIG_AWSS_CHANNELSCAN_INTERVAL_MS=200 +# end of Aliyun linkkit awss config + +# +# Aliyun linkkit network config +# +# CONFIG_SUPPORT_TCP is not set +CONFIG_TCP_ESTABLISH_TIMEOUT_MS=10000 +CONFIG_TLS_ESTABLISH_TIMEOUT_MS=10000 +# end of Aliyun linkkit network config + +# +# Aliyun linkkit device model config +# +# CONFIG_DEVICE_MODEL_GATEWAY is not set +# end of Aliyun linkkit device model config + +# +# Aliyun linkkit local control +# +# CONFIG_DEVICE_ALCS_ENABLE is not set +# end of Aliyun linkkit local control + +# +# Aliyun linkkit security OTA +# +# CONFIG_SUPPORT_SECURITY_OTA is not set +# end of Aliyun linkkit security OTA + +# +# Aliyun linkkit dynamic register +# +CONFIG_DYNAMIC_REGISTER=y +# end of Aliyun linkkit dynamic register + +# +# Aliyun linkkit mqtt config +# +CONFIG_MQTT_DIRECT=y +# end of Aliyun linkkit mqtt config + +CONFIG_HAL_SEM_MAX_COUNT=255 +CONFIG_HAL_SEM_INIT_COUNT=0 +CONFIG_HAL_TLS_HANDSHAKE_TIMEOUT=180 +# CONFIG_HAL_USE_CUSTOMER_AP_SSID is not set +CONFIG_AP_SSID_KEY="apssid" +# CONFIG_USE_SOFTAP_CONFIG is not set +# end of iotkit embedded +# end of Component config + +# +# Compatibility options +# +# CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set +# end of Compatibility options + +# Deprecated options for backward compatibility +CONFIG_TOOLPREFIX="xtensa-esp32s3-elf-" +# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set +CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y +# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL=3 +# CONFIG_APP_ROLLBACK_ENABLE is not set +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +# CONFIG_FLASHMODE_QIO is not set +# CONFIG_FLASHMODE_QOUT is not set +CONFIG_FLASHMODE_DIO=y +# CONFIG_FLASHMODE_DOUT is not set +# CONFIG_MONITOR_BAUD_9600B is not set +# CONFIG_MONITOR_BAUD_57600B is not set +CONFIG_MONITOR_BAUD_115200B=y +# CONFIG_MONITOR_BAUD_230400B is not set +# CONFIG_MONITOR_BAUD_921600B is not set +# CONFIG_MONITOR_BAUD_2MB is not set +# CONFIG_MONITOR_BAUD_OTHER is not set +CONFIG_MONITOR_BAUD_OTHER_VAL=115200 +CONFIG_MONITOR_BAUD=115200 +CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_CXX_EXCEPTIONS is not set +CONFIG_STACK_CHECK_NONE=y +# CONFIG_STACK_CHECK_NORM is not set +# CONFIG_STACK_CHECK_STRONG is not set +# CONFIG_STACK_CHECK_ALL is not set +# CONFIG_WARN_WRITE_STRINGS is not set +# CONFIG_DISABLE_GCC8_WARNINGS is not set +# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +CONFIG_ESP32_APPTRACE_DEST_NONE=y +CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y +CONFIG_ADC2_DISABLE_DAC=y +# CONFIG_EVENT_LOOP_PROFILING is not set +CONFIG_POST_EVENTS_FROM_ISR=y +CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +# CONFIG_ESP_SYSTEM_PD_FLASH is not set +CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND=y +CONFIG_IPC_TASK_STACK_SIZE=1536 +CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP32_PHY_MAX_TX_POWER=20 +# CONFIG_ESP32_REDUCE_PHY_TX_POWER is not set +CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y +# CONFIG_ESP32S2_PANIC_PRINT_HALT is not set +CONFIG_ESP32S2_PANIC_PRINT_REBOOT=y +# CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP32S2_PANIC_GDBSTUB is not set +CONFIG_ESP32S2_ALLOW_RTC_FAST_MEM_AS_HEAP=y +CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_INT_WDT=y +CONFIG_INT_WDT_TIMEOUT_MS=300 +CONFIG_INT_WDT_CHECK_CPU1=y +CONFIG_TASK_WDT=y +# CONFIG_TASK_WDT_PANIC is not set +CONFIG_TASK_WDT_TIMEOUT_S=5 +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set +CONFIG_TIMER_TASK_STACK_SIZE=3584 +# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y +CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150 +CONFIG_MB_MASTER_DELAY_MS_CONVERT=200 +CONFIG_MB_QUEUE_LENGTH=20 +CONFIG_MB_SERIAL_TASK_STACK_SIZE=4096 +CONFIG_MB_SERIAL_BUF_SIZE=256 +CONFIG_MB_SERIAL_TASK_PRIO=10 +CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT=y +CONFIG_MB_CONTROLLER_SLAVE_ID=0x00112233 +CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20 +CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 +CONFIG_MB_CONTROLLER_STACK_SIZE=4096 +CONFIG_MB_EVENT_QUEUE_TIMEOUT=20 +# CONFIG_MB_TIMER_PORT_ENABLED is not set +# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set +CONFIG_TIMER_TASK_PRIORITY=1 +CONFIG_TIMER_TASK_STACK_DEPTH=3072 +CONFIG_TIMER_QUEUE_LENGTH=10 +# CONFIG_L2_TO_L3_COPY is not set +# CONFIG_USE_ONLY_LWIP_SELECT is not set +CONFIG_ESP_GRATUITOUS_ARP=y +CONFIG_GARP_TMR_INTERVAL=60 +CONFIG_TCPIP_RECVMBOX_SIZE=32 +CONFIG_TCP_MAXRTX=12 +CONFIG_TCP_SYNMAXRTX=12 +CONFIG_TCP_MSS=1440 +CONFIG_TCP_MSL=60000 +CONFIG_TCP_SND_BUF_DEFAULT=5760 +CONFIG_TCP_WND_DEFAULT=5760 +CONFIG_TCP_RECVMBOX_SIZE=6 +CONFIG_TCP_QUEUE_OOSEQ=y +# CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set +CONFIG_TCP_OVERSIZE_MSS=y +# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_TCP_OVERSIZE_DISABLE is not set +CONFIG_UDP_RECVMBOX_SIZE=6 +CONFIG_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_PPP_SUPPORT is not set +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_ESP32_PTHREAD_STACK_MIN=768 +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set +# CONFIG_USB_ENABLED is not set +CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_SUPPORT_TERMIOS=y +CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# End of deprecated options diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig_esp32.defaults b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig_esp32.defaults new file mode 100644 index 00000000..ed820396 --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig_esp32.defaults @@ -0,0 +1,8 @@ +CONFIG_ESPTOOLPY_BAUD_921600B=y + +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y + +CONFIG_TIMER_TASK_STACK_DEPTH=3072 + +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32.csv" \ No newline at end of file diff --git a/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig_esp8266.defaults b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig_esp8266.defaults new file mode 100644 index 00000000..ce86990c --- /dev/null +++ b/sdk/ESP-IDF/esp_fastbee_aliyun/sdkconfig_esp8266.defaults @@ -0,0 +1,10 @@ +CONFIG_NEWLIB_LIBRARY_LEVEL_NORMAL=y +CONFIG_ENABLE_PTHREAD=y +CONFIG_ESPTOOLPY_BAUD_921600B=y +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=6144 +CONFIG_FREERTOS_TIMER_STACKSIZE=3072 +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp8266.csv" +CONFIG_SUPPORT_TCP=y +CONFIG_MBEDTLS_DYNAMIC_BUFFER=y +CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT=y