ethan.du 6 роки тому
коміт
61051818a9
74 змінених файлів з 19222 додано та 0 видалено
  1. 201 0
      LICENSE
  2. 114 0
      README.md
  3. 97 0
      SConscript
  4. 29 0
      docs/api.md
  5. 23 0
      docs/port.md
  6. 41 0
      ports/fal/fal_cfg.h
  7. 35 0
      ports/fal/fal_flash_port.c
  8. 224 0
      ports/rtthread/HAL_OS_rtthread.c
  9. 269 0
      ports/rtthread/HAL_TCP_rtthread.c
  10. 36 0
      ports/rtthread/HAL_Timer_Platform.h
  11. 54 0
      ports/rtthread/HAL_Timer_rtthread.c
  12. 2909 0
      ports/ssl/HAL_TLS_config.h
  13. 305 0
      ports/ssl/HAL_TLS_mbedtls.c
  14. 216 0
      samples/dev_model/dev_model_sample.c
  15. 186 0
      samples/dynamic_auth/dynamic_auth_sample.c
  16. 291 0
      samples/mqtt/mqtt_sample.c
  17. 192 0
      samples/ota/ota_sample.c
  18. 392 0
      samples/shadow/shadow_sample.c
  19. 137 0
      uiot/certs/ca.c
  20. 33 0
      uiot/certs/ca.h
  21. 51 0
      uiot/dev_model/include/dm_config.h
  22. 78 0
      uiot/dev_model/include/dm_internal.h
  23. 84 0
      uiot/dev_model/src/dm_client.c
  24. 627 0
      uiot/dev_model/src/dm_mqtt.c
  25. 504 0
      uiot/mqtt/include/mqtt_client.h
  26. 38 0
      uiot/mqtt/include/mqtt_client_net.h
  27. 482 0
      uiot/mqtt/src/mqtt_client.c
  28. 1424 0
      uiot/mqtt/src/mqtt_client_common.c
  29. 399 0
      uiot/mqtt/src/mqtt_client_connect.c
  30. 38 0
      uiot/mqtt/src/mqtt_client_net.c
  31. 357 0
      uiot/mqtt/src/mqtt_client_publish.c
  32. 209 0
      uiot/mqtt/src/mqtt_client_subscribe.c
  33. 186 0
      uiot/mqtt/src/mqtt_client_unsubscribe.c
  34. 443 0
      uiot/mqtt/src/mqtt_client_yield.c
  35. 51 0
      uiot/ota/include/ota_config.h
  36. 97 0
      uiot/ota/include/ota_internal.h
  37. 337 0
      uiot/ota/src/ota_client.c
  38. 117 0
      uiot/ota/src/ota_fetch.c
  39. 170 0
      uiot/ota/src/ota_lib.c
  40. 173 0
      uiot/ota/src/ota_mqtt.c
  41. 216 0
      uiot/sdk-impl/uiot_defs.h
  42. 56 0
      uiot/sdk-impl/uiot_export.h
  43. 138 0
      uiot/sdk-impl/uiot_export_dm.h
  44. 31 0
      uiot/sdk-impl/uiot_export_file_upload.h
  45. 243 0
      uiot/sdk-impl/uiot_export_mqtt.h
  46. 144 0
      uiot/sdk-impl/uiot_export_ota.h
  47. 158 0
      uiot/sdk-impl/uiot_export_shadow.h
  48. 334 0
      uiot/sdk-impl/uiot_import.h
  49. 61 0
      uiot/sdk-impl/uiot_internal.h
  50. 235 0
      uiot/shadow/include/shadow_client.h
  51. 92 0
      uiot/shadow/include/shadow_client_common.h
  52. 171 0
      uiot/shadow/include/shadow_client_json.h
  53. 418 0
      uiot/shadow/src/shadow_client.c
  54. 198 0
      uiot/shadow/src/shadow_client_common.c
  55. 224 0
      uiot/shadow/src/shadow_client_json.c
  56. 1050 0
      uiot/shadow/src/shadow_client_manager.c
  57. 243 0
      uiot/utils/json_parser.c
  58. 161 0
      uiot/utils/json_parser.h
  59. 172 0
      uiot/utils/json_token.c
  60. 501 0
      uiot/utils/lite-list.h
  61. 95 0
      uiot/utils/lite-utils.h
  62. 166 0
      uiot/utils/string_utils.c
  63. 572 0
      uiot/utils/utils_httpc.c
  64. 76 0
      uiot/utils/utils_httpc.h
  65. 296 0
      uiot/utils/utils_list.c
  66. 97 0
      uiot/utils/utils_list.h
  67. 330 0
      uiot/utils/utils_md5.c
  68. 93 0
      uiot/utils/utils_md5.h
  69. 341 0
      uiot/utils/utils_net.c
  70. 107 0
      uiot/utils/utils_net.h
  71. 331 0
      uiot/utils/utils_sha2.c
  72. 99 0
      uiot/utils/utils_sha2.h
  73. 44 0
      uiot/utils/utils_timer.c
  74. 80 0
      uiot/utils/utils_timer.h

+ 201 - 0
LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 114 - 0
README.md

@@ -0,0 +1,114 @@
+##  UCloud IOT SDK for rt-thread Package 
+## 1 介绍
+
+UCloud IOT SDK for rt-thread Package 是基于[UCloud设备端C-SDK](https://github.com/ucloud/ucloud-iot-device-sdk-c)在RThread环境开发的软件包,用于连接uiot-core物联网平台
+
+### 1.1 SDK架构图
+![](https://uiot.cn-sh2.ufileos.com/sdk%E6%9E%B6%E6%9E%84%E5%9B%BE.png)
+
+### 1.2 目录结构
+
+| 名称            	| 说明 |
+| ----            	| ---- |
+| uiot            	| UCloud设备端C-SDK |
+| ports           	| 移植文件目录 |
+| samples         	| 示例目录 |
+|  ├─mqtt      		| 静态注册收发消息示例 |
+|  ├─dynamic_auth   | 动态注册示例 |
+|  ├─dev_model      | 物模型示例 |
+|  ├─ota      		| ota升级示例 |
+|  ├─shadow      	| 设备影子示例 |
+| docs         	    | 说明文档 |
+| LICENSE         	| 许可证文件 |
+| README.md       	| 软件包使用说明 |
+| SConscript      	| RT-Thread 默认的构建脚本 |
+
+### 1.3 许可证
+
+许可协议Apache 2.0。
+
+### 1.4 依赖
+Tls功能需要mbedtls软件包
+[ ] mbedtls: An portable and flexible SSL/TLS library  ----
+
+ota功能需要ota_downloader
+[ ] ota_downloader: The firmware downloader which using on RT-Thread OTA component  --->
+
+## 2 如何打开软件包
+menuconfig配置
+- RT-Thread env开发工具中使用 `menuconfig` 软件包,配置产品及设备信息,
+路径如下:
+```
+RT-Thread online packages  --->
+	IoT - internet of things  --->
+		IoT Cloud  --->
+			[ ] ucloud-iot-sdk: ucloud iot sdk for uiot-core platform.  --->
+			  --- ucloud-iothub:  ucloud iot sdk for uiot-core platform 
+				[ ]   Enable Mqtt 
+				ucloud Device Config  --->  
+				Version (latest)  --->	
+```
+
+## 3 软件包的使用
+根据产品需求选择合适的应用示例修改新增业务逻辑,也可新增例程编写新的业务逻辑。
+```			
+	--- ucloud-iot-sdk: ucloud iot sdk for uiot-core platform.
+	[*]   Enable mqtt                                                                                             
+		Auth Mode (Enable Static Register)  --->                                                               
+			Ucloud Device Config  --->                                                                                 
+	[ ]   Enable Shadow                                                                                        
+	[ ]   Enable Dev Model                                                                                      
+	[ ]   Enable Ota                                                                                                
+	[ ]   Enable Tls                                                                                            
+	[ ]   Enable Ucloud Mqtt Sample                                                                                 
+	[ ]   Enable Ucloud Shadow Sample                                                                          
+	[ ]   Enable Ucloud Dev Model Sample                                                                        
+	[ ]   Enable Ucloud Ota Sample                                                                              
+		  Version (latest)  --->
+```
+
+- 选项说明
+
+`Enable mqtt`:使能MQTT功能。
+
+`Auth Mode (Enable static register)`:认证模式,分为静态认证和动态认证模式, (括号内为当前选择的模式)。
+
+`Enable Static Register`:静态注册模式使用产品号,设备号,设备密钥认证
+
+`Enable Dynamic Register`:动态注册模式使用产品号,设备号,产品密钥认证
+
+`Ucloud Device Config `:根据认证模式填写当前设备认证要素,动态认证时,设备密钥可以不填写
+
+`Enable Shadow`:使能设备影子功能
+
+`Enable Dev Model`:使能物模型功能
+
+`Enable Ota`:使能远程升级版本的功能,若使能,则会关联选中ota_downloader软件包。
+
+`Enable TLS`: 是否使能TLS,若使能,则会关联选中mbedTLS软件包。
+
+`Enable Ucloud Mqtt Sample`:使能mqtt收发消息的案例
+
+`Enable Ucloud Shadow Sample`:使能物模型的案例
+
+`Enable Ucloud Dev Model Sample`:使能物模型的案例
+
+`Enable Ucloud Ota Sample`:使能远程升级版本的案例
+
+`Version (latest)  --->`:
+
+- 使用 `pkgs --update` 命令下载软件包
+
+#### 2.2 创建可订阅可发布的Topic
+
+案例中使用的topic为订阅/接收权限的topic需要在云平台上将/${ProductSN}/${DeviceSN}/set增加权限
+
+### 2.3 编译及运行
+1. 使用命令 scons --target=xxx 输出对应的工程,编译 
+
+2. 打开生成的工程,编译下载到设备中
+
+### 2.4 运行demo程序
+系统启动后,在 MSH 中使用命令执行:
+
+

+ 97 - 0
SConscript

@@ -0,0 +1,97 @@
+import os
+from building import *
+import rtconfig
+
+cwd  = GetCurrentDir()
+
+src_base  = []
+
+sample_ucloud_mqtt_src  = []
+sample_ucloud_mqtt_dynamic_auth_src  = []
+sample_ucloud_shadow_src  = []
+sample_ucloud_dev_model_src  = []
+sample_ucloud_ota_src = []
+
+CPPPATH = []
+CPPDEFINES = []
+LOCAL_CCFLAGS = ''
+
+
+#include headfile
+CPPPATH += [cwd + '/ports/rtthread']
+CPPPATH += [cwd + '/ports/ssl']
+CPPPATH += [cwd + '/ports/fal']
+CPPPATH += [cwd + '/uiot/certs']
+CPPPATH += [cwd + '/uiot/dev_model/include']
+CPPPATH += [cwd + '/uiot/mqtt/include']
+CPPPATH += [cwd + '/uiot/ota/include']
+CPPPATH += [cwd + '/uiot/sdk-impl']
+CPPPATH += [cwd + '/uiot/shadow/include']
+CPPPATH += [cwd + '/uiot/utils']
+
+#Gen MQTT src file
+if GetDepend(['PKG_USING_UCLOUD_MQTT']):
+	src_base += Glob('uiot/mqtt/src/*.c')
+	src_base += Glob('uiot/utils/*.c')
+	src_base += Glob('ports/rtthread/*.c')
+	src_base += Glob('ports/fal/*.c')
+	SrcRemove(src_base, 'ucloud-iot-sdk/uiot/utils/utils_httpc.c')
+	SrcRemove(src_base, 'ucloud-iot-sdk/uiot/utils/utils_md5.c')
+	SrcRemove(src_base, 'ucloud-iot-sdk/uiot/utils/utils_sha2.c')	
+
+#enable dynamic auth
+if GetDepend(['PKG_USING_UCLOUD_MQTT_DYNAMIC_AUTH']):
+	CPPDEFINES += ['AUTH_MODE_DYNAMIC']
+
+#Gen shadow src file
+if GetDepend(['PKG_USING_UCLOUD_SHADOW']):
+	src_base += Glob('uiot/shadow/src/*.c')
+
+#Gen dev model src file
+if GetDepend(['PKG_USING_UCLOUD_DEV_MODEL']):
+	src_base += Glob('uiot/dev_model/src/*.c')
+
+#Gen ota src file
+if GetDepend(['PKG_USING_UCLOUD_OTA']):
+	src_base += Glob('uiot/ota/src/*.c')
+	
+#TLS used
+if GetDepend(['PKG_USING_UCLOUD_TLS']):
+	src_base += Glob('uiot/certs/ca.c')
+	src_base += Glob('ports/ssl/HAL_TLS_mbedtls.c')
+	CPPDEFINES += ['SUPPORT_TLS', 'MBEDTLS_CONFIG_FILE=<HAL_TLS_config.h>']	
+
+#Hub C-SDK core
+group = DefineGroup('ucloud-iot', src_base, depend = ['PKG_USING_UCLOUD_IOT'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)
+
+#MQTT Example
+if GetDepend(['PKG_USING_UCLOUD_MQTT_SAMPLE']):
+	sample_ucloud_mqtt_src += Glob('samples/mqtt/mqtt_sample.c')
+	
+group = DefineGroup('sample_ucloud_mqtt', sample_ucloud_mqtt_src, depend = ['PKG_USING_UCLOUD_MQTT_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)	
+
+#MQTT Dynamic Auth Example
+if GetDepend(['PKG_USING_UCLOUD_MQTT_DYNAMIC_AUTH_SAMPLE']):
+	sample_ucloud_mqtt_dynamic_auth_src += Glob('samples/dynamic_auth/dynamic_auth_sample.c')
+	
+group = DefineGroup('sample_ucloud_mqtt_dynamic_auth', sample_ucloud_mqtt_dynamic_auth_src, depend = ['PKG_USING_UCLOUD_MQTT_DYNAMIC_AUTH_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)	
+	
+#Shadow Example
+if GetDepend(['PKG_USING_UCLOUD_SHADOW_SAMPLE']):
+	sample_ucloud_shadow_src += Glob('samples/shadow/shadow_sample.c')
+	
+group = DefineGroup('sample_ucloud_shadow', sample_ucloud_shadow_src, depend = ['PKG_USING_UCLOUD_SHADOW_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)	
+
+#Dev Model Example
+if GetDepend(['PKG_USING_UCLOUD_DEV_MODEL_SAMPLE']):
+	sample_ucloud_dev_model_src += Glob('samples/dev_model/dev_model_sample.c')
+	
+group = DefineGroup('sample_ucloud_dev_model', sample_ucloud_dev_model_src, depend = ['PKG_USING_UCLOUD_DEV_MODEL_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)	
+
+#OTA Example
+if GetDepend(['PKG_USING_UCLOUD_OTA_SAMPLE']):
+	sample_ucloud_ota_src += Glob('samples/ota/ota_sample.c')
+	
+group = DefineGroup('sample_ucloud_ota', sample_ucloud_ota_src, depend = ['PKG_USING_UCLOUD_OTA_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)		
+  
+Return('group')

+ 29 - 0
docs/api.md

@@ -0,0 +1,29 @@
+## UCloud 软件包API说明
+
+## 可以修改以下宏来调整部分功能
+
+```
+
+/* MQTT心跳消息发送周期, 单位:s */
+#define UIOT_MQTT_KEEP_ALIVE_INTERNAL                               (240)
+
+/* MQTT 阻塞调用(包括连接, 订阅, 发布等)的超时时间, 单位:ms 建议5000ms */
+#define UIOT_MQTT_COMMAND_TIMEOUT                                   (5 * 10000)
+
+/* 接收到 MQTT 包头以后,接收剩余长度及剩余包,最大延迟等待时延 */
+#define UIOT_MQTT_MAX_REMAIN_WAIT_MS                                (2000)
+
+/* MQTT消息发送buffer大小, 支持最大256*1024 */
+#define UIOT_MQTT_TX_BUF_LEN                                        (2048)
+
+/* MQTT消息接收buffer大小, 支持最大256*1024 */
+#define UIOT_MQTT_RX_BUF_LEN                                        (2048)
+
+/* 重连最大等待时间 */
+#define MAX_RECONNECT_WAIT_INTERVAL 								(60 * 1000)
+
+/* 使能无限重连,0表示超过重连最大等待时间后放弃重连,
+ * 1表示超过重连最大等待时间后以固定间隔尝试重连*/
+#define ENABLE_INFINITE_RECONNECT 								    1
+
+```

+ 23 - 0
docs/port.md

@@ -0,0 +1,23 @@
+## UCloud软件包移植指南
+
+## 移植注意事项
+
+1.需要关注/ports路径下的三个文件夹,目录结构如下:
+
+| 名称            			| 说明 |
+| ----            			| ---- |
+| fal            			| flash相关 |
+|  ├─fal_cfg.h     			| flash分区表配置 |
+|  ├─fal_flash_port.c   	| flash驱动 |
+| rtthread          		| rtthread系统相关 |
+|  ├─HAL_OS_rtthread.c      | 操作系统相关接口 |
+|  ├─HAL_TCP_rtthread.c     | 网络操作相关接口 |
+|  ├─HAL_Timer_Platform.h   | 定时操作相关接口声明 |
+|  ├─HAL_Timer_rtthread.c   | 定时操作相关接口 |
+| ssl          				| ssl数据加密相关,ssl功能不开启时可以不关注 |
+|  ├─HAL_TLS_config.h       | mbedtls库相关的声明 |
+|  ├─HAL_TLS_mbedtls.c      | mbedtls库相关的接口 |
+
+2.移植到新的开发板上时只需要修改fal下的相关的文件,针对使用的开发板flash合理划分分区,修改分区配置表及驱动
+
+3.可以通过修改mbedtls文件夹下的HAL_TLS_config.h打开或关闭宏添加或删除对应的功能

+ 41 - 0
ports/fal/fal_cfg.h

@@ -0,0 +1,41 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef _FAL_CFG_H_
+#define _FAL_CFG_H_
+
+#include <rtconfig.h>
+#include <board.h>
+
+/* ===================== Flash device Configuration ========================= */
+extern const struct fal_flash_dev stm32_onchip_flash;
+
+/* flash device table */
+#define FAL_FLASH_DEV_TABLE                                          \
+{                                                                    \
+    &stm32_onchip_flash,                                           \
+}
+/* ====================== Partition Configuration ========================== */
+#ifdef FAL_PART_HAS_TABLE_CFG
+/* partition table */
+#define FAL_PART_TABLE                                                               \
+{                                                                                    \
+    {FAL_PART_MAGIC_WORD,       "app",     "onchip_flash", 512*1024,  512*1024, 0}, \
+    {FAL_PART_MAGIC_WORD,  "download",     "onchip_flash", 1024*1024, 512*1024, 0}, \
+    {FAL_PART_MAGIC_WORD,  "factory",      "onchip_flash", 1536*1024, 512*1024, 0}, \
+}
+#endif /* FAL_PART_HAS_TABLE_CFG */
+
+#endif /* _FAL_CFG_H_ */

+ 35 - 0
ports/fal/fal_flash_port.c

@@ -0,0 +1,35 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <fal.h>
+
+#include <stm32f7xx.h>
+
+static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size)
+{
+    return stm32_flash_read(stm32_onchip_flash.addr + offset, buf, size);
+}
+
+static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size)
+{
+    return stm32_flash_write(stm32_onchip_flash.addr + offset, buf, size);
+}
+
+static int fal_flash_erase(long offset, size_t size)
+{
+    return stm32_flash_erase(stm32_onchip_flash.addr + offset, size);
+}
+
+const struct fal_flash_dev stm32_onchip_flash = { "onchip_flash", STM32_FLASH_START_ADRESS, STM32_FLASH_SIZE, (512 * 1024), {NULL, fal_flash_read, fal_flash_write, fal_flash_erase} };

+ 224 - 0
ports/rtthread/HAL_OS_rtthread.c

@@ -0,0 +1,224 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+     
+#include "uiot_defs.h"
+#include "stdint.h"
+#include <rtthread.h>
+
+#define DEBUG_DEV_INFO_USED
+// 测试时可在此处填入设备四元组
+#ifdef DEBUG_DEV_INFO_USED
+/* 产品序列号 */
+static char sg_product_sn[IOT_PRODUCT_SN_LEN + 1] = "YOUR_PRODUCT_SN";
+/* 产品密钥 */
+static char sg_product_secret[IOT_PRODUCT_SECRET_LEN + 1] = "PRODUCT_SECRET";
+/* 设备序列号 */
+static char sg_device_sn[IOT_DEVICE_SN_LEN + 1] = "YOUR_DEVICE_SN";
+/* 设备密钥 */
+static char sg_device_secret[IOT_DEVICE_SECRET_LEN + 1] = "DEVICE_SECRET";
+#endif
+
+static int g_mutexnum = 0;
+
+void *HAL_MutexCreate(void) 
+{
+    char name[RT_NAME_MAX];
+    rt_snprintf(name, RT_NAME_MAX, "mutex%d", g_mutexnum);
+    g_mutexnum++;
+    return rt_mutex_create(name, RT_IPC_FLAG_FIFO);
+}
+
+void HAL_MutexDestroy(_IN_ void *mutex) 
+{
+    rt_mutex_delete((rt_mutex_t)mutex);
+    return;
+}
+
+void HAL_MutexLock(_IN_ void *mutex) 
+{
+    rt_mutex_take((rt_mutex_t)mutex, 0xFFFF);
+    return;
+}
+
+void HAL_MutexUnlock(_IN_ void *mutex) 
+{   
+    rt_mutex_release((rt_mutex_t)mutex);
+    return;
+}
+
+void *HAL_Malloc(_IN_ uint32_t size)
+{
+    return rt_malloc(size);
+}
+
+void HAL_Free(_IN_ void *ptr) 
+{
+    rt_free(ptr);
+}
+
+#define HAL_OS_LOG_MAXLEN   1024
+void HAL_Printf(_IN_ const char *fmt, ...) 
+{
+    va_list args;
+	char log_buf[HAL_OS_LOG_MAXLEN];
+    
+    va_start(args, fmt);
+    rt_vsnprintf(log_buf, HAL_OS_LOG_MAXLEN, fmt, args);
+    va_end(args);
+    printf("%s", log_buf);
+}
+
+int HAL_Snprintf(_IN_ char *str, _IN_ const int len, _IN_ 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(_OU_ char *str, _IN_ const int len, _IN_ const char *format, _IN_ va_list ap) {
+    return vsnprintf(str, len, format, ap);
+}
+
+void HAL_SleepMs(uint32_t ms)
+{
+    rt_thread_mdelay(ms);
+}
+
+IoT_Error_t HAL_GetProductSN(_OU_ char productSN[IOT_PRODUCT_SN_LEN + 1]) {
+#ifdef DEBUG_DEV_INFO_USED
+    int len = strlen(sg_product_sn);
+    memset(productSN, 0x0, IOT_PRODUCT_SN_LEN + 1);
+    strncpy(productSN, sg_product_sn, len);
+    return SUCCESS_RET;
+#else
+    HAL_Printf("HAL_GetProductSN is not implement");
+    return FAILURE_RET;
+#endif
+}
+
+IoT_Error_t HAL_GetProductSecret(_OU_ char productSecret[IOT_PRODUCT_SECRET_LEN + 1]) {
+#ifdef DEBUG_DEV_INFO_USED
+    int len = strlen(sg_product_secret);
+    memset(productSecret, 0x0, IOT_PRODUCT_SECRET_LEN + 1);
+    strncpy(productSecret, sg_product_secret, len);
+    return SUCCESS_RET;
+#else
+    Log_e("HAL_GetProductSecret is not implement");
+    return FAILURE_RET;
+#endif
+}
+
+IoT_Error_t HAL_GetDeviceSN(_OU_ char deviceSN[IOT_DEVICE_SN_LEN + 1]) {
+#ifdef DEBUG_DEV_INFO_USED
+    int len = strlen(sg_device_sn);
+    memset(deviceSN, 0x0, IOT_DEVICE_SN_LEN + 1);
+    strncpy(deviceSN, sg_device_sn, len);
+    return SUCCESS_RET;
+#else
+    HAL_Printf("HAL_GetDeviceSN is not implement");
+    return FAILURE_RET;
+#endif
+}
+
+IoT_Error_t HAL_GetDeviceSecret(_OU_ char deviceSecret[IOT_DEVICE_SECRET_LEN + 1]) {
+#ifdef DEBUG_DEV_INFO_USED
+    int len = strlen(sg_device_secret);
+    memset(deviceSecret, 0x0, IOT_DEVICE_SECRET_LEN + 1);
+    strncpy(deviceSecret, sg_device_secret, len);
+    return SUCCESS_RET;
+#else
+    HAL_Printf("HAL_GetDeviceSecret is not implement");
+    return FAILURE_RET;
+#endif
+}
+
+IoT_Error_t HAL_SetProductSN(_IN_ const char *pProductSN) {
+#ifdef DEBUG_DEV_INFO_USED
+    int len = strlen(pProductSN);
+    if (len > IOT_PRODUCT_SN_LEN) {
+        return FAILURE_RET;
+    }
+
+    memset(sg_product_sn, 0x0, IOT_PRODUCT_SN_LEN + 1);
+    strncpy(sg_product_sn, pProductSN, len);
+
+    return SUCCESS_RET;
+#else
+    HAL_Printf("HAL_SetProductSN is not implement");
+    return FAILURE_RET;
+#endif
+}
+
+IoT_Error_t HAL_SetProductSecret(_IN_ const char *pProductSecret) {
+#ifdef DEBUG_DEV_INFO_USED
+    int len = strlen(pProductSecret);
+    if (len > IOT_PRODUCT_SECRET_LEN) {
+        return FAILURE_RET;
+    }
+
+    memset(sg_product_secret, 0x0, IOT_PRODUCT_SECRET_LEN + 1);
+    strncpy(sg_product_secret, pProductSecret, len);
+
+    return SUCCESS_RET;
+#else
+    HAL_Printf("HAL_SetProductSecret is not implement");
+    return FAILURE_RET;
+#endif
+
+}
+
+IoT_Error_t HAL_SetDeviceSN(_IN_ const char *pDeviceSN) {
+#ifdef DEBUG_DEV_INFO_USED
+    int len = strlen(pDeviceSN);
+    if (len > IOT_DEVICE_SN_LEN) {
+        return FAILURE_RET;
+    }
+
+    memset(sg_device_sn, 0x0, IOT_DEVICE_SN_LEN + 1);
+    strncpy(sg_device_sn, pDeviceSN, len);
+
+    return SUCCESS_RET;
+#else
+    HAL_Printf("HAL_SetDeviceSN is not implement");
+    return FAILURE_RET;
+#endif
+}
+
+IoT_Error_t HAL_SetDeviceSecret(_IN_ const char *pDeviceSecret) {
+#ifdef DEBUG_DEV_INFO_USED
+    int len = strlen(pDeviceSecret);
+    if (len > IOT_DEVICE_SECRET_LEN) {
+        return FAILURE_RET;
+    }
+
+    memset(sg_device_secret, 0x0, IOT_DEVICE_SECRET_LEN + 1);
+    strncpy(sg_device_secret, pDeviceSecret, len);
+
+    return SUCCESS_RET;
+#else
+    HAL_Printf("HAL_SetDeviceSecret is not implement");
+    return FAILURE_RET;
+#endif
+}
+

+ 269 - 0
ports/rtthread/HAL_TCP_rtthread.c

@@ -0,0 +1,269 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+
+#include <rtthread.h>
+#include "uiot_import.h"
+
+static uint64_t rtthread_get_time_ms(void)
+{
+#if (RT_TICK_PER_SECOND == 1000)
+    /* #define RT_TICK_PER_SECOND 1000 */
+    return (unsigned long)rt_tick_get();
+#else
+    unsigned long tick = 0;
+            
+    tick = rt_tick_get();
+    tick = tick * 1000;
+    return (unsigned long)((tick + RT_TICK_PER_SECOND - 1)/RT_TICK_PER_SECOND);
+#endif
+
+}
+
+static uint64_t rtthread_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_Connect(_IN_ const char *host, _IN_ uint16_t port) {
+    struct addrinfo hints;
+    struct addrinfo *addrInfoList = NULL;
+    struct addrinfo *cur = NULL;
+    int fd = 0;
+    int rc = 0;
+    char service[6];
+
+    memset(&hints, 0, sizeof(hints));
+
+    printf("establish tcp connection with server(host='%s', port=[%u])\n", 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) {
+        printf("getaddrinfo error(%d), host = '%s', port = [%d]\n", rc, host, port);
+        return (uintptr_t) (-1);
+    }
+
+    for (cur = addrInfoList; cur != NULL; cur = cur->ai_next) {
+        if (cur->ai_family != AF_INET) {
+            printf("socket type error\n");
+            rc = -1;
+            continue;
+        }
+
+        fd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
+        if (fd < 0) {
+            printf("create socket error\n");
+            rc = -1;
+            continue;
+        }
+
+        if (connect(fd, cur->ai_addr, cur->ai_addrlen) == 0) {
+            rc = fd;
+            break;
+        }
+
+        close(fd);
+        printf("connect error\n");
+        rc = -1;
+    }
+
+    if (-1 == rc) {
+        printf("fail to establish tcp\n");
+    } else {
+        printf("success to establish tcp, fd=%d\n", rc);
+    }
+    freeaddrinfo(addrInfoList);
+
+    //忽略SIGPIPE,防止在网络异常时进程退出
+    signal(SIGPIPE, SIG_IGN);
+
+    return (uintptr_t) rc;
+}
+
+
+int32_t HAL_TCP_Disconnect(_IN_ uintptr_t fd) {
+    int rc;
+
+    /* Shutdown both send and receive operations. */
+    rc = shutdown((int) fd, 2);
+    if (0 != rc) {
+        printf("shutdown error\n");
+        return FAILURE_RET;
+    }
+
+    rc = close((int) fd);
+    if (0 != rc) {
+        printf("close socket error\n");
+        return FAILURE_RET;
+    }
+
+    return SUCCESS_RET;
+}
+
+
+int32_t HAL_TCP_Write(_IN_ uintptr_t fd, _IN_ unsigned char *buf, _IN_ size_t len, _IN_ uint32_t timeout_ms) {
+    int ret,tcp_fd;
+    size_t len_sent;
+    uint64_t t_end;
+    fd_set sets;
+    IoT_Error_t net_err = SUCCESS_RET;
+
+    t_end = rtthread_get_time_ms() + timeout_ms;
+    len_sent = 0;
+    ret = 1; /* send one time if timeout_ms is value 0 */
+
+    if (fd >= FD_SETSIZE) {
+        return -1;
+    }
+    tcp_fd = (int)fd;
+
+    do {
+        uint64_t t_left = rtthread_time_left(t_end, rtthread_get_time_ms());
+
+        if (0 != t_left) {
+            struct timeval timeout;
+
+            FD_ZERO(&sets);
+            FD_SET(tcp_fd, &sets);
+
+            timeout.tv_sec = t_left / 1000;
+            timeout.tv_usec = (t_left % 1000) * 1000;
+
+            ret = select(tcp_fd + 1, NULL, &sets, NULL, &timeout);
+            if (ret > 0) {
+                if (0 == FD_ISSET(tcp_fd, &sets)) {
+                    printf("Should NOT arrive\n");
+                    /* If timeout in next loop, it will not sent any data */
+                    ret = 0;
+                    continue;
+                }
+            } else if (0 == ret) {
+                printf("select-write timeout %d\n", tcp_fd);
+                break;
+            } else {
+                if (EINTR == errno) {
+                    printf("EINTR be caught\n");
+                    continue;
+                }
+
+                printf("select-write fail, ret = select() = %d\n", ret);
+                net_err = ERR_TCP_WRITE_FAILED;
+                break;
+            }
+        }
+
+        if (ret > 0) {
+            ret = send(tcp_fd, buf + len_sent, len - len_sent, 0);
+            if (ret > 0) {
+                len_sent += ret;
+            } else if (0 == ret) {
+                printf("No data be sent\n");
+            } else {
+                if (EINTR == errno) {
+                    printf("EINTR be caught\n");
+                    continue;
+                }
+
+                printf("send fail, ret = send() = %d\n", ret);
+                net_err = ERR_TCP_WRITE_FAILED;
+                break;
+            }
+        }
+    } while (!net_err && (len_sent < len) && (rtthread_time_left(t_end, rtthread_get_time_ms()) > 0));
+
+    return net_err != SUCCESS_RET ? net_err : len_sent;
+}
+
+
+int32_t HAL_TCP_Read(_IN_ uintptr_t fd, _OU_ unsigned char *buf, _IN_ size_t len, _IN_ uint32_t timeout_ms) {
+    int tcp_fd;
+    IoT_Error_t err_code;
+    size_t len_recv;
+    uint64_t t_end;
+    fd_set sets;
+    struct timeval timeout;
+
+    t_end = rtthread_get_time_ms() + timeout_ms;
+    len_recv = 0;
+    err_code = SUCCESS_RET;
+
+    if (fd >= FD_SETSIZE) {
+        return FAILURE_RET;
+    }
+    tcp_fd = (int)fd;
+
+    do {
+        uint64_t t_left = rtthread_time_left(t_end, rtthread_get_time_ms());
+        if (0 == t_left) {
+            break;
+        }
+        FD_ZERO(&sets);
+        FD_SET(tcp_fd, &sets);
+
+        timeout.tv_sec = t_left / 1000;
+        timeout.tv_usec = (t_left % 1000) * 1000;
+
+        int ret = select(tcp_fd + 1, &sets, NULL, NULL, &timeout);
+        if (ret > 0) {
+            ret = recv(tcp_fd, buf + len_recv, len - len_recv, 0);
+            if (ret > 0) {
+                len_recv += ret;
+            } else if (0 == ret) {
+                printf("connection is closed\n");
+                err_code = ERR_TCP_PEER_SHUTDOWN;
+                break;
+            } else {
+                if (EINTR == errno) {
+                    continue;
+                }
+                printf("recv fail\n");
+                err_code = ERR_TCP_READ_FAILED;
+                break;
+            }
+        } else if (0 == ret) {
+            break;
+        } else {
+            if (EINTR == errno) {
+                continue;
+            }
+            printf("select-recv fail\n");
+            err_code = ERR_TCP_READ_FAILED;
+            break;
+        }
+    } while ((len_recv < len));
+
+    return (0 != len_recv) ? len_recv : err_code;
+}

+ 36 - 0
ports/rtthread/HAL_Timer_Platform.h

@@ -0,0 +1,36 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_HAL_TIMER_PLATFORM_H_
+#define C_SDK_HAL_TIMER_PLATFORM_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <rtthread.h>
+
+
+/**
+ * definition of the Timer struct. Platform specific
+ */
+struct Timer {
+    rt_tick_t end_time;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif //C_SDK_HAL_TIMER_PLATFORM_H_

+ 54 - 0
ports/rtthread/HAL_Timer_rtthread.c

@@ -0,0 +1,54 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "uiot_import.h"
+#include <rtthread.h>
+
+bool HAL_Timer_Expired(Timer *timer) {
+    rt_tick_t now;
+    now = rt_tick_get();
+    return timer->end_time < now;
+}
+
+void HAL_Timer_Countdown_ms(_IN_ Timer *timer, unsigned int timeout_ms) {
+    rt_tick_t now;
+    now = rt_tick_get();
+    timer->end_time = now + rt_tick_from_millisecond(timeout_ms);
+}
+
+void HAL_Timer_Countdown(_IN_ Timer *timer, unsigned int timeout) {
+    rt_tick_t now;
+    now = rt_tick_get();
+    timer->end_time = now + rt_tick_from_millisecond(timeout * 1000);
+}
+
+uint32_t HAL_Timer_Remain_ms(Timer *timer) {
+    rt_tick_t now;
+    now = rt_tick_get();
+    rt_tick_t result = timer->end_time - now;
+    return result;
+}
+
+void HAL_Timer_Init(Timer *timer) {
+    timer->end_time = (rt_tick_t)0;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 2909 - 0
ports/ssl/HAL_TLS_config.h

@@ -0,0 +1,2909 @@
+/**
+ * \file tls_config.h
+ *
+ * \brief Configuration options (set of defines)
+ *
+ *  This set of compile-time options may be used to enable
+ *  or disable features selectively, and reduce the global
+ *  memory footprint.
+ */
+/*
+ *  Copyright (C) 2006-2019, ARM Limited, All Rights Reserved
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+#ifndef MBEDTLS_CONFIG_H
+#define MBEDTLS_CONFIG_H
+
+/* the memory allocation method configurations */
+#include <rtthread.h>
+
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+/**
+ * \name SECTION: System support
+ *
+ * This section sets system specific settings.
+ * \{
+ */
+
+/**
+ * \def MBEDTLS_HAVE_ASM
+ *
+ * The compiler has support for asm().
+ *
+ * Requires support for asm() in compiler.
+ *
+ * Used in:
+ *      library/timing.c
+ *      library/padlock.c
+ *      include/mbedtls/bn_mul.h
+ *
+ * Comment to disable the use of assembly code.
+ */
+#define MBEDTLS_HAVE_ASM
+
+/**
+ * \def MBEDTLS_NO_UDBL_DIVISION
+ *
+ * The platform lacks support for double-width integer division (64-bit
+ * division on a 32-bit platform, 128-bit division on a 64-bit platform).
+ *
+ * Used in:
+ *      include/mbedtls/bignum.h
+ *      library/bignum.c
+ *
+ * The bignum code uses double-width division to speed up some operations.
+ * Double-width division is often implemented in software that needs to
+ * be linked with the program. The presence of a double-width integer
+ * type is usually detected automatically through preprocessor macros,
+ * but the automatic detection cannot know whether the code needs to
+ * and can be linked with an implementation of division for that type.
+ * By default division is assumed to be usable if the type is present.
+ * Uncomment this option to prevent the use of double-width division.
+ *
+ * Note that division for the native integer type is always required.
+ * Furthermore, a 64-bit type is always required even on a 32-bit
+ * platform, but it need not support multiplication or division. In some
+ * cases it is also desirable to disable some double-width operations. For
+ * example, if double-width division is implemented in software, disabling
+ * it can reduce code size in some embedded targets.
+ */
+//#define MBEDTLS_NO_UDBL_DIVISION
+
+/**
+ * \def MBEDTLS_HAVE_SSE2
+ *
+ * CPU supports SSE2 instruction set.
+ *
+ * Uncomment if the CPU supports SSE2 (IA-32 specific).
+ */
+//#define MBEDTLS_HAVE_SSE2
+
+/**
+ * \def MBEDTLS_HAVE_TIME
+ *
+ * System has time.h and time().
+ * The time does not need to be correct, only time differences are used,
+ * by contrast with MBEDTLS_HAVE_TIME_DATE
+ *
+ * Defining MBEDTLS_HAVE_TIME allows you to specify MBEDTLS_PLATFORM_TIME_ALT,
+ * MBEDTLS_PLATFORM_TIME_MACRO, MBEDTLS_PLATFORM_TIME_TYPE_MACRO and
+ * MBEDTLS_PLATFORM_STD_TIME.
+ *
+ * Comment if your system does not support time functions
+ */
+#define MBEDTLS_HAVE_TIME
+
+/**
+ * \def MBEDTLS_HAVE_TIME_DATE
+ *
+ * System has time.h and time(), gmtime() and the clock is correct.
+ * The time needs to be correct (not necesarily very accurate, but at least
+ * the date should be correct). This is used to verify the validity period of
+ * X.509 certificates.
+ *
+ * Comment if your system does not have a correct clock.
+ */
+// #define MBEDTLS_HAVE_TIME_DATE
+
+/**
+ * \def MBEDTLS_PLATFORM_MEMORY
+ *
+ * Enable the memory allocation layer.
+ *
+ * By default mbed TLS uses the system-provided calloc() and free().
+ * This allows different allocators (self-implemented or provided) to be
+ * provided to the platform abstraction layer.
+ *
+ * Enabling MBEDTLS_PLATFORM_MEMORY without the
+ * MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide
+ * "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and
+ * free() function pointer at runtime.
+ *
+ * Enabling MBEDTLS_PLATFORM_MEMORY and specifying
+ * MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the
+ * alternate function at compile time.
+ *
+ * Requires: MBEDTLS_PLATFORM_C
+ *
+ * Enable this layer to allow use of alternative memory allocators.
+ */
+//#define MBEDTLS_PLATFORM_MEMORY
+
+/**
+ * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+ *
+ * Do not assign standard functions in the platform layer (e.g. calloc() to
+ * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF)
+ *
+ * This makes sure there are no linking errors on platforms that do not support
+ * these functions. You will HAVE to provide alternatives, either at runtime
+ * via the platform_set_xxx() functions or at compile time by setting
+ * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a
+ * MBEDTLS_PLATFORM_XXX_MACRO.
+ *
+ * Requires: MBEDTLS_PLATFORM_C
+ *
+ * Uncomment to prevent default assignment of standard functions in the
+ * platform layer.
+ */
+//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+
+/**
+ * \def MBEDTLS_PLATFORM_EXIT_ALT
+ *
+ * MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the
+ * function in the platform abstraction layer.
+ *
+ * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will
+ * provide a function "mbedtls_platform_set_printf()" that allows you to set an
+ * alternative printf function pointer.
+ *
+ * All these define require MBEDTLS_PLATFORM_C to be defined!
+ *
+ * \note MBEDTLS_PLATFORM_SNPRINTF_ALT is required on Windows;
+ * it will be enabled automatically by check_config.h
+ *
+ * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as
+ * MBEDTLS_PLATFORM_XXX_MACRO!
+ *
+ * Requires: MBEDTLS_PLATFORM_TIME_ALT requires MBEDTLS_HAVE_TIME
+ *
+ * Uncomment a macro to enable alternate implementation of specific base
+ * platform function
+ */
+//#define MBEDTLS_PLATFORM_EXIT_ALT
+//#define MBEDTLS_PLATFORM_TIME_ALT
+//#define MBEDTLS_PLATFORM_FPRINTF_ALT
+//#define MBEDTLS_PLATFORM_PRINTF_ALT
+//#define MBEDTLS_PLATFORM_SNPRINTF_ALT
+//#define MBEDTLS_PLATFORM_NV_SEED_ALT
+//#define MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT
+
+/**
+ * \def MBEDTLS_DEPRECATED_WARNING
+ *
+ * Mark deprecated functions so that they generate a warning if used.
+ * Functions deprecated in one version will usually be removed in the next
+ * version. You can enable this to help you prepare the transition to a new
+ * major version by making sure your code is not using these functions.
+ *
+ * This only works with GCC and Clang. With other compilers, you may want to
+ * use MBEDTLS_DEPRECATED_REMOVED
+ *
+ * Uncomment to get warnings on using deprecated functions.
+ */
+//#define MBEDTLS_DEPRECATED_WARNING
+
+/**
+ * \def MBEDTLS_DEPRECATED_REMOVED
+ *
+ * Remove deprecated functions so that they generate an error if used.
+ * Functions deprecated in one version will usually be removed in the next
+ * version. You can enable this to help you prepare the transition to a new
+ * major version by making sure your code is not using these functions.
+ *
+ * Uncomment to get errors on using deprecated functions.
+ */
+//#define MBEDTLS_DEPRECATED_REMOVED
+
+/* \} name SECTION: System support */
+
+/**
+ * \name SECTION: mbed TLS feature support
+ *
+ * This section sets support for features that are or are not needed
+ * within the modules that are enabled.
+ * \{
+ */
+
+/**
+ * \def MBEDTLS_TIMING_ALT
+ *
+ * Uncomment to provide your own alternate implementation for mbedtls_timing_hardclock(),
+ * mbedtls_timing_get_timer(), mbedtls_set_alarm(), mbedtls_set/get_delay()
+ *
+ * Only works if you have MBEDTLS_TIMING_C enabled.
+ *
+ * You will need to provide a header "timing_alt.h" and an implementation at
+ * compile time.
+ */
+#define MBEDTLS_TIMING_ALT
+
+/**
+ * \def MBEDTLS_AES_ALT
+ *
+ * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your
+ * alternate core implementation of a symmetric crypto, an arithmetic or hash
+ * module (e.g. platform specific assembly optimized implementations). Keep
+ * in mind that the function prototypes should remain the same.
+ *
+ * This replaces the whole module. If you only want to replace one of the
+ * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags.
+ *
+ * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer
+ * provide the "struct mbedtls_aes_context" definition and omit the base
+ * function declarations and implementations. "aes_alt.h" will be included from
+ * "aes.h" to include the new function definitions.
+ *
+ * Uncomment a macro to enable alternate implementation of the corresponding
+ * module.
+ *
+ * \warning   MD2, MD4, MD5, ARC4, DES and SHA-1 are considered weak and their
+ *            use constitutes a security risk. If possible, we recommend
+ *            avoiding dependencies on them, and considering stronger message
+ *            digests and ciphers instead.
+ *
+ */
+#if defined(RT_HWCRYPTO_USING_AES)
+#define MBEDTLS_AES_ALT
+#endif
+#if defined(RT_HWCRYPTO_USING_RC4)
+#define MBEDTLS_ARC4_ALT
+#endif
+#if defined(RT_HWCRYPTO_USING_DES) || defined(RT_HWCRYPTO_USING_3DES)
+#define MBEDTLS_DES_ALT
+#endif
+#if defined(RT_HWCRYPTO_USING_GCM)
+#define MBEDTLS_GCM_ALT
+#endif
+#ifdef RT_HWCRYPTO_USING_MD5
+#define MBEDTLS_MD5_ALT
+#endif
+#if defined(RT_HWCRYPTO_USING_BIGNUM)
+#define MBEDTLS_RSA_ALT
+#endif
+#if defined(RT_HWCRYPTO_USING_SHA1)
+#define MBEDTLS_SHA1_ALT
+#endif
+#if defined(RT_HWCRYPTO_USING_SHA2_256) || defined(RT_HWCRYPTO_USING_SHA2_224)
+#define MBEDTLS_SHA256_ALT
+#endif
+#if defined(RT_HWCRYPTO_USING_SHA2_512) || defined(RT_HWCRYPTO_USING_SHA2_384)
+#define MBEDTLS_SHA512_ALT
+#endif
+//#define MBEDTLS_DHM_ALT
+//#define MBEDTLS_ECJPAKE_ALT
+//#define MBEDTLS_BLOWFISH_ALT
+//#define MBEDTLS_CAMELLIA_ALT
+//#define MBEDTLS_CCM_ALT
+//#define MBEDTLS_CMAC_ALT
+//#define MBEDTLS_RIPEMD160_ALT
+//#define MBEDTLS_XTEA_ALT
+
+/*
+ * When replacing the elliptic curve module, pleace consider, that it is
+ * implemented with two .c files:
+ *      - ecp.c
+ *      - ecp_curves.c
+ * You can replace them very much like all the other MBEDTLS__MODULE_NAME__ALT
+ * macros as described above. The only difference is that you have to make sure
+ * that you provide functionality for both .c files.
+ */
+//#define MBEDTLS_ECP_ALT
+
+/**
+ * \def MBEDTLS_MD2_PROCESS_ALT
+ *
+ * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you
+ * alternate core implementation of symmetric crypto or hash function. Keep in
+ * mind that function prototypes should remain the same.
+ *
+ * This replaces only one function. The header file from mbed TLS is still
+ * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags.
+ *
+ * Example: In case you uncomment MBEDTLS_SHA256_PROCESS_ALT, mbed TLS will
+ * no longer provide the mbedtls_sha1_process() function, but it will still provide
+ * the other function (using your mbedtls_sha1_process() function) and the definition
+ * of mbedtls_sha1_context, so your implementation of mbedtls_sha1_process must be compatible
+ * with this definition.
+ *
+ * \note Because of a signature change, the core AES encryption and decryption routines are
+ *       currently named mbedtls_aes_internal_encrypt and mbedtls_aes_internal_decrypt,
+ *       respectively. When setting up alternative implementations, these functions should
+ *       be overriden, but the wrapper functions mbedtls_aes_decrypt and mbedtls_aes_encrypt
+ *       must stay untouched.
+ *
+ * \note If you use the AES_xxx_ALT macros, then is is recommended to also set
+ *       MBEDTLS_AES_ROM_TABLES in order to help the linker garbage-collect the AES
+ *       tables.
+ *
+ * Uncomment a macro to enable alternate implementation of the corresponding
+ * function.
+ *
+ * \warning   MD2, MD4, MD5, DES and SHA-1 are considered weak and their use
+ *            constitutes a security risk. If possible, we recommend avoiding
+ *            dependencies on them, and considering stronger message digests
+ *            and ciphers instead.
+ *
+ */
+//#define MBEDTLS_MD2_PROCESS_ALT
+//#define MBEDTLS_MD4_PROCESS_ALT
+//#define MBEDTLS_MD5_PROCESS_ALT
+//#define MBEDTLS_RIPEMD160_PROCESS_ALT
+//#define MBEDTLS_SHA1_PROCESS_ALT
+//#define MBEDTLS_SHA256_PROCESS_ALT
+//#define MBEDTLS_SHA512_PROCESS_ALT
+//#define MBEDTLS_DES_SETKEY_ALT
+//#define MBEDTLS_DES_CRYPT_ECB_ALT
+//#define MBEDTLS_DES3_CRYPT_ECB_ALT
+//#define MBEDTLS_AES_SETKEY_ENC_ALT
+//#define MBEDTLS_AES_SETKEY_DEC_ALT
+//#define MBEDTLS_AES_ENCRYPT_ALT
+//#define MBEDTLS_AES_DECRYPT_ALT
+//#define MBEDTLS_ECDH_GEN_PUBLIC_ALT
+//#define MBEDTLS_ECDH_COMPUTE_SHARED_ALT
+//#define MBEDTLS_ECDSA_VERIFY_ALT
+//#define MBEDTLS_ECDSA_SIGN_ALT
+//#define MBEDTLS_ECDSA_GENKEY_ALT
+
+/**
+ * \def MBEDTLS_ECP_INTERNAL_ALT
+ *
+ * Expose a part of the internal interface of the Elliptic Curve Point module.
+ *
+ * MBEDTLS_ECP__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use your
+ * alternative core implementation of elliptic curve arithmetic. Keep in mind
+ * that function prototypes should remain the same.
+ *
+ * This partially replaces one function. The header file from mbed TLS is still
+ * used, in contrast to the MBEDTLS_ECP_ALT flag. The original implementation
+ * is still present and it is used for group structures not supported by the
+ * alternative.
+ *
+ * Any of these options become available by defining MBEDTLS_ECP_INTERNAL_ALT
+ * and implementing the following functions:
+ *      unsigned char mbedtls_internal_ecp_grp_capable(
+ *          const mbedtls_ecp_group *grp )
+ *      int  mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp )
+ *      void mbedtls_internal_ecp_deinit( const mbedtls_ecp_group *grp )
+ * The mbedtls_internal_ecp_grp_capable function should return 1 if the
+ * replacement functions implement arithmetic for the given group and 0
+ * otherwise.
+ * The functions mbedtls_internal_ecp_init and mbedtls_internal_ecp_deinit are
+ * called before and after each point operation and provide an opportunity to
+ * implement optimized set up and tear down instructions.
+ *
+ * Example: In case you uncomment MBEDTLS_ECP_INTERNAL_ALT and
+ * MBEDTLS_ECP_DOUBLE_JAC_ALT, mbed TLS will still provide the ecp_double_jac
+ * function, but will use your mbedtls_internal_ecp_double_jac if the group is
+ * supported (your mbedtls_internal_ecp_grp_capable function returns 1 when
+ * receives it as an argument). If the group is not supported then the original
+ * implementation is used. The other functions and the definition of
+ * mbedtls_ecp_group and mbedtls_ecp_point will not change, so your
+ * implementation of mbedtls_internal_ecp_double_jac and
+ * mbedtls_internal_ecp_grp_capable must be compatible with this definition.
+ *
+ * Uncomment a macro to enable alternate implementation of the corresponding
+ * function.
+ */
+/* Required for all the functions in this section */
+//#define MBEDTLS_ECP_INTERNAL_ALT
+/* Support for Weierstrass curves with Jacobi representation */
+//#define MBEDTLS_ECP_RANDOMIZE_JAC_ALT
+//#define MBEDTLS_ECP_ADD_MIXED_ALT
+//#define MBEDTLS_ECP_DOUBLE_JAC_ALT
+//#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT
+//#define MBEDTLS_ECP_NORMALIZE_JAC_ALT
+/* Support for curves with Montgomery arithmetic */
+//#define MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT
+//#define MBEDTLS_ECP_RANDOMIZE_MXZ_ALT
+//#define MBEDTLS_ECP_NORMALIZE_MXZ_ALT
+
+/**
+ * \def MBEDTLS_TEST_NULL_ENTROPY
+ *
+ * Enables testing and use of mbed TLS without any configured entropy sources.
+ * This permits use of the library on platforms before an entropy source has
+ * been integrated (see for example the MBEDTLS_ENTROPY_HARDWARE_ALT or the
+ * MBEDTLS_ENTROPY_NV_SEED switches).
+ *
+ * WARNING! This switch MUST be disabled in production builds, and is suitable
+ * only for development.
+ * Enabling the switch negates any security provided by the library.
+ *
+ * Requires MBEDTLS_ENTROPY_C, MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+ *
+ */
+//#define MBEDTLS_TEST_NULL_ENTROPY
+
+/**
+ * \def MBEDTLS_ENTROPY_HARDWARE_ALT
+ *
+ * Uncomment this macro to let mbed TLS use your own implementation of a
+ * hardware entropy collector.
+ *
+ * Your function must be called \c mbedtls_hardware_poll(), have the same
+ * prototype as declared in entropy_poll.h, and accept NULL as first argument.
+ *
+ * Uncomment to use your own hardware entropy collector.
+ */
+#define MBEDTLS_ENTROPY_HARDWARE_ALT
+
+/**
+ * \def MBEDTLS_AES_ROM_TABLES
+ *
+ * Store the AES tables in ROM.
+ *
+ * Uncomment this macro to store the AES tables in ROM.
+ */
+//#define MBEDTLS_AES_ROM_TABLES
+
+/**
+ * \def MBEDTLS_CAMELLIA_SMALL_MEMORY
+ *
+ * Use less ROM for the Camellia implementation (saves about 768 bytes).
+ *
+ * Uncomment this macro to use less memory for Camellia.
+ */
+//#define MBEDTLS_CAMELLIA_SMALL_MEMORY
+
+/**
+ * \def MBEDTLS_CIPHER_MODE_CBC
+ *
+ * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers.
+ */
+#define MBEDTLS_CIPHER_MODE_CBC
+
+/**
+ * \def MBEDTLS_CIPHER_MODE_CFB
+ *
+ * Enable Cipher Feedback mode (CFB) for symmetric ciphers.
+ */
+#define MBEDTLS_CIPHER_MODE_CFB
+
+/**
+ * \def MBEDTLS_CIPHER_MODE_CTR
+ *
+ * Enable Counter Block Cipher mode (CTR) for symmetric ciphers.
+ */
+#define MBEDTLS_CIPHER_MODE_CTR
+
+/**
+ * \def MBEDTLS_CIPHER_NULL_CIPHER
+ *
+ * Enable NULL cipher.
+ * Warning: Only do so when you know what you are doing. This allows for
+ * encryption or channels without any security!
+ *
+ * Requires MBEDTLS_ENABLE_WEAK_CIPHERSUITES as well to enable
+ * the following ciphersuites:
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA
+ *      MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384
+ *      MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256
+ *      MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA
+ *      MBEDTLS_TLS_RSA_WITH_NULL_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_NULL_SHA
+ *      MBEDTLS_TLS_RSA_WITH_NULL_MD5
+ *      MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384
+ *      MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256
+ *      MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA
+ *      MBEDTLS_TLS_PSK_WITH_NULL_SHA384
+ *      MBEDTLS_TLS_PSK_WITH_NULL_SHA256
+ *      MBEDTLS_TLS_PSK_WITH_NULL_SHA
+ *
+ * Uncomment this macro to enable the NULL cipher and ciphersuites
+ */
+//#define MBEDTLS_CIPHER_NULL_CIPHER
+
+/**
+ * \def MBEDTLS_CIPHER_PADDING_PKCS7
+ *
+ * MBEDTLS_CIPHER_PADDING_XXX: Uncomment or comment macros to add support for
+ * specific padding modes in the cipher layer with cipher modes that support
+ * padding (e.g. CBC)
+ *
+ * If you disable all padding modes, only full blocks can be used with CBC.
+ *
+ * Enable padding modes in the cipher layer.
+ */
+#define MBEDTLS_CIPHER_PADDING_PKCS7
+#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS
+#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN
+#define MBEDTLS_CIPHER_PADDING_ZEROS
+
+/**
+ * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES
+ *
+ * Enable weak ciphersuites in SSL / TLS.
+ * Warning: Only do so when you know what you are doing. This allows for
+ * channels with virtually no security at all!
+ *
+ * This enables the following ciphersuites:
+ *      MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA
+ *      MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA
+ *
+ * Uncomment this macro to enable weak ciphersuites
+ *
+ * \warning   DES is considered a weak cipher and its use constitutes a
+ *            security risk. We recommend considering stronger ciphers instead.
+ */
+//#define MBEDTLS_ENABLE_WEAK_CIPHERSUITES
+
+/**
+ * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES
+ *
+ * Remove RC4 ciphersuites by default in SSL / TLS.
+ * This flag removes the ciphersuites based on RC4 from the default list as
+ * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to
+ * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them
+ * explicitly.
+ *
+ * Uncomment this macro to remove RC4 ciphersuites by default.
+ */
+#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES
+
+/**
+ * \def MBEDTLS_REMOVE_3DES_CIPHERSUITES
+ *
+ * Remove 3DES ciphersuites by default in SSL / TLS.
+ * This flag removes the ciphersuites based on 3DES from the default list as
+ * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible
+ * to enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including
+ * them explicitly.
+ *
+ * A man-in-the-browser attacker can recover authentication tokens sent through
+ * a TLS connection using a 3DES based cipher suite (see "On the Practical
+ * (In-)Security of 64-bit Block Ciphers" by Karthikeyan Bhargavan and Ga?tan
+ * Leurent, see https://sweet32.info/SWEET32_CCS16.pdf). If this attack falls
+ * in your threat model or you are unsure, then you should keep this option
+ * enabled to remove 3DES based cipher suites.
+ *
+ * Comment this macro to keep 3DES in the default ciphersuite list.
+ */
+#define MBEDTLS_REMOVE_3DES_CIPHERSUITES
+
+/**
+ * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED
+ *
+ * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve
+ * module.  By default all supported curves are enabled.
+ *
+ * Comment macros to disable the curve and functions for it
+ */
+#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
+#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
+#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
+#define MBEDTLS_ECP_DP_BP256R1_ENABLED
+#define MBEDTLS_ECP_DP_BP384R1_ENABLED
+#define MBEDTLS_ECP_DP_BP512R1_ENABLED
+#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
+
+/**
+ * \def MBEDTLS_ECP_NIST_OPTIM
+ *
+ * Enable specific 'modulo p' routines for each NIST prime.
+ * Depending on the prime and architecture, makes operations 4 to 8 times
+ * faster on the corresponding curve.
+ *
+ * Comment this macro to disable NIST curves optimisation.
+ */
+#define MBEDTLS_ECP_NIST_OPTIM
+
+/**
+ * \def MBEDTLS_ECDSA_DETERMINISTIC
+ *
+ * Enable deterministic ECDSA (RFC 6979).
+ * Standard ECDSA is "fragile" in the sense that lack of entropy when signing
+ * may result in a compromise of the long-term signing key. This is avoided by
+ * the deterministic variant.
+ *
+ * Requires: MBEDTLS_HMAC_DRBG_C
+ *
+ * Comment this macro to disable deterministic ECDSA.
+ */
+#define MBEDTLS_ECDSA_DETERMINISTIC
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
+ *
+ * Enable the PSK based ciphersuite modes in SSL / TLS.
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_PSK_WITH_RC4_128_SHA
+ */
+#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED
+ *
+ * Enable the DHE-PSK based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_DHM_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA
+ *
+ * \warning    Using DHE constitutes a security risk as it
+ *             is not possible to validate custom DH parameters.
+ *             If possible, it is recommended users should consider
+ *             preferring other methods of key exchange.
+ *             See dhm.h for more details.
+ *
+ */
+#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+ *
+ * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_ECDH_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA
+ */
+#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED
+ *
+ * Enable the RSA-PSK based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15,
+ *           MBEDTLS_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA
+ */
+#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
+ *
+ * Enable the RSA-only based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15,
+ *           MBEDTLS_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+ *      MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+ *      MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_RSA_WITH_RC4_128_SHA
+ *      MBEDTLS_TLS_RSA_WITH_RC4_128_MD5
+ */
+#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
+ *
+ * Enable the DHE-RSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15,
+ *           MBEDTLS_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+ *      MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+ *      MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+ *      MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
+ *
+ * \warning    Using DHE constitutes a security risk as it
+ *             is not possible to validate custom DH parameters.
+ *             If possible, it is recommended users should consider
+ *             preferring other methods of key exchange.
+ *             See dhm.h for more details.
+ *
+ */
+#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
+ *
+ * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15,
+ *           MBEDTLS_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+ */
+#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
+ *
+ * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C,
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+ */
+#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
+ *
+ * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+ */
+#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
+ *
+ * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ */
+#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
+
+/**
+ * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
+ *
+ * Enable the ECJPAKE based ciphersuite modes in SSL / TLS.
+ *
+ * \warning This is currently experimental. EC J-PAKE support is based on the
+ * Thread v1.0.0 specification; incompatible changes to the specification
+ * might still happen. For this reason, this is disabled by default.
+ *
+ * Requires: MBEDTLS_ECJPAKE_C
+ *           MBEDTLS_SHA256_C
+ *           MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
+ */
+//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
+
+/**
+ * \def MBEDTLS_PK_PARSE_EC_EXTENDED
+ *
+ * Enhance support for reading EC keys using variants of SEC1 not allowed by
+ * RFC 5915 and RFC 5480.
+ *
+ * Currently this means parsing the SpecifiedECDomain choice of EC
+ * parameters (only known groups are supported, not arbitrary domains, to
+ * avoid validation issues).
+ *
+ * Disable if you only need to support RFC 5915 + 5480 key formats.
+ */
+#define MBEDTLS_PK_PARSE_EC_EXTENDED
+
+/**
+ * \def MBEDTLS_ERROR_STRERROR_DUMMY
+ *
+ * Enable a dummy error function to make use of mbedtls_strerror() in
+ * third party libraries easier when MBEDTLS_ERROR_C is disabled
+ * (no effect when MBEDTLS_ERROR_C is enabled).
+ *
+ * You can safely disable this if MBEDTLS_ERROR_C is enabled, or if you're
+ * not using mbedtls_strerror() or error_strerror() in your application.
+ *
+ * Disable if you run into name conflicts and want to really remove the
+ * mbedtls_strerror()
+ */
+#define MBEDTLS_ERROR_STRERROR_DUMMY
+
+/**
+ * \def MBEDTLS_GENPRIME
+ *
+ * Enable the prime-number generation code.
+ *
+ * Requires: MBEDTLS_BIGNUM_C
+ */
+#define MBEDTLS_GENPRIME
+
+/**
+ * \def MBEDTLS_FS_IO
+ *
+ * Enable functions that use the filesystem.
+ */
+#define MBEDTLS_FS_IO
+
+/**
+ * \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+ *
+ * Do not add default entropy sources. These are the platform specific,
+ * mbedtls_timing_hardclock and HAVEGE based poll functions.
+ *
+ * This is useful to have more control over the added entropy sources in an
+ * application.
+ *
+ * Uncomment this macro to prevent loading of default entropy functions.
+ */
+//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+
+/**
+ * \def MBEDTLS_NO_PLATFORM_ENTROPY
+ *
+ * Do not use built-in platform entropy functions.
+ * This is useful if your platform does not support
+ * standards like the /dev/urandom or Windows CryptoAPI.
+ *
+ * Uncomment this macro to disable the built-in platform entropy functions.
+ */
+#define MBEDTLS_NO_PLATFORM_ENTROPY
+
+/**
+ * \def MBEDTLS_ENTROPY_FORCE_SHA256
+ *
+ * Force the entropy accumulator to use a SHA-256 accumulator instead of the
+ * default SHA-512 based one (if both are available).
+ *
+ * Requires: MBEDTLS_SHA256_C
+ *
+ * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option
+ * if you have performance concerns.
+ *
+ * This option is only useful if both MBEDTLS_SHA256_C and
+ * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used.
+ */
+//#define MBEDTLS_ENTROPY_FORCE_SHA256
+
+/**
+ * \def MBEDTLS_ENTROPY_NV_SEED
+ *
+ * Enable the non-volatile (NV) seed file-based entropy source.
+ * (Also enables the NV seed read/write functions in the platform layer)
+ *
+ * This is crucial (if not required) on systems that do not have a
+ * cryptographic entropy source (in hardware or kernel) available.
+ *
+ * Requires: MBEDTLS_ENTROPY_C, MBEDTLS_PLATFORM_C
+ *
+ * \note The read/write functions that are used by the entropy source are
+ *       determined in the platform layer, and can be modified at runtime and/or
+ *       compile-time depending on the flags (MBEDTLS_PLATFORM_NV_SEED_*) used.
+ *
+ * \note If you use the default implementation functions that read a seedfile
+ *       with regular fopen(), please make sure you make a seedfile with the
+ *       proper name (defined in MBEDTLS_PLATFORM_STD_NV_SEED_FILE) and at
+ *       least MBEDTLS_ENTROPY_BLOCK_SIZE bytes in size that can be read from
+ *       and written to or you will get an entropy source error! The default
+ *       implementation will only use the first MBEDTLS_ENTROPY_BLOCK_SIZE
+ *       bytes from the file.
+ *
+ * \note The entropy collector will write to the seed file before entropy is
+ *       given to an external source, to update it.
+ */
+//#define MBEDTLS_ENTROPY_NV_SEED
+
+/**
+ * \def MBEDTLS_MEMORY_DEBUG
+ *
+ * Enable debugging of buffer allocator memory issues. Automatically prints
+ * (to stderr) all (fatal) messages on memory allocation issues. Enables
+ * function for 'debug output' of allocated memory.
+ *
+ * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C
+ *
+ * Uncomment this macro to let the buffer allocator print out error messages.
+ */
+//#define MBEDTLS_MEMORY_DEBUG
+
+/**
+ * \def MBEDTLS_MEMORY_BACKTRACE
+ *
+ * Include backtrace information with each allocated block.
+ *
+ * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C
+ *           GLIBC-compatible backtrace() an backtrace_symbols() support
+ *
+ * Uncomment this macro to include backtrace information
+ */
+//#define MBEDTLS_MEMORY_BACKTRACE
+
+/**
+ * \def MBEDTLS_PK_RSA_ALT_SUPPORT
+ *
+ * Support external private RSA keys (eg from a HSM) in the PK layer.
+ *
+ * Comment this macro to disable support for external private RSA keys.
+ */
+#define MBEDTLS_PK_RSA_ALT_SUPPORT
+
+/**
+ * \def MBEDTLS_PKCS1_V15
+ *
+ * Enable support for PKCS#1 v1.5 encoding.
+ *
+ * Requires: MBEDTLS_RSA_C
+ *
+ * This enables support for PKCS#1 v1.5 operations.
+ */
+#define MBEDTLS_PKCS1_V15
+
+/**
+ * \def MBEDTLS_PKCS1_V21
+ *
+ * Enable support for PKCS#1 v2.1 encoding.
+ *
+ * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C
+ *
+ * This enables support for RSAES-OAEP and RSASSA-PSS operations.
+ */
+#define MBEDTLS_PKCS1_V21
+
+/**
+ * \def MBEDTLS_RSA_NO_CRT
+ *
+ * Do not use the Chinese Remainder Theorem
+ * for the RSA private operation.
+ *
+ * Uncomment this macro to disable the use of CRT in RSA.
+ *
+ */
+//#define MBEDTLS_RSA_NO_CRT
+
+/**
+ * \def MBEDTLS_SELF_TEST
+ *
+ * Enable the checkup functions (*_self_test).
+ */
+#define MBEDTLS_SELF_TEST
+
+/**
+ * \def MBEDTLS_SHA256_SMALLER
+ *
+ * Enable an implementation of SHA-256 that has lower ROM footprint but also
+ * lower performance.
+ *
+ * The default implementation is meant to be a reasonnable compromise between
+ * performance and size. This version optimizes more aggressively for size at
+ * the expense of performance. Eg on Cortex-M4 it reduces the size of
+ * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about
+ * 30%.
+ *
+ * Uncomment to enable the smaller implementation of SHA256.
+ */
+//#define MBEDTLS_SHA256_SMALLER
+
+/**
+ * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES
+ *
+ * Enable sending of alert messages in case of encountered errors as per RFC.
+ * If you choose not to send the alert messages, mbed TLS can still communicate
+ * with other servers, only debugging of failures is harder.
+ *
+ * The advantage of not sending alert messages, is that no information is given
+ * about reasons for failures thus preventing adversaries of gaining intel.
+ *
+ * Enable sending of all alert messages
+ */
+#define MBEDTLS_SSL_ALL_ALERT_MESSAGES
+
+/**
+ * \def MBEDTLS_SSL_DEBUG_ALL
+ *
+ * Enable the debug messages in SSL module for all issues.
+ * Debug messages have been disabled in some places to prevent timing
+ * attacks due to (unbalanced) debugging function calls.
+ *
+ * If you need all error reporting you should enable this during debugging,
+ * but remove this for production servers that should log as well.
+ *
+ * Uncomment this macro to report all debug messages on errors introducing
+ * a timing side-channel.
+ *
+ */
+//#define MBEDTLS_SSL_DEBUG_ALL
+
+/** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC
+ *
+ * Enable support for Encrypt-then-MAC, RFC 7366.
+ *
+ * This allows peers that both support it to use a more robust protection for
+ * ciphersuites using CBC, providing deep resistance against timing attacks
+ * on the padding or underlying cipher.
+ *
+ * This only affects CBC ciphersuites, and is useless if none is defined.
+ *
+ * Requires: MBEDTLS_SSL_PROTO_TLS1    or
+ *           MBEDTLS_SSL_PROTO_TLS1_1  or
+ *           MBEDTLS_SSL_PROTO_TLS1_2
+ *
+ * Comment this macro to disable support for Encrypt-then-MAC
+ */
+#define MBEDTLS_SSL_ENCRYPT_THEN_MAC
+
+/** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET
+ *
+ * Enable support for Extended Master Secret, aka Session Hash
+ * (draft-ietf-tls-session-hash-02).
+ *
+ * This was introduced as "the proper fix" to the Triple Handshake familiy of
+ * attacks, but it is recommended to always use it (even if you disable
+ * renegotiation), since it actually fixes a more fundamental issue in the
+ * original SSL/TLS design, and has implications beyond Triple Handshake.
+ *
+ * Requires: MBEDTLS_SSL_PROTO_TLS1    or
+ *           MBEDTLS_SSL_PROTO_TLS1_1  or
+ *           MBEDTLS_SSL_PROTO_TLS1_2
+ *
+ * Comment this macro to disable support for Extended Master Secret.
+ */
+#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET
+
+/**
+ * \def MBEDTLS_SSL_FALLBACK_SCSV
+ *
+ * Enable support for FALLBACK_SCSV (draft-ietf-tls-downgrade-scsv-00).
+ *
+ * For servers, it is recommended to always enable this, unless you support
+ * only one version of TLS, or know for sure that none of your clients
+ * implements a fallback strategy.
+ *
+ * For clients, you only need this if you're using a fallback strategy, which
+ * is not recommended in the first place, unless you absolutely need it to
+ * interoperate with buggy (version-intolerant) servers.
+ *
+ * Comment this macro to disable support for FALLBACK_SCSV
+ */
+#define MBEDTLS_SSL_FALLBACK_SCSV
+
+/**
+ * \def MBEDTLS_SSL_HW_RECORD_ACCEL
+ *
+ * Enable hooking functions in SSL module for hardware acceleration of
+ * individual records.
+ *
+ * Uncomment this macro to enable hooking functions.
+ */
+//#define MBEDTLS_SSL_HW_RECORD_ACCEL
+
+/**
+ * \def MBEDTLS_SSL_CBC_RECORD_SPLITTING
+ *
+ * Enable 1/n-1 record splitting for CBC mode in SSLv3 and TLS 1.0.
+ *
+ * This is a countermeasure to the BEAST attack, which also minimizes the risk
+ * of interoperability issues compared to sending 0-length records.
+ *
+ * Comment this macro to disable 1/n-1 record splitting.
+ */
+#define MBEDTLS_SSL_CBC_RECORD_SPLITTING
+
+/**
+ * \def MBEDTLS_SSL_RENEGOTIATION
+ *
+ * Enable support for TLS renegotiation.
+ *
+ * The two main uses of renegotiation are (1) refresh keys on long-lived
+ * connections and (2) client authentication after the initial handshake.
+ * If you don't need renegotiation, it's probably better to disable it, since
+ * it has been associated with security issues in the past and is easy to
+ * misuse/misunderstand.
+ *
+ * Comment this to disable support for renegotiation.
+ *
+ * \note   Even if this option is disabled, both client and server are aware
+ *         of the Renegotiation Indication Extension (RFC 5746) used to
+ *         prevent the SSL renegotiation attack (see RFC 5746 Sect. 1).
+ *         (See \c mbedtls_ssl_conf_legacy_renegotiation for the
+ *          configuration of this extension).
+ *
+ */
+#define MBEDTLS_SSL_RENEGOTIATION
+
+/**
+ * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO
+ *
+ * Enable support for receiving and parsing SSLv2 Client Hello messages for the
+ * SSL Server module (MBEDTLS_SSL_SRV_C).
+ *
+ * Uncomment this macro to enable support for SSLv2 Client Hello messages.
+ */
+//#define MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO
+
+/**
+ * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE
+ *
+ * Pick the ciphersuite according to the client's preferences rather than ours
+ * in the SSL Server module (MBEDTLS_SSL_SRV_C).
+ *
+ * Uncomment this macro to respect client's ciphersuite order
+ */
+//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE
+
+/**
+ * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+ *
+ * Enable support for RFC 6066 max_fragment_length extension in SSL.
+ *
+ * Comment this macro to disable support for the max_fragment_length extension
+ */
+#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+
+/**
+ * \def MBEDTLS_SSL_PROTO_SSL3
+ *
+ * Enable support for SSL 3.0.
+ *
+ * Requires: MBEDTLS_MD5_C
+ *           MBEDTLS_SHA1_C
+ *
+ * Comment this macro to disable support for SSL 3.0
+ */
+//#define MBEDTLS_SSL_PROTO_SSL3
+
+/**
+ * \def MBEDTLS_SSL_PROTO_TLS1
+ *
+ * Enable support for TLS 1.0.
+ *
+ * Requires: MBEDTLS_MD5_C
+ *           MBEDTLS_SHA1_C
+ *
+ * Comment this macro to disable support for TLS 1.0
+ */
+#define MBEDTLS_SSL_PROTO_TLS1
+
+/**
+ * \def MBEDTLS_SSL_PROTO_TLS1_1
+ *
+ * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled).
+ *
+ * Requires: MBEDTLS_MD5_C
+ *           MBEDTLS_SHA1_C
+ *
+ * Comment this macro to disable support for TLS 1.1 / DTLS 1.0
+ */
+#define MBEDTLS_SSL_PROTO_TLS1_1
+
+/**
+ * \def MBEDTLS_SSL_PROTO_TLS1_2
+ *
+ * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled).
+ *
+ * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C
+ *           (Depends on ciphersuites)
+ *
+ * Comment this macro to disable support for TLS 1.2 / DTLS 1.2
+ */
+#define MBEDTLS_SSL_PROTO_TLS1_2
+
+/**
+ * \def MBEDTLS_SSL_PROTO_DTLS
+ *
+ * Enable support for DTLS (all available versions).
+ *
+ * Enable this and MBEDTLS_SSL_PROTO_TLS1_1 to enable DTLS 1.0,
+ * and/or this and MBEDTLS_SSL_PROTO_TLS1_2 to enable DTLS 1.2.
+ *
+ * Requires: MBEDTLS_SSL_PROTO_TLS1_1
+ *        or MBEDTLS_SSL_PROTO_TLS1_2
+ *
+ * Comment this macro to disable support for DTLS
+ */
+#define MBEDTLS_SSL_PROTO_DTLS
+
+/**
+ * \def MBEDTLS_SSL_ALPN
+ *
+ * Enable support for RFC 7301 Application Layer Protocol Negotiation.
+ *
+ * Comment this macro to disable support for ALPN.
+ */
+#define MBEDTLS_SSL_ALPN
+
+/**
+ * \def MBEDTLS_SSL_DTLS_ANTI_REPLAY
+ *
+ * Enable support for the anti-replay mechanism in DTLS.
+ *
+ * Requires: MBEDTLS_SSL_TLS_C
+ *           MBEDTLS_SSL_PROTO_DTLS
+ *
+ * \warning Disabling this is often a security risk!
+ * See mbedtls_ssl_conf_dtls_anti_replay() for details.
+ *
+ * Comment this to disable anti-replay in DTLS.
+ */
+#define MBEDTLS_SSL_DTLS_ANTI_REPLAY
+
+/**
+ * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY
+ *
+ * Enable support for HelloVerifyRequest on DTLS servers.
+ *
+ * This feature is highly recommended to prevent DTLS servers being used as
+ * amplifiers in DoS attacks against other hosts. It should always be enabled
+ * unless you know for sure amplification cannot be a problem in the
+ * environment in which your server operates.
+ *
+ * \warning Disabling this can ba a security risk! (see above)
+ *
+ * Requires: MBEDTLS_SSL_PROTO_DTLS
+ *
+ * Comment this to disable support for HelloVerifyRequest.
+ */
+#define MBEDTLS_SSL_DTLS_HELLO_VERIFY
+
+/**
+ * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
+ *
+ * Enable server-side support for clients that reconnect from the same port.
+ *
+ * Some clients unexpectedly close the connection and try to reconnect using the
+ * same source port. This needs special support from the server to handle the
+ * new connection securely, as described in section 4.2.8 of RFC 6347. This
+ * flag enables that support.
+ *
+ * Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY
+ *
+ * Comment this to disable support for clients reusing the source port.
+ */
+#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
+
+/**
+ * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT
+ *
+ * Enable support for a limit of records with bad MAC.
+ *
+ * See mbedtls_ssl_conf_dtls_badmac_limit().
+ *
+ * Requires: MBEDTLS_SSL_PROTO_DTLS
+ */
+#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT
+
+/**
+ * \def MBEDTLS_SSL_SESSION_TICKETS
+ *
+ * Enable support for RFC 5077 session tickets in SSL.
+ * Client-side, provides full support for session tickets (maintainance of a
+ * session store remains the responsibility of the application, though).
+ * Server-side, you also need to provide callbacks for writing and parsing
+ * tickets, including authenticated encryption and key management. Example
+ * callbacks are provided by MBEDTLS_SSL_TICKET_C.
+ *
+ * Comment this macro to disable support for SSL session tickets
+ */
+#define MBEDTLS_SSL_SESSION_TICKETS
+
+/**
+ * \def MBEDTLS_SSL_EXPORT_KEYS
+ *
+ * Enable support for exporting key block and master secret.
+ * This is required for certain users of TLS, e.g. EAP-TLS.
+ *
+ * Comment this macro to disable support for key export
+ */
+#define MBEDTLS_SSL_EXPORT_KEYS
+
+/**
+ * \def MBEDTLS_SSL_SERVER_NAME_INDICATION
+ *
+ * Enable support for RFC 6066 server name indication (SNI) in SSL.
+ *
+ * Requires: MBEDTLS_X509_CRT_PARSE_C
+ *
+ * Comment this macro to disable support for server name indication in SSL
+ */
+#define MBEDTLS_SSL_SERVER_NAME_INDICATION
+
+/**
+ * \def MBEDTLS_SSL_TRUNCATED_HMAC
+ *
+ * Enable support for RFC 6066 truncated HMAC in SSL.
+ *
+ * Comment this macro to disable support for truncated HMAC in SSL
+ */
+#define MBEDTLS_SSL_TRUNCATED_HMAC
+
+/**
+ * \def MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT
+ *
+ * Fallback to old (pre-2.7), non-conforming implementation of the truncated
+ * HMAC extension which also truncates the HMAC key. Note that this option is
+ * only meant for a transitory upgrade period and is likely to be removed in
+ * a future version of the library.
+ *
+ * \warning The old implementation is non-compliant and has a security weakness
+ *          (2^80 brute force attack on the HMAC key used for a single,
+ *          uninterrupted connection). This should only be enabled temporarily
+ *          when (1) the use of truncated HMAC is essential in order to save
+ *          bandwidth, and (2) the peer is an Mbed TLS stack that doesn't use
+ *          the fixed implementation yet (pre-2.7).
+ *
+ * \deprecated This option is deprecated and will likely be removed in a
+ *             future version of Mbed TLS.
+ *
+ * Uncomment to fallback to old, non-compliant truncated HMAC implementation.
+ *
+ * Requires: MBEDTLS_SSL_TRUNCATED_HMAC
+ */
+//#define MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT
+
+/**
+ * \def MBEDTLS_THREADING_ALT
+ *
+ * Provide your own alternate threading implementation.
+ *
+ * Requires: MBEDTLS_THREADING_C
+ *
+ * Uncomment this to allow your own alternate threading implementation.
+ */
+//#define MBEDTLS_THREADING_ALT
+
+/**
+ * \def MBEDTLS_THREADING_PTHREAD
+ *
+ * Enable the pthread wrapper layer for the threading layer.
+ *
+ * Requires: MBEDTLS_THREADING_C
+ *
+ * Uncomment this to enable pthread mutexes.
+ */
+//#define MBEDTLS_THREADING_PTHREAD
+
+/**
+ * \def MBEDTLS_VERSION_FEATURES
+ *
+ * Allow run-time checking of compile-time enabled features. Thus allowing users
+ * to check at run-time if the library is for instance compiled with threading
+ * support via mbedtls_version_check_feature().
+ *
+ * Requires: MBEDTLS_VERSION_C
+ *
+ * Comment this to disable run-time checking and save ROM space
+ */
+#define MBEDTLS_VERSION_FEATURES
+
+/**
+ * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3
+ *
+ * If set, the X509 parser will not break-off when parsing an X509 certificate
+ * and encountering an extension in a v1 or v2 certificate.
+ *
+ * Uncomment to prevent an error.
+ */
+//#define MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3
+
+/**
+ * \def MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
+ *
+ * If set, the X509 parser will not break-off when parsing an X509 certificate
+ * and encountering an unknown critical extension.
+ *
+ * \warning Depending on your PKI use, enabling this can be a security risk!
+ *
+ * Uncomment to prevent an error.
+ */
+//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
+
+/**
+ * \def MBEDTLS_X509_CHECK_KEY_USAGE
+ *
+ * Enable verification of the keyUsage extension (CA and leaf certificates).
+ *
+ * Disabling this avoids problems with mis-issued and/or misused
+ * (intermediate) CA and leaf certificates.
+ *
+ * \warning Depending on your PKI use, disabling this can be a security risk!
+ *
+ * Comment to skip keyUsage checking for both CA and leaf certificates.
+ */
+#define MBEDTLS_X509_CHECK_KEY_USAGE
+
+/**
+ * \def MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE
+ *
+ * Enable verification of the extendedKeyUsage extension (leaf certificates).
+ *
+ * Disabling this avoids problems with mis-issued and/or misused certificates.
+ *
+ * \warning Depending on your PKI use, disabling this can be a security risk!
+ *
+ * Comment to skip extendedKeyUsage checking for certificates.
+ */
+#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE
+
+/**
+ * \def MBEDTLS_X509_RSASSA_PSS_SUPPORT
+ *
+ * Enable parsing and verification of X.509 certificates, CRLs and CSRS
+ * signed with RSASSA-PSS (aka PKCS#1 v2.1).
+ *
+ * Comment this macro to disallow using RSASSA-PSS in certificates.
+ */
+#define MBEDTLS_X509_RSASSA_PSS_SUPPORT
+
+/**
+ * \def MBEDTLS_ZLIB_SUPPORT
+ *
+ * If set, the SSL/TLS module uses ZLIB to support compression and
+ * decompression of packet data.
+ *
+ * \warning TLS-level compression MAY REDUCE SECURITY! See for example the
+ * CRIME attack. Before enabling this option, you should examine with care if
+ * CRIME or similar exploits may be a applicable to your use case.
+ *
+ * \note Currently compression can't be used with DTLS.
+ *
+ * Used in: library/ssl_tls.c
+ *          library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * This feature requires zlib library and headers to be present.
+ *
+ * Uncomment to enable use of ZLIB
+ */
+//#define MBEDTLS_ZLIB_SUPPORT
+/* \} name SECTION: mbed TLS feature support */
+
+/**
+ * \name SECTION: mbed TLS modules
+ *
+ * This section enables or disables entire modules in mbed TLS
+ * \{
+ */
+
+/**
+ * \def MBEDTLS_AESNI_C
+ *
+ * Enable AES-NI support on x86-64.
+ *
+ * Module:  library/aesni.c
+ * Caller:  library/aes.c
+ *
+ * Requires: MBEDTLS_HAVE_ASM
+ *
+ * This modules adds support for the AES-NI instructions on x86-64
+ */
+#define MBEDTLS_AESNI_C
+
+/**
+ * \def MBEDTLS_AES_C
+ *
+ * Enable the AES block cipher.
+ *
+ * Module:  library/aes.c
+ * Caller:  library/ssl_tls.c
+ *          library/pem.c
+ *          library/ctr_drbg.c
+ *
+ * This module enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA
+ *      MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384
+ *      MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384
+ *      MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA
+ *      MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256
+ *      MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256
+ *      MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA
+ *
+ * PEM_PARSE uses AES for decrypting encrypted keys.
+ */
+#define MBEDTLS_AES_C
+
+/**
+ * \def MBEDTLS_ARC4_C
+ *
+ * Enable the ARCFOUR stream cipher.
+ *
+ * Module:  library/arc4.c
+ * Caller:  library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA
+ *      MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA
+ *      MBEDTLS_TLS_RSA_WITH_RC4_128_SHA
+ *      MBEDTLS_TLS_RSA_WITH_RC4_128_MD5
+ *      MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA
+ *      MBEDTLS_TLS_PSK_WITH_RC4_128_SHA
+ *
+ * \warning   ARC4 is considered a weak cipher and its use constitutes a
+ *            security risk. If possible, we recommend avoidng dependencies on
+ *            it, and considering stronger ciphers instead.
+ *
+ */
+#define MBEDTLS_ARC4_C
+
+/**
+ * \def MBEDTLS_ASN1_PARSE_C
+ *
+ * Enable the generic ASN1 parser.
+ *
+ * Module:  library/asn1.c
+ * Caller:  library/x509.c
+ *          library/dhm.c
+ *          library/pkcs12.c
+ *          library/pkcs5.c
+ *          library/pkparse.c
+ */
+#define MBEDTLS_ASN1_PARSE_C
+
+/**
+ * \def MBEDTLS_ASN1_WRITE_C
+ *
+ * Enable the generic ASN1 writer.
+ *
+ * Module:  library/asn1write.c
+ * Caller:  library/ecdsa.c
+ *          library/pkwrite.c
+ *          library/x509_create.c
+ *          library/x509write_crt.c
+ *          library/x509write_csr.c
+ */
+#define MBEDTLS_ASN1_WRITE_C
+
+/**
+ * \def MBEDTLS_BASE64_C
+ *
+ * Enable the Base64 module.
+ *
+ * Module:  library/base64.c
+ * Caller:  library/pem.c
+ *
+ * This module is required for PEM support (required by X.509).
+ */
+#define MBEDTLS_BASE64_C
+
+/**
+ * \def MBEDTLS_BIGNUM_C
+ *
+ * Enable the multi-precision integer library.
+ *
+ * Module:  library/bignum.c
+ * Caller:  library/dhm.c
+ *          library/ecp.c
+ *          library/ecdsa.c
+ *          library/rsa.c
+ *          library/rsa_internal.c
+ *          library/ssl_tls.c
+ *
+ * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support.
+ */
+#define MBEDTLS_BIGNUM_C
+
+/**
+ * \def MBEDTLS_BLOWFISH_C
+ *
+ * Enable the Blowfish block cipher.
+ *
+ * Module:  library/blowfish.c
+ */
+#define MBEDTLS_BLOWFISH_C
+
+/**
+ * \def MBEDTLS_CAMELLIA_C
+ *
+ * Enable the Camellia block cipher.
+ *
+ * Module:  library/camellia.c
+ * Caller:  library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+ *      MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+ *      MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+ *      MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ *      MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ *      MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ */
+#define MBEDTLS_CAMELLIA_C
+
+/**
+ * \def MBEDTLS_CCM_C
+ *
+ * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher.
+ *
+ * Module:  library/ccm.c
+ *
+ * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C
+ *
+ * This module enables the AES-CCM ciphersuites, if other requisites are
+ * enabled as well.
+ */
+#define MBEDTLS_CCM_C
+
+/**
+ * \def MBEDTLS_CERTS_C
+ *
+ * Enable the test certificates.
+ *
+ * Module:  library/certs.c
+ * Caller:
+ *
+ * This module is used for testing (ssl_client/server).
+ */
+#define MBEDTLS_CERTS_C
+
+/**
+ * \def MBEDTLS_CIPHER_C
+ *
+ * Enable the generic cipher layer.
+ *
+ * Module:  library/cipher.c
+ * Caller:  library/ssl_tls.c
+ *
+ * Uncomment to enable generic cipher wrappers.
+ */
+#define MBEDTLS_CIPHER_C
+
+/**
+ * \def MBEDTLS_CMAC_C
+ *
+ * Enable the CMAC (Cipher-based Message Authentication Code) mode for block
+ * ciphers.
+ *
+ * Module:  library/cmac.c
+ *
+ * Requires: MBEDTLS_AES_C or MBEDTLS_DES_C
+ *
+ */
+//#define MBEDTLS_CMAC_C
+
+/**
+ * \def MBEDTLS_CTR_DRBG_C
+ *
+ * Enable the CTR_DRBG AES-256-based random generator.
+ *
+ * Module:  library/ctr_drbg.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_AES_C
+ *
+ * This module provides the CTR_DRBG AES-256 random number generator.
+ */
+#define MBEDTLS_CTR_DRBG_C
+
+/**
+ * \def MBEDTLS_DEBUG_C
+ *
+ * Enable the debug functions.
+ *
+ * Module:  library/debug.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *
+ * This module provides debugging functions.
+ */
+ 
+#ifdef PKG_USING_MBEDTLS_DEBUG
+#define MBEDTLS_DEBUG_C
+#endif
+
+/**
+ * \def MBEDTLS_DES_C
+ *
+ * Enable the DES block cipher.
+ *
+ * Module:  library/des.c
+ * Caller:  library/pem.c
+ *          library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA
+ *      MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA
+ *
+ * PEM_PARSE uses DES/3DES for decrypting encrypted keys.
+ *
+ * \warning   DES is considered a weak cipher and its use constitutes a
+ *            security risk. We recommend considering stronger ciphers instead.
+ */
+#define MBEDTLS_DES_C
+
+/**
+ * \def MBEDTLS_DHM_C
+ *
+ * Enable the Diffie-Hellman-Merkle module.
+ *
+ * Module:  library/dhm.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * This module is used by the following key exchanges:
+ *      DHE-RSA, DHE-PSK
+ *
+ * \warning    Using DHE constitutes a security risk as it
+ *             is not possible to validate custom DH parameters.
+ *             If possible, it is recommended users should consider
+ *             preferring other methods of key exchange.
+ *             See dhm.h for more details.
+ *
+ */
+#define MBEDTLS_DHM_C
+
+/**
+ * \def MBEDTLS_ECDH_C
+ *
+ * Enable the elliptic curve Diffie-Hellman library.
+ *
+ * Module:  library/ecdh.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * This module is used by the following key exchanges:
+ *      ECDHE-ECDSA, ECDHE-RSA, DHE-PSK
+ *
+ * Requires: MBEDTLS_ECP_C
+ */
+#define MBEDTLS_ECDH_C
+
+/**
+ * \def MBEDTLS_ECDSA_C
+ *
+ * Enable the elliptic curve DSA library.
+ *
+ * Module:  library/ecdsa.c
+ * Caller:
+ *
+ * This module is used by the following key exchanges:
+ *      ECDHE-ECDSA
+ *
+ * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C
+ */
+#define MBEDTLS_ECDSA_C
+
+/**
+ * \def MBEDTLS_ECJPAKE_C
+ *
+ * Enable the elliptic curve J-PAKE library.
+ *
+ * \warning This is currently experimental. EC J-PAKE support is based on the
+ * Thread v1.0.0 specification; incompatible changes to the specification
+ * might still happen. For this reason, this is disabled by default.
+ *
+ * Module:  library/ecjpake.c
+ * Caller:
+ *
+ * This module is used by the following key exchanges:
+ *      ECJPAKE
+ *
+ * Requires: MBEDTLS_ECP_C, MBEDTLS_MD_C
+ */
+//#define MBEDTLS_ECJPAKE_C
+
+/**
+ * \def MBEDTLS_ECP_C
+ *
+ * Enable the elliptic curve over GF(p) library.
+ *
+ * Module:  library/ecp.c
+ * Caller:  library/ecdh.c
+ *          library/ecdsa.c
+ *          library/ecjpake.c
+ *
+ * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED
+ */
+#define MBEDTLS_ECP_C
+
+/**
+ * \def MBEDTLS_ENTROPY_C
+ *
+ * Enable the platform-specific entropy code.
+ *
+ * Module:  library/entropy.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C
+ *
+ * This module provides a generic entropy pool
+ */
+#define MBEDTLS_ENTROPY_C
+
+/**
+ * \def MBEDTLS_ERROR_C
+ *
+ * Enable error code to error string conversion.
+ *
+ * Module:  library/error.c
+ * Caller:
+ *
+ * This module enables mbedtls_strerror().
+ */
+#define MBEDTLS_ERROR_C
+
+/**
+ * \def MBEDTLS_GCM_C
+ *
+ * Enable the Galois/Counter Mode (GCM) for AES.
+ *
+ * Module:  library/gcm.c
+ *
+ * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C
+ *
+ * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other
+ * requisites are enabled as well.
+ */
+#define MBEDTLS_GCM_C
+
+/**
+ * \def MBEDTLS_HAVEGE_C
+ *
+ * Enable the HAVEGE random generator.
+ *
+ * Warning: the HAVEGE random generator is not suitable for virtualized
+ *          environments
+ *
+ * Warning: the HAVEGE random generator is dependent on timing and specific
+ *          processor traits. It is therefore not advised to use HAVEGE as
+ *          your applications primary random generator or primary entropy pool
+ *          input. As a secondary input to your entropy pool, it IS able add
+ *          the (limited) extra entropy it provides.
+ *
+ * Module:  library/havege.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_TIMING_C
+ *
+ * Uncomment to enable the HAVEGE random generator.
+ */
+//#define MBEDTLS_HAVEGE_C
+
+/**
+ * \def MBEDTLS_HMAC_DRBG_C
+ *
+ * Enable the HMAC_DRBG random generator.
+ *
+ * Module:  library/hmac_drbg.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_MD_C
+ *
+ * Uncomment to enable the HMAC_DRBG random number geerator.
+ */
+#define MBEDTLS_HMAC_DRBG_C
+
+/**
+ * \def MBEDTLS_MD_C
+ *
+ * Enable the generic message digest layer.
+ *
+ * Module:  library/md.c
+ * Caller:
+ *
+ * Uncomment to enable generic message digest wrappers.
+ */
+#define MBEDTLS_MD_C
+
+/**
+ * \def MBEDTLS_MD2_C
+ *
+ * Enable the MD2 hash algorithm.
+ *
+ * Module:  library/md2.c
+ * Caller:
+ *
+ * Uncomment to enable support for (rare) MD2-signed X.509 certs.
+ *
+ * \warning   MD2 is considered a weak message digest and its use constitutes a
+ *            security risk. If possible, we recommend avoiding dependencies on
+ *            it, and considering stronger message digests instead.
+ *
+ */
+//#define MBEDTLS_MD2_C
+
+/**
+ * \def MBEDTLS_MD4_C
+ *
+ * Enable the MD4 hash algorithm.
+ *
+ * Module:  library/md4.c
+ * Caller:
+ *
+ * Uncomment to enable support for (rare) MD4-signed X.509 certs.
+ *
+ * \warning   MD4 is considered a weak message digest and its use constitutes a
+ *            security risk. If possible, we recommend avoiding dependencies on
+ *            it, and considering stronger message digests instead.
+ *
+ */
+//#define MBEDTLS_MD4_C
+
+/**
+ * \def MBEDTLS_MD5_C
+ *
+ * Enable the MD5 hash algorithm.
+ *
+ * Module:  library/md5.c
+ * Caller:  library/md.c
+ *          library/pem.c
+ *          library/ssl_tls.c
+ *
+ * This module is required for SSL/TLS up to version 1.1, and for TLS 1.2
+ * depending on the handshake parameters. Further, it is used for checking
+ * MD5-signed certificates, and for PBKDF1 when decrypting PEM-encoded
+ * encrypted keys.
+ *
+ * \warning   MD5 is considered a weak message digest and its use constitutes a
+ *            security risk. If possible, we recommend avoiding dependencies on
+ *            it, and considering stronger message digests instead.
+ *
+ */
+#define MBEDTLS_MD5_C
+
+/**
+ * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C
+ *
+ * Enable the buffer allocator implementation that makes use of a (stack)
+ * based buffer to 'allocate' dynamic memory. (replaces calloc() and free()
+ * calls)
+ *
+ * Module:  library/memory_buffer_alloc.c
+ *
+ * Requires: MBEDTLS_PLATFORM_C
+ *           MBEDTLS_PLATFORM_MEMORY (to use it within mbed TLS)
+ *
+ * Enable this module to enable the buffer memory allocator.
+ */
+//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
+
+/**
+ * \def MBEDTLS_NET_C
+ *
+ * Enable the TCP and UDP over IPv6/IPv4 networking routines.
+ *
+ * \note This module only works on POSIX/Unix (including Linux, BSD and OS X)
+ * and Windows. For other platforms, you'll want to disable it, and write your
+ * own networking callbacks to be passed to \c mbedtls_ssl_set_bio().
+ *
+ * \note See also our Knowledge Base article about porting to a new
+ * environment:
+ * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS
+ *
+ * Module:  library/net_sockets.c
+ *
+ * This module provides networking routines.
+ */
+//#define MBEDTLS_NET_C
+
+/**
+ * \def MBEDTLS_OID_C
+ *
+ * Enable the OID database.
+ *
+ * Module:  library/oid.c
+ * Caller:  library/asn1write.c
+ *          library/pkcs5.c
+ *          library/pkparse.c
+ *          library/pkwrite.c
+ *          library/rsa.c
+ *          library/x509.c
+ *          library/x509_create.c
+ *          library/x509_crl.c
+ *          library/x509_crt.c
+ *          library/x509_csr.c
+ *          library/x509write_crt.c
+ *          library/x509write_csr.c
+ *
+ * This modules translates between OIDs and internal values.
+ */
+#define MBEDTLS_OID_C
+
+/**
+ * \def MBEDTLS_PADLOCK_C
+ *
+ * Enable VIA Padlock support on x86.
+ *
+ * Module:  library/padlock.c
+ * Caller:  library/aes.c
+ *
+ * Requires: MBEDTLS_HAVE_ASM
+ *
+ * This modules adds support for the VIA PadLock on x86.
+ */
+#define MBEDTLS_PADLOCK_C
+
+/**
+ * \def MBEDTLS_PEM_PARSE_C
+ *
+ * Enable PEM decoding / parsing.
+ *
+ * Module:  library/pem.c
+ * Caller:  library/dhm.c
+ *          library/pkparse.c
+ *          library/x509_crl.c
+ *          library/x509_crt.c
+ *          library/x509_csr.c
+ *
+ * Requires: MBEDTLS_BASE64_C
+ *
+ * This modules adds support for decoding / parsing PEM files.
+ */
+#define MBEDTLS_PEM_PARSE_C
+
+/**
+ * \def MBEDTLS_PEM_WRITE_C
+ *
+ * Enable PEM encoding / writing.
+ *
+ * Module:  library/pem.c
+ * Caller:  library/pkwrite.c
+ *          library/x509write_crt.c
+ *          library/x509write_csr.c
+ *
+ * Requires: MBEDTLS_BASE64_C
+ *
+ * This modules adds support for encoding / writing PEM files.
+ */
+#define MBEDTLS_PEM_WRITE_C
+
+/**
+ * \def MBEDTLS_PK_C
+ *
+ * Enable the generic public (asymetric) key layer.
+ *
+ * Module:  library/pk.c
+ * Caller:  library/ssl_tls.c
+ *          library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C
+ *
+ * Uncomment to enable generic public key wrappers.
+ */
+#define MBEDTLS_PK_C
+
+/**
+ * \def MBEDTLS_PK_PARSE_C
+ *
+ * Enable the generic public (asymetric) key parser.
+ *
+ * Module:  library/pkparse.c
+ * Caller:  library/x509_crt.c
+ *          library/x509_csr.c
+ *
+ * Requires: MBEDTLS_PK_C
+ *
+ * Uncomment to enable generic public key parse functions.
+ */
+#define MBEDTLS_PK_PARSE_C
+
+/**
+ * \def MBEDTLS_PK_WRITE_C
+ *
+ * Enable the generic public (asymetric) key writer.
+ *
+ * Module:  library/pkwrite.c
+ * Caller:  library/x509write.c
+ *
+ * Requires: MBEDTLS_PK_C
+ *
+ * Uncomment to enable generic public key write functions.
+ */
+#define MBEDTLS_PK_WRITE_C
+
+/**
+ * \def MBEDTLS_PKCS5_C
+ *
+ * Enable PKCS#5 functions.
+ *
+ * Module:  library/pkcs5.c
+ *
+ * Requires: MBEDTLS_MD_C
+ *
+ * This module adds support for the PKCS#5 functions.
+ */
+#define MBEDTLS_PKCS5_C
+
+/**
+ * \def MBEDTLS_PKCS11_C
+ *
+ * Enable wrapper for PKCS#11 smartcard support.
+ *
+ * Module:  library/pkcs11.c
+ * Caller:  library/pk.c
+ *
+ * Requires: MBEDTLS_PK_C
+ *
+ * This module enables SSL/TLS PKCS #11 smartcard support.
+ * Requires the presence of the PKCS#11 helper library (libpkcs11-helper)
+ */
+//#define MBEDTLS_PKCS11_C
+
+/**
+ * \def MBEDTLS_PKCS12_C
+ *
+ * Enable PKCS#12 PBE functions.
+ * Adds algorithms for parsing PKCS#8 encrypted private keys
+ *
+ * Module:  library/pkcs12.c
+ * Caller:  library/pkparse.c
+ *
+ * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_CIPHER_C, MBEDTLS_MD_C
+ * Can use:  MBEDTLS_ARC4_C
+ *
+ * This module enables PKCS#12 functions.
+ */
+#define MBEDTLS_PKCS12_C
+
+/**
+ * \def MBEDTLS_PLATFORM_C
+ *
+ * Enable the platform abstraction layer that allows you to re-assign
+ * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit().
+ *
+ * Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT
+ * or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned
+ * above to be specified at runtime or compile time respectively.
+ *
+ * \note This abstraction layer must be enabled on Windows (including MSYS2)
+ * as other module rely on it for a fixed snprintf implementation.
+ *
+ * Module:  library/platform.c
+ * Caller:  Most other .c files
+ *
+ * This module enables abstraction of common (libc) functions.
+ */
+#define MBEDTLS_PLATFORM_C
+
+/**
+ * \def MBEDTLS_RIPEMD160_C
+ *
+ * Enable the RIPEMD-160 hash algorithm.
+ *
+ * Module:  library/ripemd160.c
+ * Caller:  library/md.c
+ *
+ */
+#define MBEDTLS_RIPEMD160_C
+
+/**
+ * \def MBEDTLS_RSA_C
+ *
+ * Enable the RSA public-key cryptosystem.
+ *
+ * Module:  library/rsa.c
+ *          library/rsa_internal.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *          library/x509.c
+ *
+ * This module is used by the following key exchanges:
+ *      RSA, DHE-RSA, ECDHE-RSA, RSA-PSK
+ *
+ * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C
+ */
+#define MBEDTLS_RSA_C
+
+/**
+ * \def MBEDTLS_SHA1_C
+ *
+ * Enable the SHA1 cryptographic hash algorithm.
+ *
+ * Module:  library/sha1.c
+ * Caller:  library/md.c
+ *          library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *          library/x509write_crt.c
+ *
+ * This module is required for SSL/TLS up to version 1.1, for TLS 1.2
+ * depending on the handshake parameters, and for SHA1-signed certificates.
+ *
+ * \warning   SHA-1 is considered a weak message digest and its use constitutes
+ *            a security risk. If possible, we recommend avoiding dependencies
+ *            on it, and considering stronger message digests instead.
+ *
+ */
+#define MBEDTLS_SHA1_C
+
+/**
+ * \def MBEDTLS_SHA256_C
+ *
+ * Enable the SHA-224 and SHA-256 cryptographic hash algorithms.
+ *
+ * Module:  library/sha256.c
+ * Caller:  library/entropy.c
+ *          library/md.c
+ *          library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *
+ * This module adds support for SHA-224 and SHA-256.
+ * This module is required for the SSL/TLS 1.2 PRF function.
+ */
+#define MBEDTLS_SHA256_C
+
+/**
+ * \def MBEDTLS_SHA512_C
+ *
+ * Enable the SHA-384 and SHA-512 cryptographic hash algorithms.
+ *
+ * Module:  library/sha512.c
+ * Caller:  library/entropy.c
+ *          library/md.c
+ *          library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * This module adds support for SHA-384 and SHA-512.
+ */
+#define MBEDTLS_SHA512_C
+
+/**
+ * \def MBEDTLS_SSL_CACHE_C
+ *
+ * Enable simple SSL cache implementation.
+ *
+ * Module:  library/ssl_cache.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_SSL_CACHE_C
+ */
+#define MBEDTLS_SSL_CACHE_C
+
+/**
+ * \def MBEDTLS_SSL_COOKIE_C
+ *
+ * Enable basic implementation of DTLS cookies for hello verification.
+ *
+ * Module:  library/ssl_cookie.c
+ * Caller:
+ */
+#define MBEDTLS_SSL_COOKIE_C
+
+/**
+ * \def MBEDTLS_SSL_TICKET_C
+ *
+ * Enable an implementation of TLS server-side callbacks for session tickets.
+ *
+ * Module:  library/ssl_ticket.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_CIPHER_C
+ */
+#define MBEDTLS_SSL_TICKET_C
+
+/**
+ * \def MBEDTLS_SSL_CLI_C
+ *
+ * Enable the SSL/TLS client code.
+ *
+ * Module:  library/ssl_cli.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_SSL_TLS_C
+ *
+ * This module is required for SSL/TLS client support.
+ */
+#define MBEDTLS_SSL_CLI_C
+
+/**
+ * \def MBEDTLS_SSL_SRV_C
+ *
+ * Enable the SSL/TLS server code.
+ *
+ * Module:  library/ssl_srv.c
+ * Caller:
+ *
+ * Requires: MBEDTLS_SSL_TLS_C
+ *
+ * This module is required for SSL/TLS server support.
+ */
+//#define MBEDTLS_SSL_SRV_C
+
+/**
+ * \def MBEDTLS_SSL_TLS_C
+ *
+ * Enable the generic SSL/TLS code.
+ *
+ * Module:  library/ssl_tls.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C
+ *           and at least one of the MBEDTLS_SSL_PROTO_XXX defines
+ *
+ * This module is required for SSL/TLS.
+ */
+#define MBEDTLS_SSL_TLS_C
+
+/**
+ * \def MBEDTLS_THREADING_C
+ *
+ * Enable the threading abstraction layer.
+ * By default mbed TLS assumes it is used in a non-threaded environment or that
+ * contexts are not shared between threads. If you do intend to use contexts
+ * between threads, you will need to enable this layer to prevent race
+ * conditions. See also our Knowledge Base article about threading:
+ * https://tls.mbed.org/kb/development/thread-safety-and-multi-threading
+ *
+ * Module:  library/threading.c
+ *
+ * This allows different threading implementations (self-implemented or
+ * provided).
+ *
+ * You will have to enable either MBEDTLS_THREADING_ALT or
+ * MBEDTLS_THREADING_PTHREAD.
+ *
+ * Enable this layer to allow use of mutexes within mbed TLS
+ */
+//#define MBEDTLS_THREADING_C
+
+/**
+ * \def MBEDTLS_TIMING_C
+ *
+ * Enable the semi-portable timing interface.
+ *
+ * \note The provided implementation only works on POSIX/Unix (including Linux,
+ * BSD and OS X) and Windows. On other platforms, you can either disable that
+ * module and provide your own implementations of the callbacks needed by
+ * \c mbedtls_ssl_set_timer_cb() for DTLS, or leave it enabled and provide
+ * your own implementation of the whole module by setting
+ * \c MBEDTLS_TIMING_ALT in the current file.
+ *
+ * \note See also our Knowledge Base article about porting to a new
+ * environment:
+ * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS
+ *
+ * Module:  library/timing.c
+ * Caller:  library/havege.c
+ *
+ * This module is used by the HAVEGE random number generator.
+ */
+#define MBEDTLS_TIMING_C
+
+/**
+ * \def MBEDTLS_VERSION_C
+ *
+ * Enable run-time version information.
+ *
+ * Module:  library/version.c
+ *
+ * This module provides run-time version information.
+ */
+#define MBEDTLS_VERSION_C
+
+/**
+ * \def MBEDTLS_X509_USE_C
+ *
+ * Enable X.509 core for using certificates.
+ *
+ * Module:  library/x509.c
+ * Caller:  library/x509_crl.c
+ *          library/x509_crt.c
+ *          library/x509_csr.c
+ *
+ * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C,
+ *           MBEDTLS_PK_PARSE_C
+ *
+ * This module is required for the X.509 parsing modules.
+ */
+#define MBEDTLS_X509_USE_C
+
+/**
+ * \def MBEDTLS_X509_CRT_PARSE_C
+ *
+ * Enable X.509 certificate parsing.
+ *
+ * Module:  library/x509_crt.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *
+ * Requires: MBEDTLS_X509_USE_C
+ *
+ * This module is required for X.509 certificate parsing.
+ */
+#define MBEDTLS_X509_CRT_PARSE_C
+
+/**
+ * \def MBEDTLS_X509_CRL_PARSE_C
+ *
+ * Enable X.509 CRL parsing.
+ *
+ * Module:  library/x509_crl.c
+ * Caller:  library/x509_crt.c
+ *
+ * Requires: MBEDTLS_X509_USE_C
+ *
+ * This module is required for X.509 CRL parsing.
+ */
+#define MBEDTLS_X509_CRL_PARSE_C
+
+/**
+ * \def MBEDTLS_X509_CSR_PARSE_C
+ *
+ * Enable X.509 Certificate Signing Request (CSR) parsing.
+ *
+ * Module:  library/x509_csr.c
+ * Caller:  library/x509_crt_write.c
+ *
+ * Requires: MBEDTLS_X509_USE_C
+ *
+ * This module is used for reading X.509 certificate request.
+ */
+#define MBEDTLS_X509_CSR_PARSE_C
+
+/**
+ * \def MBEDTLS_X509_CREATE_C
+ *
+ * Enable X.509 core for creating certificates.
+ *
+ * Module:  library/x509_create.c
+ *
+ * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, MBEDTLS_PK_WRITE_C
+ *
+ * This module is the basis for creating X.509 certificates and CSRs.
+ */
+#define MBEDTLS_X509_CREATE_C
+
+/**
+ * \def MBEDTLS_X509_CRT_WRITE_C
+ *
+ * Enable creating X.509 certificates.
+ *
+ * Module:  library/x509_crt_write.c
+ *
+ * Requires: MBEDTLS_X509_CREATE_C
+ *
+ * This module is required for X.509 certificate creation.
+ */
+#define MBEDTLS_X509_CRT_WRITE_C
+
+/**
+ * \def MBEDTLS_X509_CSR_WRITE_C
+ *
+ * Enable creating X.509 Certificate Signing Requests (CSR).
+ *
+ * Module:  library/x509_csr_write.c
+ *
+ * Requires: MBEDTLS_X509_CREATE_C
+ *
+ * This module is required for X.509 certificate request writing.
+ */
+#define MBEDTLS_X509_CSR_WRITE_C
+
+/**
+ * \def MBEDTLS_XTEA_C
+ *
+ * Enable the XTEA block cipher.
+ *
+ * Module:  library/xtea.c
+ * Caller:
+ */
+#define MBEDTLS_XTEA_C
+
+/* \} name SECTION: mbed TLS modules */
+
+/**
+ * \name SECTION: Module configuration options
+ *
+ * This section allows for the setting of module specific sizes and
+ * configuration options. The default values are already present in the
+ * relevant header files and should suffice for the regular use cases.
+ *
+ * Our advice is to enable options and change their values here
+ * only if you have a good reason and know the consequences.
+ *
+ * Please check the respective header file for documentation on these
+ * parameters (to prevent duplicate documentation).
+ * \{
+ */
+
+/* MPI / BIGNUM options */
+//#define MBEDTLS_MPI_WINDOW_SIZE            6 /**< Maximum windows size used. */
+//#define MBEDTLS_MPI_MAX_SIZE            1024 /**< Maximum number of bytes for usable MPIs. */
+
+/* CTR_DRBG options */
+//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN               48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */
+//#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL        10000 /**< Interval before reseed is performed by default */
+//#define MBEDTLS_CTR_DRBG_MAX_INPUT                256 /**< Maximum number of additional input bytes */
+//#define MBEDTLS_CTR_DRBG_MAX_REQUEST             1024 /**< Maximum number of requested bytes per call */
+//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT           384 /**< Maximum size of (re)seed buffer */
+
+/* HMAC_DRBG options */
+//#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL   10000 /**< Interval before reseed is performed by default */
+//#define MBEDTLS_HMAC_DRBG_MAX_INPUT           256 /**< Maximum number of additional input bytes */
+//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST        1024 /**< Maximum number of requested bytes per call */
+//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT      384 /**< Maximum size of (re)seed buffer */
+
+/* ECP options */
+//#define MBEDTLS_ECP_MAX_BITS             521 /**< Maximum bit size of groups */
+//#define MBEDTLS_ECP_WINDOW_SIZE            6 /**< Maximum window size used */
+//#define MBEDTLS_ECP_FIXED_POINT_OPTIM      1 /**< Enable fixed-point speed-up */
+
+/* Entropy options */
+//#define MBEDTLS_ENTROPY_MAX_SOURCES                20 /**< Maximum number of sources supported */
+//#define MBEDTLS_ENTROPY_MAX_GATHER                128 /**< Maximum amount requested from entropy sources */
+//#define MBEDTLS_ENTROPY_MIN_HARDWARE               32 /**< Default minimum number of bytes required for the hardware entropy source mbedtls_hardware_poll() before entropy is released */
+
+/* Memory buffer allocator options */
+//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE      4 /**< Align on multiples of this value */
+
+/* Platform options */
+//#define MBEDTLS_PLATFORM_STD_MEM_HDR   <stdlib.h> /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */
+//#define MBEDTLS_PLATFORM_STD_CALLOC        calloc /**< Default allocator to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_FREE            free /**< Default free to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_EXIT            exit /**< Default exit to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_TIME            time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
+//#define MBEDTLS_PLATFORM_STD_FPRINTF      fprintf /**< Default fprintf to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_PRINTF        printf /**< Default printf to use, can be undefined */
+/* Note: your snprintf must correclty zero-terminate the buffer! */
+//#define MBEDTLS_PLATFORM_STD_SNPRINTF    snprintf /**< Default snprintf to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS       0 /**< Default exit value to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE       1 /**< Default exit value to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_NV_SEED_READ   mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE  mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE  "seedfile" /**< Seed file to read/write with default implementation */
+
+/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */
+/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */
+//#define MBEDTLS_PLATFORM_CALLOC_MACRO        calloc /**< Default allocator macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_FREE_MACRO            free /**< Default free macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_EXIT_MACRO            exit /**< Default exit macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_TIME_MACRO            time /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
+//#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO       time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
+//#define MBEDTLS_PLATFORM_FPRINTF_MACRO      fprintf /**< Default fprintf macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_PRINTF_MACRO        printf /**< Default printf macro to use, can be undefined */
+/* Note: your snprintf must correclty zero-terminate the buffer! */
+//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO    snprintf /**< Default snprintf macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO   mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */
+//#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO  mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */
+
+/* SSL Cache options */
+//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT       86400 /**< 1 day  */
+//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES      50 /**< Maximum entries in cache */
+
+/* SSL options */
+//#define MBEDTLS_SSL_MAX_CONTENT_LEN             16384 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */
+//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME     86400 /**< Lifetime of session tickets (if enabled) */
+//#define MBEDTLS_PSK_MAX_LEN               32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */
+//#define MBEDTLS_SSL_COOKIE_TIMEOUT        60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */
+
+/**
+ * Complete list of ciphersuites to use, in order of preference.
+ *
+ * \warning No dependency checking is done on that field! This option can only
+ * be used to restrict the set of available ciphersuites. It is your
+ * responsibility to make sure the needed modules are active.
+ *
+ * Use this to save a few hundred bytes of ROM (default ordering of all
+ * available ciphersuites) and a few to a few hundred bytes of RAM.
+ *
+ * The value below is only an example, not the default.
+ */
+//#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+
+/* X509 options */
+//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA   8   /**< Maximum number of intermediate CAs in a verification chain. */
+//#define MBEDTLS_X509_MAX_FILE_PATH_LEN     512 /**< Maximum length of a path/filename string in bytes including the null terminator character ('\0'). */
+
+/**
+ * Allow SHA-1 in the default TLS configuration for certificate signing.
+ * Without this build-time option, SHA-1 support must be activated explicitly
+ * through mbedtls_ssl_conf_cert_profile. Turning on this option is not
+ * recommended because of it is possible to generate SHA-1 collisions, however
+ * this may be safe for legacy infrastructure where additional controls apply.
+ *
+ * \warning   SHA-1 is considered a weak message digest and its use constitutes
+ *            a security risk. If possible, we recommend avoiding dependencies
+ *            on it, and considering stronger message digests instead.
+ *
+ */
+// #define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES
+
+/**
+ * Allow SHA-1 in the default TLS configuration for TLS 1.2 handshake
+ * signature and ciphersuite selection. Without this build-time option, SHA-1
+ * support must be activated explicitly through mbedtls_ssl_conf_sig_hashes.
+ * The use of SHA-1 in TLS <= 1.1 and in HMAC-SHA-1 is always allowed by
+ * default. At the time of writing, there is no practical attack on the use
+ * of SHA-1 in handshake signatures, hence this option is turned on by default
+ * to preserve compatibility with existing peers, but the general
+ * warning applies nonetheless:
+ *
+ * \warning   SHA-1 is considered a weak message digest and its use constitutes
+ *            a security risk. If possible, we recommend avoiding dependencies
+ *            on it, and considering stronger message digests instead.
+ *
+ */
+#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE
+
+/* \} name SECTION: Customisation configuration options */
+
+/* Target and application specific configurations */
+//#define YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE "mbedtls/target_config.h"
+
+#if defined(TARGET_LIKE_MBED) && defined(YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE)
+#include YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE
+#endif
+
+/*
+ * Allow user to override any previous default.
+ *
+ * Use two macro names for that, as:
+ * - with yotta the prefix YOTTA_CFG_ is forced
+ * - without yotta is looks weird to have a YOTTA prefix.
+ */
+#if defined(YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE)
+#include YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE
+#elif defined(MBEDTLS_USER_CONFIG_FILE)
+#include MBEDTLS_USER_CONFIG_FILE
+#endif
+
+/*
+ * !!!!! The following two macros are added to the porting code !!!!!
+ * !!!!! The following two macros are added to the porting code !!!!!
+ * !!!!! The following two macros are added to the porting code !!!!!
+ * 
+ * Upgraded version handles the following two macro definitions
+ * 
+ * These two macros are defined in the ctr_drbg.c file
+ *
+ * #if !defined(MBEDTLS_CTR_DRBG_BLOCKSIZE)
+ * #define MBEDTLS_CTR_DRBG_BLOCKSIZE          16
+ * #endif
+ * #if !defined(MBEDTLS_CTR_DRBG_KEYSIZE)
+ * #define MBEDTLS_CTR_DRBG_KEYSIZE            32
+ * #endif 
+ * 
+*/
+
+#include "mbedtls/check_config.h"
+
+#define tls_malloc  rt_malloc
+#define tls_free    rt_free
+#define tls_realloc rt_realloc
+#define tls_calloc  rt_calloc
+#define tls_strdup  rt_strdup
+
+#endif /* MBEDTLS_CONFIG_H */

+ 305 - 0
ports/ssl/HAL_TLS_mbedtls.c

@@ -0,0 +1,305 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "uiot_import.h"
+#include "uiot_defs.h"
+
+#include "HAL_Timer_Platform.h"
+
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/error.h"
+
+/**
+ * @brief 用于保存SSL连接相关数据结构
+ */
+typedef struct {
+    mbedtls_net_context socket_fd;        // socket文件描述符
+    mbedtls_entropy_context entropy;      // 保存熵配置
+    mbedtls_ctr_drbg_context ctr_drbg;    // 随机数生成器
+    mbedtls_ssl_context ssl;              // 保存SSL基本数据
+    mbedtls_ssl_config ssl_conf;          // SSL/TLS配置信息
+    mbedtls_x509_crt ca_cert;             // ca证书信息
+    mbedtls_x509_crt client_cert;         // 客户端证书信息
+    mbedtls_pk_context private_key;       // 客户端私钥信息
+} TLSDataParams;
+
+/**
+ * @brief 释放mbedtls开辟的内存
+ */
+static void _free_mbedtls(TLSDataParams *pParams) {
+    mbedtls_net_free(&(pParams->socket_fd));
+    mbedtls_x509_crt_free(&(pParams->client_cert));
+    mbedtls_x509_crt_free(&(pParams->ca_cert));
+    mbedtls_pk_free(&(pParams->private_key));
+    mbedtls_ssl_free(&(pParams->ssl));
+    mbedtls_ssl_config_free(&(pParams->ssl_conf));
+    mbedtls_ctr_drbg_free(&(pParams->ctr_drbg));
+    mbedtls_entropy_free(&(pParams->entropy));
+
+    HAL_Free(pParams);
+}
+
+/**
+ * @brief mbedtls库初始化
+ *
+ * 1. 执行mbedtls库相关初始化函数
+ * 2. 随机数生成器
+ * 3. 加载CA证书
+ *
+ * @param pDataParams       TLS连接相关数据结构
+ * @param pConnectParams    TLS证书密钥相关
+ * @return                  返回SUCCESS, 表示成功
+ */
+static int _mbedtls_client_init(TLSDataParams *pDataParams, const char *ca_crt, size_t ca_crt_len) {
+    int ret;
+    mbedtls_net_init(&(pDataParams->socket_fd));
+    mbedtls_ssl_init(&(pDataParams->ssl));
+    mbedtls_ssl_config_init(&(pDataParams->ssl_conf));
+    mbedtls_ctr_drbg_init(&(pDataParams->ctr_drbg));
+    mbedtls_x509_crt_init(&(pDataParams->ca_cert));
+    mbedtls_x509_crt_init(&(pDataParams->client_cert));
+    mbedtls_pk_init(&(pDataParams->private_key));
+
+    LOG_DEBUG("Seeding the random number generator...");
+    mbedtls_entropy_init(&(pDataParams->entropy));
+    // 随机数, 增加custom参数, 目前为NULL
+    if ((ret = mbedtls_ctr_drbg_seed(&(pDataParams->ctr_drbg), mbedtls_entropy_func,
+                                     &(pDataParams->entropy), NULL, 0)) != 0) {
+        LOG_ERROR("failed! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret);
+        return ERR_SSL_INIT_FAILED;
+    }
+
+    LOG_DEBUG("Loading the CA root certificate ...");
+    if (ca_crt != NULL) {
+        if ((ret = mbedtls_x509_crt_parse(&(pDataParams->ca_cert), (const unsigned char *) ca_crt,
+                                          (ca_crt_len + 1 )))) {
+            LOG_ERROR("failed!  mbedtls_x509_crt_parse returned -0x%x while parsing root cert\n", -ret);
+            return ERR_SSL_CERT_FAILED;
+        }
+    }
+    return SUCCESS_RET;
+}
+
+/**
+ * @brief 建立TCP连接
+ *
+ * @param socket_fd  Socket描述符
+ * @param host       服务器主机名
+ * @param port       服务器端口地址
+ * @return 返回SUCCESS, 表示成功
+ */
+int _mbedtls_tcp_connect(mbedtls_net_context *socket_fd, const char *host, uint16_t port) {
+    int ret = 0;
+    char port_str[6];
+    HAL_Snprintf(port_str, 6, "%d", port);
+    if ((ret = mbedtls_net_connect(socket_fd, host, port_str, MBEDTLS_NET_PROTO_TCP)) != 0) {
+        LOG_ERROR("failed! mbedtls_net_connect returned -0x%x\n", -ret);
+        switch (ret) {
+            case MBEDTLS_ERR_NET_SOCKET_FAILED:
+                return ERR_TCP_SOCKET_FAILED;
+            case MBEDTLS_ERR_NET_UNKNOWN_HOST:
+                return ERR_TCP_UNKNOWN_HOST;
+            default:
+                return ERR_TCP_CONNECT_FAILED;
+        }
+    }
+#if 0
+    if ((ret = mbedtls_net_set_block(socket_fd)) != 0) {
+        LOG_ERROR("failed! net_set_(non)block() returned -0x%x\n", -ret);
+        return ERR_TCP_CONNECT_FAILED;
+    }
+#endif
+    return SUCCESS_RET;
+}
+
+/**
+ * @brief 在该函数中可对服务端证书进行自定义的校验
+ *
+ * 这种行为发生在握手过程中, 一般是校验连接服务器的主机名与服务器证书中的CN或SAN的域名信息是否一致
+ * 不过, mbedtls库已经实现该功能, 可以参考函数 `mbedtls_x509_crt_verify_with_profile`
+ *
+ * @param hostname 连接服务器的主机名
+ * @param crt x509格式的证书
+ * @param depth
+ * @param flags
+ * @return
+ */
+int _server_certificate_verify(void *hostname, mbedtls_x509_crt *crt, int depth, uint32_t *flags) {
+    return *flags;
+}
+
+uintptr_t HAL_TLS_Connect(_IN_ const char *host, _IN_ uint16_t port, _IN_ uint16_t authmode, _IN_ const char *ca_crt,
+                          _IN_ size_t ca_crt_len) {
+    int ret = 0;
+
+    TLSDataParams *pDataParams = (TLSDataParams *) HAL_Malloc(sizeof(TLSDataParams));
+
+    if ((ret = _mbedtls_client_init(pDataParams, ca_crt, ca_crt_len)) != SUCCESS_RET) {
+        goto error;
+    }
+
+    LOG_INFO("Connecting to /%s/%d...", host, port);
+    if ((ret = _mbedtls_tcp_connect(&(pDataParams->socket_fd), host, port)) != SUCCESS_RET) {
+        goto error;
+    }
+
+    LOG_DEBUG("Setting up the SSL/TLS structure...");
+    if ((ret = mbedtls_ssl_config_defaults(&(pDataParams->ssl_conf), MBEDTLS_SSL_IS_CLIENT,
+                                           MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+        LOG_ERROR("failed! mbedtls_ssl_config_defaults returned -0x%x\n", -ret);
+        goto error;
+    }
+
+    mbedtls_ssl_conf_verify(&(pDataParams->ssl_conf), _server_certificate_verify, (void *) host);
+
+    mbedtls_ssl_conf_authmode(&(pDataParams->ssl_conf), authmode);
+
+    mbedtls_ssl_conf_rng(&(pDataParams->ssl_conf), mbedtls_ctr_drbg_random, &(pDataParams->ctr_drbg));
+
+    mbedtls_ssl_conf_ca_chain(&(pDataParams->ssl_conf), &(pDataParams->ca_cert), NULL);
+
+    mbedtls_ssl_conf_read_timeout(&(pDataParams->ssl_conf), 10000);
+    if ((ret = mbedtls_ssl_setup(&(pDataParams->ssl), &(pDataParams->ssl_conf))) != 0) {
+        LOG_ERROR("failed! mbedtls_ssl_setup returned -0x%x\n", -ret);
+        goto error;
+    }
+
+    // Set the hostname to check against the received server certificate and sni
+    if ((ret = mbedtls_ssl_set_hostname(&(pDataParams->ssl), host)) != 0) {
+        LOG_ERROR("failed! mbedtls_ssl_set_hostname returned %d\n", ret);
+        goto error;
+    }
+
+    LOG_DEBUG("SSL state connect : %d ", pDataParams->ssl.state);
+    mbedtls_ssl_set_bio(&(pDataParams->ssl), &(pDataParams->socket_fd), mbedtls_net_send, mbedtls_net_recv,
+                        mbedtls_net_recv_timeout);
+    LOG_DEBUG("SSL state connect : %d ", pDataParams->ssl.state);
+
+    LOG_DEBUG("Performing the SSL/TLS handshake...");
+    while ((ret = mbedtls_ssl_handshake(&(pDataParams->ssl))) != 0) {
+        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+            LOG_ERROR("failed! mbedtls_ssl_handshake returned -0x%x\n", -ret);
+            if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
+                LOG_ERROR("Unable to verify the server's certificate");
+            }
+            goto error;
+        }
+    }
+
+    if ((ret = mbedtls_ssl_get_verify_result(&(pDataParams->ssl))) != 0) {
+        LOG_ERROR("mbedtls_ssl_get_verify_result failed returned 0x%04x\n", -ret);
+        goto error;
+    }
+
+    //mbedtls_ssl_conf_read_timeout(&(pDataParams->ssl_conf), 100);
+
+    LOG_INFO("connected with /%s/%d...", host, port);
+
+    return (uintptr_t) pDataParams;
+
+    error:
+    _free_mbedtls(pDataParams);
+    return 0;
+}
+
+int32_t HAL_TLS_Disconnect(_IN_ uintptr_t handle) {
+    if ((uintptr_t) NULL == handle) {
+        LOG_DEBUG("handle is NULL");
+        return FAILURE_RET;
+    }
+    TLSDataParams *pParams = (TLSDataParams *) handle;
+    int ret = 0;
+    do {
+        ret = mbedtls_ssl_close_notify(&(pParams->ssl));
+    } while (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+    _free_mbedtls(pParams);
+    return SUCCESS_RET;
+}
+
+int32_t HAL_TLS_Write(_IN_ uintptr_t handle, _IN_ unsigned char *buf, _IN_ size_t len, _IN_ uint32_t timeout_ms) {
+    Timer timer;
+    HAL_Timer_Init(&timer);
+    HAL_Timer_Countdown_ms(&timer, (unsigned int) timeout_ms);
+    size_t written_so_far;
+    bool errorFlag = false;
+    int write_rc = 0;
+
+    TLSDataParams *pParams = (TLSDataParams *) handle;
+
+    for (written_so_far = 0; written_so_far < len && !HAL_Timer_Expired(&timer); written_so_far += write_rc) {
+        while (!HAL_Timer_Expired(&timer) &&
+               (write_rc = mbedtls_ssl_write(&(pParams->ssl), (unsigned char *)(buf + written_so_far), len - written_so_far)) <= 0) {
+            if (write_rc != MBEDTLS_ERR_SSL_WANT_READ && write_rc != MBEDTLS_ERR_SSL_WANT_WRITE) {
+                LOG_ERROR("failed! mbedtls_ssl_write returned -0x%x\n", -write_rc);
+                errorFlag = true;
+                break;
+            }
+        }
+
+        if (errorFlag) {
+            break;
+        }
+    }
+
+    if (errorFlag) {
+        return ERR_SSL_WRITE_FAILED;
+    }
+
+    return written_so_far;
+}
+
+int32_t HAL_TLS_Read(_IN_ uintptr_t handle, _OU_ unsigned char *buf, _IN_ size_t len, _IN_ uint32_t timeout_ms) {
+    Timer timer;
+    HAL_Timer_Init(&timer);
+    HAL_Timer_Countdown_ms(&timer, timeout_ms);
+    size_t read_len = 0;
+
+    TLSDataParams *pParams = (TLSDataParams *) handle;
+
+    while (read_len < len) {
+        int read_rc = 0;
+        read_rc = mbedtls_ssl_read(&(pParams->ssl), (unsigned char *)(buf + read_len), len - read_len);
+
+        if (read_rc > 0) {
+            read_len += read_rc;
+        } else if (read_rc == 0 || (read_rc != MBEDTLS_ERR_SSL_WANT_WRITE
+                                    && read_rc != MBEDTLS_ERR_SSL_WANT_READ && read_rc != MBEDTLS_ERR_SSL_TIMEOUT)) {
+            LOG_ERROR("failed! mbedtls_ssl_read returned -0x%x\n", -read_rc);
+            return ERR_SSL_READ_FAILED;
+        }
+
+        if (HAL_Timer_Expired(&timer)) {
+            break;
+        }
+    }
+
+    return read_len;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 216 - 0
samples/dev_model/dev_model_sample.c

@@ -0,0 +1,216 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+
+#include "uiot_export.h"
+#include "uiot_import.h"
+#include "uiot_export_dm.h"
+
+static int running_state = 0;
+
+static void event_handler(void *pClient, void *handle_context, MQTTEventMsg *msg)
+{
+	switch(msg->event_type) {
+		case MQTT_EVENT_UNDEF:
+			LOG_INFO("undefined event occur.\n");
+			break;
+
+		case MQTT_EVENT_DISCONNECT:
+			LOG_INFO("MQTT disconnect.\n");
+			break;
+
+		case MQTT_EVENT_RECONNECT:
+			LOG_INFO("MQTT reconnect.\n");
+			break;
+
+		case MQTT_EVENT_SUBSCRIBE_SUCCESS:
+			LOG_INFO("subscribe success.\n");
+			break;
+
+		case MQTT_EVENT_SUBSCRIBE_TIMEOUT:
+			LOG_INFO("subscribe wait ack timeout.\n");
+			break;
+
+		case MQTT_EVENT_SUBSCRIBE_NACK:
+			LOG_INFO("subscribe nack.\n");
+			break;
+
+		case MQTT_EVENT_PUBLISH_SUCCESS:
+			LOG_INFO("publish success.\n");
+			break;
+
+		case MQTT_EVENT_PUBLISH_TIMEOUT:
+			LOG_INFO("publish timeout.\n");
+			break;
+
+		case MQTT_EVENT_PUBLISH_NACK:
+			LOG_INFO("publish nack.\n");
+			break;
+
+		default:
+			LOG_INFO("Should NOT arrive here.\n");
+			break;
+	}
+}
+
+
+int event_post_cb(const char *request_id, const int ret_code){
+    LOG_INFO("event_post_cb; request_id: %s; ret_code: %d", request_id, ret_code);
+    return SUCCESS_RET;
+}
+
+int property_post_cb(const char *request_id, const int ret_code){
+    LOG_INFO("property_post_cb; request_id: %s; ret_code: %d", request_id, ret_code);
+    return SUCCESS_RET;
+}
+
+int command_cb(const char *request_id, const char *identifier, const char *input, char **output){
+    LOG_INFO("command_cb; request_id: %s; identifier: %s; input: %s", request_id, identifier, input);
+    *output = (char *)HAL_Malloc(100);
+    HAL_Snprintf(*output, 1000, "{\"result\":%d}", 1);
+    return SUCCESS_RET;
+}
+
+int property_set_cb(const char *request_id, const char *property){
+    LOG_INFO("property_set_cb; request_id: %s; property: %s", request_id, property);
+    return SUCCESS_RET;
+}
+
+static int _setup_connect_init_params(MQTTInitParams* initParams)
+{
+	initParams->device_sn = PKG_USING_UCLOUD_IOT_DEVICE_SN;
+	initParams->product_sn = PKG_USING_UCLOUD_IOT_PRODUCT_SN;
+	initParams->device_secret = PKG_USING_UCLOUD_IOT_DEVICE_SECRET;
+	initParams->command_timeout = UIOT_MQTT_COMMAND_TIMEOUT;
+	initParams->keep_alive_interval = UIOT_MQTT_KEEP_ALIVE_INTERNAL;
+	initParams->auto_connect_enable = 1;
+    initParams->event_handler.h_fp = event_handler;
+
+    return SUCCESS_RET;
+}
+
+static void mqtt_devmodel_thread(void)
+{
+    int rc;
+
+    MQTTInitParams init_params = DEFAULT_MQTT_INIT_PARAMS;
+    rc = _setup_connect_init_params(&init_params);
+	if (rc != SUCCESS_RET) {
+		return;
+	}
+
+    void *client = IOT_MQTT_Construct(&init_params);
+    if (client != NULL) {
+        LOG_INFO("Cloud Device Construct Success");
+    } else {
+        LOG_ERROR("Cloud Device Construct Failed");
+		return;
+    }
+    IOT_MQTT_Yield(client, 50);
+
+    void *h_dm = IOT_DM_Init(PKG_USING_UCLOUD_IOT_PRODUCT_SN, PKG_USING_UCLOUD_IOT_DEVICE_SN, client);
+    if (NULL == h_dm) {
+        LOG_ERROR("initialize device model failed");
+		return;
+    }
+    IOT_DM_Yield(h_dm, 50);
+
+    IOT_DM_RegisterCallback(EVENT_POST, h_dm, event_post_cb);
+    IOT_DM_RegisterCallback(COMMAND , h_dm, command_cb);
+    IOT_DM_RegisterCallback(PROPERTY_POST , h_dm, property_post_cb);
+    IOT_DM_RegisterCallback(PROPERTY_SET , h_dm, property_set_cb);
+
+    for (int i = 0; i < 10; i++) {
+        IOT_DM_Property_Report(h_dm, PROPERTY_POST, i * 2, "{\"volume\": {\"Value\":50}}");
+        IOT_DM_TriggerEvent(h_dm, i * 2 + 1, "low_power_alert", "{\"power\": 5}");
+
+        IOT_DM_Yield(h_dm, 200);
+        HAL_SleepMs(2000);
+    }
+
+    //等待属性设置及命令下发
+    IOT_DM_Yield(h_dm, 60000);
+
+    IOT_DM_Destroy(h_dm);
+
+    IOT_MQTT_Destroy(&client);
+
+    return;
+}
+
+static int devmodel_test_example(int argc, char **argv)
+{
+    rt_thread_t tid;
+    int stack_size = 8192;
+
+	if (2 == argc)
+	{
+		if (!strcmp("start", argv[1]))
+		{
+			if (1 == running_state)
+			{
+				HAL_Printf("devmodel_test_example is already running\n");
+				return 0;
+			}			
+		}
+		else if (!strcmp("stop", argv[1]))
+		{
+			if (0 == running_state)
+			{
+				HAL_Printf("devmodel_test_example is already stopped\n");
+				return 0;
+			}
+			running_state = 0;
+			return 0;
+		}
+		else
+		{
+			HAL_Printf("Usage: devmodel_test_example start/stop");
+			return 0;			  
+		}
+	}
+	else
+	{
+		HAL_Printf("Para err, usage: devmodel_test_example start/stop");
+		return 0;
+	}
+	
+	tid = rt_thread_create("devmodel_test", (void (*)(void *))mqtt_devmodel_thread, 
+							NULL, stack_size, RT_THREAD_PRIORITY_MAX / 2 - 1, 100);  
+
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+
+    return 0;
+}
+
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(devmodel_test_example, startup mqtt devmodel example);
+#endif
+
+#ifdef FINSH_USING_MSH
+MSH_CMD_EXPORT(devmodel_test_example, startup mqtt devmodel example);
+#endif
+
+

+ 186 - 0
samples/dynamic_auth/dynamic_auth_sample.c

@@ -0,0 +1,186 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+#include "uiot_export.h"
+#include "uiot_import.h"
+#include "lite-utils.h"
+
+#define MAX_SIZE_OF_TOPIC_CONTENT 100
+MQTTInitParams init_params = DEFAULT_MQTT_INIT_PARAMS;
+static int running_state = 0;
+
+void dynamic_event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg) {
+	LOG_DEBUG("Enter event_handler!type:%d\n",msg->event_type);
+}
+
+static void on_message_callback(void *pClient, MQTTMessage *message, void *userData) {
+	if (message == NULL) {
+		return;
+	}
+
+	LOG_DEBUG("Receive Message With topicName:%.*s, payload:%.*s",
+		  (int) message->topic_len, message->topic, (int) message->payload_len, (char *) message->payload);
+}
+
+static int _publish_msg(void *client)
+{
+    char topicName[128] = {0};
+    int num = 18;
+    HAL_Snprintf(topicName, 128, "/%s/%s/set", PKG_USING_UCLOUD_IOT_PRODUCT_SN, PKG_USING_UCLOUD_IOT_DEVICE_SN);
+
+    PublishParams pub_params = DEFAULT_PUB_PARAMS;
+    
+    char topic_content[MAX_SIZE_OF_TOPIC_CONTENT + 1] = {0};
+
+	HAL_Snprintf(topic_content, MAX_SIZE_OF_TOPIC_CONTENT, "{\"test\": \"%d\"}", num);
+
+	pub_params.payload = topic_content;
+	pub_params.payload_len = strlen(topic_content);
+
+    return IOT_MQTT_Publish(client, topicName, &pub_params);
+}
+
+static int _register_subscribe_topics(void *client)
+{
+    static char topic_name[128] = {0};
+    HAL_Snprintf(topic_name, 128, "/%s/%s/set", PKG_USING_UCLOUD_IOT_PRODUCT_SN, PKG_USING_UCLOUD_IOT_DEVICE_SN);
+
+    SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
+    sub_params.on_message_handler = on_message_callback;
+    return IOT_MQTT_Subscribe(client, topic_name, &sub_params);
+}
+
+/**
+ * 设置MQTT connet初始化参数
+ *
+ * @param initParams MQTT connet初始化参数
+ *
+ * @return 0: 参数初始化成功  非0: 失败
+ */
+static int _setup_connect_init_params(MQTTInitParams* initParams)
+{
+	initParams->device_sn = (char *)PKG_USING_UCLOUD_IOT_DEVICE_SN;
+	initParams->product_sn = (char *)PKG_USING_UCLOUD_IOT_PRODUCT_SN;
+	initParams->product_secret = (char *)PKG_USING_UCLOUD_IOT_PRODUCT_SECRET;
+
+	initParams->command_timeout = UIOT_MQTT_COMMAND_TIMEOUT;
+	initParams->keep_alive_interval = UIOT_MQTT_KEEP_ALIVE_INTERNAL;
+
+	initParams->auto_connect_enable = 1;
+	initParams->event_handler.h_fp = dynamic_event_handler;
+	initParams->event_handler.context = NULL;
+
+    return SUCCESS_RET;
+}
+
+static void dynamic_test_thread(void) 
+{
+    int ret = 0;
+    char secret[IOT_DEVICE_SECRET_LEN+1];
+    ret = _setup_connect_init_params(&init_params);
+	if (ret != SUCCESS_RET) {
+		return;
+	}
+    
+    ret = IOT_MQTT_Dynamic_Register(&init_params);
+	if (ret != SUCCESS_RET) {
+		return;
+	}
+    
+    ret = HAL_GetDeviceSecret(secret);
+    if(ret != SUCCESS_RET)
+    {   
+        LOG_ERROR("get device secret fail\n");
+		return;
+    }
+    LOG_DEBUG("Password:%s\n",init_params.device_secret);
+    init_params.device_secret = secret;
+    void *static_client = IOT_MQTT_Construct(&init_params);
+    if(static_client == NULL)
+    {   
+        LOG_ERROR("static_client Construct fail\n");
+		return;
+    }
+    _register_subscribe_topics(static_client);
+    IOT_MQTT_Yield(static_client, 200);
+    _publish_msg(static_client);
+    IOT_MQTT_Yield(static_client, 200);
+    ret = IOT_MQTT_Destroy(&static_client);
+    return;
+}
+
+static int dynamic_test_example(int argc, char **argv)
+{
+    rt_thread_t tid;
+    int stack_size = 8192;
+
+	if (2 == argc)
+	{
+		if (!strcmp("start", argv[1]))
+		{
+			if (1 == running_state)
+			{
+				HAL_Printf("dynamic_test_example is already running\n");
+				return 0;
+			}			
+		}
+		else if (!strcmp("stop", argv[1]))
+		{
+			if (0 == running_state)
+			{
+				HAL_Printf("dynamic_test_example is already stopped\n");
+				return 0;
+			}
+			running_state = 0;
+			return 0;
+		}
+		else
+		{
+			HAL_Printf("Usage: dynamic_test_example start/stop");
+			return 0;			  
+		}
+	}
+	else
+	{
+		HAL_Printf("Para err, usage: dynamic_test_example start/stop");
+		return 0;
+	}
+	
+	tid = rt_thread_create("dynamic_test", (void (*)(void *))dynamic_test_thread, 
+							NULL, stack_size, RT_THREAD_PRIORITY_MAX / 2 - 1, 100);  
+
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+
+    return 0;
+}
+
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(dynamic_test_example, startup mqtt dynamic example);
+#endif
+
+#ifdef FINSH_USING_MSH
+MSH_CMD_EXPORT(dynamic_test_example, startup mqtt dynamic example);
+#endif
+
+

+ 291 - 0
samples/mqtt/mqtt_sample.c

@@ -0,0 +1,291 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <string.h>
+#include <signal.h>
+
+#include "uiot_export.h"
+#include "uiot_import.h"
+
+#define MAX_SIZE_OF_TOPIC_CONTENT 100
+
+static int sg_count = 0;
+static int sg_sub_packet_id = -1;
+static int running_state = 0;
+
+void event_handler(void *pClient, void *handle_context, MQTTEventMsg *msg) {
+	MQTTMessage* mqtt_message = (MQTTMessage*)msg->msg;
+	uintptr_t packet_id = (uintptr_t)msg->msg;
+
+	switch(msg->event_type) {
+		case MQTT_EVENT_UNDEF:
+			HAL_Printf("undefined event occur.\n");
+			break;
+
+		case MQTT_EVENT_DISCONNECT:
+			HAL_Printf("MQTT disconnect.\n");
+			break;
+
+		case MQTT_EVENT_RECONNECT:
+			HAL_Printf("MQTT reconnect.\n");
+			break;
+
+		case MQTT_EVENT_PUBLISH_RECEIVED:
+			HAL_Printf("topic message arrived but without any related handle: topic=%.*s, topic_msg=%.*s\n",
+					  mqtt_message->topic_len,
+					  mqtt_message->topic,
+					  mqtt_message->payload_len,
+					  mqtt_message->payload);
+			break;
+		case MQTT_EVENT_SUBSCRIBE_SUCCESS:
+			HAL_Printf("subscribe success, packet-id=%u\n", (unsigned int)packet_id);
+			sg_sub_packet_id = packet_id;
+			break;
+
+		case MQTT_EVENT_SUBSCRIBE_TIMEOUT:
+			HAL_Printf("subscribe wait ack timeout, packet-id=%u\n", (unsigned int)packet_id);
+			sg_sub_packet_id = packet_id;
+			break;
+
+		case MQTT_EVENT_SUBSCRIBE_NACK:
+			HAL_Printf("subscribe nack, packet-id=%u\n", (unsigned int)packet_id);
+			sg_sub_packet_id = packet_id;
+			break;
+
+		case MQTT_EVENT_UNSUBSCRIBE_SUCCESS:
+			HAL_Printf("unsubscribe success, packet-id=%u\n", (unsigned int)packet_id);
+			break;
+
+		case MQTT_EVENT_UNSUBSCRIBE_TIMEOUT:
+			HAL_Printf("unsubscribe timeout, packet-id=%u\n", (unsigned int)packet_id);
+			break;
+
+		case MQTT_EVENT_UNSUBSCRIBE_NACK:
+			HAL_Printf("unsubscribe nack, packet-id=%u\n", (unsigned int)packet_id);
+			break;
+
+		case MQTT_EVENT_PUBLISH_SUCCESS:
+			HAL_Printf("publish success, packet-id=%u\n", (unsigned int)packet_id);
+			break;
+
+		case MQTT_EVENT_PUBLISH_TIMEOUT:
+			HAL_Printf("publish timeout, packet-id=%u\n", (unsigned int)packet_id);
+			break;
+
+		case MQTT_EVENT_PUBLISH_NACK:
+			HAL_Printf("publish nack, packet-id=%u\n", (unsigned int)packet_id);
+			break;
+		default:
+			HAL_Printf("Should NOT arrive here.\n");
+			break;
+	}
+}
+
+/**
+ * MQTT消息接收处理函数
+ *
+ * @param topicName         topic主题
+ * @param topicNameLen      topic长度
+ * @param message           已订阅消息的结构
+ * @param userData         消息负载
+ */
+static void on_message_callback(void *pClient, MQTTMessage *message, void *userData) {
+	if (message == NULL) {
+		return;
+	}
+
+	HAL_Printf("Receive Message With topicName:%.*s, payload:%.*s\n",
+		  (int) message->topic_len, message->topic, (int) message->payload_len, (char *) message->payload);
+}
+
+/**
+ * 设置MQTT connet初始化参数
+ *
+ * @param initParams MQTT connet初始化参数
+ *
+ * @return 0: 参数初始化成功  非0: 失败
+ */
+static int _setup_connect_init_params(MQTTInitParams* initParams)
+{
+	initParams->device_sn = PKG_USING_UCLOUD_IOT_DEVICE_SN;
+	initParams->product_sn = PKG_USING_UCLOUD_IOT_PRODUCT_SN;
+	initParams->device_secret = PKG_USING_UCLOUD_IOT_DEVICE_SECRET;
+
+	initParams->command_timeout = UIOT_MQTT_COMMAND_TIMEOUT;
+	initParams->keep_alive_interval = UIOT_MQTT_KEEP_ALIVE_INTERNAL;
+
+	initParams->auto_connect_enable = 1;
+	initParams->event_handler.h_fp = event_handler;
+	initParams->event_handler.context = NULL;
+
+    HAL_SetProductSN(initParams->product_sn);  
+    HAL_SetDeviceSN(initParams->device_sn);
+    HAL_SetDeviceSecret(initParams->device_secret);
+
+    return SUCCESS_RET;
+}
+
+/**
+ * 发送topic消息
+ *
+ */
+static int _publish_msg(void *client)
+{
+    char topicName[128] = {0};
+    HAL_Snprintf(topicName, 128, "/%s/%s/%s", PKG_USING_UCLOUD_IOT_PRODUCT_SN, PKG_USING_UCLOUD_IOT_DEVICE_SN, "set");
+
+    PublishParams pub_params = DEFAULT_PUB_PARAMS;
+    pub_params.qos = QOS1;
+
+    char topic_content[MAX_SIZE_OF_TOPIC_CONTENT + 1] = {0};
+
+	int size = HAL_Snprintf(topic_content, sizeof(topic_content), "{\"test\": \"%d\"}", sg_count++);
+	if (size < 0 || size > sizeof(topic_content) - 1)
+	{
+		HAL_Printf("payload content length not enough! content size:%d  buf size:%d\n", size, (int)sizeof(topic_content));
+		return -3;
+	}
+
+	pub_params.payload = topic_content;
+	pub_params.payload_len = strlen(topic_content);
+
+    return IOT_MQTT_Publish(client, topicName, &pub_params);
+}
+
+/**
+ * 订阅关注topic和注册相应回调处理
+ *
+ */
+static int _register_subscribe_topics(void *client)
+{
+    static char topic_name[128] = {0};
+    int size = HAL_Snprintf(topic_name, sizeof(topic_name), "/%s/%s/%s", PKG_USING_UCLOUD_IOT_PRODUCT_SN, PKG_USING_UCLOUD_IOT_DEVICE_SN, "set");
+    if (size < 0 || size > sizeof(topic_name) - 1)
+    {
+        HAL_Printf("topic content length not enough! content size:%d  buf size:%d\n", size, (int)sizeof(topic_name));
+        return FAILURE_RET;
+    }
+    SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
+    sub_params.on_message_handler = on_message_callback;
+    return IOT_MQTT_Subscribe(client, topic_name, &sub_params);
+}
+
+static void mqtt_test_thread(void) {    
+    int rc;
+
+    // to avoid process crash when writing to a broken socket
+    signal(SIGPIPE, SIG_IGN);
+    
+    //init connection
+    MQTTInitParams init_params = DEFAULT_MQTT_INIT_PARAMS;
+    rc = _setup_connect_init_params(&init_params);
+	if (rc != SUCCESS_RET) {
+		return;
+	}
+    void *client = IOT_MQTT_Construct(&init_params);
+    if (client != NULL) {
+        HAL_Printf("Cloud Device Construct Success");
+    } else {
+        HAL_Printf("Cloud Device Construct Failed");
+        return;
+    }
+
+	//register subscribe topics here
+    rc = _register_subscribe_topics(client);
+    if (rc < 0) {
+        HAL_Printf("Client Subscribe Topic Failed: %d", rc);
+        return;
+    }
+
+	rc = IOT_MQTT_Yield(client, 200);
+
+    do {
+		// 等待订阅结果
+		if (sg_sub_packet_id > 0) {
+			rc = _publish_msg(client);
+			if (rc < 0) {
+				HAL_Printf("client publish topic failed :%d.", rc);
+			}
+
+            rc = IOT_MQTT_Yield(client, 200);
+		}
+    } while (running_state == 1);
+    return;
+}
+
+static int mqtt_test_example(int argc, char **argv)
+{
+    rt_thread_t tid;
+    int stack_size = 8192;
+
+	if (2 == argc)
+	{
+		if (!strcmp("start", argv[1]))
+		{
+			if (1 == running_state)
+			{
+				HAL_Printf("mqtt_test_example is already running\n");
+				return 0;
+			}	
+		}
+		else if (!strcmp("stop", argv[1]))
+		{
+			if (0 == running_state)
+			{
+				HAL_Printf("mqtt_test_example is already stopped\n");
+				return 0;
+			}
+			running_state = 0;
+			return 0;
+		}
+		else
+		{
+			HAL_Printf("Usage: mqtt_test_example start/stop");
+			return 0;			  
+		}
+	}
+	else
+	{
+		HAL_Printf("Para err, usage: mqtt_test_example start/stop");
+		return 0;
+	}
+	
+	tid = rt_thread_create("mqtt_test", (void (*)(void *))mqtt_test_thread, 
+							NULL, stack_size, RT_THREAD_PRIORITY_MAX / 2 - 1, 100);  
+
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+        running_state = 1;
+    }
+
+    return 0;
+}
+
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(mqtt_test_example, startup mqtt basic example);
+#endif
+
+#ifdef FINSH_USING_MSH
+MSH_CMD_EXPORT(mqtt_test_example, startup mqtt basic example);
+#endif
+

+ 192 - 0
samples/ota/ota_sample.c

@@ -0,0 +1,192 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+
+#include "uiot_export.h"
+#include "uiot_import.h"
+#include "uiot_export_ota.h"
+
+#define OTA_BUF_LEN (1024)
+static int running_state = 0;
+
+static void event_handler(void *pClient, void *handle_context, MQTTEventMsg *msg)
+{
+	switch(msg->event_type) {
+		case MQTT_EVENT_UNDEF:
+			LOG_INFO("undefined event occur.\n");
+			break;
+
+		case MQTT_EVENT_DISCONNECT:
+			LOG_INFO("MQTT disconnect.\n");
+			break;
+
+		case MQTT_EVENT_RECONNECT:
+			LOG_INFO("MQTT reconnect.\n");
+			break;
+
+		case MQTT_EVENT_SUBSCRIBE_SUCCESS:
+			LOG_INFO("subscribe success.\n");
+			break;
+
+		case MQTT_EVENT_SUBSCRIBE_TIMEOUT:
+			LOG_INFO("subscribe wait ack timeout.\n");
+			break;
+
+		case MQTT_EVENT_SUBSCRIBE_NACK:
+			LOG_INFO("subscribe nack.\n");
+			break;
+
+		case MQTT_EVENT_PUBLISH_SUCCESS:
+			LOG_INFO("publish success.\n");
+			break;
+
+		case MQTT_EVENT_PUBLISH_TIMEOUT:
+			LOG_INFO("publish timeout.\n");
+			break;
+
+		case MQTT_EVENT_PUBLISH_NACK:
+			LOG_INFO("publish nack.\n");
+			break;
+		default:
+			LOG_INFO("Should NOT arrive here.\n");
+			break;
+	}
+}
+
+
+static int _setup_connect_init_params(MQTTInitParams* initParams)
+{
+	initParams->device_sn = PKG_USING_UCLOUD_IOT_DEVICE_SN;
+	initParams->product_sn = PKG_USING_UCLOUD_IOT_PRODUCT_SN;
+	initParams->device_secret = PKG_USING_UCLOUD_IOT_DEVICE_SECRET;
+	initParams->command_timeout = UIOT_MQTT_COMMAND_TIMEOUT;    
+	initParams->keep_alive_interval = UIOT_MQTT_KEEP_ALIVE_INTERNAL;
+	initParams->auto_connect_enable = 1;
+    initParams->event_handler.h_fp = event_handler;
+
+    return SUCCESS_RET;
+}
+
+static void ota_test_thread(void)
+{
+    int rc;
+    int ota_over = 0;
+    bool upgrade_fetch_success = true;
+    // 用于存放云端下发的固件版本
+    char msg_version[33];
+    FILE *fp;
+    char buf_ota[OTA_BUF_LEN];
+
+    MQTTInitParams init_params = DEFAULT_MQTT_INIT_PARAMS;
+    rc = _setup_connect_init_params(&init_params);
+	if (rc != SUCCESS_RET) {
+		return;
+	}
+
+    void *client = IOT_MQTT_Construct(&init_params);
+    if (client != NULL) {
+        LOG_INFO("MQTT Construct Success");
+    } else {
+        LOG_ERROR("MQTT Construct Failed");
+		return;
+    }
+
+    void *h_ota = IOT_OTA_Init(PKG_USING_UCLOUD_IOT_PRODUCT_SN, PKG_USING_UCLOUD_IOT_DEVICE_SN, client);
+    if (NULL == h_ota) {
+        LOG_ERROR("init OTA failed");
+		return;
+    }
+
+    /* Must report version first */
+    if (IOT_OTA_ReportVersion(h_ota, "1.0.0") < 0) {
+        LOG_ERROR("report OTA version failed");
+		return;
+    }
+
+    if (IOT_OTA_RequestFirmware(h_ota, "1.0.0") < 0) {
+        LOG_ERROR("Request firmware failed");
+		return;
+    }
+
+    do {
+        IOT_MQTT_Yield(client, 10);
+    } while(1);
+
+    return;
+}
+
+static int ota_test_example(int argc, char **argv)
+{
+    rt_thread_t tid;
+    int stack_size = 10240;
+
+	if (2 == argc)
+	{
+		if (!strcmp("start", argv[1]))
+		{
+			if (1 == running_state)
+			{
+				HAL_Printf("mqtt_ota_example is already running\n");
+				return 0;
+			}			
+		}
+		else if (!strcmp("stop", argv[1]))
+		{
+			if (0 == running_state)
+			{
+				HAL_Printf("mqtt_ota_example is already stopped\n");
+				return 0;
+			}
+			running_state = 0;
+			return 0;
+		}
+		else
+		{
+			HAL_Printf("Usage: mqtt_ota_example start/stop");
+			return 0;			  
+		}
+	}
+	else
+	{
+		HAL_Printf("Para err, usage: mqtt_ota_example start/stop");
+		return 0;
+	}
+	
+	tid = rt_thread_create("ota_test", (void (*)(void *))ota_test_thread, 
+							NULL, stack_size, 9, 10);  
+
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+
+    return 0;
+}
+
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(ota_test_example, startup mqtt ota example);
+#endif
+
+#ifdef FINSH_USING_MSH
+MSH_CMD_EXPORT(ota_test_example, startup mqtt ota example);
+#endif
+

+ 392 - 0
samples/shadow/shadow_sample.c

@@ -0,0 +1,392 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <string.h>
+#include <signal.h>
+
+#include "uiot_export_shadow.h"
+#include "uiot_import.h"
+#include "shadow_client.h"
+
+#define MAX_SIZE_OF_TOPIC_CONTENT 100
+
+#define SIZE_OF_JSON_BUFFER 256
+static int running_state = 0;
+
+static UIoT_Shadow    *sg_pshadow;
+static MQTTInitParams sg_initParams = DEFAULT_MQTT_INIT_PARAMS;
+
+//当设备直接按照desired字段中的属性值更新时不需要上报
+void RegCallback_update(void *pClient, RequestParams *pParams, char *pJsonValueBuffer, uint32_t valueLength, DeviceProperty *pProperty)
+{
+    LOG_DEBUG("key:%s val:%s\n",pProperty->key, pJsonValueBuffer);
+    IOT_Shadow_Direct_Update_Value(pJsonValueBuffer, pProperty);
+    return;
+}
+
+//当设备没有完全按照desired字段中的属性更新时,需要将当前真实值上报
+void RegCallback_hold(void *pClient, RequestParams *pParams, char *pJsonValueBuffer, uint32_t valueLength, DeviceProperty *pProperty)
+{
+    LOG_DEBUG("key:%s val:%s\n",pProperty->key, pJsonValueBuffer);
+    int num = 10;
+    pProperty->data = &num;
+    IOT_Shadow_Request_Add_Delta_Property(pClient, pParams,pProperty);
+    return;
+}
+
+static void _update_ack_cb(void *pClient, Method method, RequestAck requestAck, const char *pReceivedJsonDocument, void *pUserdata) 
+{
+	LOG_DEBUG("requestAck=%d\n", requestAck);
+
+    if (NULL != pReceivedJsonDocument) {
+        LOG_DEBUG("Received Json Document=%s\n", pReceivedJsonDocument);
+    } else {
+        LOG_DEBUG("Received Json Document is NULL\n");
+    }
+
+    *((RequestAck *)pUserdata) = requestAck;
+    return;
+}
+
+
+/**
+ * 设置MQTT connet初始化参数
+ *
+ * @param initParams MQTT connet初始化参数
+ *
+ * @return 0: 参数初始化成功  非0: 失败
+ */
+static int _setup_connect_init_params(MQTTInitParams* initParams)
+{
+    int ret = SUCCESS_RET;
+	initParams->device_sn = (char *)PKG_USING_UCLOUD_IOT_DEVICE_SN;
+	initParams->product_sn = (char *)PKG_USING_UCLOUD_IOT_PRODUCT_SN;
+	initParams->device_secret = (char *)PKG_USING_UCLOUD_IOT_DEVICE_SECRET;
+
+	initParams->command_timeout = UIOT_MQTT_COMMAND_TIMEOUT;
+	initParams->keep_alive_interval = UIOT_MQTT_KEEP_ALIVE_INTERNAL;
+	initParams->auto_connect_enable = 1;
+
+    return ret;
+}
+
+static void shadow_test_thread(void) 
+{    
+    int ret = SUCCESS_RET;
+    ret = _setup_connect_init_params(&sg_initParams);
+    if(ret != SUCCESS_RET)
+    {
+        HAL_Printf("_setup_connect_init_params fail:%d\n", ret);
+        return;
+    }
+    
+    void *mqtt_client = IOT_MQTT_Construct(&sg_initParams);
+    if(mqtt_client == NULL)
+    {
+        HAL_Printf("IOT_MQTT_Construct fail\n");
+        return;
+    }
+    
+    void *shadow_client = IOT_Shadow_Construct(PKG_USING_UCLOUD_IOT_PRODUCT_SN, PKG_USING_UCLOUD_IOT_DEVICE_SN, mqtt_client);
+    if(shadow_client == NULL)
+    {
+        HAL_Printf("IOT_Shadow_Construct fail\n");
+        return;
+    }
+    
+    sg_pshadow = (UIoT_Shadow *)shadow_client;
+    bool isConnected = IOT_MQTT_IsConnected(sg_pshadow->mqtt);
+    if(isConnected != true)
+    {
+        HAL_Printf("IOT_MQTT_IsConnected fail\n");
+        return;
+    }
+    
+    int time_sec = MAX_WAIT_TIME_SEC;
+	RequestAck ack_update = ACK_NONE;
+
+    DeviceProperty *Property1 = (DeviceProperty *)HAL_Malloc(sizeof(DeviceProperty));
+    int32_t num1 = 18;
+    char str1[6] = "data1";
+    Property1->key= str1;
+    Property1->data = &num1;
+    Property1->type = JINT32;
+    ret = IOT_Shadow_Register_Property(sg_pshadow, Property1, RegCallback_hold); 
+    if(SUCCESS_RET != ret)
+    {
+        HAL_Printf("Register Property1 fail:%d\n", ret);
+        return;
+    }
+    
+    DeviceProperty *Property2 = (DeviceProperty *)HAL_Malloc(sizeof(DeviceProperty));
+    float num2 = 20.2;
+    char str2[6] = "data2";
+    Property2->key= str2;
+    Property2->data = &num2;
+    Property2->type = JFLOAT;
+    ret = IOT_Shadow_Register_Property(sg_pshadow, Property2, RegCallback_update); 
+    if(SUCCESS_RET != ret)
+    {
+        HAL_Printf("Register Property2 fail:%d\n", ret);
+        return;
+    }
+
+    DeviceProperty *Property3 = (DeviceProperty *)HAL_Malloc(sizeof(DeviceProperty));
+    double num3 = 22.9;
+    char str3[6] = "data3";
+    Property3->key= str3;
+    Property3->data = &num3;
+    Property3->type = JDOUBLE;
+    ret = IOT_Shadow_Register_Property(sg_pshadow, Property3, RegCallback_update); 
+    if(SUCCESS_RET != ret)
+    {
+        HAL_Printf("Register Property3 fail:%d\n", ret);
+        return;
+    }
+    
+    DeviceProperty *Property4 = (DeviceProperty *)HAL_Malloc(sizeof(DeviceProperty));
+    char num4[5] = "num4";
+    char str4[6] = "data4";
+    Property4->key= str4;
+    Property4->data = num4;
+    Property4->type = JSTRING;
+    ret = IOT_Shadow_Register_Property(sg_pshadow, Property4, RegCallback_update); 
+    if(SUCCESS_RET != ret)
+    {
+        HAL_Printf("Register Property4 fail:%d\n", ret);
+        return;
+    }
+
+    DeviceProperty *Property5 = (DeviceProperty *)HAL_Malloc(sizeof(DeviceProperty));
+    bool num5 = false;
+    char str5[6] = "data5";
+    Property5->key= str5;
+    Property5->data = &num5;
+    Property5->type = JBOOL;
+    ret = IOT_Shadow_Register_Property(sg_pshadow, Property5, RegCallback_update); 
+    if(SUCCESS_RET != ret)
+    {
+        HAL_Printf("Register Property5 fail:%d\n", ret);
+        return;
+    }
+
+    DeviceProperty *Property6 = (DeviceProperty *)HAL_Malloc(sizeof(DeviceProperty));
+    char num6[20] = "{\"temp\":25}";
+    char str6[6] = "data6";
+    Property6->key= str6;
+    Property6->data = num6;
+    Property6->type = JOBJECT;
+    ret = IOT_Shadow_Register_Property(sg_pshadow, Property6, RegCallback_update); 
+    if(SUCCESS_RET != ret)
+    {
+        HAL_Printf("Register Property6 fail:%d\n", ret);
+        return;
+    }
+
+    /* 先同步一下版本号和设备掉电期间更新的属性 */
+    ret = IOT_Shadow_Get_Sync(sg_pshadow, _update_ack_cb, time_sec, &ack_update);
+    if(SUCCESS_RET != ret)
+    {
+        HAL_Printf("Get Sync fail:%d\n", ret);
+        return;
+    }
+
+	while (ACK_NONE == ack_update) {
+        IOT_Shadow_Yield(sg_pshadow, MAX_WAIT_TIME_MS);
+    }
+   
+    /* update */    
+    ack_update = ACK_NONE;
+    ret = IOT_Shadow_Update(sg_pshadow, _update_ack_cb, time_sec, &ack_update, 6, Property1, Property2, Property3, Property4, Property5, Property6);
+    if(SUCCESS_RET != ret)
+    {
+        HAL_Printf("Update Property1 Property2 Property3 Property4 Property5 Property6 fail:%d\n", ret);
+        return;
+    }
+    
+	while (ACK_NONE == ack_update) {
+        IOT_Shadow_Yield(sg_pshadow, MAX_WAIT_TIME_MS);
+    }
+
+    ack_update = ACK_NONE;
+    ret = IOT_Shadow_Get_Sync(sg_pshadow, _update_ack_cb, time_sec, &ack_update);
+
+	while (ACK_NONE == ack_update) {
+        IOT_Shadow_Yield(sg_pshadow, MAX_WAIT_TIME_MS);
+    }
+#if 0
+    /* update */    
+    num1 = 123;
+    Property1->data = &num1;
+
+    char num9[5] = "num9";
+    Property4->data = num9;
+
+    ack_update = ACK_NONE;
+    ret = IOT_Shadow_Update(sg_pshadow, _update_ack_cb, time_sec, &ack_update, 2, Property1, Property4);
+    if(SUCCESS_RET != ret)
+    {
+        HAL_Printf("Update Property1 Property4 fail:%d\n", ret);
+        return ret;
+    }
+    
+	while (ACK_NONE == ack_update) {
+        IOT_Shadow_Yield(sg_pshadow, MAX_WAIT_TIME_MS);
+    }
+
+    /* delete */    
+    ack_update = ACK_NONE;
+    ret = IOT_Shadow_Delete(sg_pshadow, _update_ack_cb, time_sec, &ack_update, 2, Property1, Property2);
+    if(SUCCESS_RET != ret)
+    {
+        HAL_Printf("Delete Property1 Property2 fail:%d\n", ret);
+        return ret;
+    }
+
+	while (ACK_NONE == ack_update) {
+        IOT_Shadow_Yield(sg_pshadow, MAX_WAIT_TIME_MS);
+    }
+
+    ack_update = ACK_NONE;
+    ret = IOT_Shadow_Get_Sync(sg_pshadow, _update_ack_cb, time_sec, &ack_update);
+
+
+	while (ACK_NONE == ack_update) {
+        IOT_Shadow_Yield(sg_pshadow, MAX_WAIT_TIME_MS);
+    }
+
+    /* delete all */
+    ack_update = ACK_NONE;
+    ret = IOT_Shadow_Delete_All(sg_pshadow, _update_ack_cb, time_sec, &ack_update);
+    if(SUCCESS_RET != ret)
+    {
+        HAL_Printf("Delete All fail:%d\n", ret);
+        return ret;
+    }
+
+
+	while (ACK_NONE == ack_update) {
+        IOT_Shadow_Yield(sg_pshadow, MAX_WAIT_TIME_MS);
+    }
+
+    ack_update = ACK_NONE;
+    ret = IOT_Shadow_Get_Sync(sg_pshadow, _update_ack_cb, time_sec, &ack_update);
+
+
+	while (ACK_NONE == ack_update) {
+        IOT_Shadow_Yield(sg_pshadow, MAX_WAIT_TIME_MS);
+    }
+
+    Property1->data = &num1;
+    Property4->data = num4;
+    Property5->data = &num5;
+    Property6->data = num6;
+
+    /* update */    
+    ack_update = ACK_NONE;
+    ret = IOT_Shadow_Update_And_Reset_Version(sg_pshadow, _update_ack_cb, time_sec, &ack_update, 4, Property1, Property4, Property5, Property6);
+    if(SUCCESS_RET != ret)
+    {
+        HAL_Printf("Update and Reset Ver fail:%d\n", ret);
+        return ret;
+    }
+    
+	while (ACK_NONE == ack_update) {
+        IOT_Shadow_Yield(sg_pshadow, MAX_WAIT_TIME_MS);
+    }
+
+    ack_update = ACK_NONE;
+    ret = IOT_Shadow_Get_Sync(sg_pshadow, _update_ack_cb, time_sec, &ack_update);
+
+	while (ACK_NONE == ack_update) {
+        IOT_Shadow_Yield(sg_pshadow, MAX_WAIT_TIME_MS);
+    }
+#endif
+    HAL_Free(Property1);
+    HAL_Free(Property2);
+    HAL_Free(Property3);
+    HAL_Free(Property4);
+    HAL_Free(Property5);
+    HAL_Free(Property6);
+    IOT_Shadow_Destroy(sg_pshadow);
+
+    return;
+}
+
+
+static int shadow_test_example(int argc, char **argv)
+{
+    rt_thread_t tid;
+    int stack_size = 8192;
+
+	if (2 == argc)
+	{
+		if (!strcmp("start", argv[1]))
+		{
+			if (1 == running_state)
+			{
+				HAL_Printf("shadow_test_example is already running\n");
+				return 0;
+			}			
+		}
+		else if (!strcmp("stop", argv[1]))
+		{
+			if (0 == running_state)
+			{
+				HAL_Printf("shadow_test_example is already stopped\n");
+				return 0;
+			}
+			running_state = 0;
+			return 0;
+		}
+		else
+		{
+			HAL_Printf("Usage: shadow_test_example start/stop");
+			return 0;			  
+		}
+	}
+	else
+	{
+		HAL_Printf("Para err, usage: shadow_test_example start/stop");
+		return 0;
+	}
+	
+	tid = rt_thread_create("shadow_test", (void (*)(void *))shadow_test_thread, 
+							NULL, stack_size, RT_THREAD_PRIORITY_MAX / 2 - 1, 100);  
+
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+
+    return 0;
+}
+
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(shadow_test_example, startup mqtt shadow example);
+#endif
+
+#ifdef FINSH_USING_MSH
+MSH_CMD_EXPORT(shadow_test_example, startup mqtt shadow example);
+#endif
+
+

+ 137 - 0
uiot/certs/ca.c

@@ -0,0 +1,137 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ca.h"
+
+#include <stdlib.h>
+
+#ifdef SUPPORT_TLS
+static const char *iot_ca_crt = \
+{
+    "-----BEGIN CERTIFICATE-----\r\n"
+    "MIIDsjCCApoCCQCudOie27G3QDANBgkqhkiG9w0BAQsFADCBmjELMAkGA1UEBhMC\r\n"
+    "Q04xETAPBgNVBAgMCFNoYW5naGFpMREwDwYDVQQHDAhTaGFuZ2hhaTEPMA0GA1UE\r\n"
+    "CgwGVUNsb3VkMRgwFgYDVQQLDA9VQ2xvdWQgSW9ULUNvcmUxFjAUBgNVBAMMDXd3\r\n"
+    "dy51Y2xvdWQuY24xIjAgBgkqhkiG9w0BCQEWE3Vpb3QtY29yZUB1Y2xvdWQuY24w\r\n"
+    "HhcNMTkwNzI5MTIyMDQxWhcNMzkwNzI0MTIyMDQxWjCBmjELMAkGA1UEBhMCQ04x\r\n"
+    "ETAPBgNVBAgMCFNoYW5naGFpMREwDwYDVQQHDAhTaGFuZ2hhaTEPMA0GA1UECgwG\r\n"
+    "VUNsb3VkMRgwFgYDVQQLDA9VQ2xvdWQgSW9ULUNvcmUxFjAUBgNVBAMMDXd3dy51\r\n"
+    "Y2xvdWQuY24xIjAgBgkqhkiG9w0BCQEWE3Vpb3QtY29yZUB1Y2xvdWQuY24wggEi\r\n"
+    "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0g9bzkQBipln/nRsUKeQcwAkU\r\n"
+    "ZUk/VMWrg5AzBislYW9hujCGZHWXUknVHPSQM2Pk30tPeIdmupSkOJllYtFplI6U\r\n"
+    "6kqHpVsyPn925H5zz4uP5Ty0hkkNK+rIR/YjbEjGn8loTqWk++/o6qST5QOrZLUR\r\n"
+    "vxaWvshpce0QUcYU9xMfUPzLa6/ZfmaNHgn1aWExYMJAWDyBCyw4OxeSMUyH+ydh\r\n"
+    "egW7VHNQuVHOYdnXiC+VYImNJ8+QAyCIZ88lP0nqVPSKTt1XXmGW6vXrWSl+/XhO\r\n"
+    "GaHNMzlwb1kqlFx/ZagTQoQ0hpmqSUKtqPgKSqGPxY9go1Rda1m2rYc8k3gJAgMB\r\n"
+    "AAEwDQYJKoZIhvcNAQELBQADggEBAHU0KKqEbR7uoY1tlE+MDsfx/2zXNk9gYw44\r\n"
+    "O+xGVdbvTC298Ko4uUEwc1C+l9FaMmN/2qUPSXWsSrAYDGMS63rzaxqNuADTgmo9\r\n"
+    "QY0ITtTf0lZTkUahVSqAxzMFaaPzSfFeP9/EaUu14T5RPQbUZMVOAEPKDNmfK4rD\r\n"
+    "06R6dnO12be4Qlha14o67+ojaNtyZ7/ESePXA/RjO9YMkeQAoa4BdnsJCZgCFmXf\r\n"
+    "iKvGM+50+L/qSbH5F//byLGTO1t3TWCCdBE5/Mc/QLYEXDmZM6LMHyEAw4VuinIa\r\n"
+    "I8m1P/ceVO0RjNNBG0pDH9PH4OA7ikY81c63PBCQaYMKaiksCzs=\r\n"
+    "-----END CERTIFICATE-----\r\n"
+};
+
+
+static const char *iot_https_ca_crt = \
+{
+    "-----BEGIN CERTIFICATE-----\r\n"
+    "MIIFlTCCBH2gAwIBAgIQDaPkQo/2q3qn5J5qQPDu0jANBgkqhkiG9w0BAQsFADBy\r\n"
+    "MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg\r\n"
+    "SW5jLjEdMBsGA1UECxMURG9tYWluIFZhbGlkYXRlZCBTU0wxHTAbBgNVBAMTFFRy\r\n"
+    "dXN0QXNpYSBUTFMgUlNBIENBMB4XDTE4MDgyMTAwMDAwMFoXDTE5MTExOTEyMDAw\r\n"
+    "MFowHzEdMBsGA1UEAwwUKi5jbi1zaDIudWZpbGVvcy5jb20wggEiMA0GCSqGSIb3\r\n"
+    "DQEBAQUAA4IBDwAwggEKAoIBAQCag2wjy4p9TmCn+4ctlNW4nAfRoiOGvlplH6qy\r\n"
+    "fol68e9zPFdocAbi6lKfOtUdDPJ0TBhrefwFvK/oUr/wWUmCBoQdjmeFlKc5cidU\r\n"
+    "h186OrXdDgh5n28tsgDMkUuniKXsvD46Z5ibGKmjgQufTvOrvZprOI2zGpYvLKb+\r\n"
+    "naxSNAiL3Nc5+jqFTVEKdzooYMNEn3dz0QIkVafWjK6sW6Q0poBzRcIQzyCkkqUA\r\n"
+    "0hp5w6kGFqg/W3QyNAXpdcpWwSfEhZr8e4e+v4mkYmm0LyS5p5WEsiAYPizdRFD3\r\n"
+    "3llpF2S0NcNAV2jMobnu5TaoniRH9CbRgHFlHTtmn+QI5AWxAgMBAAGjggJ4MIIC\r\n"
+    "dDAfBgNVHSMEGDAWgBR/05nzoEcOMQBWViKOt8ye3coBijAdBgNVHQ4EFgQU0Bcs\r\n"
+    "CP1fX/9fw1pf+794ru6m0VkwHwYDVR0RBBgwFoIUKi5jbi1zaDIudWZpbGVvcy5j\r\n"
+    "b20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD\r\n"
+    "AjBMBgNVHSAERTBDMDcGCWCGSAGG/WwBAjAqMCgGCCsGAQUFBwIBFhxodHRwczov\r\n"
+    "L3d3dy5kaWdpY2VydC5jb20vQ1BTMAgGBmeBDAECATCBgQYIKwYBBQUHAQEEdTBz\r\n"
+    "MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcDIuZGlnaWNlcnQuY29tMEoGCCsGAQUF\r\n"
+    "BzAChj5odHRwOi8vY2FjZXJ0cy5kaWdpdGFsY2VydHZhbGlkYXRpb24uY29tL1Ry\r\n"
+    "dXN0QXNpYVRMU1JTQUNBLmNydDAJBgNVHRMEAjAAMIIBAwYKKwYBBAHWeQIEAgSB\r\n"
+    "9ASB8QDvAHYApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFlWoEO\r\n"
+    "fQAABAMARzBFAiEA0jMXM/NgCK3+ftZGN601WUrksHceAjmgXtBPj3dKmSECIFHU\r\n"
+    "+LRLgezuroBPOI1f+qku68Zl6+l896PXF/G+KqMEAHUAh3W/51l8+IxDmV+9827/\r\n"
+    "Vo1HVjb/SrVgwbTq/16ggw8AAAFlWoEPSwAABAMARjBEAiAEHMUqOh3eCHsTDcNZ\r\n"
+    "iDTbNtVYcGMEqlAe0AAjh4OFpAIgFoWqCuPEy+RCXIAgEn8qJsqZLxw+9YQIEmbF\r\n"
+    "5NzjDikwDQYJKoZIhvcNAQELBQADggEBABzhM36Bqia/CfTxe8pK8Rto1imTQaML\r\n"
+    "AJ/Rkr2jO21ieOZ0myixtzsu4COWFssk25OTbUPVhoHJgIatsic86BWBVGZ6K2pU\r\n"
+    "ZtEmMvYEYotjSLMlRmDGnwECLz19A6wYXEBZLIjoA1yrUwvGTPlgJrsOrjIxBhNc\r\n"
+    "CPT4/TIgUssBrLCXrl22I2KXVX9HdZR7xRdCx6KcLFwt9+xyIdVDUqaPOPi7BqBg\r\n"
+    "vqr78XRvgk5cc6lqn8Ssg7hF7RvZV5wlHuswFzJgyjgXD+T8jc22sqaMyzAjyGWs\r\n"
+    "teKjO3mGVDRPHd5S+FRksQx97atAFBlRWc8S+njWgCbbrTorujV6Sxk=\r\n"
+    "-----END CERTIFICATE-----\r\n"
+    "-----BEGIN CERTIFICATE-----\r\n"
+    "MIIErjCCA5agAwIBAgIQBYAmfwbylVM0jhwYWl7uLjANBgkqhkiG9w0BAQsFADBh\r\n"
+    "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\r\n"
+    "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\r\n"
+    "QTAeFw0xNzEyMDgxMjI4MjZaFw0yNzEyMDgxMjI4MjZaMHIxCzAJBgNVBAYTAkNO\r\n"
+    "MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQL\r\n"
+    "ExREb21haW4gVmFsaWRhdGVkIFNTTDEdMBsGA1UEAxMUVHJ1c3RBc2lhIFRMUyBS\r\n"
+    "U0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgWa9X+ph+wAm8\r\n"
+    "Yh1Fk1MjKbQ5QwBOOKVaZR/OfCh+F6f93u7vZHGcUU/lvVGgUQnbzJhR1UV2epJa\r\n"
+    "e+m7cxnXIKdD0/VS9btAgwJszGFvwoqXeaCqFoP71wPmXjjUwLT70+qvX4hdyYfO\r\n"
+    "JcjeTz5QKtg8zQwxaK9x4JT9CoOmoVdVhEBAiD3DwR5fFgOHDwwGxdJWVBvktnoA\r\n"
+    "zjdTLXDdbSVC5jZ0u8oq9BiTDv7jAlsB5F8aZgvSZDOQeFrwaOTbKWSEInEhnchK\r\n"
+    "ZTD1dz6aBlk1xGEI5PZWAnVAba/ofH33ktymaTDsE6xRDnW97pDkimCRak6CEbfe\r\n"
+    "3dXw6OV5AgMBAAGjggFPMIIBSzAdBgNVHQ4EFgQUf9OZ86BHDjEAVlYijrfMnt3K\r\n"
+    "AYowHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD\r\n"
+    "AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG\r\n"
+    "AQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au\r\n"
+    "ZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj\r\n"
+    "ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwTAYDVR0gBEUwQzA3Bglg\r\n"
+    "hkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t\r\n"
+    "L0NQUzAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAK3dVOj5dlv4MzK2i233\r\n"
+    "lDYvyJ3slFY2X2HKTYGte8nbK6i5/fsDImMYihAkp6VaNY/en8WZ5qcrQPVLuJrJ\r\n"
+    "DSXT04NnMeZOQDUoj/NHAmdfCBB/h1bZ5OGK6Sf1h5Yx/5wR4f3TUoPgGlnU7EuP\r\n"
+    "ISLNdMRiDrXntcImDAiRvkh5GJuH4YCVE6XEntqaNIgGkRwxKSgnU3Id3iuFbW9F\r\n"
+    "UQ9Qqtb1GX91AJ7i4153TikGgYCdwYkBURD8gSVe8OAco6IfZOYt/TEwii1Ivi1C\r\n"
+    "qnuUlWpsF1LdQNIdfbW3TSe0BhQa7ifbVIfvPWHYOu3rkg1ZeMo6XRU9B4n5VyJY\r\n"
+    "RmE=\r\n"
+    "-----END CERTIFICATE-----"
+};
+#endif
+
+const char *iot_ca_get() {
+#ifdef SUPPORT_TLS
+    return iot_ca_crt;
+#else
+    return NULL;
+#endif
+}
+
+const char *iot_https_ca_get() {
+#ifdef SUPPORT_TLS
+    return iot_https_ca_crt;
+#else
+    return NULL;
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+

+ 33 - 0
uiot/certs/ca.h

@@ -0,0 +1,33 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_CA_H_
+#define C_SDK_CA_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *iot_ca_get(void);
+
+const char *iot_https_ca_get(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif /* C_SDK_CA_H_ */

+ 51 - 0
uiot/dev_model/include/dm_config.h

@@ -0,0 +1,51 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_DM_CONFIG_H_
+#define C_SDK_DM_CONFIG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DM_TOPIC_BUF_LEN         (128)
+#define DM_MSG_REPLY_BUF_LEN     (128)
+#define DM_MSG_REPORT_BUF_LEN    (256)
+#define DM_EVENT_POST_BUF_LEN    (256)
+#define DM_CMD_REPLY_BUF_LEN     (256)
+
+//pub
+#define PROPERTY_RESTORE_TOPIC_TEMPLATE                  "/$system/%s/%s/tmodel/property/restore"
+#define PROPERTY_POST_TOPIC_TEMPLATE                     "/$system/%s/%s/tmodel/property/post"
+#define PROPERTY_SET_REPLY_TOPIC_TEMPLATE                "/$system/%s/%s/tmodel/property/set_reply"
+#define PROPERTY_DESIRED_GET_TOPIC_TEMPLATE              "/$system/%s/%s/tmodel/property/desired/get"
+#define PROPERTY_DESIRED_DELETE_TOPIC_TEMPLATE           "/$system/%s/%s/tmodel/property/desired/delete"
+#define EVENT_POST_TOPIC_TEMPLATE                        "/$system/%s/%s/tmodel/event/post"
+#define COMMAND_REPLY_TOPIC_TEMPLATE                     "/$system/%s/%s/tmodel/command_reply/%s"
+
+//sub
+#define PROPERTY_RESTORE_REPLY_TOPIC_TEMPLATE            "/$system/%s/%s/tmodel/property/restore_reply"
+#define PROPERTY_POST_REPLY_TOPIC_TEMPLATE               "/$system/%s/%s/tmodel/property/post_reply"
+#define PROPERTY_SET_TOPIC_TEMPLATE                      "/$system/%s/%s/tmodel/property/set"
+#define PROPERTY_DESIRED_GET_REPLY_TOPIC_TEMPLATE        "/$system/%s/%s/tmodel/property/desired/get_reply"
+#define PROPERTY_DESIRED_DELETE_REPLY_TOPIC_TEMPLATE     "/$system/%s/%s/tmodel/property/desired/delete_reply"
+#define EVENT_POST_REPLY_TOPIC_TEMPLATE                  "/$system/%s/%s/tmodel/event/post_reply"
+#define COMMAND_TOPIC_TEMPLATE                           "/$system/%s/%s/tmodel/command"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //C_SDK_DM_CONFIG_H_

+ 78 - 0
uiot/dev_model/include/dm_internal.h

@@ -0,0 +1,78 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_DM_INTERNAL_H_
+#define C_SDK_DM_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "uiot_export_dm.h"
+
+typedef struct  {
+    void       *ch_signal;
+} DM_Struct_t;
+
+typedef struct {
+    int               dm_type;
+    char              *upstream_topic_template;
+    char              *downstream_topic_template;
+    OnMessageHandler  callback;
+} DM_MQTT_CB_t;
+
+typedef struct {
+    void       *mqtt;
+    const char *product_sn;
+    const char *device_sn;
+    void       *callbacks[DM_TYPE_MAX];
+    char       *upstream_topic_templates[DM_TYPE_MAX];
+    char       *downstream_topic_templates[DM_TYPE_MAX];
+    void       *context;
+} DM_MQTT_Struct_t;
+
+#define DEFINE_DM_CALLBACK(type, cb_type)  int uiot_register_for_##type(void *handle, cb_type cb) { \
+        if (type < 0 || type >= sizeof(g_dm_mqtt_cb)/sizeof(DM_MQTT_CB_t)) {return -1;} \
+        _dsc_mqtt_register_callback((DM_MQTT_Struct_t *)(((DM_Struct_t *)handle)->ch_signal), type, (void *)cb);return 0;}
+
+
+void dm_mqtt_property_restore_cb(void *pClient, MQTTMessage *message, void *pContext);
+
+void dm_mqtt_property_post_cb(void *pClient, MQTTMessage *message, void *pContext);
+
+void dm_mqtt_property_set_cb(void *pClient, MQTTMessage *message, void *pContext);
+
+void dm_mqtt_property_desired_get_cb(void *pClient, MQTTMessage *message, void *pContext);
+
+void dm_mqtt_property_desired_delete_cb(void *pClient, MQTTMessage *message, void *pContext);
+
+void dm_mqtt_event_post_cb(void *pClient, MQTTMessage *message, void *pContext);
+
+void dm_mqtt_command_cb(void *pClient, MQTTMessage *message, void *pContext);
+
+
+void *dsc_init(const char *product_sn, const char *device_sn, void *channel, void *context);
+
+int dsc_deinit(void *handle);
+
+int dm_mqtt_property_report_publish(DM_MQTT_Struct_t *handle, DM_Type type, int request_id, const char *payload);
+
+int dm_mqtt_event_publish(DM_MQTT_Struct_t *handle, int request_id, const char *identifier, const char *payload);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //C_SDK_DM_INTERNAL_H_

+ 84 - 0
uiot/dev_model/src/dm_client.c

@@ -0,0 +1,84 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <string.h>
+
+#include "uiot_defs.h"
+#include "uiot_internal.h"
+
+#include "dm_internal.h"
+
+void *IOT_DM_Init(const char *product_sn, const char *device_sn, void *ch_signal)
+{
+    POINTER_VALID_CHECK(product_sn, NULL);
+    POINTER_VALID_CHECK(device_sn, NULL);
+    POINTER_VALID_CHECK(ch_signal, NULL);
+
+    DM_Struct_t *h_dm = NULL;
+
+    if (NULL == (h_dm = HAL_Malloc(sizeof(DM_Struct_t)))) {
+        LOG_ERROR("allocate failed");
+        return NULL;
+    }
+    memset(h_dm, 0, sizeof(DM_Struct_t));
+
+    h_dm->ch_signal = dsc_init(product_sn, device_sn, ch_signal, h_dm);
+    if (NULL == h_dm->ch_signal) {
+        LOG_ERROR("initialize signal channel failed");
+        HAL_Free(h_dm);
+        return NULL;
+    }
+    return h_dm;
+}
+
+int IOT_DM_Destroy(void *handle)
+{
+    POINTER_VALID_CHECK(handle, FAILURE_RET);
+
+    DM_Struct_t *h_dm = (DM_Struct_t*) handle;
+
+    dsc_deinit(h_dm->ch_signal);
+    HAL_Free(h_dm);
+    return SUCCESS_RET;
+}
+
+int IOT_DM_Property_Report(void *handle, DM_Type type, int request_id, const char *payload)
+{
+    POINTER_VALID_CHECK(handle, FAILURE_RET);
+
+    DM_Struct_t *h_dm = (DM_Struct_t*) handle;
+
+    return dm_mqtt_property_report_publish(h_dm->ch_signal, type, request_id, payload);
+}
+
+int IOT_DM_TriggerEvent(void *handle, int request_id, const char *identifier, const char *payload)
+{
+    POINTER_VALID_CHECK(handle, FAILURE_RET);
+
+    DM_Struct_t *h_dm = (DM_Struct_t*) handle;
+
+    return dm_mqtt_event_publish(h_dm->ch_signal, request_id, identifier, payload);
+}
+
+int IOT_DM_Yield(void *handle, uint32_t timeout_ms)
+{
+    POINTER_VALID_CHECK(handle, FAILURE_RET);
+
+    DM_Struct_t *h_dm = (DM_Struct_t*) handle;
+
+    return IOT_MQTT_Yield(((DM_MQTT_Struct_t *)h_dm->ch_signal)->mqtt, timeout_ms);
+}
+
+

+ 627 - 0
uiot/dev_model/src/dm_mqtt.c

@@ -0,0 +1,627 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include "uiot_defs.h"
+#include "uiot_export_mqtt.h"
+
+#include "dm_config.h"
+#include "dm_internal.h"
+#include "lite-utils.h"
+
+
+DM_MQTT_CB_t g_dm_mqtt_cb[] = {
+        {PROPERTY_RESTORE,        PROPERTY_RESTORE_TOPIC_TEMPLATE,        PROPERTY_RESTORE_REPLY_TOPIC_TEMPLATE,        dm_mqtt_property_restore_cb},
+        {PROPERTY_POST,           PROPERTY_POST_TOPIC_TEMPLATE,           PROPERTY_POST_REPLY_TOPIC_TEMPLATE,           dm_mqtt_property_post_cb},
+        {PROPERTY_SET,            PROPERTY_SET_REPLY_TOPIC_TEMPLATE,      PROPERTY_SET_TOPIC_TEMPLATE,                  dm_mqtt_property_set_cb},
+        {PROPERTY_DESIRED_GET,    PROPERTY_DESIRED_GET_TOPIC_TEMPLATE,    PROPERTY_DESIRED_GET_REPLY_TOPIC_TEMPLATE,    dm_mqtt_property_desired_get_cb},
+        {PROPERTY_DESIRED_DELETE, PROPERTY_DESIRED_DELETE_TOPIC_TEMPLATE, PROPERTY_DESIRED_DELETE_REPLY_TOPIC_TEMPLATE, dm_mqtt_property_desired_delete_cb},
+        {EVENT_POST,              EVENT_POST_TOPIC_TEMPLATE,              EVENT_POST_REPLY_TOPIC_TEMPLATE,              dm_mqtt_event_post_cb},
+        {COMMAND,                 COMMAND_REPLY_TOPIC_TEMPLATE,           COMMAND_TOPIC_TEMPLATE,                       dm_mqtt_command_cb}
+};
+
+static int _dm_mqtt_gen_topic_name(char *buf, size_t buf_len, const char *topic_template, const char *product_sn,
+                                   const char *device_sn) {
+    FUNC_ENTRY;
+
+    int ret;
+    ret = HAL_Snprintf(buf, buf_len, topic_template, product_sn, device_sn);
+
+    if (ret < 0 || ret >= buf_len) {
+        LOG_ERROR("HAL_Snprintf failed");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+static int _dm_mqtt_gen_property_payload(char *buf, size_t buf_len, DM_Type type, int request_id, const char *payload) {
+    FUNC_ENTRY;
+
+    int ret;
+    switch (type) {
+        case PROPERTY_RESTORE:
+            ret = HAL_Snprintf(buf, buf_len, "{\"RequestID\": \"%d\"}", request_id);
+            break;
+        case PROPERTY_POST:
+            ret = HAL_Snprintf(buf, buf_len, "{\"RequestID\": \"%d\", \"Property\": %s}", request_id, payload);
+            break;
+        case PROPERTY_DESIRED_GET:
+            ret = HAL_Snprintf(buf, buf_len, "{\"RequestID\": \"%d\", \"Require\": %s}", request_id, payload);
+            break;
+        case PROPERTY_DESIRED_DELETE:
+            ret = HAL_Snprintf(buf, buf_len, "{\"RequestID\": \"%d\", \"Delete\": %s}", request_id, payload);
+            break;
+        default: FUNC_EXIT_RC(FAILURE_RET);
+    }
+    if (ret < 0 || ret >= buf_len) {
+        LOG_ERROR("generate property payload failed");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+static int _dm_mqtt_gen_event_payload(char *buf, size_t buf_len, int request_id, const char *identifier, const char *payload) {
+    FUNC_ENTRY;
+
+    int ret;
+    ret = HAL_Snprintf(buf, buf_len, "{\"RequestID\": \"%d\", \"Identifier\": \"%s\", \"Output\": %s}", request_id,
+                       identifier, payload);
+
+    if (ret < 0 || ret >= buf_len) {
+        LOG_ERROR("generate event payload failed");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+static int _dm_mqtt_publish(DM_MQTT_Struct_t *handle, char *topic_name, int qos, const char *msg) {
+    FUNC_ENTRY;
+
+    int ret;
+    PublishParams pub_params = DEFAULT_PUB_PARAMS;
+
+    //暂不支持QOS2
+    if (0 == qos) {
+        pub_params.qos = QOS0;
+    } else {
+        pub_params.qos = QOS1;
+    }
+    pub_params.payload = (void *) msg;
+    pub_params.payload_len = strlen(msg);
+
+    ret = IOT_MQTT_Publish(handle->mqtt, topic_name, &pub_params);
+    if (ret < 0) {
+        LOG_ERROR("publish to topic: %s failed", topic_name);
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+
+    FUNC_EXIT_RC(ret);
+}
+
+static void _dm_mqtt_common_reply_cb(MQTTMessage *message, CommonReplyCB cb) {
+    FUNC_ENTRY;
+
+    int8_t ret_code;
+    char *request_id = NULL;
+    char *ret_code_char = NULL;
+    char *msg = NULL;
+
+    if (NULL == (msg = HAL_Malloc(message->payload_len + 1))) {
+        LOG_ERROR("allocate for message failed");
+        FUNC_EXIT;
+    }
+
+    HAL_Snprintf(msg, message->payload_len + 1, "%s", message->payload);
+
+    if (NULL == (ret_code_char = LITE_json_value_of((char *) "RetCode", msg))) {
+        LOG_ERROR("allocate for ret_code_char failed");
+        goto do_exit;
+    }
+    if (SUCCESS_RET != LITE_get_int8(&ret_code, ret_code_char)) {
+        LOG_ERROR("get ret_code failed");
+        goto do_exit;
+    }
+    if (NULL == (request_id = LITE_json_value_of((char *) "RequestID", msg))) {
+        LOG_ERROR("allocate for request_id failed");
+        goto do_exit;
+    }
+
+    cb(request_id, ret_code);
+
+do_exit:
+    HAL_Free(msg);
+    HAL_Free(request_id);
+    HAL_Free(ret_code_char);
+
+    FUNC_EXIT;
+}
+
+void dm_mqtt_property_restore_cb(void *pClient, MQTTMessage *message, void *pContext) {
+    FUNC_ENTRY;
+
+    LOG_DEBUG("topic=%s", message->topic);
+    LOG_INFO("len=%u, topic_msg=%.*s", message->payload_len, message->payload_len, (char *)message->payload);
+
+    DM_MQTT_Struct_t *handle = (DM_MQTT_Struct_t *) pContext;
+    if (NULL == handle->callbacks[PROPERTY_RESTORE]) {
+        FUNC_EXIT;
+    }
+
+    PropertyRestoreCB cb;
+    int8_t ret_code;
+    char *request_id = NULL;
+    char *ret_code_char = NULL;
+    char *property = NULL;
+    char *msg = NULL;
+
+    if (NULL == (msg = HAL_Malloc(message->payload_len + 1))) {
+        LOG_ERROR("allocate for message failed");
+        FUNC_EXIT;
+    }
+
+    HAL_Snprintf(msg, message->payload_len + 1, "%s", message->payload);
+
+    if (NULL == (ret_code_char = LITE_json_value_of((char *) "RetCode", msg))) {
+        LOG_ERROR("allocate for ret_code_char failed");
+        goto do_exit;
+    }
+    if (SUCCESS_RET != LITE_get_int8(&ret_code, ret_code_char)) {
+        LOG_ERROR("get for ret_code failed");
+        goto do_exit;
+    }
+    if (NULL == (request_id = LITE_json_value_of((char *) "RequestID", msg))) {
+        LOG_ERROR("allocate for request_id failed");
+        goto do_exit;
+    }
+    if (NULL == (property = LITE_json_value_of((char *) "Property", msg))) {
+        LOG_ERROR("allocate for property failed");
+        goto do_exit;
+    }
+
+    cb = (PropertyRestoreCB) handle->callbacks[PROPERTY_RESTORE];
+    cb(request_id, ret_code, property);
+
+do_exit:
+    HAL_Free(msg);
+    HAL_Free(ret_code_char);
+    HAL_Free(property);
+    HAL_Free(request_id);
+
+    FUNC_EXIT;
+}
+
+void dm_mqtt_property_post_cb(void *pClient, MQTTMessage *message, void *pContext) {
+    FUNC_ENTRY;
+
+    LOG_DEBUG("topic=%s", message->topic);
+    LOG_INFO("len=%u, topic_msg=%.*s", message->payload_len, message->payload_len, (char *)message->payload);
+
+    DM_MQTT_Struct_t *handle = (DM_MQTT_Struct_t *) pContext;
+    if (NULL == handle->callbacks[PROPERTY_POST]) {
+        FUNC_EXIT;
+    }
+
+    _dm_mqtt_common_reply_cb(message, (CommonReplyCB) handle->callbacks[PROPERTY_POST]);
+
+    FUNC_EXIT;
+}
+
+void dm_mqtt_property_set_cb(void *pClient, MQTTMessage *message, void *pContext) {
+    FUNC_ENTRY;
+
+    LOG_DEBUG("topic=%s", message->topic);
+    LOG_INFO("len=%u, topic_msg=%.*s", message->payload_len, message->payload_len, (char *)message->payload);
+
+    DM_MQTT_Struct_t *handle = (DM_MQTT_Struct_t *) pContext;
+    if (NULL == handle->callbacks[PROPERTY_SET]) {
+        FUNC_EXIT;
+    }
+
+    int ret;
+    PropertySetCB cb;
+    int cb_ret;
+    char *request_id = NULL;
+    char *property = NULL;
+    char *msg_reply = NULL;
+    char *topic = NULL;
+    char *msg = NULL;
+
+    if (NULL == (msg = HAL_Malloc(message->payload_len + 1))) {
+        LOG_ERROR("allocate for message failed");
+        FUNC_EXIT;
+    }
+
+    HAL_Snprintf(msg, message->payload_len + 1, "%s", message->payload);
+
+    if (NULL == (request_id = LITE_json_value_of((char *) "RequestID", msg))) {
+        LOG_ERROR("allocate for request_id failed");
+        goto do_exit;
+    }
+    if (NULL == (property = LITE_json_value_of((char *) "Property", msg))) {
+        LOG_ERROR("allocate for property failed");
+        goto do_exit;
+    }
+
+    cb = (PropertySetCB) handle->callbacks[PROPERTY_SET];
+    cb_ret = cb(request_id, property);
+
+    if (NULL == (msg_reply = HAL_Malloc(DM_MSG_REPLY_BUF_LEN))) {
+        LOG_ERROR("allocate for msg_reply failed");
+        goto do_exit;
+    }
+    if (NULL == (topic = HAL_Malloc(DM_TOPIC_BUF_LEN))) {
+        LOG_ERROR("allocate for topic failed");
+        goto do_exit;
+    }
+    if (SUCCESS_RET != _dm_mqtt_gen_topic_name(topic, DM_TOPIC_BUF_LEN, handle->upstream_topic_templates[PROPERTY_SET],
+            handle->product_sn, handle->device_sn)) {
+        LOG_ERROR("generate topic name failed");
+        goto do_exit;
+    }
+    ret = HAL_Snprintf(msg_reply, DM_MSG_REPLY_BUF_LEN, "{\"RequestID\": \"%s\", \"RetCode\": %d}", request_id, cb_ret);
+    if (ret < 0 || ret >= DM_MSG_REPLY_BUF_LEN) {
+        LOG_ERROR("HAL_Snprintf msg_reply failed");
+        goto do_exit;
+    }
+    ret = _dm_mqtt_publish(handle, topic, 1, msg_reply);
+    if (ret < 0) {
+        LOG_ERROR("mqtt publish msg failed");
+        goto do_exit;
+    }
+
+do_exit:
+    HAL_Free(msg);
+    HAL_Free(request_id);
+    HAL_Free(property);
+    HAL_Free(msg_reply);
+    HAL_Free(topic);
+
+    FUNC_EXIT;
+}
+
+void dm_mqtt_property_desired_get_cb(void *pClient, MQTTMessage *message, void *pContext) {
+    FUNC_ENTRY;
+
+    LOG_DEBUG("topic=%s", message->topic);
+    LOG_INFO("len=%u, topic_msg=%.*s", message->payload_len, message->payload_len, (char *)message->payload);
+
+    DM_MQTT_Struct_t *handle = (DM_MQTT_Struct_t *) pContext;
+    if (NULL == handle->callbacks[PROPERTY_DESIRED_GET]) {
+        FUNC_EXIT;
+    }
+
+    PropertyDesiredGetCB cb;
+    int8_t ret_code;
+    char *request_id = NULL;
+    char *ret_code_char = NULL;
+    char *desired = NULL;
+    char *msg = NULL;
+
+    if (NULL == (msg = HAL_Malloc(message->payload_len + 1))) {
+        LOG_ERROR("allocate for message failed");
+        goto do_exit;
+    }
+
+    HAL_Snprintf(msg, message->payload_len + 1, "%s", message->payload);
+
+    if (NULL == (ret_code_char = LITE_json_value_of((char *) "RetCode", msg))) {
+        LOG_ERROR("allocate for ret_code_char failed");
+        goto do_exit;
+    }
+    if (SUCCESS_RET != LITE_get_int8(&ret_code, ret_code_char)) {
+        LOG_ERROR("get ret_code failed");
+        goto do_exit;
+    }
+    if (NULL == (request_id = LITE_json_value_of((char *) "RequestID", msg))) {
+        LOG_ERROR("allocate for request_id failed");
+        goto do_exit;
+    }
+    if (NULL == (desired = LITE_json_value_of((char *) "Desired", msg))) {
+        LOG_ERROR("allocate for desired failed");
+        goto do_exit;
+    }
+
+    cb = (PropertyDesiredGetCB) handle->callbacks[PROPERTY_DESIRED_GET];
+    cb(request_id, ret_code, desired);
+
+do_exit:
+    HAL_Free(msg);
+    HAL_Free(ret_code_char);
+    HAL_Free(request_id);
+    HAL_Free(desired);
+
+    FUNC_EXIT;
+}
+
+void dm_mqtt_property_desired_delete_cb(void *pClient, MQTTMessage *message, void *pContext) {
+    FUNC_ENTRY;
+
+    LOG_DEBUG("topic=%s", message->topic);
+    LOG_INFO("len=%u, topic_msg=%.*s", message->payload_len, message->payload_len, (char *)message->payload);
+
+    DM_MQTT_Struct_t *handle = (DM_MQTT_Struct_t *) pContext;
+    if (NULL == handle->callbacks[PROPERTY_DESIRED_DELETE]) {
+        FUNC_EXIT;
+    }
+
+    _dm_mqtt_common_reply_cb(message, (CommonReplyCB) handle->callbacks[PROPERTY_DESIRED_DELETE]);
+
+    FUNC_EXIT;
+}
+
+void dm_mqtt_event_post_cb(void *pClient, MQTTMessage *message, void *pContext) {
+    FUNC_ENTRY;
+
+    LOG_DEBUG("topic=%s", message->topic);
+    LOG_INFO("len=%u, topic_msg=%.*s", strlen(message->payload), message->payload_len, (char *)message->payload);
+
+    DM_MQTT_Struct_t *handle = (DM_MQTT_Struct_t *) pContext;
+    if (NULL == handle->callbacks[EVENT_POST]) {
+        FUNC_EXIT;
+    }
+
+    _dm_mqtt_common_reply_cb(message, (CommonReplyCB) handle->callbacks[EVENT_POST]);
+
+    FUNC_EXIT;
+}
+
+void dm_mqtt_command_cb(void *pClient, MQTTMessage *message, void *pContext) {
+    FUNC_ENTRY;
+
+    LOG_DEBUG("topic=%s", message->topic);
+    LOG_INFO("len=%u, topic_msg=%.*s", message->payload_len, message->payload_len, (char *)message->payload);
+
+    DM_MQTT_Struct_t *handle = (DM_MQTT_Struct_t *) pContext;
+    if (NULL == handle->callbacks[COMMAND]) {
+        FUNC_EXIT;
+    }
+
+    CommandCB cb;
+    int cb_ret;
+    char *request_id = NULL;
+    char *identifier = NULL;
+    char *input = NULL;
+    char *output = NULL;
+    char *topic = NULL;
+    char *cmd_reply = NULL;
+    char *msg = NULL;
+
+    if (NULL == (msg = HAL_Malloc(message->payload_len + 1))) {
+        LOG_ERROR("allocate for message failed");
+        FUNC_EXIT;
+    }
+
+    HAL_Snprintf(msg, message->payload_len + 1, "%s", message->payload);
+
+    if (NULL == (request_id = LITE_json_value_of((char *) "RequestID", msg))) {
+        LOG_ERROR("allocate for request_id failed");
+        goto do_exit;
+    }
+    if (NULL == (identifier = LITE_json_value_of((char *) "Identifier", msg))) {
+        LOG_ERROR("allocate for identifier failed");
+        goto do_exit;
+    }
+
+    if (NULL == (input = LITE_json_value_of((char *) "Input", msg))) {
+        LOG_ERROR("allocate for input failed");
+        goto do_exit;
+    }
+
+    cb = (CommandCB) handle->callbacks[COMMAND];
+    cb_ret = cb(request_id, identifier, input, &output);
+
+    if (NULL == output) {
+        LOG_ERROR("output error");
+        goto do_exit;
+    }
+    if (NULL == (cmd_reply = HAL_Malloc(DM_CMD_REPLY_BUF_LEN))) {
+        LOG_ERROR("allocate for cmd_reply failed");
+        goto do_exit;
+    }
+    if (NULL == (topic = HAL_Malloc(DM_TOPIC_BUF_LEN))) {
+        LOG_ERROR("allocate for topic failed");
+        goto do_exit;
+    }
+    int ret = HAL_Snprintf(topic, DM_TOPIC_BUF_LEN, handle->upstream_topic_templates[COMMAND], handle->product_sn,
+                           handle->device_sn, request_id);
+    if (ret < 0 || ret > DM_TOPIC_BUF_LEN) {
+        LOG_ERROR("topic error");
+        goto do_exit;
+    }
+
+    ret = HAL_Snprintf(cmd_reply, DM_CMD_REPLY_BUF_LEN,
+                       "{\"RequestID\": \"%s\", \"RetCode\": %d, \"Identifier\": \"%s\", \"Output\": %s}",
+                       request_id, cb_ret, identifier, output);
+    if (ret < 0 || ret > DM_CMD_REPLY_BUF_LEN) {
+        LOG_ERROR("generate cmd_reply msg failed");
+        goto do_exit;
+    }
+    ret = _dm_mqtt_publish(handle, topic, 1, cmd_reply);
+    if (ret < 0) {
+        LOG_ERROR("mqtt publish msg failed");
+        goto do_exit;
+    }
+
+do_exit:
+    HAL_Free(msg);
+    HAL_Free(request_id);
+    HAL_Free(identifier);
+    HAL_Free(input);
+    HAL_Free(output);
+    HAL_Free(topic);
+    HAL_Free(cmd_reply);
+
+    FUNC_EXIT;
+}
+
+int _dsc_mqtt_register_callback(DM_MQTT_Struct_t *handle, DM_Type dm_type, void *callback) {
+    FUNC_ENTRY;
+
+    int ret;
+    if (NULL == handle || callback == NULL) {
+        LOG_ERROR("params error!");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+    handle->callbacks[dm_type] = callback;
+    handle->upstream_topic_templates[dm_type] = g_dm_mqtt_cb[dm_type].upstream_topic_template;
+    handle->downstream_topic_templates[dm_type] = g_dm_mqtt_cb[dm_type].downstream_topic_template;
+
+    char topic[DM_TOPIC_BUF_LEN];
+    ret = _dm_mqtt_gen_topic_name(topic, DM_TOPIC_BUF_LEN, handle->downstream_topic_templates[dm_type],
+                                  handle->product_sn, handle->device_sn);
+    if (ret < 0) {
+        LOG_ERROR("generate topic name failed");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+
+    SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
+    sub_params.on_message_handler = g_dm_mqtt_cb[dm_type].callback;
+    sub_params.qos = QOS1;
+    sub_params.user_data = handle;
+
+    ret = IOT_MQTT_Subscribe(handle->mqtt, topic, &sub_params);
+    if (ret < 0) {
+        LOG_ERROR("mqtt subscribe failed!");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+
+DEFINE_DM_CALLBACK(PROPERTY_RESTORE, PropertyRestoreCB)
+
+DEFINE_DM_CALLBACK(PROPERTY_POST, CommonReplyCB)
+
+DEFINE_DM_CALLBACK(PROPERTY_SET, PropertySetCB)
+
+DEFINE_DM_CALLBACK(PROPERTY_DESIRED_GET, PropertyDesiredGetCB)
+
+DEFINE_DM_CALLBACK(PROPERTY_DESIRED_DELETE, CommonReplyCB)
+
+DEFINE_DM_CALLBACK(EVENT_POST, CommonReplyCB)
+
+DEFINE_DM_CALLBACK(COMMAND, CommandCB)
+
+void *dsc_init(const char *product_sn, const char *device_sn, void *channel, void *context) {
+    FUNC_ENTRY;
+
+    DM_MQTT_Struct_t *h_dsc = NULL;
+
+    if (NULL == (h_dsc = HAL_Malloc(sizeof(DM_MQTT_Struct_t)))) {
+        LOG_ERROR("allocate for h_dsc failed");
+        FUNC_EXIT_RC(NULL);
+    }
+
+    memset(h_dsc, 0, sizeof(DM_MQTT_Struct_t));
+
+    h_dsc->mqtt = channel;
+    h_dsc->product_sn = product_sn;
+    h_dsc->device_sn = device_sn;
+    h_dsc->context = context;
+
+    FUNC_EXIT_RC(h_dsc);
+}
+
+int dsc_deinit(void *handle) {
+    FUNC_ENTRY;
+
+    if (NULL != handle) {
+        HAL_Free(handle);
+    }
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+int dm_mqtt_property_report_publish(DM_MQTT_Struct_t *handle, DM_Type type, int request_id, const char *payload) {
+    FUNC_ENTRY;
+
+    int ret = FAILURE_RET;
+    char *msg_report = NULL;
+    char *topic = NULL;
+
+    if (NULL == (msg_report = HAL_Malloc(DM_MSG_REPORT_BUF_LEN))) {
+        LOG_ERROR("allocate for msg_report failed");
+        goto do_exit;
+    }
+    if (NULL == (topic = HAL_Malloc(DM_TOPIC_BUF_LEN))) {
+        LOG_ERROR("allocate for topic failed");
+        goto do_exit;
+    }
+
+    if (SUCCESS_RET != _dm_mqtt_gen_topic_name(topic, DM_TOPIC_BUF_LEN, handle->upstream_topic_templates[type],
+            handle->product_sn, handle->device_sn)) {
+        LOG_ERROR("generate topic failed");
+        goto do_exit;
+    }
+
+    ret = _dm_mqtt_gen_property_payload(msg_report, DM_MSG_REPORT_BUF_LEN, type, request_id, payload);
+    if (ret < 0) {
+        LOG_ERROR("generate msg_report failed");
+        ret = FAILURE_RET;
+        goto do_exit;
+    }
+    ret = _dm_mqtt_publish(handle, topic, 1, msg_report);
+    if (ret < 0) {
+        LOG_ERROR("mqtt publish msg failed");
+    }
+
+do_exit:
+    HAL_Free(topic);
+    HAL_Free(msg_report);
+
+    FUNC_EXIT_RC(ret);
+}
+
+int dm_mqtt_event_publish(DM_MQTT_Struct_t *handle, int request_id, const char *identifier, const char *payload) {
+    FUNC_ENTRY;
+
+    int ret = FAILURE_RET;
+    char *msg_report = NULL;
+    char *topic = NULL;
+
+    if (NULL == (msg_report = HAL_Malloc(DM_EVENT_POST_BUF_LEN))) {
+        LOG_ERROR("allocate for msg_report failed");
+        goto do_exit;
+    }
+    if (NULL == (topic = HAL_Malloc(DM_TOPIC_BUF_LEN))) {
+        LOG_ERROR("allocate for topic failed");
+        goto do_exit;
+    }
+
+    if (SUCCESS_RET != _dm_mqtt_gen_topic_name(topic, DM_TOPIC_BUF_LEN, handle->upstream_topic_templates[EVENT_POST],
+            handle->product_sn, handle->device_sn)) {
+        LOG_ERROR("generate topic failed");
+        goto do_exit;
+    }
+
+    ret = _dm_mqtt_gen_event_payload(msg_report, DM_EVENT_POST_BUF_LEN, request_id, identifier, payload);
+    if (ret < 0) {
+        LOG_ERROR("generate msg_report failed");
+        goto do_exit;
+    }
+    ret = _dm_mqtt_publish(handle, topic, 1, msg_report);
+    if (ret < 0) {
+        LOG_ERROR("mqtt publish msg failed");
+    }
+
+do_exit:
+    HAL_Free(topic);
+    HAL_Free(msg_report);
+
+    FUNC_EXIT_RC(ret);
+}

+ 504 - 0
uiot/mqtt/include/mqtt_client.h

@@ -0,0 +1,504 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+
+#ifndef C_SDK_MQTT_CLIENT_H_
+#define C_SDK_MQTT_CLIENT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "uiot_export.h"
+#include "uiot_import.h"
+#include "uiot_internal.h"
+
+#include "mqtt_client_net.h"
+
+#include "utils_timer.h"
+#include "utils_list.h"
+
+/* 报文id最大值 */
+#define MAX_PACKET_ID               								(65535)
+
+/* 成功订阅主题的最大个数 */
+#define MAX_SUB_TOPICS        								        (10)
+
+/* 在列表中最大的重新发布数量 */
+#define MAX_REPUB_NUM                                               (20)
+
+/* 重连最小等待时间 */
+#define MIN_RECONNECT_WAIT_INTERVAL 								(1000)
+
+/* MQTT报文最小超时时间 */
+#define MIN_COMMAND_TIMEOUT         								(500)
+
+/* MQTT报文最大超时时间 */
+#define MAX_COMMAND_TIMEOUT         								(50000)
+
+/* 云端保留主题的最大长度 */
+#define MAX_SIZE_OF_CLOUD_TOPIC                                     (128)
+
+/* 动态注册相关的topic */
+#define DYNAMIC_REGISTER_PUB_TEMPLATE          "/$system/%s/%s/password"
+
+#define DYNAMIC_REGISTER_SUB_TEMPLATE          "/$system/%s/%s/password_reply"
+
+/* 获取设备密钥的消息中的字段 */
+#define PASSWORD_REPLY_RETCODE                 "RetCode"
+
+#define PASSWORD_REPLY_REQUEST_ID              "RequestID"
+
+#define PASSWORD_REPLY_PASSWORD                "Password"
+
+/**
+ * @brief MQTT Message Type
+ */
+typedef enum msgTypes {
+	RESERVED    = 0,     // Reserved
+	CONNECT     = 1,     // Client request to connect to Server
+	CONNACK     = 2,     // Connect Acknowledgment
+	PUBLISH     = 3,     // Publish message
+	PUBACK      = 4,     // Publish Acknowledgment
+	PUBREC      = 5,     // Publish Received
+	PUBREL      = 6,     // Publish Release
+	PUBCOMP     = 7,     // Publish Complete
+	SUBSCRIBE   = 8,     // Client Subscribe request
+	SUBACK      = 9,     // Subscribe Acknowledgment
+	UNSUBSCRIBE = 10,    // Client Unsubscribe request
+	UNSUBACK    = 11,    // Unsubscribe Acknowledgment
+	PINGREQ     = 12,    // PING Request
+	PINGRESP    = 13,    // PING Response
+	DISCONNECT  = 14     // Client is Disconnecting
+} MessageTypes;
+
+typedef enum {
+	DISCONNECTED = 0,
+	CONNECTED	 = 1
+} ConnStatus;
+
+typedef enum {
+	STATIC_AUTH	 = 1,        
+	DYNAMIC_AUTH = 2,
+} AuthStatus;
+
+/** 
+ * MQTT byte 1: fixed header
+ * bits  |7654: Message Type  | 3:DUP flag |  21:QoS level | 0:RETAIN |
+ */
+#define MQTT_HEADER_TYPE_SHIFT          0x04
+#define MQTT_HEADER_TYPE_MASK           0xF0
+#define MQTT_HEADER_DUP_SHIFT           0x03
+#define MQTT_HEADER_DUP_MASK            0x08
+#define MQTT_HEADER_QOS_SHIFT           0x01
+#define MQTT_HEADER_QOS_MASK            0x06
+#define MQTT_HEADER_RETAIN_MASK	        0x01
+
+
+/**
+ * @brief MQTT 遗嘱消息参数结构体定义
+ *
+ * 当客户端异常断开连接, 若客户端在连接时有设置遗嘱消息, 服务端会发布遗嘱消息。
+ */
+typedef struct {
+    char        struct_id[4];      // The eyecatcher for this structure. must be MQTW
+    uint8_t     struct_version;    // 结构体 0
+    char        *topic_name;       // 遗嘱消息主题名
+    char        *message;          // 遗嘱消息负载部分数据
+    uint8_t     retained;          // 遗嘱消息retain标志位
+    QoS         qos;               // 遗嘱消息qos标志位
+} WillOptions;
+
+/**
+ * MQTT遗嘱消息结构体默认值定义
+ */
+#define DEFAULT_WILL_OPTIONS { {'M', 'Q', 'T', 'W'}, 0, NULL, NULL, 0, QOS0 }
+
+/**
+ * @brief MQTT 连接参数结构体定义
+ *
+ */
+typedef struct {
+    char            			*client_id;             // 客户端标识符, 请保持唯一
+    char            			*username;              // 用户名
+    char						*password;				// 密码
+
+    char            			struct_id[4];           // The eyecatcher for this structure.  must be MQTC.
+    uint8_t         			struct_version;         // 结构体版本号, 必须为0
+    uint8_t         			mqtt_version;           // MQTT版本协议号 4 = 3.1.1
+    uint16_t        			keep_alive_interval;    // 心跳周期, 单位: s
+    uint8_t         			clean_session;          // 清理会话标志位, 具体含义请参考MQTT协议说明文档3.1.2.4小结
+
+    uint8_t                   	auto_connect_enable;    // 是否开启自动重连
+} MQTTConnectParams;
+
+/**
+ * MQTT连接参数结构体默认值定义
+ */
+#define DEFAULT_MQTT_CONNECT_PARAMS { NULL, NULL, NULL, {'M', 'Q', 'T', 'C'}, 0, 4, 240, 1 , 1,}
+
+/**
+ * @brief 订阅主题对应的消息处理结构体定义
+ */
+typedef struct SubTopicHandle {
+    const char              *topic_filter;               // 订阅主题名, 可包含通配符
+    OnMessageHandler        message_handler;             // 订阅主题消息回调:wq函数指针
+    void                    *message_handler_data;       // 用户数据, 通过回调函数返回
+    QoS                     qos;                         // 服务质量等级
+} SubTopicHandle;
+
+/**
+ * @brief MQTT Client结构体定义
+ */
+typedef struct Client {
+    uint8_t                  is_connected;                                  // 网络是否连接
+    uint8_t                  was_manually_disconnected;                     // 是否手动断开连接
+    uint8_t                  is_ping_outstanding;                           // 心跳包是否未完成, 即未收到服务器响应
+
+    uint16_t                 next_packet_id;                                // MQTT报文标识符
+    uint32_t                 command_timeout_ms;                            // MQTT消息超时时间, 单位:ms
+
+    uint32_t                 current_reconnect_wait_interval;               // MQTT重连周期, 单位:ms
+    uint32_t                 counter_network_disconnected;                  // 网络断开连接次数
+
+    size_t                   write_buf_size;                                // 消息发送buffer长度
+    size_t                   read_buf_size;                                 // 消息接收buffer长度
+    unsigned char            write_buf[UIOT_MQTT_TX_BUF_LEN];               // MQTT消息发送buffer
+    unsigned char            read_buf[UIOT_MQTT_RX_BUF_LEN];                // MQTT消息接收buffer
+
+    void                     *lock_generic;                                 // client原子锁
+    void                     *lock_write_buf;                          		// 输出流的锁
+
+    void                     *lock_list_pub;                                // 等待发布消息ack列表的锁
+    void                     *lock_list_sub;                                // 等待订阅消息ack列表的锁
+
+    List                     *list_pub_wait_ack;                            // 等待发布消息ack列表
+    List                     *list_sub_wait_ack;                            // 等待订阅消息ack列表
+
+    MQTTEventHandler         event_handler;                                 // 事件句柄
+
+    MQTTConnectParams        options;                                       // 连接相关参数
+
+    utils_network_t          network_stack;                                 // MQTT底层使用的网络参数
+
+    Timer                    ping_timer;                                    // MQTT心跳包发送定时器
+    Timer                    reconnect_delay_timer;                         // MQTT重连定时器, 判断是否已到重连时间
+
+    SubTopicHandle           sub_handles[MAX_SUB_TOPICS];                   // 订阅主题对应的消息处理结构数组
+} UIoT_Client;
+
+/**
+ * @brief MQTT协议版本
+ */
+typedef enum {
+    MQTT_3_1_1 = 4
+} MQTT_VERSION;
+
+
+typedef enum MQTT_NODE_STATE {
+    MQTT_NODE_STATE_NORMAL = 0,
+    MQTT_NODE_STATE_INVALID,
+} MQTTNodeState;
+
+/* 记录已经发布的topic的信息 */
+typedef struct REPUBLISH_INFO {
+    Timer                   pub_start_time;     /* 发布的时间 */
+    MQTTNodeState           node_state;         /* 节点状态 */
+    uint16_t                msg_id;             /* 发布消息的packet id */
+    uint32_t                len;                /* 消息长度 */
+    unsigned char           *buf;               /* 消息内容 */
+} UIoTPubInfo;
+
+/* 记录已经订阅的topic的信息 */
+typedef struct SUBSCRIBE_INFO {
+    enum msgTypes           type;           /* 类型, (sub or unsub) */
+    uint16_t                msg_id;         /* 订阅/取消订阅的 packet id */
+    Timer                   sub_start_time; /* 订阅的开始时间 */
+    MQTTNodeState           node_state;     /* 节点状态 */
+    SubTopicHandle          handler;        /* handle of topic subscribed(unsubscribed) */
+    uint16_t                len;            /* 消息长度 */
+    unsigned char           *buf;           /* 消息内容 */
+} UIoTSubInfo;
+
+/**
+ * @brief 对结构体Client进行初始化
+ *
+ * @param pClient MQTT客户端结构体
+ * @param pParams MQTT客户端初始化参数
+ * @return 返回SUCCESS, 表示成功
+ */
+int uiot_mqtt_init(UIoT_Client *pClient, MQTTInitParams *pParams);
+
+/**
+ * @brief 建立基于TLS的MQTT连接
+ *
+ * 注意: Client ID不能为NULL或空字符串
+ *
+ * @param pClient MQTT客户端结构体
+ * @param pParams MQTT连接相关参数, 可参考MQTT协议说明
+ * @return 返回SUCCESS, 表示成功
+ */
+int uiot_mqtt_connect(UIoT_Client *pClient, MQTTConnectParams *pParams);
+
+/**
+ * @brief 与服务器重新建立MQTT连接
+ *
+ * 1. 与服务器重新建立MQTT连接
+ * 2. 连接成功后, 重新订阅之前的订阅过的主题
+ *
+ * @param pClient MQTT Client结构体
+ *
+ * @return 返回ERR_MQTT_RECONNECTED, 表示重连成功
+ */
+int uiot_mqtt_attempt_reconnect(UIoT_Client *pClient);
+
+/**
+ * @brief 断开MQTT连接
+ *
+ * @param pClient MQTT Client结构体
+ * @return 返回SUCCESS, 表示成功
+ */
+int uiot_mqtt_disconnect(UIoT_Client *pClient);
+
+/**
+ * @brief 发布MQTT消息
+ *
+ * @param pClient MQTT客户端结构体
+ * @param topicName 主题名
+ * @param pParams 发布参数
+ * @return < 0  :   表示失败
+ *         >= 0 :   返回唯一的packet id 
+ */
+int uiot_mqtt_publish(UIoT_Client *pClient, char *topicName, PublishParams *pParams);
+
+/**
+ * @brief 订阅MQTT主题
+ *
+ * @param pClient MQTT客户端结构体
+ * @param topicFilter 主题过滤器, 可参考MQTT协议说明 4.7
+ * @param pParams 订阅参数
+ * @return < 0  :   表示失败
+ *         >= 0 :   返回唯一的packet id 
+ */
+int uiot_mqtt_subscribe(UIoT_Client *pClient, char *topicFilter, SubscribeParams *pParams);
+
+/**
+ * @brief 重新订阅断开连接之前已订阅的主题
+ *
+ * @param pClient MQTT客户端结构体
+ * @return 返回SUCCESS, 表示成功
+ */
+int uiot_mqtt_resubscribe(UIoT_Client *pClient);
+
+/**
+ * @brief 取消订阅已订阅的MQTT主题
+ *
+ * @param pClient MQTT客户端结构体
+ * @param topicFilter  主题过滤器, 可参考MQTT协议说明 4.7
+ * @return < 0  :   表示失败
+ *         >= 0 :   返回唯一的packet id   
+ */
+int uiot_mqtt_unsubscribe(UIoT_Client *pClient, char *topicFilter);
+
+/**
+ * @brief 在当前线程为底层MQTT客户端让出一定CPU执行时间
+ *
+ * 在这段时间内, MQTT客户端会用用处理消息接收, 以及发送PING报文, 监控网络状态
+ *
+ * @param pClient    MQTT Client结构体
+ * @param timeout_ms Yield操作超时时间
+ * @return 返回SUCCESS, 表示成功, 返回ERR_MQTT_ATTEMPTING_RECONNECT, 表示正在重连
+ */
+int uiot_mqtt_yield(UIoT_Client *pClient, uint32_t timeout_ms);
+
+/**
+ * @brief 客户端自动重连是否开启
+ *
+ * @param pClient MQTT客户端结构体
+ * @return 返回true, 表示客户端已开启自动重连功能
+ */
+bool uiot_mqtt_is_autoreconnect_enabled(UIoT_Client *pClient);
+
+/**
+ * @brief 设置客户端是否开启自动重连
+ *
+ * @param pClient MQTT客户端结构体
+ * @param value 是否开启该功能
+ * @return 返回SUCCESS, 表示设置成功
+ */
+int uiot_mqtt_set_autoreconnect(UIoT_Client *pClient, bool value);
+
+/**
+ * @brief 获取网络断开的次数
+ *
+ * @param pClient MQTT Client结构体
+ * @return 返回客户端MQTT网络断开的次数
+ */
+int uiot_mqtt_get_network_disconnected_count(UIoT_Client *pClient);
+
+/**
+ * @brief 重置连接断开次数
+ *
+ * @param pClient MQTT Client结构体
+ * @return 返回SUCCESS, 表示设置成功
+ */
+int uiot_mqtt_reset_network_disconnected_count(UIoT_Client *pClient);
+
+/**
+ * @brief 获取报文标识符
+ *
+ * @param pClient
+ * @return
+ */
+uint16_t get_next_packet_id(UIoT_Client *pClient);
+
+/**
+ *
+ * @param header
+ * @param message_type
+ * @param qos
+ * @param dup
+ * @param retained
+ * @return
+ */
+int mqtt_init_packet_header(unsigned char *header, MessageTypes message_type, QoS qos, uint8_t dup, uint8_t retained);
+
+/**
+ * @brief 接收服务端消息
+ *
+ * @param pClient
+ * @param timer
+ * @param packet_type
+ * @param qos
+ * @return
+ */
+int cycle_for_read(UIoT_Client *pClient, Timer *timer, uint8_t *packet_type, QoS qos);
+
+/**
+ * @brief 发送报文数据
+ *
+ * @param pClient       Client结构体
+ * @param length        报文长度
+ * @param timer         定时器
+ * @return
+ */
+int send_mqtt_packet(UIoT_Client *pClient, size_t length, Timer *timer);
+
+/**
+ * @brief 等待指定类型的MQTT控制报文
+ *
+ * only used in single-threaded mode where one command at a time is in process
+ *
+ * @param pClient       MQTT Client结构体
+ * @param packet_type   控制报文类型
+ * @param timer         定时器
+ * @return
+ */
+int wait_for_read(UIoT_Client *pClient, uint8_t packet_type, Timer *timer, QoS qos);
+
+/**
+ * @brief 设置MQTT当前连接状态
+ *
+ * @param pClient 		Client结构体
+ * @param connected 	0: 连接断开状态  1: 已连接状态
+ * @return
+ */
+void set_client_conn_state(UIoT_Client *pClient, uint8_t connected);
+
+/**
+ * @brief 获取MQTT当前连接状态
+ *
+ * @param pClient 		Client结构体
+ * @return				0: 连接断开状态  1: 已连接状态
+ */
+uint8_t get_client_conn_state(UIoT_Client *pClient);
+
+/**
+ * @brief 检查 Publish ACK 等待列表,若有成功接收或者超时,则将对应节点从列表中移除
+ *
+ * @param pClient MQTT客户端
+ * @return 返回SUCCESS, 表示成功
+ */
+int uiot_mqtt_pub_info_proc(UIoT_Client *pClient);
+
+/**
+ * @brief 检查 Subscribe ACK 等待列表,若有成功接收或者超时,则将对应节点从列表中移除
+ *
+ * @param pClient MQTT客户端
+ * @return 返回SUCCESS, 表示成功
+ */
+int uiot_mqtt_sub_info_proc(UIoT_Client *pClient);
+
+int push_sub_info_to(UIoT_Client *c, int len, unsigned short msgId, MessageTypes type,
+								   SubTopicHandle *handler, ListNode **node);
+
+int serialize_pub_ack_packet(unsigned char *buf, size_t buf_len, MessageTypes packet_type, uint8_t dup,
+							 uint16_t packet_id,
+							 uint32_t *serialized_len);
+
+int serialize_packet_with_zero_payload(unsigned char *buf, size_t buf_len, MessageTypes packetType, uint32_t *serialized_len);
+
+int deserialize_publish_packet(unsigned char *dup, QoS *qos, uint8_t *retained, uint16_t *packet_id, char **topicName,
+							   uint16_t *topicNameLen, unsigned char **payload, size_t *payload_len, unsigned char *buf, size_t buf_len);
+
+int deserialize_suback_packet(uint16_t *packet_id, uint32_t max_count, uint32_t *count,
+                                     QoS *grantedQoSs, unsigned char *buf, size_t buf_len);
+
+int deserialize_unsuback_packet(uint16_t *packet_id, unsigned char *buf, size_t buf_len);
+
+int deserialize_ack_packet(uint8_t *packet_type, uint8_t *dup, uint16_t *packet_id, unsigned char *buf, size_t buf_len);
+
+bool parse_mqtt_payload_retcode_type(char *pJsonDoc, uint32_t *pRetCode); 
+
+bool parse_mqtt_state_request_id_type(char *pJsonDoc, char **pType);
+
+bool parse_mqtt_state_password_type(char *pJsonDoc, char **pType);
+
+#ifdef MQTT_CHECK_REPEAT_MSG
+
+void reset_repeat_packet_id_buffer(void);
+
+#endif
+/**
+ * @brief 根据剩余长度计算整个MQTT报文的长度
+ *
+ * @param rem_len    剩余长度
+ * @return           整个MQTT报文的长度
+ */
+size_t get_mqtt_packet_len(size_t rem_len);
+
+size_t mqtt_write_packet_rem_len(unsigned char *buf, uint32_t length);
+
+int mqtt_read_packet_rem_len_form_buf(unsigned char *buf, uint32_t *value, uint32_t *readBytesLen);
+
+uint16_t mqtt_read_uint16_t(unsigned char **pptr);
+
+unsigned char mqtt_read_char(unsigned char **pptr);
+
+void mqtt_write_char(unsigned char **pptr, unsigned char c);
+
+void mqtt_write_uint_16(unsigned char **pptr, uint16_t anInt);
+
+void mqtt_write_utf8_string(unsigned char **pptr, const char *string);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //C_SDK_MQTT_CLIENT_H_

+ 38 - 0
uiot/mqtt/include/mqtt_client_net.h

@@ -0,0 +1,38 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+
+#ifndef C_SDK_MQTT_CLIENT_NET_H_
+#define C_SDK_MQTT_CLIENT_NET_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "utils_net.h"
+
+/**
+ * @brief 初始化TLS实现
+ *
+ * @param pNetwork 网络操作相关结构体
+ * @return 返回0, 表示初始化成功
+ */
+int uiot_mqtt_network_init(utils_network_pt pNetwork, const char *host, uint16_t port, uint16_t authmode, const char *ca_crt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //C_SDK_MQTT_CLIENT_NET_H_

+ 482 - 0
uiot/mqtt/src/mqtt_client.c

@@ -0,0 +1,482 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mqtt_client.h"
+#include "ca.h"
+
+#include "uiot_import.h"
+#include "uiot_export.h"
+#include "utils_list.h"
+#include "utils_net.h"
+
+
+#define HOST_STR_LENGTH 64
+static char s_uiot_host[HOST_STR_LENGTH] = {0};
+
+#ifdef SUPPORT_TLS
+static int s_uiot_port = 8883;
+#else
+static int s_uiot_port = 1883; 
+#endif
+
+void* IOT_MQTT_Construct(MQTTInitParams *pParams)
+{
+	POINTER_VALID_CHECK(pParams, NULL);
+	STRING_PTR_VALID_CHECK(pParams->product_sn, NULL);
+	STRING_PTR_VALID_CHECK(pParams->device_sn, NULL);
+#ifndef AUTH_MODE_DYNAMIC
+    STRING_PTR_VALID_CHECK(pParams->device_secret, NULL);
+#endif
+
+	UIoT_Client* mqtt_client = NULL;
+
+	// 初始化MQTTClient
+	if ((mqtt_client = (UIoT_Client*) HAL_Malloc (sizeof(UIoT_Client))) == NULL)
+    {
+		LOG_ERROR("malloc MQTTClient failed\n");
+		return NULL;
+	}
+    
+	int ret = uiot_mqtt_init(mqtt_client, pParams);
+	if (ret != SUCCESS_RET) {
+		LOG_ERROR("mqtt init failed: %d\n", ret);
+        goto end;
+    }
+
+    MQTTConnectParams connect_params = DEFAULT_MQTT_CONNECT_PARAMS;
+    int client_id_len = strlen(pParams->product_sn) + strlen(pParams->device_sn)+ 2;
+	if((connect_params.client_id = (char*)HAL_Malloc(client_id_len)) == NULL)
+    {
+        LOG_ERROR("client_id init failed: %d\n", ret);
+        goto end;
+    }
+    int username_len = strlen(pParams->product_sn) + strlen(pParams->device_sn) + 4;
+    if((connect_params.username = (char*)HAL_Malloc(username_len)) == NULL)
+    {
+        LOG_ERROR("username init failed: %d\n", ret);
+        HAL_Free(connect_params.client_id);
+        goto end;
+    }
+
+    int auth_mode = 0;
+#ifdef AUTH_MODE_DYNAMIC
+    //动态认证时如果还未获取设备密钥则先使用产品密钥进行预认证
+    if(NULL == pParams->device_secret)
+    {
+        auth_mode = DYNAMIC_AUTH;
+        int password_len = strlen(pParams->product_secret) + 1;
+        if((connect_params.password = (char*)HAL_Malloc(password_len)) == NULL)
+        {
+            LOG_ERROR("Dynamic password init failed: %d\n", ret);
+            HAL_Free(connect_params.username);
+            HAL_Free(connect_params.client_id);
+            goto end;
+        }
+        HAL_Snprintf(connect_params.password, password_len, "%s", pParams->product_secret);
+    }
+#endif
+    //使用获取到的设备密钥进行静态注册
+    if(NULL != pParams->device_secret)
+    {
+        auth_mode = STATIC_AUTH;
+        int password_len = strlen(pParams->device_secret) + 1;
+        if((connect_params.password = (char*)HAL_Malloc(password_len)) == NULL)
+        {
+            LOG_ERROR("password init failed: %d\n", ret);
+            HAL_Free(connect_params.username);
+            HAL_Free(connect_params.client_id);
+            goto end;
+        }
+        HAL_Snprintf(connect_params.password, password_len, "%s", pParams->device_secret); 
+    }
+
+    HAL_Snprintf(connect_params.client_id, client_id_len, "%s.%s", pParams->product_sn, pParams->device_sn);
+    HAL_Snprintf(connect_params.username, username_len, "%s|%s|%d", pParams->product_sn, pParams->device_sn, auth_mode);
+    connect_params.keep_alive_interval = pParams->keep_alive_interval;
+	connect_params.clean_session = pParams->clean_session;
+	connect_params.auto_connect_enable = pParams->auto_connect_enable;
+
+	ret = uiot_mqtt_connect(mqtt_client, &connect_params);
+	if (ret != SUCCESS_RET) {
+		LOG_ERROR("mqtt connect failed: %d\n", ret);
+        HAL_Free(connect_params.username);
+        HAL_Free(connect_params.client_id);
+        HAL_Free(connect_params.password);
+        goto end;
+	}
+	else {
+		LOG_INFO("mqtt connect success\n");
+	}
+
+	return mqtt_client;
+end:
+    HAL_Free(mqtt_client);
+    return NULL;
+}
+
+int IOT_MQTT_Destroy(void **pClient) {
+	POINTER_VALID_CHECK(*pClient, ERR_PARAM_INVALID);
+
+	UIoT_Client *mqtt_client = (UIoT_Client *)(*pClient);
+
+	int ret = uiot_mqtt_disconnect(mqtt_client);
+    int loop = 0;
+#ifdef MQTT_CHECK_REPEAT_MSG
+    reset_repeat_packet_id_buffer();
+#endif
+
+    HAL_MutexDestroy(mqtt_client->lock_generic);
+	HAL_MutexDestroy(mqtt_client->lock_write_buf);
+
+    HAL_MutexDestroy(mqtt_client->lock_list_sub);
+    HAL_MutexDestroy(mqtt_client->lock_list_pub);
+
+    list_destroy(mqtt_client->list_pub_wait_ack);
+    list_destroy(mqtt_client->list_sub_wait_ack);
+
+    HAL_Free(mqtt_client->options.username);
+    HAL_Free(mqtt_client->options.client_id);
+    HAL_Free(mqtt_client->options.password);
+
+    for (loop = 0; loop < MAX_SUB_TOPICS; ++loop)
+    {
+        HAL_Free((char *)mqtt_client->sub_handles[loop].topic_filter);
+    }
+
+    HAL_Free(*pClient);
+    *pClient = NULL;
+
+	return ret;
+}
+
+int IOT_MQTT_Yield(void *pClient, uint32_t timeout_ms) {
+
+	UIoT_Client   *mqtt_client = (UIoT_Client *)pClient;
+    int ret = uiot_mqtt_yield(mqtt_client, timeout_ms);
+
+	return ret;
+}
+
+int IOT_MQTT_Publish(void *pClient, char *topicName, PublishParams *pParams) {
+
+	UIoT_Client   *mqtt_client = (UIoT_Client *)pClient;
+
+	return uiot_mqtt_publish(mqtt_client, topicName, pParams);
+}
+
+int IOT_MQTT_Subscribe(void *pClient, char *topicFilter, SubscribeParams *pParams) {
+
+	UIoT_Client   *mqtt_client = (UIoT_Client *)pClient;
+
+	return uiot_mqtt_subscribe(mqtt_client, topicFilter, pParams);
+}
+
+int IOT_MQTT_Unsubscribe(void *pClient, char *topicFilter) {
+
+	UIoT_Client   *mqtt_client = (UIoT_Client *)pClient;
+
+	return uiot_mqtt_unsubscribe(mqtt_client, topicFilter);
+}
+
+bool IOT_MQTT_IsConnected(void *pClient) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+
+    UIoT_Client   *mqtt_client = (UIoT_Client *)pClient;
+
+    return get_client_conn_state(mqtt_client) == 1;
+}
+
+static void on_message_callback_get_device_secret(void *pClient, MQTTMessage *message, void *userData) 
+{    
+    LOG_DEBUG("Receive Message With topicName:%.*s, payload:%.*s\n",
+          (int) message->topic_len, message->topic, (int) message->payload_len, (char *) message->payload);
+    uint32_t RetCode = 0;
+    if(false == parse_mqtt_payload_retcode_type((char *)message->payload, &RetCode))
+    {
+        LOG_ERROR("parse retcode fail\n");
+        return;
+    }
+
+    if(SUCCESS_RET != RetCode)
+    {
+        LOG_ERROR("get device secret fail\n");
+        return;
+    }
+    
+    char *Request_id = NULL;
+    if(false == parse_mqtt_state_request_id_type((char *)message->payload, &Request_id))
+    {
+        LOG_ERROR("parse request_id fail\n");
+        HAL_Free(Request_id);
+        return;
+    }
+
+    if(0 != strcmp(Request_id, "1"))
+    {
+        LOG_ERROR("request_id error\n");
+        HAL_Free(Request_id);
+        return;
+    }
+    
+    char *Password = NULL;
+    if(false == parse_mqtt_state_password_type((char *)message->payload, &Password))
+    {
+        LOG_ERROR("parse password fail\n");
+        HAL_Free(Request_id);
+        HAL_Free(Password);
+        return;
+    }
+    HAL_SetDeviceSecret(Password);
+    HAL_Free(Request_id);
+    HAL_Free(Password);    
+    return;
+}
+
+int IOT_MQTT_Dynamic_Register(MQTTInitParams *pParams)
+{   
+    POINTER_VALID_CHECK(pParams, ERR_PARAM_INVALID);
+    int ret = SUCCESS_RET;
+
+    void *client = IOT_MQTT_Construct(pParams);
+    if(NULL == client)
+    {
+        LOG_ERROR("mqtt client Dynamic register fail\n");
+        return FAILURE_RET;
+    }
+
+    char *pub_name = (char *)HAL_Malloc(MAX_SIZE_OF_CLOUD_TOPIC * sizeof(char));
+    if (pub_name == NULL) 
+    {
+        LOG_ERROR("topic_name malloc fail\n");
+        IOT_MQTT_Destroy(&client);
+        return FAILURE_RET;
+    }
+    memset(pub_name, 0x0, MAX_SIZE_OF_CLOUD_TOPIC);
+	HAL_Snprintf(pub_name, MAX_SIZE_OF_CLOUD_TOPIC, DYNAMIC_REGISTER_PUB_TEMPLATE, pParams->product_sn, pParams->device_sn);
+
+    /* 订阅回复设备密钥的topic */
+    char *sub_name = (char *)HAL_Malloc(MAX_SIZE_OF_CLOUD_TOPIC * sizeof(char));
+    if (sub_name == NULL) 
+    {
+        LOG_ERROR("topic_name malloc fail\n");
+        HAL_Free(pub_name);
+        IOT_MQTT_Destroy(&client);
+        return FAILURE_RET;
+    }
+    memset(sub_name, 0x0, MAX_SIZE_OF_CLOUD_TOPIC);
+	HAL_Snprintf(sub_name, MAX_SIZE_OF_CLOUD_TOPIC, DYNAMIC_REGISTER_SUB_TEMPLATE, pParams->product_sn, pParams->device_sn);
+
+    SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
+    sub_params.qos = QOS1;
+    sub_params.user_data = (void *)pParams->device_sn;
+    sub_params.on_message_handler = on_message_callback_get_device_secret;
+    ret = IOT_MQTT_Subscribe(client, sub_name, &sub_params);
+    if(ret <= 0)
+    {
+        LOG_ERROR("subscribe %s fail\n",sub_name);
+        goto end;
+    }
+    
+    ret = IOT_MQTT_Yield(client,200);
+
+    /* 向topic发送消息请求回复设备密钥 */
+	char auth_msg[UIOT_MQTT_TX_BUF_LEN];
+    HAL_Snprintf(auth_msg, UIOT_MQTT_TX_BUF_LEN, "{\"RequestID\":\"%d\"}", 1);
+    PublishParams pub_params = DEFAULT_PUB_PARAMS;
+
+    pub_params.qos = QOS1;
+    pub_params.payload = (void *)auth_msg;
+    pub_params.payload_len = strlen(auth_msg);
+    
+    IOT_MQTT_Publish(client, pub_name, &pub_params);
+
+    ret = IOT_MQTT_Yield(client,5000);
+    if (SUCCESS_RET != ret) 
+    {
+        LOG_ERROR("get device password fail\n");
+        goto end;
+    }
+    
+    IOT_MQTT_Unsubscribe(client, sub_name);
+    ret = IOT_MQTT_Yield(client,200);
+    if (SUCCESS_RET != ret) 
+    {
+        LOG_ERROR("unsub %s fail\n", sub_name);
+        goto end;
+    }
+    
+end:
+    HAL_Free(pub_name);
+    HAL_Free(sub_name);
+    IOT_MQTT_Destroy(&client);
+    return ret;
+}
+
+int uiot_mqtt_init(UIoT_Client *pClient, MQTTInitParams *pParams) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pParams, ERR_PARAM_INVALID);
+
+	memset(pClient, 0x0, sizeof(UIoT_Client));
+
+    int size = HAL_Snprintf(s_uiot_host, HOST_STR_LENGTH, "%s", UIOT_MQTT_DIRECT_DOMAIN);
+    if (size < 0 || size > HOST_STR_LENGTH - 1) {
+		return FAILURE_RET;
+	}
+
+    if (pParams->command_timeout < MIN_COMMAND_TIMEOUT)
+    	pParams->command_timeout = MIN_COMMAND_TIMEOUT;
+    if (pParams->command_timeout > MAX_COMMAND_TIMEOUT)
+    	pParams->command_timeout = MAX_COMMAND_TIMEOUT;
+    pClient->command_timeout_ms = pParams->command_timeout;
+
+    // packet id 初始化时取1
+    pClient->next_packet_id = 1;
+    pClient->write_buf_size = UIOT_MQTT_TX_BUF_LEN;
+    pClient->read_buf_size = UIOT_MQTT_RX_BUF_LEN;
+    
+    pClient->event_handler = pParams->event_handler;
+
+    pClient->lock_generic = HAL_MutexCreate();
+    if (NULL == pClient->lock_generic) {
+        return FAILURE_RET;
+    }
+
+    set_client_conn_state(pClient, DISCONNECTED);
+
+    if ((pClient->lock_write_buf = HAL_MutexCreate()) == NULL) {
+    	LOG_ERROR("create write buf lock failed.");
+    	goto error;
+    }
+    if ((pClient->lock_list_sub = HAL_MutexCreate()) == NULL) {
+    	LOG_ERROR("create sub list lock failed.");
+    	goto error;
+    }
+    if ((pClient->lock_list_pub = HAL_MutexCreate()) == NULL) {
+    	LOG_ERROR("create pub list lock failed.");
+    	goto error;
+    }
+
+    if ((pClient->list_pub_wait_ack = list_new()) == NULL) {
+    	LOG_ERROR("create pub wait list failed.");
+    	goto error;
+    }
+    pClient->list_pub_wait_ack->free = HAL_Free;
+
+    if ((pClient->list_sub_wait_ack = list_new()) == NULL) {
+    	LOG_ERROR("create sub wait list failed.");
+        goto error;
+    }
+    pClient->list_sub_wait_ack->free = HAL_Free;
+
+#ifdef SUPPORT_TLS
+    // TLS连接参数初始化
+    pClient->network_stack.authmode = SSL_CA_VERIFY_NONE;
+    pClient->network_stack.ca_crt = iot_ca_get();
+    pClient->network_stack.ca_crt_len = strlen(pClient->network_stack.ca_crt);
+#endif
+    pClient->network_stack.pHostAddress = s_uiot_host;
+    pClient->network_stack.port = s_uiot_port;
+
+    // 底层网络操作相关的数据结构初始化
+    #ifdef SUPPORT_AT_CMD
+    uiot_mqtt_network_init(&(pClient->network_stack), pClient->network_stack.pHostAddress,
+            pClient->network_stack.port, pClient->network_stack.authmode, NULL);
+    #else
+    uiot_mqtt_network_init(&(pClient->network_stack), pClient->network_stack.pHostAddress,
+            pClient->network_stack.port, pClient->network_stack.authmode, pClient->network_stack.ca_crt);
+    #endif
+
+
+    // ping定时器以及重连延迟定时器相关初始化
+    init_timer(&(pClient->ping_timer));
+    init_timer(&(pClient->reconnect_delay_timer));
+
+    return SUCCESS_RET;
+
+error:
+	if (pClient->list_pub_wait_ack) {
+		pClient->list_pub_wait_ack->free(pClient->list_pub_wait_ack);
+		pClient->list_pub_wait_ack = NULL;
+	}
+	if (pClient->list_sub_wait_ack) {
+		pClient->list_sub_wait_ack->free(pClient->list_sub_wait_ack);
+		pClient->list_sub_wait_ack = NULL;
+	}
+	if (pClient->lock_generic) {
+		HAL_MutexDestroy(pClient->lock_generic);
+		pClient->lock_generic = NULL;
+	}
+	if (pClient->lock_list_sub) {
+		HAL_MutexDestroy(pClient->lock_list_sub);
+		pClient->lock_list_sub = NULL;
+	}
+	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;
+	}
+
+	return FAILURE_RET;
+}
+
+int uiot_mqtt_set_autoreconnect(UIoT_Client *pClient, bool value) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+
+    pClient->options.auto_connect_enable = (uint8_t) value;
+
+    return SUCCESS_RET;
+}
+
+bool uiot_mqtt_is_autoreconnect_enabled(UIoT_Client *pClient) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+
+    bool is_enabled = false;
+    if (pClient->options.auto_connect_enable == 1) {
+        is_enabled = true;
+    }
+
+    return is_enabled;
+}
+
+int uiot_mqtt_get_network_disconnected_count(UIoT_Client *pClient) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+
+    return pClient->counter_network_disconnected;
+}
+
+int uiot_mqtt_reset_network_disconnected_count(UIoT_Client *pClient) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+
+    pClient->counter_network_disconnected = 0;
+
+    return SUCCESS_RET;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 1424 - 0
uiot/mqtt/src/mqtt_client_common.c

@@ -0,0 +1,1424 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+#include <time.h>
+
+#include "mqtt_client.h"
+
+#include "utils_list.h"
+#include "lite-utils.h"
+
+
+#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
+
+/* return: 0, identical; NOT 0, different. */
+static int _check_handle_is_identical(SubTopicHandle *sub_handle1, SubTopicHandle *sub_handle2)
+{
+    if (!sub_handle1 || !sub_handle2) {
+        return 1;
+    }
+
+    int topic_name_Len = strlen(sub_handle1->topic_filter);
+
+    if (topic_name_Len != strlen(sub_handle2->topic_filter)) {
+        return 1;
+    }
+
+    if (0 != strncmp(sub_handle1->topic_filter, sub_handle2->topic_filter, topic_name_Len)) {
+        return 1;
+    }
+
+    if (sub_handle1->message_handler != sub_handle2->message_handler) {
+        return 1;
+    }
+
+    return 0;
+}
+
+uint16_t get_next_packet_id(UIoT_Client *pClient) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+
+    HAL_MutexLock(pClient->lock_generic);
+    pClient->next_packet_id = (uint16_t) ((MAX_PACKET_ID == pClient->next_packet_id) ? 1 : (pClient->next_packet_id + 1));
+    HAL_MutexUnlock(pClient->lock_generic);
+
+    return pClient->next_packet_id;
+}
+
+/**
+ * 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
+ */
+size_t mqtt_write_packet_rem_len(unsigned char *buf, uint32_t length) {
+    size_t outLen = 0;
+
+    do {
+        unsigned char encodeByte;
+        encodeByte = (unsigned char) (length % 128);
+        length /= 128;
+        /* if there are more digits to encode, set the top bit of this digit */
+        if (length > 0) {
+            encodeByte |= 0x80;
+        }
+        buf[outLen++] = encodeByte;
+    } while (length > 0);
+
+    return (int)outLen;
+}
+
+size_t get_mqtt_packet_len(size_t 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;
+}
+
+/**
+ * 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
+ */
+static int _decode_packet_rem_len_from_buf_read(uint32_t (*getcharfn)(unsigned char *, uint32_t), uint32_t *value,
+                                                uint32_t *readBytesLen) {
+    unsigned char c;
+    uint32_t multiplier = 1;
+    uint32_t len = 0;
+    *value = 0;
+    do {
+        if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) {
+            /* bad data */
+            return ERR_MQTT_PACKET_READ_ERROR;
+        }
+        uint32_t getLen = 0;
+        getLen = (*getcharfn)(&c, 1);
+        if (1 != getLen) {
+            return FAILURE_RET;
+        }
+        *value += (c & 127) * multiplier;
+        multiplier *= 128;
+    } while ((c & 128) != 0);
+
+    *readBytesLen = len;
+
+    return SUCCESS_RET;
+}
+
+static unsigned char *bufptr;
+uint32_t bufchar(unsigned char *c, uint32_t count) {
+    uint32_t i;
+
+    for (i = 0; i < count; ++i) {
+        *c = *bufptr++;
+    }
+
+    return count;
+}
+
+int mqtt_read_packet_rem_len_form_buf(unsigned char *buf, uint32_t *value, uint32_t *readBytesLen) {
+    bufptr = buf;
+    return _decode_packet_rem_len_from_buf_read(bufchar, value, readBytesLen);
+}
+
+/**
+ * Calculates uint16 packet id 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 value calculated
+ */
+uint16_t mqtt_read_uint16_t(unsigned char **pptr) {
+    unsigned char *ptr = *pptr;
+    uint8_t firstByte = (uint8_t) (*ptr);
+    uint8_t secondByte = (uint8_t) (*(ptr + 1));
+    uint16_t len = (uint16_t) (secondByte + (256 * firstByte));
+    *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
+ */
+unsigned char mqtt_read_char(unsigned char **pptr) {
+    unsigned 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 mqtt_write_char(unsigned char **pptr, unsigned 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 mqtt_write_uint_16(unsigned char **pptr, uint16_t 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 mqtt_write_utf8_string(unsigned char **pptr, const char *string) {
+    size_t len = strlen(string);
+    mqtt_write_uint_16(pptr, (uint16_t) len);
+    memcpy(*pptr, string, len);
+    *pptr += len;
+}
+
+/**
+ * Initialize the MQTT Header fixed byte. Used to ensure that Header bits are
+ */
+int mqtt_init_packet_header(unsigned char *header, MessageTypes message_type,
+                            QoS Qos, uint8_t dup, uint8_t retained)
+{
+    POINTER_VALID_CHECK(header, ERR_PARAM_INVALID);
+    unsigned char type, qos;
+
+    switch (message_type) {
+        case RESERVED:
+            /* Should never happen */
+            return ERR_MQTT_UNKNOWN_ERROR;
+        case CONNECT:
+            type = 0x01;
+            break;
+        case CONNACK:
+            type = 0x02;
+            break;
+        case PUBLISH:
+            type = 0x03;
+            break;
+        case PUBACK:
+            type = 0x04;
+            break;
+        case PUBREC:
+            type = 0x05;
+            break;
+        case PUBREL:
+            type = 0x06;
+            break;
+        case PUBCOMP:
+            type = 0x07;
+            break;
+        case SUBSCRIBE:
+            type = 0x08;
+            break;
+        case SUBACK:
+            type = 0x09;
+            break;
+        case UNSUBSCRIBE:
+            type = 0x0A;
+            break;
+        case UNSUBACK:
+            type = 0x0B;
+            break;
+        case PINGREQ:
+            type = 0x0C;
+            break;
+        case PINGRESP:
+            type = 0x0D;
+            break;
+        case DISCONNECT:
+            type = 0x0E;
+            break;
+        default:
+            /* Should never happen */
+            return ERR_MQTT_UNKNOWN_ERROR;
+    }
+
+    switch (Qos) {
+        case QOS0:
+            qos = 0x00;
+            break;
+        case QOS1:
+            qos = 0x01;
+            break;
+        case QOS2:
+            qos = 0x02;
+            break;
+        default:
+            /* Using QOS0 as default */
+            qos = 0x00;
+            break;
+    }
+
+    /* Generate the final protocol header by using bitwise operator */
+    *header  = ((type<<MQTT_HEADER_TYPE_SHIFT)&MQTT_HEADER_TYPE_MASK)
+                | ((dup<<MQTT_HEADER_DUP_SHIFT)&MQTT_HEADER_DUP_MASK)
+                | ((qos<<MQTT_HEADER_QOS_SHIFT)&MQTT_HEADER_QOS_MASK)
+                | (retained&MQTT_HEADER_RETAIN_MASK);
+
+    return SUCCESS_RET;
+}
+
+/**
+  * Deserializes the supplied (wire) buffer into an ack
+  * @param packet_type returned integer - the MQTT packet type
+  * @param dup returned integer - the MQTT dup flag
+  * @param packet_id returned integer - the MQTT packet identifier
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buf_len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int deserialize_ack_packet(uint8_t *packet_type, uint8_t *dup, uint16_t *packet_id, unsigned char *buf, size_t buf_len) {
+    POINTER_VALID_CHECK(packet_type, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(dup, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(packet_id, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(buf, ERR_PARAM_INVALID);
+
+    int ret;
+    unsigned char header = 0;
+    unsigned char *curdata = buf;
+    unsigned char *enddata = NULL;
+    uint32_t decodedLen = 0, readBytesLen = 0;
+
+    /* PUBACK fixed header size is two bytes, variable header is 2 bytes, MQTT v3.1.1 Specification 3.4.1 */
+    if (4 > buf_len) {
+        return ERR_MQTT_BUFFER_TOO_SHORT;
+    }
+
+    header = mqtt_read_char(&curdata);        
+    *packet_type = ((header&MQTT_HEADER_TYPE_MASK)>>MQTT_HEADER_TYPE_SHIFT);
+    *dup  = ((header&MQTT_HEADER_DUP_MASK)>>MQTT_HEADER_DUP_SHIFT);
+
+    /* read remaining length */
+    ret = mqtt_read_packet_rem_len_form_buf(curdata, &decodedLen, &readBytesLen);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+    curdata += (readBytesLen);
+    enddata = curdata + decodedLen;
+
+    if (enddata - curdata < 2) {
+        return FAILURE_RET;
+    }
+
+    *packet_id = mqtt_read_uint16_t(&curdata);
+    
+    // 返回错误码处理
+    if (enddata - curdata >= 1) {
+        unsigned char ack_code = mqtt_read_char(&curdata);
+        if (ack_code != 0) {
+            LOG_ERROR("deserialize_ack_packet failure! ack_code = 0x%02x", ack_code);
+            return FAILURE_RET;
+        }
+    }
+
+    return SUCCESS_RET;
+}
+
+/**
+  * Deserializes the supplied (wire) buffer into suback data
+  * @param packet_id returned integer - the MQTT packet identifier
+  * @param max_count - 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 buf_len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int deserialize_suback_packet(uint16_t *packet_id, uint32_t max_count, uint32_t *count,
+                                     QoS *grantedQoSs, unsigned char *buf, size_t buf_len) 
+{
+    POINTER_VALID_CHECK(packet_id, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(count, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(grantedQoSs, ERR_PARAM_INVALID);
+
+    unsigned char header, type = 0;
+    unsigned char *curdata = buf;
+    unsigned char *enddata = NULL;
+    int decodeRc;
+    uint32_t decodedLen = 0;
+    uint32_t readBytesLen = 0;
+
+    // SUBACK头部大小为4字节, 负载部分至少为1字节QOS返回码
+    if (5 > buf_len) {
+        return ERR_MQTT_BUFFER_TOO_SHORT;
+    }
+    // 读取报文固定头部的第一个字节
+    header = mqtt_read_char(&curdata);
+    type = (header&MQTT_HEADER_TYPE_MASK)>>MQTT_HEADER_TYPE_SHIFT;
+    if (type != SUBACK) {
+        return FAILURE_RET;
+    }
+
+    // 读取报文固定头部的剩余长度
+    decodeRc = mqtt_read_packet_rem_len_form_buf(curdata, &decodedLen, &readBytesLen);
+    if (decodeRc != SUCCESS_RET) {
+        return decodeRc;
+    }
+
+    curdata += (readBytesLen);
+    enddata = curdata + decodedLen;
+    if (enddata - curdata < 2) {
+        return FAILURE_RET;
+    }
+
+    // 读取报文可变头部的报文标识符
+    *packet_id = mqtt_read_uint16_t(&curdata);
+
+    // 读取报文的负载部分
+    *count = 0;
+    while (curdata < enddata) {
+        if (*count > max_count) {
+            return FAILURE_RET;
+        }
+        grantedQoSs[(*count)++] = (QoS) mqtt_read_char(&curdata);
+    }
+
+    return SUCCESS_RET;
+}
+
+/**
+  * Deserializes the supplied (wire) buffer into unsuback data
+  * @param packet_id returned integer - the MQTT packet identifier
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buf_len the length in bytes of the data in the supplied buffer
+  * @return int indicating function execution status
+  */
+int deserialize_unsuback_packet(uint16_t *packet_id, unsigned char *buf, size_t buf_len) 
+{
+    POINTER_VALID_CHECK(buf, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(packet_id, ERR_PARAM_INVALID);
+
+    unsigned char type = 0;
+    unsigned char dup = 0;
+    int ret;
+
+    ret = deserialize_ack_packet(&type, &dup, packet_id, buf, buf_len);
+    if (SUCCESS_RET == ret && UNSUBACK != type) {
+        ret = FAILURE_RET;
+    }
+
+    return ret;
+}
+
+/**
+  * 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 buf_len the length in bytes of the supplied buffer, to avoid overruns
+  * @param packettype the message type
+  * @param serialized length
+  * @return int indicating function execution status
+  */
+int serialize_packet_with_zero_payload(unsigned char *buf, size_t buf_len, MessageTypes packetType, uint32_t *serialized_len) {
+    POINTER_VALID_CHECK(buf, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(serialized_len, ERR_PARAM_INVALID);
+
+    unsigned char header = 0;
+    unsigned char *ptr = buf;
+    int ret;
+
+    /* Buffer should have at least 2 bytes for the header */
+    if (4 > buf_len) {
+        return ERR_MQTT_BUFFER_TOO_SHORT;
+    }
+
+    ret = mqtt_init_packet_header(&header, packetType, QOS0, 0, 0);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+
+    /* write header */
+    mqtt_write_char(&ptr, header);
+
+    /* write remaining length */
+    ptr += mqtt_write_packet_rem_len(ptr, 0);
+    *serialized_len = (uint32_t) (ptr - buf);
+
+    return SUCCESS_RET;
+}
+
+int send_mqtt_packet(UIoT_Client *pClient, size_t length, Timer *timer) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(timer, ERR_PARAM_INVALID);
+
+    size_t sent = 0;
+
+    if (length >= pClient->write_buf_size) {
+        return ERR_MQTT_BUFFER_TOO_SHORT;
+    }
+
+    while (sent < length && !has_expired(timer)) {
+        int send_len = 0;
+        send_len = pClient->network_stack.write(&(pClient->network_stack), &(pClient->write_buf[sent]), length, left_ms(timer));
+        if (send_len < 0) {
+            /* there was an error writing the data */
+            break;
+        }
+        sent = sent + send_len;
+    }
+
+    if (sent == length) {
+        /* record the fact that we have successfully sent the packet */
+        //countdown(&c->ping_timer, c->keep_alive_interval);
+        return SUCCESS_RET;
+    }
+
+    return FAILURE_RET;
+}
+
+/**
+ * @brief 解析报文的剩余长度字段
+ *
+ * 每从网络中读取一个字节, 按照MQTT协议算法计算剩余长度
+ *
+ * @param pClient Client结构体
+ * @param value   剩余长度
+ * @param timeout 超时时间
+ * @return
+ */
+static int _decode_packet_rem_len_with_net_read(UIoT_Client *pClient, uint32_t *value, uint32_t timeout) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(value, ERR_PARAM_INVALID);
+
+    unsigned char i;
+    uint32_t multiplier = 1;
+    uint32_t len = 0;
+
+    *value = 0;
+
+    do {
+        if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) {
+            /* bad data */
+            return ERR_MQTT_PACKET_READ_ERROR;
+        }
+
+        if (pClient->network_stack.read(&(pClient->network_stack), &i, 1, timeout) <= 0) {
+            /* The value argument is the important value. len is just used temporarily
+             * and never used by the calling function for anything else */
+            return FAILURE_RET;
+        }
+
+        *value += ((i & 127) * multiplier);
+        multiplier *= 128;
+    } while ((i & 128) != 0);
+
+    /* The value argument is the important value. len is just used temporarily
+     * and never used by the calling function for anything else */
+    return SUCCESS_RET;
+}
+
+/**
+ * @brief 从底层SSL/TCP层读取报文数据
+ *
+ * 1. 读取第一个字节确定报文的类型;
+ * 2. 读取剩余长度字段, 最大为四个字节; 剩余长度表示可变包头和有效负载的长度
+ * 3. 根据剩余长度, 读取剩下的数据, 包括可变包头和有效负荷
+ *
+ * @param pClient        Client结构体
+ * @param timer          定时器
+ * @param packet_type    报文类型
+ * @return
+ */
+static int _read_mqtt_packet(UIoT_Client *pClient, Timer *timer, uint8_t *packet_type) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(timer, ERR_PARAM_INVALID);
+
+    uint32_t len = 0;
+    uint32_t rem_len = 0;
+    int read_len = 0;
+    int ret;
+	int timer_left_ms = left_ms(timer);
+	
+	if (timer_left_ms <= 0) {
+        timer_left_ms = 1;
+    }
+
+    // 1. 读取报文固定头部的第一个字节
+    read_len = pClient->network_stack.read(&(pClient->network_stack), pClient->read_buf, 1, timer_left_ms);
+    if (read_len < 0) {
+        return read_len;
+    } else if (read_len == 0) {
+        return ERR_MQTT_NOTHING_TO_READ;
+    }
+
+    len = 1;
+
+    // 2. 读取报文固定头部剩余长度部分
+	timer_left_ms = left_ms(timer);
+    if (timer_left_ms <= 0) {
+        timer_left_ms = 1;
+    }
+    timer_left_ms += UIOT_MQTT_MAX_REMAIN_WAIT_MS; //确保一包MQTT报文接收完
+	
+    ret = _decode_packet_rem_len_with_net_read(pClient, &rem_len, timer_left_ms);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+
+    // 如果读缓冲区的大小小于报文的剩余长度, 报文会被丢弃
+    if (rem_len >= pClient->read_buf_size) {
+        size_t total_bytes_read = 0;
+        size_t bytes_to_be_read;
+
+		timer_left_ms = left_ms(timer);
+        if (timer_left_ms <= 0) {
+            timer_left_ms = 1;
+        }
+        timer_left_ms += UIOT_MQTT_MAX_REMAIN_WAIT_MS;
+
+        bytes_to_be_read = pClient->read_buf_size;
+        do {
+            read_len = pClient->network_stack.read(&(pClient->network_stack), pClient->read_buf, bytes_to_be_read, timer_left_ms);
+            if (read_len > 0) {
+                total_bytes_read += read_len;
+                if ((rem_len - total_bytes_read) >= pClient->read_buf_size) {
+                    bytes_to_be_read = pClient->read_buf_size;
+                } else {
+                    bytes_to_be_read = rem_len - total_bytes_read;
+                }
+            }
+        } while (total_bytes_read < rem_len && read_len > 0);
+
+        LOG_ERROR("MQTT Recv buffer not enough: %d < %d", pClient->read_buf_size, rem_len);
+        return ERR_MQTT_BUFFER_TOO_SHORT;
+    }
+
+    // 将剩余长度写入读缓冲区
+    len += mqtt_write_packet_rem_len(pClient->read_buf + 1, rem_len);
+
+    // 3. 读取报文的剩余部分数据
+    if (rem_len > 0 && ((len + rem_len) > pClient->read_buf_size)) {
+		
+		timer_left_ms = left_ms(timer);
+        if (timer_left_ms <= 0) {
+            timer_left_ms = 1;
+        }
+        timer_left_ms += UIOT_MQTT_MAX_REMAIN_WAIT_MS;
+	
+    	pClient->network_stack.read(&(pClient->network_stack), pClient->read_buf, rem_len, timer_left_ms);
+    	return ERR_MQTT_BUFFER_TOO_SHORT;
+    } else {
+        if (rem_len > 0) {
+
+			timer_left_ms = left_ms(timer);
+	        if (timer_left_ms <= 0) {
+	            timer_left_ms = 1;
+	        }
+	        timer_left_ms += UIOT_MQTT_MAX_REMAIN_WAIT_MS;
+        	read_len = pClient->network_stack.read(&(pClient->network_stack), pClient->read_buf + len, rem_len, timer_left_ms);
+            if (read_len < 0) {
+                return read_len;
+            } else if (read_len == 0) {
+                return ERR_MQTT_NOTHING_TO_READ;
+            }
+        }
+    }
+
+    *packet_type = (pClient->read_buf[0]&MQTT_HEADER_TYPE_MASK)>>MQTT_HEADER_TYPE_SHIFT;
+    
+    return SUCCESS_RET;
+}
+
+/**
+ * @brief 消息主题是否相同
+ *
+ * @param topic_filter
+ * @param topicName
+ * @return
+ */
+static uint8_t _is_topic_equals(char *topic_filter, char *topicName) {
+    return (uint8_t) (strlen(topic_filter) == strlen(topicName) && !strcmp(topic_filter, topicName));
+}
+
+/**
+ * @brief 消息主题匹配
+ *
+ * assume topic filter and name is in correct format
+ * # can only be at end
+ * + and # can only be next to separator
+ *
+ * @param topic_filter   订阅消息的主题名
+ * @param topicName     收到消息的主题名, 不能包含通配符
+ * @param topicNameLen  主题名的长度
+ * @return
+ */
+static uint8_t _is_topic_matched(char *topic_filter, char *topicName, uint16_t topicNameLen) {
+    char *curf;
+    char *curn;
+    char *curn_end;
+
+    curf = topic_filter;
+    curn = topicName;
+    curn_end = curn + topicNameLen;
+
+    while (*curf && (curn < curn_end)) {
+
+        if (*curf == '+' && *curn == '/') {
+            curf++;
+            continue;
+        }
+
+        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 == '#') {
+            /* skip until end of string */
+            curn = curn_end - 1;
+        }
+
+        curf++;
+        curn++;
+    };
+
+    if (*curf == '\0') {
+        return (uint8_t) (curn == curn_end);
+    } else {
+        return (uint8_t) ((*curf == '#') || *(curf + 1) == '#' || (*curf == '+' && *(curn - 1) == '/'));
+    }
+}
+
+/**
+ * @brief 终端收到服务器的的PUBLISH消息之后, 传递消息给消息回调处理函数
+ *
+ * @param pClient
+ * @param topicName
+ * @param message
+ * @return
+ */
+static int _deliver_message(UIoT_Client *pClient, char *topicName, uint16_t topicNameLen, MQTTMessage *message) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(topicName, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(message, ERR_PARAM_INVALID);
+
+    message->topic = topicName;
+    message->topic_len = (size_t)topicNameLen;
+
+    uint32_t i;
+    int flag_matched = 0;
+    
+    HAL_MutexLock(pClient->lock_generic);
+    for (i = 0; i < MAX_SUB_TOPICS; ++i) {
+        if ((pClient->sub_handles[i].topic_filter != NULL)
+            && (_is_topic_equals(topicName, (char *) pClient->sub_handles[i].topic_filter) ||
+                _is_topic_matched((char *) pClient->sub_handles[i].topic_filter, topicName, topicNameLen)))
+        {
+            HAL_MutexUnlock(pClient->lock_generic);
+            if (pClient->sub_handles[i].message_handler != NULL) {
+                pClient->sub_handles[i].message_handler(pClient, message, pClient->sub_handles[i].message_handler_data);
+                return SUCCESS_RET;
+            }
+            HAL_MutexLock(pClient->lock_generic);
+        }
+    }
+
+    /* Message handler not found for topic */
+    /* May be we do not care  change FAILURE  use SUCCESS*/
+    HAL_MutexUnlock(pClient->lock_generic);
+
+    if (0 == flag_matched) {
+        LOG_DEBUG("no matching any topic, call default handle function");
+
+        if (NULL != pClient->event_handler.h_fp) {
+            MQTTEventMsg msg;
+            msg.event_type = MQTT_EVENT_PUBLISH_RECEIVED;
+            msg.msg = message;
+            pClient->event_handler.h_fp(pClient, pClient->event_handler.context, &msg);
+        }
+    }
+
+    return SUCCESS_RET;
+}
+
+/**
+ * @brief 从等待 publish ACK 的列表中,移除由 msdId 标记的元素
+ *
+ * @param c
+ * @param msgId
+ *
+ * @return 0, success; NOT 0, fail;
+ */
+static int _mask_pubInfo_from(UIoT_Client *c, uint16_t msgId)
+{
+    if (!c) {
+        return FAILURE_RET;
+    }
+
+    HAL_MutexLock(c->lock_list_pub);
+    if (c->list_pub_wait_ack->len) {
+        ListIterator *iter;
+        ListNode *node = NULL;
+        UIoTPubInfo *repubInfo = NULL;
+
+        if (NULL == (iter = list_iterator_new(c->list_pub_wait_ack, LIST_TAIL))) {
+            HAL_MutexUnlock(c->lock_list_pub);
+            return SUCCESS_RET;
+        }
+
+        for (;;) {
+            node = list_iterator_next(iter);
+
+            if (NULL == node) {
+                break;
+            }
+
+            repubInfo = (UIoTPubInfo *) node->val;
+            if (NULL == repubInfo) {
+                LOG_ERROR("node's value is invalid!");
+                continue;
+            }
+
+            if (repubInfo->msg_id == msgId) {
+                repubInfo->node_state = MQTT_NODE_STATE_INVALID; /* 标记为无效节点 */
+            }
+        }
+
+        list_iterator_destroy(iter);
+    }
+    HAL_MutexUnlock(c->lock_list_pub);
+
+    return SUCCESS_RET;
+}
+
+/* 从等待 subscribe(unsubscribe) ACK 的列表中,移除由 msdId 标记的元素 */
+/* 同时返回消息处理数据 messageHandler */
+/* return: 0, success; NOT 0, fail; */
+static int _mask_sub_info_from(UIoT_Client *c, unsigned int msgId, SubTopicHandle *messageHandler)
+{
+    if (NULL == c || NULL == messageHandler) {
+        return FAILURE_RET;
+    }
+
+    HAL_MutexLock(c->lock_list_sub);
+    if (c->list_sub_wait_ack->len) {
+        ListIterator *iter;
+        ListNode *node = NULL;
+        UIoTSubInfo *sub_info = NULL;
+
+        if (NULL == (iter = list_iterator_new(c->list_sub_wait_ack, LIST_TAIL))) {
+            HAL_MutexUnlock(c->lock_list_sub);
+            return SUCCESS_RET;
+        }
+
+        for (;;) {
+            node = list_iterator_next(iter);
+            if (NULL == node) {
+                break;
+            }
+
+            sub_info = (UIoTSubInfo *) node->val;
+            if (NULL == sub_info) {
+                LOG_ERROR("node's value is invalid!");
+                continue;
+            }
+
+            if (sub_info->msg_id == msgId) {
+                *messageHandler = sub_info->handler; /* return handle */
+                sub_info->node_state = MQTT_NODE_STATE_INVALID; /* mark as invalid node */
+            } 
+        }
+
+        list_iterator_destroy(iter);
+    }
+    HAL_MutexUnlock(c->lock_list_sub);
+
+    return SUCCESS_RET;
+}
+
+/**
+ * @brief 终端收到服务器的的PUBACK消息之后, 处理收到的PUBACK报文
+ */
+static int _handle_puback_packet(UIoT_Client *pClient, Timer *timer)
+{
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(timer, ERR_PARAM_INVALID);
+
+    uint16_t packet_id;
+    uint8_t dup, type;
+    int ret;
+
+    ret = deserialize_ack_packet(&type, &dup, &packet_id, pClient->read_buf, pClient->read_buf_size);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+
+    (void)_mask_pubInfo_from(pClient, packet_id);
+
+    /* 调用回调函数,通知外部PUBLISH成功. */
+    if (NULL != pClient->event_handler.h_fp) {
+        MQTTEventMsg msg;
+        msg.event_type = MQTT_EVENT_PUBLISH_SUCCESS;
+        msg.msg = (void *)(uintptr_t)packet_id;
+        pClient->event_handler.h_fp(pClient, pClient->event_handler.context, &msg);
+    }
+
+    return SUCCESS_RET;
+}
+
+/**
+ * @brief 终端收到服务器的的 SUBACK 消息之后, 处理收到的 SUBACK 报文
+ */
+static int _handle_suback_packet(UIoT_Client *pClient, Timer *timer, QoS qos)
+{
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(timer, ERR_PARAM_INVALID);
+
+    uint32_t count = 0;
+    uint16_t packet_id = 0;
+    QoS grantedQoS[3] = {QOS0, QOS0, QOS0};
+    int ret;
+    bool sub_nack = false;
+    
+    // 反序列化SUBACK报文
+    ret = deserialize_suback_packet(&packet_id, 1, &count, grantedQoS, pClient->read_buf, pClient->read_buf_size);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+
+    int flag_dup = 0, i_free = -1;
+
+    for (int j = 0; j <  count; j++) {
+        /* In negative case, grantedQoS will be 0xFFFF FF80, which means -128 */
+        if ((uint8_t)grantedQoS[j] == 0x80) {
+            sub_nack = true;
+            LOG_ERROR("MQTT SUBSCRIBE failed, ack code is 0x80");
+        }
+    }
+
+    HAL_MutexLock(pClient->lock_generic);
+    
+    SubTopicHandle sub_handle;
+    memset(&sub_handle, 0, sizeof(SubTopicHandle));
+    (void)_mask_sub_info_from(pClient, (unsigned int)packet_id, &sub_handle);
+
+    if (/*(NULL == sub_handle.message_handler) || */(NULL == sub_handle.topic_filter)) {
+        LOG_ERROR("sub_handle is illegal, topic is null");
+        HAL_MutexUnlock(pClient->lock_generic);
+        return ERR_MQTT_SUB_FAILED;
+    }
+
+    if (sub_nack) {
+        LOG_ERROR("MQTT SUBSCRIBE failed, packet_id: %u topic: %s", packet_id, sub_handle.topic_filter);
+        /* 调用回调函数,通知外部 SUBSCRIBE 失败. */
+        if (NULL != pClient->event_handler.h_fp) {
+            MQTTEventMsg msg;
+            msg.event_type = MQTT_EVENT_SUBSCRIBE_NACK;
+            msg.msg = (void *)(uintptr_t)packet_id;
+            if (pClient->event_handler.h_fp != NULL)
+                pClient->event_handler.h_fp(pClient, pClient->event_handler.context, &msg);
+        }
+        HAL_Free((void *)sub_handle.topic_filter);
+        sub_handle.topic_filter = NULL;
+        HAL_MutexUnlock(pClient->lock_generic);
+        return ERR_MQTT_SUB_FAILED;
+    }
+
+    int i;
+    for (i = 0; i < MAX_SUB_TOPICS; ++i) {
+        if ((NULL != pClient->sub_handles[i].topic_filter)) {
+            if (0 == _check_handle_is_identical(&pClient->sub_handles[i], &sub_handle)) {
+                flag_dup = 1;
+                HAL_Free((void *)sub_handle.topic_filter);
+                sub_handle.topic_filter = NULL;
+                break;
+            }
+        } else {
+            if (-1 == i_free) {
+                i_free = i; /* record available element */
+            }
+        }
+    }
+
+    if (0 == flag_dup) {
+        if (-1 == i_free) {
+            LOG_ERROR("NO more @sub_handles space!");
+            HAL_MutexUnlock(pClient->lock_generic);
+            return FAILURE_RET;
+        } else {
+            pClient->sub_handles[i_free].topic_filter = sub_handle.topic_filter;
+            pClient->sub_handles[i_free].message_handler = sub_handle.message_handler;
+            pClient->sub_handles[i_free].qos = sub_handle.qos;
+            pClient->sub_handles[i_free].message_handler_data = sub_handle.message_handler_data;
+        }
+    }
+    
+    HAL_MutexUnlock(pClient->lock_generic);
+
+    /* 调用回调函数,通知外部 SUBSCRIBE 成功. */
+    if (NULL != pClient->event_handler.h_fp) {
+        MQTTEventMsg msg;
+        msg.event_type = MQTT_EVENT_SUBSCRIBE_SUCCESS;
+        msg.msg = (void *)(uintptr_t)packet_id;
+        if (pClient->event_handler.h_fp != NULL)
+            pClient->event_handler.h_fp(pClient, pClient->event_handler.context, &msg);
+    }
+
+    return SUCCESS_RET;
+}
+
+/**
+ * @brief 终端收到服务器的的 USUBACK 消息之后, 处理收到的 USUBACK 报文
+ */
+static int _handle_unsuback_packet(UIoT_Client *pClient, Timer *timer)
+{
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(timer, ERR_PARAM_INVALID);
+
+    uint16_t packet_id = 0;
+
+    int ret =  deserialize_unsuback_packet(&packet_id, pClient->read_buf, pClient->read_buf_size);
+    if (ret != SUCCESS_RET) {
+        return ret;
+    }
+
+    SubTopicHandle messageHandler;
+    (void)_mask_sub_info_from(pClient, packet_id, &messageHandler);
+
+    /* Remove from message handler array */
+    HAL_MutexLock(pClient->lock_generic);
+
+    /* actually below code is nonsense as unsub handle is different with sub handle even the same topic_filter*/
+    #if 0
+    int i;
+    for (i = 0; i < MAX_SUB_TOPICS; ++i) {
+        if ((pClient->sub_handles[i].topic_filter != NULL)
+            && (0 == _check_handle_is_identical(&pClient->sub_handles[i], &messageHandler))) {            
+            memset(&pClient->sub_handles[i], 0, sizeof(SubTopicHandle));
+
+            /* NOTE: in case of more than one register(subscribe) with different callback function,
+             *       so we must keep continuously searching related message handle. */
+        }
+    }
+    #endif
+
+    /* Free the topic filter malloced in uiot_mqtt_unsubscribe */
+    if (messageHandler.topic_filter) {
+        HAL_Free((void *)messageHandler.topic_filter);
+        messageHandler.topic_filter = NULL;
+    }
+
+    if (NULL != pClient->event_handler.h_fp) {
+        MQTTEventMsg msg;
+        msg.event_type = MQTT_EVENT_UNSUBSCRIBE_SUCCESS;
+        msg.msg = (void *)(uintptr_t)packet_id;
+
+        pClient->event_handler.h_fp(pClient, pClient->event_handler.context, &msg);
+    }
+
+    HAL_MutexUnlock(pClient->lock_generic);
+
+    return SUCCESS_RET;
+}
+
+#ifdef MQTT_CHECK_REPEAT_MSG
+
+#define MQTT_MAX_REPEAT_BUF_LEN 50
+static uint16_t sg_repeat_packet_id_buf[MQTT_MAX_REPEAT_BUF_LEN];
+
+/**
+ * @brief 判断packet_id缓存中是否已经存有传入的packet_id;
+ */
+static int _get_packet_id_in_repeat_buf(uint16_t packet_id)
+{
+    int i;
+    for (i = 0; i < MQTT_MAX_REPEAT_BUF_LEN; ++i)
+    {
+        if (packet_id == sg_repeat_packet_id_buf[i])
+        {
+            return packet_id;
+        }
+    }
+    return -1;
+}
+
+static void _add_packet_id_to_repeat_buf(uint16_t packet_id)
+{
+    static unsigned int current_packet_id_cnt = 0;
+    if (_get_packet_id_in_repeat_buf(packet_id) > 0)
+        return;
+
+    sg_repeat_packet_id_buf[current_packet_id_cnt++] = packet_id;
+
+    if (current_packet_id_cnt >= MQTT_MAX_REPEAT_BUF_LEN)
+        current_packet_id_cnt = current_packet_id_cnt % 50;
+}
+
+void reset_repeat_packet_id_buffer(void)
+{
+    int i;
+    for (i = 0; i < MQTT_MAX_REPEAT_BUF_LEN; ++i)
+    {
+        sg_repeat_packet_id_buf[i] = 0;
+    }
+}
+
+#endif
+
+/**
+ * @brief 终端收到服务器的的PUBLISH消息之后, 处理收到的PUBLISH报文
+ */
+static int _handle_publish_packet(UIoT_Client *pClient, Timer *timer) {
+    char *topic_name;
+    uint16_t topic_len;
+    MQTTMessage msg;
+    int ret;
+    uint32_t len = 0;
+
+    ret = deserialize_publish_packet(&msg.dup, &msg.qos, &msg.retained, &msg.id, &topic_name, &topic_len, (unsigned char **) &msg.payload,
+                                    &msg.payload_len, pClient->read_buf, pClient->read_buf_size);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+    
+    // 传过来的topicName没有截断,会把payload也带过来
+    char fix_topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0};
+	
+	if(topic_len > MAX_SIZE_OF_CLOUD_TOPIC){
+		topic_len = MAX_SIZE_OF_CLOUD_TOPIC - 1;
+		LOG_ERROR("topic len exceed buffer len");
+	}
+    memcpy(fix_topic, topic_name, topic_len);
+
+    if (QOS0 == msg.qos)
+    {
+        ret = _deliver_message(pClient, fix_topic, topic_len, &msg);
+        if (SUCCESS_RET != ret)
+            return ret;
+
+        /* No further processing required for QOS0 */
+        return ret;
+
+    } else {
+#ifdef MQTT_CHECK_REPEAT_MSG
+        // 判断packet_id之前是否已经收到过
+        int repeat_id = _get_packet_id_in_repeat_buf(msg.id);
+
+        // 执行订阅消息的回调函数
+        if (repeat_id < 0)
+        {
+#endif
+            ret = _deliver_message(pClient, fix_topic, topic_len, &msg);
+            if (SUCCESS_RET != ret)
+                return ret;
+#ifdef MQTT_CHECK_REPEAT_MSG
+        }
+        _add_packet_id_to_repeat_buf(msg.id);
+#endif
+    }
+    
+    HAL_MutexLock(pClient->lock_write_buf);
+    if (QOS1 == msg.qos) {
+        ret = serialize_pub_ack_packet(pClient->write_buf, pClient->write_buf_size, PUBACK, 0, msg.id, &len);
+    } else { /* Message is not QOS0 or 1 means only option left is QOS2 */
+        ret = serialize_pub_ack_packet(pClient->write_buf, pClient->write_buf_size, PUBREC, 0, msg.id, &len);
+    }
+
+    if (SUCCESS_RET != ret) {
+        HAL_MutexUnlock(pClient->lock_write_buf);
+        return ret;
+    }
+
+    ret = send_mqtt_packet(pClient, len, timer);
+    if (SUCCESS_RET != ret) {
+        HAL_MutexUnlock(pClient->lock_write_buf);
+        return ret;
+    }
+
+    HAL_MutexUnlock(pClient->lock_write_buf);
+    return SUCCESS_RET;
+}
+
+/**
+ * @brief 处理PUBREC报文, 并发送PUBREL报文, PUBLISH报文为QOS2时
+ *
+ * @param pClient
+ * @param timer
+ * @return
+ */
+static int _handle_pubrec_packet(UIoT_Client *pClient, Timer *timer) {
+    uint16_t packet_id;
+    unsigned char dup, type;
+    int ret;
+    uint32_t len;
+
+    ret = deserialize_ack_packet(&type, &dup, &packet_id, pClient->read_buf, pClient->read_buf_size);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+
+    HAL_MutexLock(pClient->lock_write_buf);
+    ret = serialize_pub_ack_packet(pClient->write_buf, pClient->write_buf_size, PUBREL, 0, packet_id, &len);
+    if (SUCCESS_RET != ret) {
+        HAL_MutexUnlock(pClient->lock_write_buf);
+        return ret;
+    }
+
+    /* send the PUBREL packet */
+    ret = send_mqtt_packet(pClient, len, timer);
+    if (SUCCESS_RET != ret) {
+        HAL_MutexUnlock(pClient->lock_write_buf);
+        /* there was a problem */
+        return ret;
+    }
+
+    HAL_MutexUnlock(pClient->lock_write_buf);
+    return SUCCESS_RET;
+}
+
+/**
+ * @brief 处理服务器的心跳包回包
+ *
+ * @param pClient
+ */
+static void _handle_pingresp_packet(UIoT_Client *pClient) {
+    HAL_MutexLock(pClient->lock_generic);
+    pClient->is_ping_outstanding = 0;
+    countdown(&pClient->ping_timer, pClient->options.keep_alive_interval);
+    HAL_MutexUnlock(pClient->lock_generic);
+
+    return;
+}
+
+int cycle_for_read(UIoT_Client *pClient, Timer *timer, uint8_t *packet_type, QoS qos) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(timer, ERR_PARAM_INVALID);
+
+    int ret;
+    /* read the socket, see what work is due */
+    ret = _read_mqtt_packet(pClient, timer, packet_type);
+
+    if (ERR_MQTT_NOTHING_TO_READ == ret) {
+        /* Nothing to read, not a cycle failure */
+        return SUCCESS_RET;
+    }
+
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+
+    switch (*packet_type) {
+        case CONNACK:
+            break;
+        case PUBACK:
+            ret = _handle_puback_packet(pClient, timer);
+            break;
+        case SUBACK:
+            ret = _handle_suback_packet(pClient, timer, qos);
+            break;
+        case UNSUBACK:
+            ret = _handle_unsuback_packet(pClient, timer);
+            break;
+        case PUBLISH: {
+            ret = _handle_publish_packet(pClient, timer);
+            break;
+        }
+        case PUBREC: {
+            ret = _handle_pubrec_packet(pClient, timer);
+            break;
+        }
+        case PUBREL: {
+            LOG_ERROR("Packet type PUBREL is currently NOT handled!");
+            break;
+        }
+        case PUBCOMP:
+            break;
+        case PINGRESP: 
+            break;
+        default: {
+            /* Either unknown packet type or Failure occurred
+             * Should not happen */
+             
+            return ERR_MQTT_RX_MESSAGE_PACKET_TYPE_INVALID;
+            break;
+        }
+    }
+
+    switch (*packet_type) {
+        /* Recv below msgs are all considered as PING OK */
+        case PUBACK:
+        case SUBACK:
+        case UNSUBACK:
+        case PINGRESP: {
+            _handle_pingresp_packet(pClient);
+            break;
+        }
+        /* Recv downlink pub means link is OK but we still need to send PING request */
+        case PUBLISH: {
+            HAL_MutexLock(pClient->lock_generic);
+            pClient->is_ping_outstanding = 0;
+            HAL_MutexUnlock(pClient->lock_generic);
+            break;
+        }
+    }
+
+    return ret;
+}
+
+int wait_for_read(UIoT_Client *pClient, uint8_t packet_type, Timer *timer, QoS qos) {
+	int ret;
+	uint8_t read_packet_type = 0;
+
+	POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+	POINTER_VALID_CHECK(timer, ERR_PARAM_INVALID);
+
+	do {
+		if (has_expired(timer)) {
+			ret = ERR_MQTT_REQUEST_TIMEOUT;
+			break;
+		}
+		ret = cycle_for_read(pClient, timer, &read_packet_type, qos);
+	} while (SUCCESS_RET == ret && read_packet_type != packet_type );
+
+	return ret;
+}
+
+void set_client_conn_state(UIoT_Client *pClient, uint8_t connected) {
+    HAL_MutexLock(pClient->lock_generic);
+    pClient->is_connected = connected;
+    HAL_MutexUnlock(pClient->lock_generic);
+}
+
+uint8_t get_client_conn_state(UIoT_Client *pClient) {
+	uint8_t is_connected = 0;
+	HAL_MutexLock(pClient->lock_generic);
+	is_connected = pClient->is_connected;
+	HAL_MutexUnlock(pClient->lock_generic);
+    return is_connected;
+}
+
+/*
+ * @brief 向 subscribe(unsubscribe) ACK 等待列表中添加元素
+ *
+ *
+ * return: 0, success; NOT 0, fail;
+ */
+int push_sub_info_to(UIoT_Client *c, int len, unsigned short msgId, MessageTypes type,
+                                   SubTopicHandle *handler, ListNode **node)
+{
+    if (!c || !handler || !node) {
+        return ERR_PARAM_INVALID;
+    }
+
+    HAL_MutexLock(c->lock_list_sub);
+
+    if (c->list_sub_wait_ack->len >= MAX_SUB_TOPICS) {
+        HAL_MutexUnlock(c->lock_list_sub);
+        LOG_ERROR("number of sub_info more than max! size = %d", c->list_sub_wait_ack->len);
+        return ERR_MQTT_MAX_SUBSCRIPTIONS_REACHED;
+    }
+
+    UIoTSubInfo *sub_info = (UIoTSubInfo *)HAL_Malloc(sizeof(
+            UIoTSubInfo) + len);
+    if (NULL == sub_info) {
+        HAL_MutexUnlock(c->lock_list_sub);
+        LOG_ERROR("malloc failed!");
+        return FAILURE_RET;
+    }
+    
+    sub_info->node_state = MQTT_NODE_STATE_NORMAL;
+    sub_info->msg_id = msgId;
+    sub_info->len = len;
+
+    init_timer(&sub_info->sub_start_time);
+    countdown_ms(&sub_info->sub_start_time, c->command_timeout_ms);
+
+    sub_info->type = type;
+    sub_info->handler = *handler;
+    sub_info->buf = (unsigned char *)sub_info + sizeof(UIoTSubInfo);
+
+    memcpy(sub_info->buf, c->write_buf, len);
+
+    *node = list_node_new(sub_info);
+    if (NULL == *node) {
+        HAL_MutexUnlock(c->lock_list_sub);
+        LOG_ERROR("list_node_new failed!");
+        return FAILURE_RET;
+    }
+
+    list_rpush(c->list_sub_wait_ack, *node);
+
+    HAL_MutexUnlock(c->lock_list_sub);
+
+    return SUCCESS_RET;
+}
+
+bool parse_mqtt_payload_retcode_type(char *pJsonDoc, uint32_t *pRetCode) 
+{
+    FUNC_ENTRY;
+
+    bool ret = false;
+
+    char *ret_code = (char *)LITE_json_value_of(PASSWORD_REPLY_RETCODE, pJsonDoc);
+    if (ret_code == NULL) FUNC_EXIT_RC(false);
+
+    if (sscanf(ret_code, "%" SCNu32, pRetCode) != 1) 
+    {
+        LOG_ERROR("parse RetCode failed, errCode: %d\n", ERR_JSON_PARSE);
+    }
+    else {
+        ret = true;
+    }
+
+    HAL_Free(ret_code);
+
+    FUNC_EXIT_RC(ret);
+}
+
+bool parse_mqtt_state_request_id_type(char *pJsonDoc, char **pType)
+{
+    *pType = (char *)LITE_json_value_of(PASSWORD_REPLY_REQUEST_ID, pJsonDoc);
+    return *pType == NULL ? false : true;
+}
+
+bool parse_mqtt_state_password_type(char *pJsonDoc, char **pType)
+{
+    *pType = (char *)LITE_json_value_of(PASSWORD_REPLY_PASSWORD, pJsonDoc);
+    return *pType == NULL ? false : true;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 399 - 0
uiot/mqtt/src/mqtt_client_connect.c

@@ -0,0 +1,399 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+#include <limits.h>
+
+#include "mqtt_client.h"
+
+
+#define MQTT_CONNECT_FLAG_USERNAME      0x80
+#define MQTT_CONNECT_FLAG_PASSWORD      0x40
+#define MQTT_CONNECT_FLAG_WILL_RETAIN   0x20
+#define MQTT_CONNECT_FLAG_WILL_QOS2     0x18
+#define MQTT_CONNECT_FLAG_WILL_QOS1     0x08
+#define MQTT_CONNECT_FLAG_WILL_QOS0     0x00
+#define MQTT_CONNECT_FLAG_WILL_FLAG     0x04
+#define MQTT_CONNECT_FLAG_CLEAN_SES     0x02
+
+#define MQTT_CONNACK_FLAG_SES_PRE       0x01
+
+/**
+ * Connect return code
+ */
+typedef enum {
+    CONNACK_CONNECTION_ACCEPTED = 0,    // connection accepted
+    CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = 1,    // connection refused: unaccpeted protocol verison
+    CONNACK_IDENTIFIER_REJECTED_ERROR = 2,    // connection refused: identifier rejected
+    CONNACK_SERVER_UNAVAILABLE_ERROR = 3,    // connection refused: server unavailable
+    CONNACK_BAD_USERDATA_ERROR = 4,    // connection refused: bad user name or password
+    CONNACK_NOT_AUTHORIZED_ERROR = 5     // connection refused: not authorized
+} MQTTConnackReturnCodes;
+
+/**
+  * 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
+  * @param the length of buffer needed to contain the serialized version of the packet
+  * @return int indicating function execution status
+  */
+static uint32_t _get_packet_connect_rem_len(MQTTConnectParams *options) {
+    size_t len = 0;
+    /* variable depending on MQTT or MQIsdp */
+    if (3 == options->mqtt_version) {
+        len = 12;
+    } else if (4 == options->mqtt_version) {
+        len = 10;
+    }
+
+    len += strlen(options->client_id) + 2;
+
+    if (options->username) {
+        len += strlen(options->username) + 2;
+    }
+
+    if (options->password) {
+        len += strlen(options->password) + 2;
+    }
+
+    return (uint32_t) len;
+}
+
+static void _copy_connect_params(MQTTConnectParams *destination, MQTTConnectParams *source) {
+	POINTER_VALID_CHECK_RTN(destination);
+	POINTER_VALID_CHECK_RTN(source);
+
+    destination->mqtt_version = source->mqtt_version;
+    destination->client_id = source->client_id;
+    destination->username = source->username;
+    destination->keep_alive_interval = source->keep_alive_interval;
+    destination->clean_session = source->clean_session;
+    destination->auto_connect_enable = source->auto_connect_enable;
+    destination->password = source->password;
+}
+
+/**
+  * 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
+  * @param serialized length
+  * @return int indicating function execution status
+  */
+static int _serialize_connect_packet(unsigned char *buf, size_t buf_len, MQTTConnectParams *options, uint32_t *serialized_len) {
+    POINTER_VALID_CHECK(buf, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(options, ERR_PARAM_INVALID);
+    STRING_PTR_VALID_CHECK(options->client_id, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(serialized_len, ERR_PARAM_INVALID);
+
+    unsigned char *ptr = buf;
+    unsigned char header = 0;
+    unsigned char flags = 0;
+    uint32_t rem_len = 0;
+    int ret;
+
+    rem_len = _get_packet_connect_rem_len(options);
+    if (get_mqtt_packet_len(rem_len) > buf_len) {
+        return ERR_MQTT_BUFFER_TOO_SHORT;
+    }
+
+    ret = mqtt_init_packet_header(&header, CONNECT, QOS0, 0, 0);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+
+    // 报文固定头部第一个字节
+    mqtt_write_char(&ptr, header);
+
+    // 报文固定头部剩余长度字段
+    ptr += mqtt_write_packet_rem_len(ptr, rem_len);
+
+    // 报文可变头部协议名 + 协议版本号
+    if (4 == options->mqtt_version) {
+        mqtt_write_utf8_string(&ptr, "MQTT");
+        mqtt_write_char(&ptr, (unsigned char) 4);
+    } else {
+        mqtt_write_utf8_string(&ptr, "MQIsdp");
+        mqtt_write_char(&ptr, (unsigned char) 3);
+    }
+
+    // 报文可变头部连接标识位
+    
+    flags |= (options->clean_session) ? MQTT_CONNECT_FLAG_CLEAN_SES : 0;
+    flags |= (options->username != NULL) ? MQTT_CONNECT_FLAG_USERNAME : 0;
+
+	flags |= MQTT_CONNECT_FLAG_PASSWORD;
+    
+    mqtt_write_char(&ptr, flags);
+
+    // 报文可变头部心跳周期/保持连接, 一个以秒为单位的时间间隔, 表示为一个16位的字
+    mqtt_write_uint_16(&ptr, options->keep_alive_interval);
+
+    // 有效负载部分: 客户端标识符
+    mqtt_write_utf8_string(&ptr, options->client_id);
+
+    // 用户名
+    if ((flags & MQTT_CONNECT_FLAG_USERNAME) && options->username != NULL) {
+        mqtt_write_utf8_string(&ptr, options->username);
+    }
+
+    if ((flags & MQTT_CONNECT_FLAG_PASSWORD) && options->password != NULL) {
+    	mqtt_write_utf8_string(&ptr, options->password);
+    }
+
+    *serialized_len = (uint32_t) (ptr - buf);
+    
+    return SUCCESS_RET;
+}
+
+/**
+  * 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 buflen the length in bytes of the data in the supplied buffer
+  * @return int indicating function execution status
+  */
+static int _deserialize_connack_packet(uint8_t *sessionPresent, int *connack_rc, unsigned char *buf, size_t buflen) {
+    POINTER_VALID_CHECK(sessionPresent, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(connack_rc, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(buf, ERR_PARAM_INVALID);
+
+    unsigned char header, type = 0;
+    unsigned char *curdata = buf;
+    unsigned char *enddata = NULL;
+    int ret;
+    uint32_t decodedLen = 0, readBytesLen = 0;
+    unsigned char flags = 0;
+    unsigned char connack_rc_char;
+
+    // CONNACK 头部大小是固定的2字节长度, 可变头部也是两个字节的长度, 无有效负载
+    if (4 > buflen) {
+        return ERR_MQTT_BUFFER_TOO_SHORT;
+    }
+
+    // 读取固定头部第一个字节
+    header = mqtt_read_char(&curdata);
+    type = (header&MQTT_HEADER_TYPE_MASK)>>MQTT_HEADER_TYPE_SHIFT;
+    if (CONNACK != type) {
+        return FAILURE_RET;
+    }
+
+    // 读取固定头部剩余长度字段
+    ret = mqtt_read_packet_rem_len_form_buf(curdata, &decodedLen, &readBytesLen);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+    curdata += (readBytesLen);
+    enddata = curdata + decodedLen;
+    if (enddata - curdata != 2) {
+        return FAILURE_RET;
+    }
+
+    // 读取可变头部-连接确认标志 参考MQTT协议说明文档3.2.2.1小结
+    flags = mqtt_read_char(&curdata);
+    *sessionPresent = flags & MQTT_CONNACK_FLAG_SES_PRE;
+
+    // 读取可变头部-连接返回码 参考MQTT协议说明文档3.2.2.3小结
+    connack_rc_char = mqtt_read_char(&curdata);
+    switch (connack_rc_char) {
+        case CONNACK_CONNECTION_ACCEPTED:
+            *connack_rc = MQTT_CONNECTION_ACCEPTED;
+            break;
+        case CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR:
+            *connack_rc = ERR_MQTT_CONNACK_UNACCEPTABLE_PROTOCOL_VERSION;
+            break;
+        case CONNACK_IDENTIFIER_REJECTED_ERROR:
+            *connack_rc = ERR_MQTT_CONNACK_IDENTIFIER_REJECTED;
+            break;
+        case CONNACK_SERVER_UNAVAILABLE_ERROR:
+            *connack_rc = ERR_MQTT_CONNACK_SERVER_UNAVAILABLE;
+            break;
+        case CONNACK_BAD_USERDATA_ERROR:
+            *connack_rc = ERR_MQTT_CONNACK_BAD_USERDATA;
+            break;
+        case CONNACK_NOT_AUTHORIZED_ERROR:
+            *connack_rc = ERR_MQTT_CONNACK_NOT_AUTHORIZED;
+            break;
+        default:
+            *connack_rc = ERR_MQTT_CONNACK_UNKNOWN;
+            break;
+    }
+
+    return SUCCESS_RET;
+}
+
+/**
+ * @brief 与服务器建立MQTT连接
+ *
+ * @param pClient
+ * @param options
+ * @return
+ */
+static int _mqtt_connect(UIoT_Client *pClient, MQTTConnectParams *options) {
+    Timer connect_timer;
+    int connack_rc = FAILURE_RET, ret = FAILURE_RET;
+    uint8_t sessionPresent = 0;
+    uint32_t len = 0;
+
+    init_timer(&connect_timer);
+    countdown_ms(&connect_timer, pClient->command_timeout_ms);
+
+    if (NULL != options) {
+        _copy_connect_params(&(pClient->options), options);
+    }
+
+    // 根据连接参数,建立TLS或NOTLS连接
+    ret = pClient->network_stack.connect(&(pClient->network_stack));
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+
+    HAL_MutexLock(pClient->lock_write_buf);
+    // 序列化CONNECT报文
+    ret = _serialize_connect_packet(pClient->write_buf, pClient->write_buf_size, &(pClient->options), &len);
+    if (SUCCESS_RET != ret || 0 == len) {
+    	HAL_MutexUnlock(pClient->lock_write_buf);
+        return ret;
+    }
+
+    // 发送CONNECT报文
+    ret = send_mqtt_packet(pClient, len, &connect_timer);
+    if (SUCCESS_RET != ret) {
+    	HAL_MutexUnlock(pClient->lock_write_buf);
+        return ret;
+    }
+    HAL_MutexUnlock(pClient->lock_write_buf);
+
+    // 阻塞等待CONNACK的报文,
+    ret = wait_for_read(pClient, CONNACK, &connect_timer, 0);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+
+    // 反序列化CONNACK包, 检查返回码
+    ret = _deserialize_connack_packet(&sessionPresent, &connack_rc, pClient->read_buf, pClient->read_buf_size);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+
+    if (MQTT_CONNECTION_ACCEPTED != connack_rc) {
+        return connack_rc;
+    }
+
+    set_client_conn_state(pClient, CONNECTED);
+    HAL_MutexLock(pClient->lock_generic);
+    pClient->was_manually_disconnected = 0;
+    pClient->is_ping_outstanding = 0;
+    countdown(&pClient->ping_timer, pClient->options.keep_alive_interval);
+    HAL_MutexUnlock(pClient->lock_generic);
+
+    return SUCCESS_RET;
+}
+
+int uiot_mqtt_connect(UIoT_Client *pClient, MQTTConnectParams *pParams) {
+    int ret;
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pParams, ERR_PARAM_INVALID);
+
+    // 如果MQTT连接已经建立, 不要重复发送CONNECT报文
+    if (get_client_conn_state(pClient)) {
+        return MQTT_ALREADY_CONNECTED;
+    }
+
+    ret = _mqtt_connect(pClient, pParams);
+
+    // 如果MQTT连接建立失败, 则断开底层的TLS连接
+    if (ret != SUCCESS_RET) {
+        pClient->network_stack.disconnect(&(pClient->network_stack));
+    }
+
+    return ret;
+}
+
+int uiot_mqtt_attempt_reconnect(UIoT_Client *pClient) {
+    int ret;
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+
+    LOG_INFO("attempt to reconnect...");
+
+    if (get_client_conn_state(pClient)) {
+        return MQTT_ALREADY_CONNECTED;
+    }
+
+    ret = uiot_mqtt_connect(pClient, &pClient->options);
+
+    if (!get_client_conn_state(pClient)) {
+        return ret;
+    }
+
+    ret = uiot_mqtt_resubscribe(pClient);
+    if (ret != SUCCESS_RET) {
+        return ret;
+    }
+
+    return MQTT_RECONNECTED;
+}
+
+int uiot_mqtt_disconnect(UIoT_Client *pClient) {
+    int ret;
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+
+    Timer timer;
+    uint32_t serialized_len = 0;
+
+    if (get_client_conn_state(pClient) == 0) {
+        return ERR_MQTT_NO_CONN;
+    }
+
+    // 1. 组disconnect包
+    HAL_MutexLock(pClient->lock_write_buf);
+    ret = serialize_packet_with_zero_payload(pClient->write_buf, pClient->write_buf_size, DISCONNECT, &serialized_len);
+    if (ret != SUCCESS_RET) {
+        HAL_MutexUnlock(pClient->lock_write_buf);
+        return ret;
+    }
+
+    init_timer(&timer);
+    countdown_ms(&timer, pClient->command_timeout_ms);
+
+    // 2. 发送disconnect包
+    if (serialized_len > 0) {
+        ret = send_mqtt_packet(pClient, serialized_len, &timer);
+        if (ret != SUCCESS_RET) {
+            HAL_MutexUnlock(pClient->lock_write_buf);
+            return ret;
+        }
+    }
+    HAL_MutexUnlock(pClient->lock_write_buf);
+
+    // 3. 断开底层TCP连接, 并修改相关标识位
+    pClient->network_stack.disconnect(&(pClient->network_stack));
+    set_client_conn_state(pClient, DISCONNECTED);
+    pClient->was_manually_disconnected = 1;
+
+    LOG_INFO("mqtt disconnect!");
+
+    return SUCCESS_RET;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+

+ 38 - 0
uiot/mqtt/src/mqtt_client_net.c

@@ -0,0 +1,38 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mqtt_client_net.h"
+
+/**
+ * @brief 初始化Network结构体
+ *
+ * @param pNetwork
+ * @param pConnectParams
+ * @return
+ */
+int uiot_mqtt_network_init(utils_network_pt pNetwork, const char *host, uint16_t port, uint16_t authmode, const char *ca_crt) {
+    int ret;
+    ret = utils_net_init(pNetwork, host, port, authmode, ca_crt);
+
+    return ret;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 357 - 0
uiot/mqtt/src/mqtt_client_publish.c

@@ -0,0 +1,357 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+
+#include "mqtt_client.h"
+
+/**
+ * @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 SUCCESS if successful, FAILURE if not
+ */
+static int _read_string_with_len(char **string, uint16_t *stringLen, unsigned char **pptr, unsigned char *enddata) {
+    int ret = FAILURE_RET;
+
+    /* the first two bytes are the length of the string */
+    /* enough length to read the integer? */
+    if (enddata - (*pptr) > 1) {
+        *stringLen = mqtt_read_uint16_t(pptr); /* increments pptr to point past length */
+		
+		if(*stringLen > UIOT_MQTT_RX_BUF_LEN){
+			LOG_ERROR("stringLen exceed UIOT_MQTT_RX_BUF_LEN");
+			return FAILURE_RET;
+		}
+		
+        if (&(*pptr)[*stringLen] <= enddata) {
+            *string = (char *) *pptr;
+            *pptr += *stringLen;
+            return SUCCESS_RET;
+        }
+    }
+
+    return ret;
+}
+
+/**
+  * 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 payload_len the length of the payload to be sent
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+static uint32_t _get_publish_packet_len(uint8_t qos, char *topicName, size_t payload_len) {
+    size_t len = 0;
+
+    len += 2 + strlen(topicName) + payload_len;
+    if (qos > 0) {
+        len += 2; /* packetid */
+    }
+    return (uint32_t) len;
+}
+
+static int _mask_push_pubInfo_to(UIoT_Client *c, int len, unsigned short msgId, ListNode **node)
+{
+    if (!c || !node) {
+        LOG_ERROR("invalid parameters!");
+        return ERR_MQTT_PUSH_TO_LIST_FAILED;
+    }
+
+    if ((len < 0) || (len > c->write_buf_size)) {
+        LOG_ERROR("the param of len is error!");
+        return FAILURE_RET;
+    }
+
+    HAL_MutexLock(c->lock_list_pub);
+
+    if (c->list_pub_wait_ack->len >= MAX_REPUB_NUM) {
+        HAL_MutexUnlock(c->lock_list_pub);
+        LOG_ERROR("more than %u elements in republish list. List overflow!", c->list_pub_wait_ack->len);
+        return FAILURE_RET;
+    }
+
+    UIoTPubInfo *repubInfo = (UIoTPubInfo *)HAL_Malloc(sizeof(UIoTPubInfo) + len);
+    if (NULL == repubInfo) {
+        HAL_MutexUnlock(c->lock_list_pub);
+        LOG_ERROR("memory malloc failed!");
+        return FAILURE_RET;
+    }
+
+    repubInfo->node_state = MQTT_NODE_STATE_NORMAL;
+    repubInfo->msg_id = msgId;
+    repubInfo->len = len;
+    init_timer(&repubInfo->pub_start_time);
+    countdown_ms(&repubInfo->pub_start_time, c->command_timeout_ms);
+
+    repubInfo->buf = (unsigned char *)repubInfo + sizeof(UIoTPubInfo);
+
+    memcpy(repubInfo->buf, c->write_buf, len);
+
+    *node = list_node_new(repubInfo);
+    if (NULL == *node) {
+        HAL_MutexUnlock(c->lock_list_pub);
+        LOG_ERROR("list_node_new failed!");
+        return FAILURE_RET;
+    }
+
+    list_rpush(c->list_pub_wait_ack, *node);
+
+    HAL_MutexUnlock(c->lock_list_pub);
+
+    return SUCCESS_RET;
+}
+
+/**
+  * 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 packet_id 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 payload_len 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 buf_len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success
+  */
+int deserialize_publish_packet(uint8_t *dup, QoS *qos, uint8_t *retained, uint16_t *packet_id, char **topicName,
+                               uint16_t *topicNameLen,unsigned char **payload, size_t *payload_len, unsigned char *buf, size_t buf_len) 
+{
+    POINTER_VALID_CHECK(dup, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(qos, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(retained, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(packet_id, ERR_PARAM_INVALID);
+
+    unsigned char header, type = 0;
+    unsigned char *curdata = buf;
+    unsigned char *enddata = NULL;
+    int ret;
+    uint32_t decodedLen = 0;
+    uint32_t readBytesLen = 0;
+
+    /* Publish header size is at least four bytes.
+     * Fixed header is two bytes.
+     * Variable header size depends on QoS And Topic Name.
+     * QoS level 0 doesn't have a message identifier (0 - 2 bytes)
+     * Topic Name length fields decide size of topic name field (at least 2 bytes)
+     * MQTT v3.1.1 Specification 3.3.1 */
+    if (4 > buf_len) {
+        return ERR_MQTT_BUFFER_TOO_SHORT;
+    }
+
+    header = mqtt_read_char(&curdata);
+    type = (header&MQTT_HEADER_TYPE_MASK)>>MQTT_HEADER_TYPE_SHIFT;
+    *dup  = (header&MQTT_HEADER_DUP_MASK)>>MQTT_HEADER_DUP_SHIFT;
+    *qos  = (QoS)((header&MQTT_HEADER_QOS_MASK)>>MQTT_HEADER_QOS_SHIFT);
+    *retained  = header&MQTT_HEADER_RETAIN_MASK;
+        
+    if (PUBLISH != type) {
+        return FAILURE_RET;
+    }
+
+    /* read remaining length */
+    ret = mqtt_read_packet_rem_len_form_buf(curdata, &decodedLen, &readBytesLen);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+    curdata += (readBytesLen);
+    enddata = curdata + decodedLen;
+
+    /* do we have enough data to read the protocol version byte? */
+    if (SUCCESS_RET != _read_string_with_len(topicName, topicNameLen, &curdata, enddata) || (0 > (enddata - curdata))) {
+        return FAILURE_RET;
+    }
+
+    if (QOS0 != *qos) {
+        *packet_id = mqtt_read_uint16_t(&curdata);
+    }
+
+    *payload_len = (size_t) (enddata - curdata);
+    *payload = curdata;
+
+    return SUCCESS_RET;
+}
+
+/**
+  * Serializes the ack packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buf_len the length in bytes of the supplied buffer
+  * @param packet_type the MQTT packet type: 1.PUBACK; 2.PUBREL; 3.PUBCOMP
+  * @param dup the MQTT dup flag
+  * @param packet_id the MQTT packet identifier
+  * @return serialized length, or error if 0
+  */
+int serialize_pub_ack_packet(unsigned char *buf, size_t buf_len, MessageTypes packet_type, uint8_t dup,
+                             uint16_t packet_id,
+                             uint32_t *serialized_len) {
+    POINTER_VALID_CHECK(buf, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(serialized_len, ERR_PARAM_INVALID);
+
+    unsigned char header = 0;
+    unsigned char *ptr = buf;
+    QoS requestQoS = (PUBREL == packet_type) ? QOS1 : QOS0;  // 详见 MQTT协议说明 3.6.1小结
+    int ret = mqtt_init_packet_header(&header, packet_type, requestQoS, dup, 0);
+
+    /* Minimum byte length required by ACK headers is
+     * 2 for fixed and 2 for variable part */
+    if (4 > buf_len) {
+        return ERR_MQTT_BUFFER_TOO_SHORT;
+    }
+
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+    mqtt_write_char(&ptr, header); /* write header */
+
+    ptr += mqtt_write_packet_rem_len(ptr, 2); /* write remaining length */
+    mqtt_write_uint_16(&ptr, packet_id);
+    *serialized_len = (uint32_t) (ptr - buf);
+
+    return SUCCESS_RET;
+}
+
+
+/**
+  * Serializes the supplied publish data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buf_len 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 packet_id integer - the MQTT packet identifier
+  * @param topicName MQTTString - the MQTT topic in the publish
+  * @param payload byte buffer - the MQTT publish payload
+  * @param payload_len integer - the length of the MQTT payload
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+static int _serialize_publish_packet(unsigned char *buf, size_t buf_len, uint8_t dup, QoS qos, uint8_t retained,
+                                     uint16_t packet_id,
+                                     char *topicName, unsigned char *payload, size_t payload_len,
+                                     uint32_t *serialized_len) {
+    POINTER_VALID_CHECK(buf, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(serialized_len, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(payload, ERR_PARAM_INVALID);
+
+    unsigned char *ptr = buf;
+    unsigned char header = 0;
+    uint32_t rem_len = 0;
+    int ret;
+
+    rem_len = _get_publish_packet_len(qos, topicName, payload_len);
+    if (get_mqtt_packet_len(rem_len) > buf_len) {
+        return ERR_MQTT_BUFFER_TOO_SHORT;
+    }
+
+    ret = mqtt_init_packet_header(&header, PUBLISH, qos, dup, retained);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+
+    mqtt_write_char(&ptr, header); /* write header */
+
+    ptr += mqtt_write_packet_rem_len(ptr, rem_len); /* write remaining length */;
+
+    mqtt_write_utf8_string(&ptr, topicName);   /* Variable Header: Topic Name */
+
+    if (qos > 0) {
+        mqtt_write_uint_16(&ptr, packet_id);  /* Variable Header: Topic Name */
+    }
+
+    memcpy(ptr, payload, payload_len);
+    ptr += payload_len;
+
+    *serialized_len = (uint32_t) (ptr - buf);
+
+    return SUCCESS_RET;
+}
+
+int uiot_mqtt_publish(UIoT_Client *pClient, char *topicName, PublishParams *pParams) {
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pParams, ERR_PARAM_INVALID);
+    STRING_PTR_VALID_CHECK(topicName, ERR_PARAM_INVALID);
+
+    Timer timer;
+    uint32_t len = 0;
+    int ret;
+
+    ListNode *node = NULL;
+    
+    size_t topicLen = strlen(topicName);
+    if (topicLen > MAX_SIZE_OF_CLOUD_TOPIC) {
+        return ERR_MAX_TOPIC_LENGTH;
+    }
+
+    if (pParams->qos == QOS2) {
+        LOG_ERROR("QoS2 is not supported currently");
+        return ERR_MQTT_QOS_NOT_SUPPORT;
+    }
+
+    if (!get_client_conn_state(pClient)) {
+        return ERR_MQTT_NO_CONN;
+    }
+
+    init_timer(&timer);
+    countdown_ms(&timer, pClient->command_timeout_ms);
+
+    HAL_MutexLock(pClient->lock_write_buf);
+    if (pParams->qos == QOS1) {
+        pParams->id = get_next_packet_id(pClient);
+        LOG_INFO("publish qos1 seq=%d|topicName=%s|payload=%s", pParams->id, topicName, (char *)pParams->payload);
+    }
+    else {
+        LOG_INFO("publish qos0 seq=%d|topicName=%s|payload=%s", pParams->id, topicName, (char *)pParams->payload);
+    }
+    ret = _serialize_publish_packet(pClient->write_buf, pClient->write_buf_size, 0, pParams->qos, pParams->retained, pParams->id,
+                                   topicName, (unsigned char *) pParams->payload, pParams->payload_len, &len);
+    if (SUCCESS_RET != ret) {
+    	HAL_MutexUnlock(pClient->lock_write_buf);
+        return ret;
+    }
+
+    if (pParams->qos > QOS0) {
+        ret = _mask_push_pubInfo_to(pClient, len, pParams->id, &node);
+        if (SUCCESS_RET != ret) {
+            LOG_ERROR("push publish into pubInfolist failed!");
+            HAL_MutexUnlock(pClient->lock_write_buf);
+            return ret;
+        }
+    }
+
+    /* send the publish packet */
+    ret = send_mqtt_packet(pClient, len, &timer);
+	if (SUCCESS_RET != ret) {
+		if (pParams->qos > QOS0) {
+			HAL_MutexLock(pClient->lock_list_pub);
+			list_remove(pClient->list_pub_wait_ack, node);
+			HAL_MutexUnlock(pClient->lock_list_pub);
+		}
+
+		HAL_MutexUnlock(pClient->lock_write_buf);
+		return ret;
+	}
+
+	HAL_MutexUnlock(pClient->lock_write_buf);
+
+    return pParams->id;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 209 - 0
uiot/mqtt/src/mqtt_client_subscribe.c

@@ -0,0 +1,209 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+
+#include "mqtt_client.h"
+
+/**
+  * 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
+  */
+static uint32_t _get_subscribe_packet_rem_len(uint32_t count, char **topicFilters) {
+    size_t i;
+    size_t len = 2; /* packetid */
+
+    for (i = 0; i < count; ++i) {
+        len += 2 + strlen(*topicFilters + i) + 1; /* length + topic + req_qos */
+    }
+
+    return (uint32_t) 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 buf_len the length in bytes of the supplied buffer
+  * @param dup integer - the MQTT dup flag
+  * @param packet_id 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
+  */
+static int _serialize_subscribe_packet(unsigned char *buf, size_t buf_len, uint8_t dup, uint16_t packet_id, uint32_t count,
+                                char **topicFilters, QoS *requestedQoSs, uint32_t *serialized_len) {
+    POINTER_VALID_CHECK(buf, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(serialized_len, ERR_PARAM_INVALID);
+
+    unsigned char *ptr = buf;
+    unsigned char header = 0;
+    uint32_t rem_len = 0;
+    uint32_t i = 0;
+    int ret;
+
+    // SUBSCRIBE报文的剩余长度 = 报文标识符(2 byte) + count * (长度字段(2 byte) + topicLen + qos(1 byte))
+    rem_len = _get_subscribe_packet_rem_len(count, topicFilters);
+    if (get_mqtt_packet_len(rem_len) > buf_len) {
+        return ERR_MQTT_BUFFER_TOO_SHORT;
+    }
+    // 初始化报文头部
+    ret = mqtt_init_packet_header(&header, SUBSCRIBE, QOS1, dup, 0);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+    // 写报文固定头部第一个字节
+    mqtt_write_char(&ptr, header);
+    // 写报文固定头部剩余长度字段
+    ptr += mqtt_write_packet_rem_len(ptr, rem_len);
+    // 写可变头部: 报文标识符
+    mqtt_write_uint_16(&ptr, packet_id);
+    // 写报文的负载部分数据
+    for (i = 0; i < count; ++i) {
+        mqtt_write_utf8_string(&ptr, *topicFilters + i);
+        mqtt_write_char(&ptr, (unsigned char) requestedQoSs[i]);
+    }
+
+    *serialized_len = (uint32_t) (ptr - buf);
+
+    return SUCCESS_RET;
+}
+
+int uiot_mqtt_subscribe(UIoT_Client *pClient, char *topicFilter, SubscribeParams *pParams) {
+    int ret;
+
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pParams, ERR_PARAM_INVALID);
+    STRING_PTR_VALID_CHECK(topicFilter, ERR_PARAM_INVALID);
+
+    Timer timer;
+    uint32_t len = 0;
+    uint16_t packet_id = 0;
+
+    ListNode *node = NULL;
+    
+    size_t topicLen = strlen(topicFilter);
+    if (topicLen > MAX_SIZE_OF_CLOUD_TOPIC) {
+        return ERR_MAX_TOPIC_LENGTH;
+    }
+
+    if (pParams->qos == QOS2) {
+        LOG_ERROR("QoS2 is not supported currently");
+        return ERR_MQTT_QOS_NOT_SUPPORT;
+    }
+    
+    if (!get_client_conn_state(pClient)) {
+        return ERR_MQTT_NO_CONN;
+    }
+
+    /* topic filter should be valid in the whole sub life */
+    char *topic_filter_stored = HAL_Malloc(topicLen + 1);
+    if (topic_filter_stored == NULL) {
+        LOG_ERROR("malloc failed");
+        return FAILURE_RET;
+    }
+    
+    strcpy(topic_filter_stored, topicFilter);
+    topic_filter_stored[topicLen] = 0;
+    
+    init_timer(&timer);
+    countdown_ms(&timer, pClient->command_timeout_ms);
+
+    HAL_MutexLock(pClient->lock_write_buf);
+    // 序列化SUBSCRIBE报文
+    packet_id = get_next_packet_id(pClient);
+    LOG_DEBUG("topicName=%s|packet_id=%d|Userdata=%s\n", topic_filter_stored, packet_id, (char *)pParams->user_data);
+
+    ret = _serialize_subscribe_packet(pClient->write_buf, pClient->write_buf_size, 0, packet_id, 1, &topic_filter_stored,
+                                     &pParams->qos, &len);
+    if (SUCCESS_RET != ret) {
+    	HAL_MutexUnlock(pClient->lock_write_buf);
+    	HAL_Free(topic_filter_stored);
+        return ret;
+    }
+
+    /* 等待 sub ack 列表中添加元素 */
+    SubTopicHandle sub_handle;
+    sub_handle.topic_filter = topic_filter_stored;
+    sub_handle.message_handler = pParams->on_message_handler;
+    sub_handle.qos = pParams->qos;
+    sub_handle.message_handler_data = pParams->user_data;
+
+    ret = push_sub_info_to(pClient, len, (unsigned int)packet_id, SUBSCRIBE, &sub_handle, &node);
+    if (SUCCESS_RET != ret) {
+        LOG_ERROR("push publish into to pubInfolist failed!");
+        HAL_MutexUnlock(pClient->lock_write_buf);
+        HAL_Free(topic_filter_stored);
+        return ret;
+    }
+    
+    // 发送SUBSCRIBE报文
+    ret = send_mqtt_packet(pClient, len, &timer);
+    if (SUCCESS_RET != ret) {
+        HAL_MutexLock(pClient->lock_list_sub);
+        list_remove(pClient->list_sub_wait_ack, node);
+        HAL_MutexUnlock(pClient->lock_list_sub);
+
+    	HAL_MutexUnlock(pClient->lock_write_buf);
+    	HAL_Free(topic_filter_stored);
+        return ret;
+    }
+
+    HAL_MutexUnlock(pClient->lock_write_buf);
+
+    return packet_id;
+}
+
+int uiot_mqtt_resubscribe(UIoT_Client *pClient) {
+    int ret;
+
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+
+    uint32_t itr = 0;
+    char *topic = NULL;
+    SubscribeParams temp_param;
+
+    if (!get_client_conn_state(pClient)) {
+        return ERR_MQTT_NO_CONN;
+    }
+
+    for (itr = 0; itr < MAX_SUB_TOPICS; itr++) {
+        topic = (char *) pClient->sub_handles[itr].topic_filter;
+        if (topic == NULL) {
+            continue;
+        }
+        temp_param.on_message_handler = pClient->sub_handles[itr].message_handler;
+        temp_param.qos = pClient->sub_handles[itr].qos;
+        temp_param.user_data = pClient->sub_handles[itr].message_handler_data;
+
+        ret = uiot_mqtt_subscribe(pClient, topic, &temp_param);
+        if (ret < 0) {
+        	LOG_ERROR("resubscribe failed %d, topic: %s", ret, topic);
+            return ret;
+        }
+    }
+
+    return SUCCESS_RET;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 186 - 0
uiot/mqtt/src/mqtt_client_unsubscribe.c

@@ -0,0 +1,186 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+
+#include "mqtt_client.h"
+
+/**
+  * 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
+  */
+static uint32_t _get_unsubscribe_packet_rem_len(uint32_t count, char **topicFilters) {
+    size_t i;
+    size_t len = 2; /* packetid */
+
+    for (i = 0; i < count; ++i) {
+        len += 2 + strlen(*topicFilters + i); /* length + topic*/
+    }
+
+    return (uint32_t) 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 buf_len the length in bytes of the data in the supplied buffer
+  * @param dup integer - the MQTT dup flag
+  * @param packet_id integer - the MQTT packet identifier
+  * @param count - number of members in the topicFilters array
+  * @param topicFilters - array of topic filter names
+  * @param serialized_len - the length of the serialized data
+  * @return int indicating function execution status
+  */
+static int _serialize_unsubscribe_packet(unsigned char *buf, size_t buf_len,
+                                         uint8_t dup, uint16_t packet_id,
+                                         uint32_t count, char **topicFilters,
+                                         uint32_t *serialized_len) {
+    POINTER_VALID_CHECK(buf, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(serialized_len, ERR_PARAM_INVALID);
+
+    unsigned char *ptr = buf;
+    unsigned char header = 0;
+    uint32_t rem_len = 0;
+    uint32_t i = 0;
+    int ret;
+
+    rem_len = _get_unsubscribe_packet_rem_len(count, topicFilters);
+    if (get_mqtt_packet_len(rem_len) > buf_len) {
+        return ERR_MQTT_BUFFER_TOO_SHORT;
+    }
+
+    ret = mqtt_init_packet_header(&header, UNSUBSCRIBE, QOS1, dup, 0);
+    if (SUCCESS_RET != ret) {
+        return ret;
+    }
+    mqtt_write_char(&ptr, header); /* write header */
+
+    ptr += mqtt_write_packet_rem_len(ptr, rem_len); /* write remaining length */
+
+    mqtt_write_uint_16(&ptr, packet_id);
+
+    for (i = 0; i < count; ++i) {
+        mqtt_write_utf8_string(&ptr, *topicFilters + i);
+    }
+
+    *serialized_len = (uint32_t) (ptr - buf);
+
+    return SUCCESS_RET;
+}
+
+int uiot_mqtt_unsubscribe(UIoT_Client *pClient, char *topicFilter) {
+    int ret;
+
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    STRING_PTR_VALID_CHECK(topicFilter, ERR_PARAM_INVALID);
+
+    int i = 0;
+    Timer timer;
+    uint32_t len = 0;
+    uint16_t packet_id = 0;
+    bool suber_exists = false;
+
+    ListNode *node = NULL;
+
+    size_t topicLen = strlen(topicFilter);
+    if (topicLen > MAX_SIZE_OF_CLOUD_TOPIC) {
+        return ERR_MAX_TOPIC_LENGTH;
+    }
+    
+    /* Remove from message handler array */
+    HAL_MutexLock(pClient->lock_generic);
+    for (i = 0; i < MAX_SUB_TOPICS; ++i) {        
+        if ((pClient->sub_handles[i].topic_filter != NULL && !strcmp(pClient->sub_handles[i].topic_filter, topicFilter))
+            || strstr(topicFilter,"/#") != NULL || strstr(topicFilter,"/+") != NULL) {
+            /* Free the topic filter malloced in uiot_mqtt_subscribe */
+            HAL_Free((void *)pClient->sub_handles[i].topic_filter);
+            pClient->sub_handles[i].topic_filter = NULL;
+            /* We don't want to break here, if the same topic is registered
+             * with 2 callbacks. Unlikely scenario */
+            suber_exists = true;
+        }
+    }
+    HAL_MutexUnlock(pClient->lock_generic);
+
+    if (suber_exists == false) {
+        LOG_ERROR("subscription does not exists: %s", topicFilter);
+        return ERR_MQTT_UNSUB_FAILED;
+    }
+
+    if (!get_client_conn_state(pClient)) {
+        return ERR_MQTT_NO_CONN;
+    }
+
+    /* topic filter should be valid in the whole sub life */
+    char *topic_filter_stored = HAL_Malloc(topicLen + 1);
+    if (topic_filter_stored == NULL) {
+        LOG_ERROR("malloc failed");
+        return FAILURE_RET;
+    }
+    strcpy(topic_filter_stored, topicFilter);
+    topic_filter_stored[topicLen] = 0;
+
+    init_timer(&timer);
+    countdown_ms(&timer, pClient->command_timeout_ms);
+
+    HAL_MutexLock(pClient->lock_write_buf);
+    packet_id = get_next_packet_id(pClient);
+    ret = _serialize_unsubscribe_packet(pClient->write_buf, pClient->write_buf_size, 0, packet_id, 1, &topic_filter_stored,
+                                       &len);
+    if (SUCCESS_RET != ret) {
+    	HAL_MutexUnlock(pClient->lock_write_buf);
+    	HAL_Free(topic_filter_stored);
+        return ret;
+    }
+
+    SubTopicHandle sub_handle;
+    sub_handle.topic_filter = topic_filter_stored;
+    sub_handle.message_handler = NULL;
+    sub_handle.message_handler_data = NULL;
+
+    ret = push_sub_info_to(pClient, len, (unsigned int)packet_id, UNSUBSCRIBE, &sub_handle, &node);
+    if (SUCCESS_RET != ret) {
+        LOG_ERROR("push publish into to pubInfolist failed: %d", ret);
+        HAL_MutexUnlock(pClient->lock_write_buf);
+        HAL_Free(topic_filter_stored);
+        return ret;
+    }
+
+    /* send the unsubscribe packet */
+    ret = send_mqtt_packet(pClient, len, &timer);
+    if (SUCCESS_RET != ret) {
+        HAL_MutexLock(pClient->lock_list_sub);
+        list_remove(pClient->list_sub_wait_ack, node);
+        HAL_MutexUnlock(pClient->lock_list_sub);
+
+    	HAL_MutexUnlock(pClient->lock_write_buf);
+    	HAL_Free(topic_filter_stored);
+        return ret;
+    }
+
+    HAL_MutexUnlock(pClient->lock_write_buf);
+
+    return packet_id;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 443 - 0
uiot/mqtt/src/mqtt_client_yield.c

@@ -0,0 +1,443 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mqtt_client.h"
+
+#define MQTT_PING_RETRY_TIMES   2
+
+static void _iot_disconnect_callback(UIoT_Client *pClient)
+{
+    if (NULL != pClient->event_handler.h_fp) {
+        MQTTEventMsg msg;
+        msg.event_type = MQTT_EVENT_DISCONNECT;
+        msg.msg = NULL;
+
+        pClient->event_handler.h_fp(pClient, pClient->event_handler.context, &msg);
+    }
+}
+
+static void _reconnect_callback(UIoT_Client* pClient) 
+{
+    if (NULL != pClient->event_handler.h_fp) {
+        MQTTEventMsg msg;
+        msg.event_type = MQTT_EVENT_RECONNECT;
+        msg.msg = NULL;
+
+        pClient->event_handler.h_fp(pClient, pClient->event_handler.context, &msg);
+    }
+}
+
+/**
+ * @brief 处理非手动断开连接的情况
+ *
+ * @param pClient
+ * @return
+ */
+static int _handle_disconnect(UIoT_Client *pClient) {
+    int ret;
+    
+    if (0 == get_client_conn_state(pClient)) {
+        return ERR_MQTT_NO_CONN;
+    }
+
+    ret = uiot_mqtt_disconnect(pClient);
+    // 若断开连接失败, 强制断开底层TLS层连接
+    if (ret != SUCCESS_RET) {
+        pClient->network_stack.disconnect(&(pClient->network_stack));
+        set_client_conn_state(pClient, DISCONNECTED);
+    }
+
+    LOG_ERROR("disconnect MQTT for some reasons..");
+    
+    _iot_disconnect_callback(pClient);
+
+    // 非手动断开连接
+    pClient->was_manually_disconnected = 0;
+    return ERR_MQTT_NO_CONN;
+}
+
+/**
+ * @brief 处理自动重连的相关逻辑
+ *
+ * @param pClient
+ * @return
+ */
+static int _handle_reconnect(UIoT_Client *pClient) {
+    int ret = MQTT_RECONNECTED;
+
+    // 自动重连等待时间还未过期, 还未到重连的时候, 返回正在进行重连
+    if (!has_expired(&(pClient->reconnect_delay_timer))) {
+        return ERR_MQTT_ATTEMPTING_RECONNECT;
+    }
+
+    ret = uiot_mqtt_attempt_reconnect(pClient);
+    if (ret == MQTT_RECONNECTED) {
+        LOG_ERROR("attempt to reconnect success.");
+        _reconnect_callback(pClient);
+        return ret;
+    }
+    else {
+        LOG_ERROR("attempt to reconnect failed, errCode: %d", ret);
+        ret = ERR_MQTT_ATTEMPTING_RECONNECT;
+    }
+
+    pClient->current_reconnect_wait_interval *= 2;
+
+    if (MAX_RECONNECT_WAIT_INTERVAL < pClient->current_reconnect_wait_interval) {
+        if (ENABLE_INFINITE_RECONNECT) {
+            pClient->current_reconnect_wait_interval = MAX_RECONNECT_WAIT_INTERVAL;
+        } else {
+            return ERR_MQTT_RECONNECT_TIMEOUT;
+        }
+    }
+    countdown_ms(&(pClient->reconnect_delay_timer), pClient->current_reconnect_wait_interval);
+
+    return ret;
+}
+
+/**
+ * @brief 处理与服务器维持心跳的相关逻辑
+ *
+ * @param pClient
+ * @return
+ */
+static int _mqtt_keep_alive(UIoT_Client *pClient)
+{
+    int ret;
+    Timer timer;
+    uint32_t serialized_len = 0;
+
+    if (0 == pClient->options.keep_alive_interval) {
+        return SUCCESS_RET;
+    }
+
+    if (!has_expired(&pClient->ping_timer)) {
+        return SUCCESS_RET;
+    }
+
+    if (pClient->is_ping_outstanding >= MQTT_PING_RETRY_TIMES) {
+        //Reaching here means we haven't received any MQTT packet for a long time (keep_alive_interval)
+        LOG_ERROR("Fail to recv MQTT msg. Something wrong with the connection.");
+        ret = _handle_disconnect(pClient);
+        return ret;
+    }
+
+    /* there is no ping outstanding - send one */    
+    HAL_MutexLock(pClient->lock_write_buf);
+    ret = serialize_packet_with_zero_payload(pClient->write_buf, pClient->write_buf_size, PINGREQ, &serialized_len);
+    if (SUCCESS_RET != ret) {
+        HAL_MutexUnlock(pClient->lock_write_buf);
+        return ret;
+    }
+
+    /* send the ping packet */
+    int i = 0;
+    init_timer(&timer);    
+    do {
+        countdown_ms(&timer, pClient->command_timeout_ms);
+        ret = send_mqtt_packet(pClient, serialized_len, &timer);
+    } while (SUCCESS_RET != ret && (i++ < 3));
+    
+    if (SUCCESS_RET != ret) {
+        HAL_MutexUnlock(pClient->lock_write_buf);        
+        //If sending a PING fails, probably the connection is not OK and we decide to disconnect and begin reconnection attempts
+        LOG_ERROR("Fail to send PING request. Something wrong with the connection.");
+        ret = _handle_disconnect(pClient);
+        return ret;
+    }
+    HAL_MutexUnlock(pClient->lock_write_buf);
+    
+    HAL_MutexLock(pClient->lock_generic);
+    pClient->is_ping_outstanding++;
+    /* start a timer to wait for PINGRESP from server */
+    countdown(&pClient->ping_timer, Min(5, pClient->options.keep_alive_interval/2));
+    HAL_MutexUnlock(pClient->lock_generic);
+    LOG_DEBUG("PING request %u has been sent...", pClient->is_ping_outstanding);
+
+    return SUCCESS_RET;
+}
+
+int uiot_mqtt_yield(UIoT_Client *pClient, uint32_t timeout_ms) {
+    int ret = SUCCESS_RET;
+    Timer timer;
+    uint8_t packet_type;
+
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+    NUMERIC_VALID_CHECK(timeout_ms, ERR_PARAM_INVALID);
+
+    // 1. 检查连接是否已经手动断开
+    if (!get_client_conn_state(pClient) && pClient->was_manually_disconnected == 1) {
+        return MQTT_MANUALLY_DISCONNECTED;
+    }
+
+    // 2. 检查连接是否断开, 自动连接是否开启
+    if (!get_client_conn_state(pClient) && pClient->options.auto_connect_enable == 0) {
+        return ERR_MQTT_NO_CONN;
+    }
+
+    init_timer(&timer);
+    countdown_ms(&timer, timeout_ms);
+
+    // 3. 循环读取消息以及心跳包管理
+    while (!has_expired(&timer)) {
+        if (!get_client_conn_state(pClient)) {
+            if (pClient->current_reconnect_wait_interval > MAX_RECONNECT_WAIT_INTERVAL) {
+                ret = ERR_MQTT_RECONNECT_TIMEOUT;
+                break;
+            }
+            ret = _handle_reconnect(pClient);
+
+            continue;
+        }        
+
+        //防止任务独占CPU时间过长
+        HAL_SleepMs(10);
+
+        ret = cycle_for_read(pClient, &timer, &packet_type, 0);
+
+        if (ret == SUCCESS_RET) {
+            /* check list of wait publish ACK to remove node that is ACKED or timeout */
+            uiot_mqtt_pub_info_proc(pClient);
+
+            /* check list of wait subscribe(or unsubscribe) ACK to remove node that is ACKED or timeout */
+            uiot_mqtt_sub_info_proc(pClient);
+
+            ret = _mqtt_keep_alive(pClient);
+        }          
+        else if (ret == ERR_SSL_READ_TIMEOUT || ret == ERR_SSL_READ_FAILED ||
+                 ret == ERR_TCP_PEER_SHUTDOWN || ret == ERR_TCP_READ_FAILED){
+        	LOG_ERROR("network read failed, ret: %d. MQTT Disconnect.", ret);
+        	ret = _handle_disconnect(pClient);
+        }
+        else if(ret == FAILURE_RET) //最后一次读肯定失败,因为没有数据了
+        {
+            ret = SUCCESS_RET;
+        }
+
+        if (ret == ERR_MQTT_NO_CONN) {
+            pClient->counter_network_disconnected++;
+
+            if (pClient->options.auto_connect_enable == 1) {
+                pClient->current_reconnect_wait_interval = MIN_RECONNECT_WAIT_INTERVAL;
+                countdown_ms(&(pClient->reconnect_delay_timer), pClient->current_reconnect_wait_interval);
+
+                // 如果超时时间到了,则会直接返回
+                ret = ERR_MQTT_ATTEMPTING_RECONNECT;
+            } else {
+                break;
+            }
+        } else if (ret != SUCCESS_RET) {
+            break;
+        }
+        
+    }
+
+    return ret;
+}
+
+/**
+ * @brief puback等待超时检测
+ *
+ * @param pClient MQTTClient对象
+ *
+ */
+int uiot_mqtt_pub_info_proc(UIoT_Client *pClient)
+{
+    POINTER_VALID_CHECK(pClient, ERR_PARAM_INVALID);
+
+    HAL_MutexLock(pClient->lock_list_pub);
+    do {
+        if (0 == pClient->list_pub_wait_ack->len) {
+            break;
+        }
+
+        ListIterator *iter;
+        ListNode *node = NULL;
+        ListNode *temp_node = NULL;
+
+        if (NULL == (iter = list_iterator_new(pClient->list_pub_wait_ack, LIST_TAIL))) {
+            LOG_ERROR("new list failed");
+            break;
+        }
+
+        for (;;) {
+            node = list_iterator_next(iter);
+
+            if (NULL != temp_node) {
+                list_remove(pClient->list_pub_wait_ack, temp_node);
+                temp_node = NULL;
+            }
+
+            if (NULL == node) {
+                break; /* end of list */
+            }
+
+            UIoTPubInfo *repubInfo = (UIoTPubInfo *) node->val;
+            if (NULL == repubInfo) {
+                LOG_ERROR("node's value is invalid!");
+                temp_node = node;
+                continue;
+            }
+
+            /* remove invalid node */
+            if (MQTT_NODE_STATE_INVALID == repubInfo->node_state) {
+                temp_node = node;
+                continue;
+            }
+
+            if (!pClient->is_connected) {
+                continue;
+            }
+
+            /* check the request if timeout or not */
+            if (left_ms(&repubInfo->pub_start_time) > 0) {
+                continue;
+            }
+
+            /* If wait ACK timeout, republish */
+            HAL_MutexUnlock(pClient->lock_list_pub);
+            /* 重发机制交给上层用户二次开发, 这里先把超时的节点从列表中移除 */
+            temp_node = node;
+
+            countdown_ms(&repubInfo->pub_start_time, pClient->command_timeout_ms);
+            HAL_MutexLock(pClient->lock_list_pub);
+
+                /* 通知外部网络已经断开 */
+            if (NULL != pClient->event_handler.h_fp) {
+                MQTTEventMsg msg;
+                msg.event_type = MQTT_EVENT_PUBLISH_TIMEOUT;
+                msg.msg = (void *)(uintptr_t)repubInfo->msg_id;
+                pClient->event_handler.h_fp(pClient, pClient->event_handler.context, &msg);
+            }
+        }
+
+        list_iterator_destroy(iter);
+
+    } while (0);
+
+    HAL_MutexUnlock(pClient->lock_list_pub);
+
+    return SUCCESS_RET;
+}
+
+/**
+ * @brief suback等待超时检测
+ *
+ * @param pClient MQTTClient对象
+ *
+ */
+int uiot_mqtt_sub_info_proc(UIoT_Client *pClient)
+{
+    int ret = SUCCESS_RET;
+
+    if (!pClient) {
+        return ERR_PARAM_INVALID;
+    }
+
+    HAL_MutexLock(pClient->lock_list_sub);
+    do {
+        if (0 == pClient->list_sub_wait_ack->len) {
+            break;
+        }
+
+        ListIterator *iter;
+        ListNode *node = NULL;
+        ListNode *temp_node = NULL;
+        uint16_t packet_id = 0;
+        MessageTypes msg_type;
+
+        if (NULL == (iter = list_iterator_new(pClient->list_sub_wait_ack, LIST_TAIL))) {
+            LOG_ERROR("new list failed");
+            HAL_MutexUnlock(pClient->lock_list_sub);
+            return SUCCESS_RET;
+        }
+
+        for (;;) {
+            node = list_iterator_next(iter);
+
+            if (NULL != temp_node) {
+                list_remove(pClient->list_sub_wait_ack, temp_node);
+                temp_node = NULL;
+            }
+
+            if (NULL == node) {
+                break; /* end of list */
+            }
+
+            UIoTSubInfo *sub_info = (UIoTSubInfo *) node->val;
+            if (NULL == sub_info) {
+                LOG_ERROR("node's value is invalid!");
+                temp_node = node;
+                continue;
+            }
+
+            /* remove invalid node */
+            if (MQTT_NODE_STATE_INVALID == sub_info->node_state) {
+                temp_node = node;
+                continue;
+            }
+
+            if (pClient->is_connected <= 0) {
+                continue;
+            }
+
+            /* check the request if timeout or not */
+            if (left_ms(&sub_info->sub_start_time) > 0) {
+                continue;
+            }
+
+            /* When arrive here, it means timeout to wait ACK */
+            packet_id = sub_info->msg_id;
+            msg_type = sub_info->type;
+
+            /* Wait MQTT SUBSCRIBE ACK timeout */
+            if (NULL != pClient->event_handler.h_fp) {
+                MQTTEventMsg msg;
+
+                if (SUBSCRIBE == msg_type) {
+                    /* subscribe timeout */
+                    msg.event_type = MQTT_EVENT_SUBSCRIBE_TIMEOUT;
+                    msg.msg = (void *)(uintptr_t)packet_id;
+                } else { 
+                    /* unsubscribe timeout */
+                    msg.event_type = MQTT_EVENT_UNSUBSCRIBE_TIMEOUT;
+                    msg.msg = (void *)(uintptr_t)packet_id;
+                }
+
+                pClient->event_handler.h_fp(pClient, pClient->event_handler.context, &msg);
+            }
+
+            if (NULL != sub_info->handler.topic_filter)
+                HAL_Free((void *)(sub_info->handler.topic_filter));
+                
+            temp_node = node;
+        }
+
+        list_iterator_destroy(iter);
+
+    } while (0);
+
+    HAL_MutexUnlock(pClient->lock_list_sub);
+
+    return ret;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 51 - 0
uiot/ota/include/ota_config.h

@@ -0,0 +1,51 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_OTA_CONFIG_H_
+#define C_SDK_OTA_CONFIG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TYPE_FIELD 				    "Method"
+#define MD5_FIELD				    "Payload.MD5"
+#define VERSION_FIELD			    "Payload.Version"
+#define URL_FIELD				    "Payload.URL"
+#define SIZE_FIELD			        "Payload.Size"
+#define UPDATE_FIRMWARE_METHOD      "update_firmware"
+
+#define REPORT_PROGRESS_MSG_TEMPLATE      "{\"Method\": \"report_progress\", \"Payload\": {\"State\":\"%s\", \"Percent\":%d}}"
+#define REPORT_SUCCESS_MSG_TEMPLATE       "{\"Method\": \"report_success\", \"Payload\":{\"Version\":\"%s\"}}"
+#define REPORT_FAIL_MSG_TEMPLATE          "{\"Method\": \"report_fail\", \"Payload\": {\"ErrCode\": %d}}"
+#define REPORT_VERSION_MSG_TEMPLATE       "{\"Method\": \"report_version\", \"Payload\":{\"Version\":\"%s\"}}"
+#define REQUEST_FIRMWARE_MSG_TEMPLATE     "{\"Method\": \"request_firmware\", \"Payload\":{\"Version\":\"%s\"}}"
+
+#define OTA_VERSION_STR_LEN_MIN     (1)
+#define OTA_VERSION_STR_LEN_MAX     (32)
+#define OTA_UPSTREAM_MSG_BUF_LEN    (129)
+#define OTA_TOPIC_BUF_LEN           (129)
+
+#define OTA_UPSTREAM_TOPIC_TYPE      "upstream"
+#define OTA_DOWNSTREAM_TOPIC_TYPE    "downstream"
+#define OTA_TOPIC_TEMPLATE           "/$system/%s/%s/ota/%s"
+
+#define OTA_REPORT_PROGRESS_INTERVAL 5  //下载固件过程中,上报progress的时间间隔,单位: s
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //C_SDK_OTA_CONFIG_H_

+ 97 - 0
uiot/ota/include/ota_internal.h

@@ -0,0 +1,97 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_OTA_INTERNAL_H_
+#define C_SDK_OTA_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include "uiot_export_ota.h"
+
+typedef enum {
+
+    OTA_REPORT_UNDEFINED_ERROR = -6,
+    OTA_REPORT_FIRMWARE_BURN_FAILED = -5,
+    OTA_REPORT_MD5_MISMATCH = -4,
+    OTA_REPORT_DOWNLOAD_TIMEOUT = -3,
+    OTA_REPORT_SIGNATURE_EXPIRED = -2,
+    OTA_REPORT_FIRMWARE_NOT_EXIST = -1,
+    OTA_REPORT_NONE = 0,
+    OTA_REPORT_DOWNLOADING = 1,
+    OTA_REPORT_BURNING = 2,
+    OTA_REPORT_SUCCESS = 3,
+    OTA_REQUEST_FIRMWARE = 4,
+    OTA_REPORT_VERSION = 5,
+
+} IOT_OTA_UpstreamMsgType;
+
+/* OTA状态 */
+typedef enum {
+
+    OTA_STATE_UNINITED = 0,  /* 未初始化 */
+    OTA_STATE_INITED,        /* 初始化完成 */
+    OTA_STATE_FETCHING,      /* 正在下载固件 */
+    OTA_STATE_FETCHED,       /* 固件下载完成 */
+    OTA_STATE_DISCONNECTED   /* 连接已经断开 */
+
+} IOT_OTA_State;
+
+// OTA Signal Channel
+typedef void (*OnOTAMessageCallback)(void *pContext, const char *msg, uint32_t msgLen);
+
+void *osc_init(const char *product_sn, const char *device_sn, void *channel, OnOTAMessageCallback callback,
+               void *context);
+
+int osc_deinit(void *handle);
+
+int osc_report_progress(void *handle, const char *msg);
+
+int osc_upstream_publish(void *handle, const char *msg);
+
+// OTA Fetch Channel
+void *ofc_init(const char *url);
+
+int32_t ofc_connect(void *handle);
+
+int32_t ofc_fetch(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s);
+
+int ofc_deinit(void *handle);
+
+// ota_lib
+void *ota_lib_md5_init(void);
+
+void ota_lib_md5_update(void *md5, const char *buf, size_t buf_len);
+
+void ota_lib_md5_finalize(void *md5, char *output_str);
+
+void ota_lib_md5_deinit(void *md5);
+
+int ota_lib_get_msg_type(char *json, char **type);
+
+int ota_lib_get_params(char *json, char **url, char **version, char **md5,
+                       uint32_t *fileSize);
+
+int ota_lib_gen_upstream_msg(char *buf, size_t bufLen, const char *version, int progress,
+                             IOT_OTA_UpstreamMsgType reportType);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //C_SDK_OTA_INTERNAL_H_

+ 337 - 0
uiot/ota/src/ota_client.c

@@ -0,0 +1,337 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "uiot_defs.h"
+#include "uiot_export_ota.h"
+#include "uiot_internal.h"
+
+#include "ota_config.h"
+#include "ota_internal.h"
+
+#include "utils_timer.h"
+
+
+typedef struct  {
+    uint32_t 				id;                		/* message id */
+    IOT_OTA_State 		    state;   				/* OTA state */
+    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 					*url;                 	/* point to URL */
+    char 					*version;              	/* point to version */
+    char 					*md5sum;            	/* MD5 string */
+
+    void 					*md5;                  	/* MD5 handle */
+    void 					*ch_signal;           	/* channel handle of signal exchanged with OTA server */
+    void 					*ch_fetch;             	/* channel handle of download */
+
+    int 					err;                    /* last error code */
+
+    Timer                   report_timer;
+} OTA_Struct_t;
+
+extern int http_ota_fw_download(const char* uri);
+
+static void _ota_callback(void *pContext, const char *msg, uint32_t msg_len) {
+    char *msg_method = NULL;
+    char *msg_str = NULL;
+
+    OTA_Struct_t *h_ota = (OTA_Struct_t *) pContext;
+
+    if (h_ota == NULL || msg == NULL) {
+        LOG_ERROR("pointer is NULL");
+        return;
+    }
+
+    if (h_ota->state == OTA_STATE_FETCHING) {
+        LOG_INFO("In OTA_STATE_FETCHING state");
+        return;
+    }
+
+    if (NULL == (msg_str = HAL_Malloc(msg_len + 1))) {
+        LOG_ERROR("HAL_Malloc failed!");
+        return;
+    }
+
+    HAL_Snprintf(msg_str, msg_len + 1, "%s", msg);
+
+    if (SUCCESS_RET != ota_lib_get_msg_type(msg_str, &msg_method)) {
+        LOG_ERROR("Get message type failed!");
+        goto do_exit;
+    }
+
+    if (strcmp(msg_method, UPDATE_FIRMWARE_METHOD) != 0) {
+        LOG_ERROR("Message type error! type: %s", msg_method);
+        goto do_exit;
+    }
+
+    if (SUCCESS_RET != ota_lib_get_params(msg_str, &h_ota->url, &h_ota->version,
+                                &h_ota->md5sum, &h_ota->size_file)) {
+        LOG_ERROR("Get firmware parameter failed");
+        goto do_exit;
+    }
+
+    char **argurl = NULL;
+    argurl[1] = h_ota->url;
+    http_ota(2, argurl);
+
+do_exit:
+    HAL_Free(msg_str);
+    HAL_Free(msg_method);
+    return;
+}
+
+
+int IOT_OTA_ReportProgress(void *handle, int progress, IOT_OTA_ProgressState state)
+{
+    POINTER_VALID_CHECK(handle, ERR_OTA_INVALID_PARAM);
+
+    int ret;
+    char *msg_report;
+    OTA_Struct_t *h_ota = (OTA_Struct_t *) handle;
+
+    if (OTA_STATE_UNINITED == h_ota->state) {
+        LOG_ERROR("handle is uninitialized");
+        h_ota->err = ERR_OTA_INVALID_STATE;
+        return ERR_OTA_INVALID_STATE;
+    }
+
+    if (progress < 0 || progress > 100) {
+        LOG_ERROR("progress is a invalid parameter");
+        h_ota->err = ERR_OTA_INVALID_PARAM;
+        return ERR_OTA_INVALID_PARAM;
+    }
+
+    if (NULL == (msg_report = HAL_Malloc(OTA_UPSTREAM_MSG_BUF_LEN))) {
+        LOG_ERROR("allocate memory for msg_report failed");
+        h_ota->err = ERR_OTA_NO_MEMORY;
+        return ERR_OTA_NO_MEMORY;
+    }
+
+    ret = ota_lib_gen_upstream_msg(msg_report, OTA_UPSTREAM_MSG_BUF_LEN, h_ota->version, progress, (IOT_OTA_UpstreamMsgType)state);
+    if (SUCCESS_RET != ret) {
+        LOG_ERROR("generate reported message failed");
+        h_ota->err = ret;
+        goto do_exit;
+    }
+
+    ret = osc_report_progress(h_ota->ch_signal, msg_report);
+    if (ret < 0) {
+        LOG_ERROR("Report progress failed");
+        h_ota->err = ret;
+        goto do_exit;
+    }
+
+do_exit:
+    if (NULL != msg_report) {
+        HAL_Free(msg_report);
+    }
+    return ret;
+}
+
+
+static int send_upstream_msg_with_version(void *handle, const char *version, IOT_OTA_UpstreamMsgType reportType)
+{
+    POINTER_VALID_CHECK(handle, ERR_OTA_INVALID_PARAM);
+    POINTER_VALID_CHECK(version, ERR_OTA_INVALID_PARAM);
+
+    int ret, len;
+    char *msg_upstream;
+    OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
+
+    if (OTA_STATE_UNINITED == h_ota->state) {
+        LOG_ERROR("handle is uninitialized");
+        h_ota->err = ERR_OTA_INVALID_STATE;
+        return ERR_OTA_INVALID_STATE;
+    }
+
+    len = strlen(version);
+    if ((len < OTA_VERSION_STR_LEN_MIN) || (len > OTA_VERSION_STR_LEN_MAX)) {
+        LOG_ERROR("version string is invalid: must be [1, 32] chars");
+        h_ota->err = ERR_OTA_INVALID_PARAM;
+        return ERR_OTA_INVALID_PARAM;
+    }
+
+    if (NULL == (msg_upstream = HAL_Malloc(OTA_UPSTREAM_MSG_BUF_LEN))) {
+        LOG_ERROR("allocate for msg_informed failed");
+        h_ota->err = ERR_OTA_NO_MEMORY;
+        return ERR_OTA_NO_MEMORY;
+    }
+
+    ret = ota_lib_gen_upstream_msg(msg_upstream, OTA_UPSTREAM_MSG_BUF_LEN, version, 0, reportType);
+    if (SUCCESS_RET != ret) {
+        LOG_ERROR("generate upstream message failed");
+        h_ota->err = ret;
+        goto do_exit;
+    }
+
+    ret = osc_upstream_publish(h_ota->ch_signal, msg_upstream);
+    if (ret < 0) {
+        LOG_ERROR("Report result failed");
+        h_ota->err = ret;
+        goto do_exit;
+    }
+
+do_exit:
+    if (NULL != msg_upstream) {
+        HAL_Free(msg_upstream);
+    }
+    return ret;
+}
+
+
+void *IOT_OTA_Init(const char *product_sn, const char *device_sn, void *ch_signal)
+{
+    POINTER_VALID_CHECK(product_sn, NULL);
+    POINTER_VALID_CHECK(device_sn, NULL);
+    POINTER_VALID_CHECK(ch_signal, NULL);
+
+    OTA_Struct_t *h_ota = NULL;
+
+    if (NULL == (h_ota = HAL_Malloc(sizeof(OTA_Struct_t)))) {
+        LOG_ERROR("allocate failed");
+        return NULL;
+    }
+    memset(h_ota, 0, sizeof(OTA_Struct_t));
+    h_ota->state = OTA_STATE_UNINITED;
+
+    h_ota->ch_signal = osc_init(product_sn, device_sn, ch_signal, _ota_callback, h_ota);
+    if (NULL == h_ota->ch_signal) {
+        LOG_ERROR("initialize signal channel failed");
+        goto do_exit;
+    }
+
+    h_ota->md5 = ota_lib_md5_init();
+    if (NULL == h_ota->md5) {
+        LOG_ERROR("initialize md5 failed");
+        goto do_exit;
+    }
+
+    h_ota->state = OTA_STATE_INITED;
+    return h_ota;
+
+do_exit:
+    if (NULL != h_ota->ch_signal) {
+        osc_deinit(h_ota->ch_signal);
+    }
+
+    if (NULL != h_ota->md5) {
+        ota_lib_md5_deinit(h_ota->md5);
+    }
+
+    if (NULL != h_ota) {
+        HAL_Free(h_ota);
+    }
+
+    return NULL;
+}
+
+
+int IOT_OTA_Destroy(void *handle)
+{
+    POINTER_VALID_CHECK(handle, ERR_OTA_INVALID_PARAM);
+
+    OTA_Struct_t *h_ota = (OTA_Struct_t*) handle;
+
+    if (OTA_STATE_UNINITED == h_ota->state) {
+        LOG_ERROR("handle is uninitialized");
+        return FAILURE_RET;
+    }
+
+    osc_deinit(h_ota->ch_signal);
+    ofc_deinit(h_ota->ch_fetch);
+    ota_lib_md5_deinit(h_ota->md5);
+
+    if (NULL != h_ota->url) {
+        HAL_Free(h_ota->url);
+    }
+
+    if (NULL != h_ota->version) {
+        HAL_Free(h_ota->version);
+    }
+
+    if (NULL != h_ota->md5sum) {
+        HAL_Free(h_ota->md5sum);
+    }
+
+    HAL_Free(h_ota);
+    return SUCCESS_RET;
+}
+
+
+int IOT_OTA_ReportVersion(void *handle, const char *version)
+{
+    return send_upstream_msg_with_version(handle, version, OTA_REPORT_VERSION);
+}
+
+
+int IOT_OTA_RequestFirmware(void *handle, const char *version)
+{
+    return send_upstream_msg_with_version(handle, version, OTA_REQUEST_FIRMWARE);
+}
+
+int IOT_OTA_ReportSuccess(void *handle, const char *version)
+{
+    return send_upstream_msg_with_version(handle, version, OTA_REPORT_SUCCESS);
+}
+
+
+int IOT_OTA_ReportFail(void *handle, IOT_OTA_ReportErrCode err_code)
+{
+    POINTER_VALID_CHECK(handle, ERR_OTA_INVALID_PARAM);
+
+    int ret;
+    char *msg_upstream;
+    OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
+
+    if (OTA_STATE_UNINITED == h_ota->state) {
+        LOG_ERROR("handle is uninitialized");
+        h_ota->err = ERR_OTA_INVALID_STATE;
+        return ERR_OTA_INVALID_STATE;
+    }
+
+    if (NULL == (msg_upstream = HAL_Malloc(OTA_UPSTREAM_MSG_BUF_LEN))) {
+        LOG_ERROR("allocate for msg_informed failed");
+        h_ota->err = ERR_OTA_NO_MEMORY;
+        return ERR_OTA_NO_MEMORY;
+    }
+
+    ret = ota_lib_gen_upstream_msg(msg_upstream, OTA_UPSTREAM_MSG_BUF_LEN, "", 0, (IOT_OTA_UpstreamMsgType)err_code);
+    if (SUCCESS_RET != ret) {
+        LOG_ERROR("generate upstream message failed");
+        h_ota->err = ret;
+        goto do_exit;
+    }
+
+    ret = osc_upstream_publish(h_ota->ch_signal, msg_upstream);
+    if (ret < 0) {
+        LOG_ERROR("Report result failed");
+        h_ota->err = ret;
+        goto do_exit;
+    }
+
+    do_exit:
+    if (NULL != msg_upstream) {
+        HAL_Free(msg_upstream);
+    }
+    return ret;
+}
+
+

+ 117 - 0
uiot/ota/src/ota_fetch.c

@@ -0,0 +1,117 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <string.h>
+
+#include "uiot_export_ota.h"
+#include "uiot_import.h"
+#include "ota_internal.h"
+#include "ca.h"
+#include "utils_httpc.h"
+
+typedef struct {
+
+    const char *url;
+    http_client_t http;             /* http client */
+    http_client_data_t http_data;   /* http client data */
+
+} OTA_Http_Client;
+
+
+void *ofc_init(const char *url)
+{
+    FUNC_ENTRY;
+
+    OTA_Http_Client *h_ofc;
+
+    if (NULL == (h_ofc = HAL_Malloc(sizeof(OTA_Http_Client)))) {
+        LOG_ERROR("allocate for h_odc failed");
+        FUNC_EXIT_RC(NULL);
+    }
+
+    memset(h_ofc, 0, sizeof(OTA_Http_Client));
+
+    /* set http request-header parameter */
+    h_ofc->http.header = "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" \
+                         "Accept-Encoding: gzip, deflate\r\n";
+
+    h_ofc->url = url;
+
+    FUNC_EXIT_RC(h_ofc);
+}
+
+
+int32_t ofc_connect(void *handle)
+{
+    FUNC_ENTRY;
+
+    OTA_Http_Client * h_ofc = (OTA_Http_Client *)handle;
+
+#ifdef SUPPORT_TLS
+    int port = 443;
+    const char *ca_crt = iot_https_ca_get();
+#else
+    int port = 80;
+    const char *ca_crt = NULL;
+#endif
+
+    int32_t rc = http_client_common(&h_ofc->http, h_ofc->url, port, ca_crt, HTTP_GET, &h_ofc->http_data, 5000);
+
+    FUNC_EXIT_RC(rc);
+}
+
+
+int32_t ofc_fetch(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s)
+{
+    FUNC_ENTRY;
+
+    int diff;
+    OTA_Http_Client * h_ofc = (OTA_Http_Client *)handle;
+
+    h_ofc->http_data.response_buf = buf;
+    h_ofc->http_data.response_buf_len = buf_len;
+    diff = h_ofc->http_data.response_content_len - h_ofc->http_data.retrieve_len;
+    
+    int rc = http_client_recv_data(&h_ofc->http, timeout_s * 1000, &h_ofc->http_data);
+    if (SUCCESS_RET != rc) {
+        if (rc == ERR_HTTP_NOT_FOUND)
+            FUNC_EXIT_RC(ERR_OTA_FILE_NOT_EXIST);
+        
+        if (rc == ERR_HTTP_AUTH_ERROR)
+            FUNC_EXIT_RC(ERR_OTA_FETCH_AUTH_FAIL);
+        
+        if (rc == ERR_HTTP_TIMEOUT)
+            FUNC_EXIT_RC(ERR_OTA_FETCH_TIMEOUT);
+        
+        FUNC_EXIT_RC(rc);
+    }
+
+    FUNC_EXIT_RC(h_ofc->http_data.response_content_len - h_ofc->http_data.retrieve_len - diff);
+}
+
+
+int ofc_deinit(void *handle)
+{
+    FUNC_ENTRY;
+
+    OTA_Http_Client *h_ofc = (OTA_Http_Client *)handle;
+
+    http_client_close(&h_ofc->http);
+    if (NULL != handle) {
+        HAL_Free(handle);
+    }
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}

+ 170 - 0
uiot/ota/src/ota_lib.c

@@ -0,0 +1,170 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <string.h>
+#include <stdio.h>
+
+#include "ota_config.h"
+#include "ota_internal.h"
+
+#include "utils_md5.h"
+#include "lite-utils.h"
+
+
+void *ota_lib_md5_init(void) {
+    iot_md5_context *ctx = HAL_Malloc(sizeof(iot_md5_context));
+    if (NULL == ctx) {
+        return NULL;
+    }
+
+    utils_md5_init(ctx);
+    utils_md5_starts(ctx);
+
+    return ctx;
+}
+
+
+void ota_lib_md5_update(void *md5, const char *buf, size_t buf_len) {
+    utils_md5_update(md5, (unsigned char *) buf, buf_len);
+}
+
+
+void ota_lib_md5_finalize(void *md5, char *output_str) {
+    utils_md5_finish_hb2hex(md5, output_str);
+}
+
+
+void ota_lib_md5_deinit(void *md5) {
+    if (NULL != md5) {
+        HAL_Free(md5);
+    }
+}
+
+
+int ota_lib_get_msg_type(char *json, char **type) {
+    FUNC_ENTRY;
+
+    if (NULL == (*type = LITE_json_value_of(TYPE_FIELD, json))) {
+        LOG_ERROR("get value of type key failed");
+        FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
+    }
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+
+int ota_lib_get_params(char *json, char **url, char **version, char **md5,
+                       uint32_t *fileSize) {
+    FUNC_ENTRY;
+
+    char *file_size_str;
+    char *version_str;
+    char *url_str;
+    char *md5_str;
+
+    /* get version */
+    if (NULL == (version_str = LITE_json_value_of(VERSION_FIELD, json))) {
+        LOG_ERROR("get value of version key failed");
+        FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
+    }
+    if (NULL != *version) {
+        HAL_Free(*version);
+    }
+    *version = version_str;
+
+    /* get URL */
+    if (NULL == (url_str = LITE_json_value_of(URL_FIELD, json))) {
+        LOG_ERROR("get value of url key failed");
+        FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
+    }
+    if (NULL != *url) {
+        HAL_Free(*url);
+    }
+    *url = url_str;
+
+    /* get md5 */
+    if (NULL == (md5_str = LITE_json_value_of(MD5_FIELD, json))) {
+        LOG_ERROR("get value of md5 failed");
+        FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
+    }
+    if (NULL != *md5) {
+        HAL_Free(*md5);
+    }
+    *md5 = md5_str;
+
+    /* get file size */
+    if (NULL == (file_size_str = LITE_json_value_of(SIZE_FIELD, json))) {
+        LOG_ERROR("get value of file size failed");
+        FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
+    }
+
+    if (SUCCESS_RET != LITE_get_uint32(fileSize, file_size_str)) {
+        LOG_ERROR("get uint32 failed");
+        HAL_Free(file_size_str);
+        FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
+    }
+    HAL_Free(file_size_str);
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+int ota_lib_gen_upstream_msg(char *buf, size_t bufLen, const char *version, int progress,
+                             IOT_OTA_UpstreamMsgType reportType) {
+    FUNC_ENTRY;
+
+    int ret;
+
+    switch (reportType) {
+        case OTA_REPORT_DOWNLOAD_TIMEOUT:
+        case OTA_REPORT_FIRMWARE_NOT_EXIST:
+        case OTA_REPORT_MD5_MISMATCH:
+        case OTA_REPORT_SIGNATURE_EXPIRED:
+        case OTA_REPORT_FIRMWARE_BURN_FAILED:
+        case OTA_REPORT_UNDEFINED_ERROR:
+            ret = HAL_Snprintf(buf, bufLen, REPORT_FAIL_MSG_TEMPLATE, reportType);
+            break;
+
+        case OTA_REPORT_DOWNLOADING:
+            ret = HAL_Snprintf(buf, bufLen, REPORT_PROGRESS_MSG_TEMPLATE, "downloading", progress);
+            break;
+
+        case OTA_REPORT_BURNING:
+            ret = HAL_Snprintf(buf, bufLen, REPORT_PROGRESS_MSG_TEMPLATE, "burning", progress);
+            break;
+
+        case OTA_REPORT_SUCCESS:
+            ret = HAL_Snprintf(buf, bufLen, REPORT_SUCCESS_MSG_TEMPLATE, version);
+            break;
+
+        case OTA_REQUEST_FIRMWARE:
+            ret = HAL_Snprintf(buf, bufLen, REQUEST_FIRMWARE_MSG_TEMPLATE, version);
+            break;
+
+        case OTA_REPORT_VERSION:
+            ret = HAL_Snprintf(buf, bufLen, REPORT_VERSION_MSG_TEMPLATE, version);
+            break;
+
+        default: FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
+    }
+
+    if (ret < 0) {
+        LOG_ERROR("HAL_Snprintf failed");
+        FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
+    } else if (ret >= bufLen) {
+        LOG_ERROR("msg is too long");
+        FUNC_EXIT_RC(ERR_OTA_STR_TOO_LONG);
+    }
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}

+ 173 - 0
uiot/ota/src/ota_mqtt.c

@@ -0,0 +1,173 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <string.h>
+
+#include "uiot_defs.h"
+#include "uiot_export_mqtt.h"
+#include "uiot_export_ota.h"
+#include "uiot_import.h"
+
+#include "ota_config.h"
+#include "ota_internal.h"
+
+/* OSC, OTA signal channel */
+typedef struct  {
+    void 					*mqtt;
+    const char 				*product_sn;
+    const char 				*device_sn;
+    char 					topic_upgrade[OTA_TOPIC_BUF_LEN];
+    OnOTAMessageCallback 	msg_callback;
+    void                    *context;
+} OTA_MQTT_Struct_t;
+
+static int _ota_mqtt_gen_topic_name(char *buf, size_t buf_len, const char *ota_topic_type, const char *product_sn,
+                                    const char *device_sn)
+{
+    FUNC_ENTRY;
+
+    int ret;
+    ret = HAL_Snprintf(buf, buf_len, OTA_TOPIC_TEMPLATE, product_sn, device_sn, ota_topic_type);
+
+    if(ret >= buf_len) {
+        FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
+    }
+
+    if (ret < 0) {
+        LOG_ERROR("HAL_Snprintf failed");
+        FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
+    }
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+static int _ota_mqtt_publish(OTA_MQTT_Struct_t *handle, const char *topic_type, int qos, const char *msg)
+{
+    FUNC_ENTRY;
+
+    int ret;
+    char topic_name[OTA_TOPIC_BUF_LEN];
+    PublishParams pub_params = DEFAULT_PUB_PARAMS;
+
+    //暂不支持QOS2
+    if (0 == qos) {
+        pub_params.qos = QOS0;
+    } else {
+        pub_params.qos = QOS1;
+    }
+    pub_params.payload = (void *)msg;
+    pub_params.payload_len = strlen(msg);
+
+    ret = _ota_mqtt_gen_topic_name(topic_name, OTA_TOPIC_BUF_LEN, topic_type, handle->product_sn, handle->device_sn);
+    if (ret < 0) {
+       LOG_ERROR("generate topic name of info failed");
+       FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
+    }
+
+    ret = IOT_MQTT_Publish(handle->mqtt, topic_name, &pub_params);
+    if (ret < 0) {
+        LOG_ERROR("publish to topic: %s failed", topic_name);
+        FUNC_EXIT_RC(ERR_OTA_OSC_FAILED);
+    }
+
+    FUNC_EXIT_RC(ret);
+}
+
+static void _ota_mqtt_upgrade_cb(void *pClient, MQTTMessage *message, void *pContext)
+{
+    FUNC_ENTRY;
+
+    OTA_MQTT_Struct_t *handle = (OTA_MQTT_Struct_t *) pContext;
+
+    LOG_DEBUG("topic=%s", message->topic);
+    LOG_INFO("len=%u, topic_msg=%.*s", message->payload_len, message->payload_len, (char *)message->payload);
+
+    if (NULL != handle->msg_callback) {
+        handle->msg_callback(handle->context, message->payload, message->payload_len);
+    }
+
+    FUNC_EXIT;
+}
+
+void *osc_init(const char *product_sn, const char *device_sn, void *channel, OnOTAMessageCallback callback,
+               void *context)
+{
+    int ret;
+    OTA_MQTT_Struct_t *h_osc = NULL;
+
+    if (NULL == (h_osc = HAL_Malloc(sizeof(OTA_MQTT_Struct_t)))) {
+        LOG_ERROR("allocate for h_osc failed");
+        goto do_exit;
+    }
+
+    memset(h_osc, 0, sizeof(OTA_MQTT_Struct_t));
+
+    h_osc->mqtt = channel;
+    h_osc->product_sn = product_sn;
+    h_osc->device_sn = device_sn;
+    h_osc->msg_callback = callback;
+    h_osc->context = context;
+
+    /* subscribe the OTA topic: "/$system/$(product_sn)/$(device_sn)/ota/downstream" */
+    ret = _ota_mqtt_gen_topic_name(h_osc->topic_upgrade, OTA_TOPIC_BUF_LEN, OTA_DOWNSTREAM_TOPIC_TYPE, product_sn,
+                                   device_sn);
+    if (ret < 0) {
+        LOG_ERROR("generate topic name of upgrade failed");
+        goto do_exit;
+    }
+
+    SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
+    sub_params.on_message_handler = _ota_mqtt_upgrade_cb;
+    sub_params.qos = QOS1;
+    sub_params.user_data = h_osc;
+
+    ret = IOT_MQTT_Subscribe(channel, h_osc->topic_upgrade, &sub_params);
+    if (ret < 0) {
+        LOG_ERROR("ota mqtt subscribe failed!");
+        goto do_exit;
+    }
+
+    return h_osc;
+
+do_exit:
+    if (NULL != h_osc) {
+         HAL_Free(h_osc);
+    }
+
+    return NULL;
+}
+
+int osc_deinit(void *handle)
+{
+    FUNC_ENTRY;
+
+    if (NULL != handle) {
+        HAL_Free(handle);
+    }
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+/* report progress of OTA */
+int osc_report_progress(void *handle, const char *msg)
+{
+    return _ota_mqtt_publish(handle, OTA_UPSTREAM_TOPIC_TYPE, QOS0, msg);
+}
+
+/* report version of firmware */
+int osc_upstream_publish(void *handle, const char *msg)
+{
+    return _ota_mqtt_publish(handle, OTA_UPSTREAM_TOPIC_TYPE, QOS1, msg);
+}

+ 216 - 0
uiot/sdk-impl/uiot_defs.h

@@ -0,0 +1,216 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_UIOT_DEFS_H_
+#define C_SDK_UIOT_DEFS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IOT_PRODUCT_SN_LEN             (16)
+#define IOT_PRODUCT_SECRET_LEN         (16)
+
+#define IOT_DEVICE_SN_LEN              (64)
+#define IOT_DEVICE_SECRET_LEN          (16)
+
+
+#ifndef _IN_
+#define _IN_
+#endif
+
+#ifndef _OU_
+#define _OU_
+#endif
+
+typedef enum {
+    MQTT_ALREADY_CONNECTED                            = 4,       // 表示与MQTT服务器已经建立连接
+    MQTT_CONNECTION_ACCEPTED                          = 3,       // 表示服务器接受客户端MQTT连接
+    MQTT_MANUALLY_DISCONNECTED                        = 2,       // 表示与MQTT服务器已经手动断开
+    MQTT_RECONNECTED                                  = 1,       // 表示与MQTT服务器重连成功
+
+    SUCCESS_RET                                       = 0,       // 表示成功返回
+    FAILURE_RET                                       = -1,      // 表示失败返回
+
+    ERR_PARAM_INVALID                                 = -2,      // 表示参数无效错误
+
+    ERR_HTTP_CLOSED                                   = -3,      // 远程主机关闭连接
+    ERR_HTTP_UNKNOWN_ERROR                            = -4,      // HTTP未知错误
+    ERR_HTTP_PROTOCOL_ERROR                           = -5,      // 协议错误
+    ERR_HTTP_UNRESOLVED_DNS                           = -6,      // 域名解析失败
+    ERR_HTTP_URL_PARSE_ERROR                          = -7,      // URL解析失败
+    ERR_HTTP_CONN_ERROR                               = -8,      // HTTP连接失败
+    ERR_HTTP_AUTH_ERROR                               = -9,      // HTTP鉴权问题
+    ERR_HTTP_NOT_FOUND                                = -10,     // HTTP 404
+    ERR_HTTP_TIMEOUT                                  = -11,     // HTTP 超时
+
+    ERR_MQTT_PUSH_TO_LIST_FAILED                      = -102,    // 表示往等待 ACK 列表中添加元素失败
+    ERR_MQTT_NO_CONN                                  = -103,    // 表示未与MQTT服务器建立连接或已经断开连接
+    ERR_MQTT_UNKNOWN_ERROR                            = -104,    // 表示MQTT相关的未知错误
+    ERR_MQTT_ATTEMPTING_RECONNECT                     = -105,    // 表示正在与MQTT服务重新建立连接
+    ERR_MQTT_RECONNECT_TIMEOUT                        = -106,    // 表示重连已经超时
+    ERR_MQTT_MAX_SUBSCRIPTIONS_REACHED                = -107,    // 表示超过可订阅的主题数
+    ERR_MQTT_SUB_FAILED                               = -108,    // 表示订阅主题失败, 即服务器拒绝
+    ERR_MQTT_NOTHING_TO_READ                          = -109,    // 表示无MQTT相关报文可以读取
+    ERR_MQTT_PACKET_READ_ERROR                        = -110,    // 表示读取的MQTT报文有问题
+    ERR_MQTT_REQUEST_TIMEOUT                          = -111,    // 表示MQTT相关操作请求超时
+    ERR_MQTT_CONNACK_UNKNOWN                          = -112,    // 表示客户端MQTT连接未知错误
+    ERR_MQTT_CONNACK_UNACCEPTABLE_PROTOCOL_VERSION    = -113,    // 表示客户端MQTT版本错误
+    ERR_MQTT_CONNACK_IDENTIFIER_REJECTED              = -114,    // 表示客户端标识符错误
+    ERR_MQTT_CONNACK_SERVER_UNAVAILABLE               = -115,    // 表示服务器不可用
+    ERR_MQTT_CONNACK_BAD_USERDATA                     = -116,    // 表示客户端连接参数中的username或password错误
+    ERR_MQTT_CONNACK_NOT_AUTHORIZED                   = -117,    // 表示客户端连接认证失败
+    ERR_MQTT_RX_MESSAGE_PACKET_TYPE_INVALID           = -118,    // 表示收到的消息无效
+    ERR_MQTT_BUFFER_TOO_SHORT                         = -119,    // 表示消息接收缓冲区的长度小于消息的长度
+    ERR_MQTT_QOS_NOT_SUPPORT                          = -120,    // 表示该QOS级别不支持
+    ERR_MQTT_UNSUB_FAILED                             = -121,    // 表示取消订阅主题失败,比如该主题不存在
+
+    ERR_JSON_PARSE                                    = -132,    // 表示JSON解析错误
+    ERR_JSON_BUFFER_TRUNCATED                         = -133,    // 表示JSON文档会被截断
+    ERR_JSON_BUFFER_TOO_SMALL                         = -134,    // 表示存储JSON文档的缓冲区太小
+    ERR_JSON                                          = -135,    // 表示JSON文档生成错误
+    ERR_MAX_JSON_TOKEN                                = -136,    // 表示超过JSON文档中的最大Token数
+    ERR_MAX_APPENDING_REQUEST                         = -137,    // 表示超过同时最大的文档请求
+    ERR_MAX_TOPIC_LENGTH                              = -138,    // 表示超过规定最大的topic长度
+
+    ERR_SHADOW_PROPERTY_EXIST                         = -201,    // 表示注册的属性已经存在
+    ERR_SHADOW_NOT_PROPERTY_EXIST                     = -202,    // 表示注册的属性不存在
+    ERR_SHADOW_UPDATE_TIMEOUT                         = -203,    // 表示更新设备影子文档超时
+    ERR_SHADOW_UPDATE_REJECTED                        = -204,    // 表示更新设备影子文档被拒绝
+    ERR_SHADOW_GET_TIMEOUT                            = -205,    // 表示拉取设备影子文档超时
+    ERR_SHADOW_GET_REJECTED                           = -206,    // 表示拉取设备影子文档被拒绝
+
+    ERR_OTA_GENERAL_FAILURE                           = -301,    // 表示OTA通用FAILURE返回值
+    ERR_OTA_INVALID_PARAM                             = -302,    // 表示OTA参数错误
+    ERR_OTA_INVALID_STATE                             = -303,    // 表示OTA状态错误
+    ERR_OTA_STR_TOO_LONG                              = -304,    // 表示OTA字符串长度超过限制
+    ERR_OTA_FETCH_FAILED                              = -305,    // 表示固件下载失败
+    ERR_OTA_FILE_NOT_EXIST                            = -306,    // 表示固件不存在
+    ERR_OTA_FETCH_AUTH_FAIL                           = -307,    // 表示预签名认证失败
+    ERR_OTA_FETCH_TIMEOUT                             = -308,    // 表示下载超时
+    ERR_OTA_NO_MEMORY                                 = -309,    // 表示内存不足
+    ERR_OTA_OSC_FAILED                                = -310,    // 表示OTA信号通道错误
+    ERR_OTA_MD5_MISMATCH                              = -311,    // 表示MD5不匹配
+
+
+    ERR_TCP_SOCKET_FAILED                             = -601,    // 表示TCP连接建立套接字失败
+    ERR_TCP_UNKNOWN_HOST                              = -602,    // 表示无法通过主机名获取IP地址
+    ERR_TCP_CONNECT_FAILED                            = -603,    // 表示建立TCP连接失败
+    ERR_TCP_READ_TIMEOUT                              = -604,    // 表示TCP读超时
+    ERR_TCP_WRITE_TIMEOUT                             = -605,    // 表示TCP写超时
+    ERR_TCP_READ_FAILED                               = -606,    // 表示TCP读错误
+    ERR_TCP_WRITE_FAILED                              = -607,    // 表示TCP写错误
+    ERR_TCP_PEER_SHUTDOWN                             = -608,    // 表示TCP对端关闭了连接
+    ERR_TCP_NOTHING_TO_READ                           = -609,    // 表示底层没有数据可以读取
+
+    ERR_SSL_INIT_FAILED                               = -701,    // 表示SSL初始化失败
+    ERR_SSL_CERT_FAILED                               = -702,    // 表示SSL证书相关问题
+    ERR_SSL_CONNECT_FAILED                            = -703,    // 表示SSL连接失败
+    ERR_SSL_CONNECT_TIMEOUT                           = -704,    // 表示SSL连接超时
+    ERR_SSL_WRITE_TIMEOUT                             = -705,    // 表示SSL写超时
+    ERR_SSL_WRITE_FAILED                              = -706,    // 表示SSL写错误
+    ERR_SSL_READ_TIMEOUT                              = -707,    // 表示SSL读超时
+    ERR_SSL_READ_FAILED                               = -708,    // 表示SSL读错误
+    ERR_SSL_NOTHING_TO_READ                           = -709,    // 表示底层没有数据可以读取
+} IoT_Error_t;
+
+#define Max(a,b) ((a) > (b) ? (a) : (b))
+#define Min(a,b) ((a) < (b) ? (a) : (b))
+
+#ifdef ENABLE_LOG_DEBUG
+#define LOG_DEBUG(...)    \
+	{\
+	HAL_Printf("DEBUG:   %s L#%d ", __func__, __LINE__);  \
+	HAL_Printf(__VA_ARGS__); \
+	HAL_Printf("\n"); \
+	}
+#else
+#define LOG_DEBUG(...)
+#endif
+
+/**
+ * @brief Info level logging macro.
+ *
+ * Macro to expose desired log message.  Info messages do not include automatic function names and line numbers.
+ */
+#ifdef ENABLE_LOG_INFO
+#define LOG_INFO(...)    \
+	{\
+	HAL_Printf(__VA_ARGS__); \
+	HAL_Printf("\n"); \
+	}
+#else
+#define LOG_INFO(...)
+#endif
+
+/**
+ * @brief Warn level logging macro.
+ *
+ * Macro to expose function, line number as well as desired log message.
+ */
+#ifdef ENABLE_LOG_WARN
+#define LOG_WARN(...)   \
+	{ \
+	HAL_Printf("WARN:  %s L#%d ", __func__, __LINE__);  \
+	HAL_Printf(__VA_ARGS__); \
+	HAL_Printf("\n"); \
+	}
+#else
+#define LOG_WARN(...)
+#endif
+
+/**
+ * @brief Error level logging macro.
+ *
+ * Macro to expose function, line number as well as desired log message.
+ */
+#ifdef ENABLE_LOG_ERROR
+#define LOG_ERROR(...)  \
+	{ \
+	HAL_Printf("ERROR: %s L#%d ", __func__, __LINE__); \
+	HAL_Printf(__VA_ARGS__); \
+	HAL_Printf("\n"); \
+	}
+#else
+#define LOG_ERROR(...)
+#endif
+
+#ifdef ENABLE_IOT_TRACE
+#define FUNC_ENTRY    \
+	{\
+	HAL_Printf("FUNC_ENTRY:   %s L#%d \n", __func__, __LINE__);  \
+	}
+#define FUNC_EXIT    \
+	{\
+	HAL_Printf("FUNC_EXIT:   %s L#%d \n", __func__, __LINE__);  \
+	return; \
+	}
+#define FUNC_EXIT_RC(x)    \
+	{\
+	HAL_Printf("FUNC_EXIT:   %s L#%d Return Code : %d \n", __func__, __LINE__, x);  \
+	return x; \
+	}
+#else
+#define FUNC_ENTRY
+
+#define FUNC_EXIT       { return; }
+#define FUNC_EXIT_RC(x) { return x; }
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //C_SDK_UIOT_DEFS_H_

+ 56 - 0
uiot/sdk-impl/uiot_export.h

@@ -0,0 +1,56 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_UIOT_EXPORT_H_
+#define C_SDK_UIOT_EXPORT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* MQTT心跳消息发送周期, 单位:s */
+#define UIOT_MQTT_KEEP_ALIVE_INTERNAL                               (240)
+
+/* MQTT 阻塞调用(包括连接, 订阅, 发布等)的超时时间, 单位:ms 建议5000ms */
+#define UIOT_MQTT_COMMAND_TIMEOUT                                   (5 * 10000)
+
+/* 接收到 MQTT 包头以后,接收剩余长度及剩余包,最大延迟等待时延 */
+#define UIOT_MQTT_MAX_REMAIN_WAIT_MS                                (2000)
+
+/* MQTT消息发送buffer大小, 支持最大256*1024 */
+#define UIOT_MQTT_TX_BUF_LEN                                        (2048)
+
+/* MQTT消息接收buffer大小, 支持最大256*1024 */
+#define UIOT_MQTT_RX_BUF_LEN                                        (2048)
+
+/* 重连最大等待时间 */
+#define MAX_RECONNECT_WAIT_INTERVAL 								(60 * 1000)
+
+/* 使能无限重连,0表示超过重连最大等待时间后放弃重连,
+ * 1表示超过重连最大等待时间后以固定间隔尝试重连*/
+#define ENABLE_INFINITE_RECONNECT 								    1
+
+/* MQTT连接域名 */
+#define UIOT_MQTT_DIRECT_DOMAIN        						        "mqtt-cn-sh2.iot.ucloud.cn"
+
+
+#include "uiot_export_mqtt.h"
+#include "uiot_defs.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* C_SDK_UIOT_EXPORT_H_ */

+ 138 - 0
uiot/sdk-impl/uiot_export_dm.h

@@ -0,0 +1,138 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_UIOT_EXPORT_DM_H_
+#define C_SDK_UIOT_EXPORT_DM_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include "uiot_defs.h"
+
+/* 设备物模型消息类型 */
+typedef enum _dm_type {
+    PROPERTY_RESTORE,         //设备恢复属性
+    PROPERTY_POST,            //设备上报属性
+    PROPERTY_SET,             //云端下发属性
+    PROPERTY_DESIRED_GET,     //设备获取desire属性
+    PROPERTY_DESIRED_DELETE,  //删除云端desire属性
+    EVENT_POST,               //设备上报事件
+    COMMAND,                  //命令下发
+    DM_TYPE_MAX
+}DM_Type;
+
+
+typedef int (* PropertyRestoreCB)(const char *request_id, const int ret_code, const char *property);
+typedef int (* PropertySetCB)(const char *request_id, const char *property);
+typedef int (* PropertyDesiredGetCB)(const char *request_id, const int ret_code, const char *desired);
+typedef int (* CommandCB)(const char *request_id, const char *identifier, const char *input, char **output);
+typedef int (* CommonReplyCB)(const char *request_id, const int ret_code);
+
+#define DECLARE_DM_CALLBACK(type, cb)  int uiot_register_for_##type(void*, cb);
+
+DECLARE_DM_CALLBACK(PROPERTY_RESTORE,          PropertyRestoreCB)
+DECLARE_DM_CALLBACK(PROPERTY_POST,             CommonReplyCB)
+DECLARE_DM_CALLBACK(PROPERTY_SET,              PropertySetCB)
+DECLARE_DM_CALLBACK(PROPERTY_DESIRED_GET,      PropertyDesiredGetCB)
+DECLARE_DM_CALLBACK(PROPERTY_DESIRED_DELETE,   CommonReplyCB)
+DECLARE_DM_CALLBACK(EVENT_POST,                CommonReplyCB)
+DECLARE_DM_CALLBACK(COMMAND,                   CommandCB)
+
+/**
+ * @brief 注册消息回调函数的宏
+ *
+ * @param type:      消息类型,七种DM_Type之一
+ * @param handle:    IOT_DM_Init返回的句柄
+ * @param cb:        回调函数指针,函数类型必须与DECLARE_DM_CALLBACK声明的类型相同,
+ *                   例如如果type是PROPERTY_RESTORE,cb则必须为PropertyRestoreCB类型
+ *
+ * @retval   0 : 成功
+ * @retval < 0 : 失败,返回具体错误码
+ */
+#define IOT_DM_RegisterCallback(type, handle, cb)        uiot_register_for_##type(handle, cb);
+
+/**
+ * @brief 初始化dev_model模块和返回句柄
+ *
+ * @param product_sn:   指定产品序列号
+ * @param device_sn:    指定设备序列号
+ * @param ch_signal:    指定的信号通道.
+ *
+ * @retval 成功返回句柄,失败返回NULL.
+ */
+void *IOT_DM_Init(const char *product_sn, const char *device_sn, void *ch_signal);
+
+
+/**
+ * @brief 释放dev_model相关的资源
+ *
+ * @param handle: IOT_DM_Init返回的句柄
+ *
+ * @retval   0 : 成功
+ * @retval < 0 : 失败,返回具体错误码
+ */
+int IOT_DM_Destroy(void *handle);
+
+
+/**
+ * @brief 属性有关的消息上报
+ *
+ * @param handle:     IOT_DM_Init返回的句柄
+ * @param type:       消息类型,此处为
+    PROPERTY_RESTORE,
+    PROPERTY_POST,
+    PROPERTY_DESIRED_GET,
+    PROPERTY_DESIRED_DELETE
+    四种消息类型之一
+ * @param request_id: 消息的request_id
+ * @param payload:    消息体
+ *
+ * @retval   0 : 成功
+ * @retval < 0 : 失败,返回具体错误码
+ */
+int IOT_DM_Property_Report(void *handle, DM_Type type, int request_id, const char *payload);
+
+
+/**
+ * @brief 事件消息上报
+ *
+ * @param handle:     IOT_DM_Init返回的句柄
+ * @param request_id: 消息的request_id
+ * @param identifier: 事件标识符
+ * @param payload:    事件Output消息体
+ *
+ * @retval   0 : 成功
+ * @retval < 0 : 失败,返回具体错误码
+ */
+int IOT_DM_TriggerEvent(void *handle, int request_id, const char *identifier, const char *payload);
+
+
+/**
+ * @brief 在当前线程为底层MQTT客户端让出一定CPU执行时间,让其接收网络报文并将消息分发到用户的回调函数中
+ *
+ * @param handle:     IOT_DM_Init返回的句柄
+ * @param timeout_ms: 超时时间,单位ms
+ *
+ * @retval   0 : 成功
+ * @retval < 0 : 失败,返回具体错误码
+ */
+int IOT_DM_Yield(void *handle, uint32_t timeout_ms);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif //C_SDK_UIOT_EXPORT_DM_H_

+ 31 - 0
uiot/sdk-impl/uiot_export_file_upload.h

@@ -0,0 +1,31 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_UIOT_EXPORT_FILE_UPLOAD_
+#define C_SDK_UIOT_EXPORT_FILE_UPLOAD_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+int IOT_GET_URL_AND_AUTH(const char *product_sn, const char *device_sn, const char *device_sercret, char *file_path, char *md5, char *authorization, char *put_url);
+
+int IOT_UPLOAD_FILE(char *file_path, char *md5, char *authorization, char *url, uint32_t timeout_ms);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif 

+ 243 - 0
uiot/sdk-impl/uiot_export_mqtt.h

@@ -0,0 +1,243 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+
+#ifndef C_SDK_UIOT_EXPORT_MQTT_H_
+#define C_SDK_UIOT_EXPORT_MQTT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+/**
+ * @brief 服务质量等级。服务质量等级表示PUBLISH消息分发的质量等级。可参考MQTT协议说明 4.7
+ */
+typedef enum _QoS {
+    QOS0 = 0,    // 至多分发一次
+    QOS1 = 1,    // 至少分发一次, 消息的接收者需回复PUBACK报文
+    QOS2 = 2     // 仅分发一次, 目前暂不支持
+} QoS;
+
+/**
+ * @brief 发布或接收已订阅消息的结构体定义
+ */
+typedef struct {
+    QoS         			qos;          // MQTT 服务质量等级
+    uint8_t     			retained;     // RETAIN 标识位
+    uint8_t     			dup;          // DUP 标识位
+    uint16_t    			id;           // MQTT 消息标识符
+
+    const char  			*topic;       // MQTT topic
+    size_t      			topic_len;    // topic 长度
+
+    void        			*payload;     // MQTT 消息负载
+    size_t      			payload_len;  // MQTT 消息负载长度
+} MQTTMessage;
+
+typedef MQTTMessage PublishParams;
+
+#define DEFAULT_PUB_PARAMS {QOS0, 0, 0, 0, NULL, 0, NULL, 0}
+
+/**
+ * @brief 接收已订阅消息的回调函数定义
+ */
+typedef void (*OnMessageHandler)(void *pClient, MQTTMessage *message, void *pUserData);
+
+/**
+ * @brief 订阅主题的结构体定义
+ */
+typedef struct {
+    QoS                     qos;                    // QOS服务质量标识
+    OnMessageHandler        on_message_handler;     // 接收已订阅消息的回调函数
+    void                    *user_data;             // 用户数据, 通过callback返回
+} SubscribeParams;
+
+#define DEFAULT_SUB_PARAMS {QOS0, NULL, NULL}
+
+typedef enum {
+
+    /* 未定义事件 */
+    MQTT_EVENT_UNDEF = 0,
+
+    /* MQTT 断开连接 */
+    MQTT_EVENT_DISCONNECT = 1,
+
+    /* MQTT 重连 */
+    MQTT_EVENT_RECONNECT = 2,
+
+    /* 订阅成功 */
+    MQTT_EVENT_SUBSCRIBE_SUCCESS = 3,
+
+    /* 订阅超时 */
+    MQTT_EVENT_SUBSCRIBE_TIMEOUT = 4,
+
+    /* 订阅失败 */
+    MQTT_EVENT_SUBSCRIBE_NACK = 5,
+
+    /* 取消订阅成功 */
+    MQTT_EVENT_UNSUBSCRIBE_SUCCESS = 6,
+
+    /* 取消订阅超时 */
+    MQTT_EVENT_UNSUBSCRIBE_TIMEOUT = 7,
+
+    /* 取消订阅失败 */
+    MQTT_EVENT_UNSUBSCRIBE_NACK = 8,
+
+    /* 发布成功 */
+    MQTT_EVENT_PUBLISH_SUCCESS = 9,
+
+    /* 发布超时 */
+    MQTT_EVENT_PUBLISH_TIMEOUT = 10,
+
+    /* 发布失败 */
+    MQTT_EVENT_PUBLISH_NACK = 11,
+
+    /* SDK订阅的topic收到后台push消息 */
+    MQTT_EVENT_PUBLISH_RECEIVED = 12,
+
+} MQTTEventType;
+
+typedef struct {
+    MQTTEventType  event_type;
+    void           *msg;
+} MQTTEventMsg;
+
+/**
+ * @brief 定义了函数指针的数据类型. 当相关事件发生时,将调用这种类型的函数.
+ *
+ * @param context, the program context
+ * @param pClient, the MQTT client
+ * @param msg, the event message.
+ *
+ * @return none
+ */
+typedef void (*MQTTEventHandlerFun)(void *pClient, void *context, MQTTEventMsg *msg);
+
+
+/* The structure of MQTT event handle */
+typedef struct {
+    MQTTEventHandlerFun      h_fp;
+    void                     *context;
+} MQTTEventHandler;
+
+typedef struct {
+	/**
+	 * 设备基础信息
+	 */
+    char 						*product_sn;	         // 产品序列号
+    char 						*device_sn;			     // 设备序列号
+    char                        *product_secret;         // 产品密钥 用于动态注册,不填则认为是静态注册
+    char                        *device_secret;          // 设备密钥 用于静态注册,动态注册时可以不填
+
+    uint32_t					command_timeout;		 // 发布订阅信令读写超时时间 ms
+    uint32_t					keep_alive_interval;	 // 心跳周期, 单位: s
+
+    uint8_t         			clean_session;			 // 清理会话标志位
+
+    uint8_t                   	auto_connect_enable;     // 是否开启自动重连 1:启用自动重连 0:不启用自动重连  建议为1
+
+    MQTTEventHandler            event_handler;           // 事件回调
+
+} MQTTInitParams;
+
+#define DEFAULT_MQTT_INIT_PARAMS { NULL, NULL, NULL, NULL, 2000, 240, 1, 1, {0}}
+
+/**
+ * @brief 构造MQTTClient并完成MQTT连接
+ *
+ * @param pParams MQTT协议连接接入与连接维持阶段所需要的参数
+ *
+ * @return        构造成功返回MQTT句柄,构造失败返回NULL
+ */
+void* IOT_MQTT_Construct(MQTTInitParams *pParams);
+
+/**
+ * @brief 关闭MQTT连接并销毁MQTTClient
+ *
+ * @param pClient MQTT句柄
+ *
+ * @return        返回SUCCESS, 表示销毁成功,返回FAILURE表示失败
+ */
+int IOT_MQTT_Destroy(void **pClient);
+
+/**
+ * @brief 在当前线程为底层MQTT客户端让出一定CPU执行时间
+ *
+ * 在这段时间内, MQTT客户端会用用处理消息接收, 以及发送PING报文, 监控网络状态
+ *
+ * @param pClient    MQTT句柄
+ * @param timeout_ms Yield操作超时时间
+ * @return           返回SUCCESS, 表示成功, 返回ERR_MQTT_ATTEMPTING_RECONNECT, 表示正在重连
+ */
+int IOT_MQTT_Yield(void *pClient, uint32_t timeout_ms);
+
+/**
+ * @brief 发布MQTT消息
+ *
+ * @param pClient   MQTT句柄
+ * @param topicName 主题名
+ * @param pParams   发布参数
+ * @return < 0  :   表示失败
+ *         >= 0 :   返回唯一的packet id 
+ */
+int IOT_MQTT_Publish(void *pClient, char *topicName, PublishParams *pParams);
+
+/**
+ * @brief 订阅MQTT主题
+ *
+ * @param pClient     MQTT句柄
+ * @param topicFilter 主题过滤器, 可参考MQTT协议说明 4.7
+ * @param pParams     订阅参数
+ * @return <  0 :     表示失败
+ *         >= 0 :     返回唯一的packet id
+ */
+int IOT_MQTT_Subscribe(void *pClient, char *topicFilter, SubscribeParams *pParams);
+
+/**
+ * @brief 取消订阅已订阅的MQTT主题
+ *
+ * @param pClient      MQTT客户端结构体
+ * @param topicFilter  主题过滤器, 可参考MQTT协议说明 4.7
+ * @return <  0 :      表示失败
+ *         >= 0 :      返回唯一的packet id
+ */
+int IOT_MQTT_Unsubscribe(void *pClient, char *topicFilter);
+
+/**
+ * @brief 客户端目前是否已连接
+ *
+ * @param pClient  MQTT Client结构体
+ * @return         返回true, 表示客户端已连接,返回false表示断开连接
+ */
+bool IOT_MQTT_IsConnected(void *pClient);
+
+/**
+ * @brief 构造MQTTClient动态注册
+ *
+ * @param  pParams MQTT协议连接接入与连接维持阶段所需要的参数
+ *
+ * @return 成功返回SUCCESS,否则返回错误码
+ */
+int IOT_MQTT_Dynamic_Register(MQTTInitParams *pParams);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* C_SDK_UIOT_EXPORT_MQTT_H_ */

+ 144 - 0
uiot/sdk-impl/uiot_export_ota.h

@@ -0,0 +1,144 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_UIOT_EXPORT_OTA_H_
+#define C_SDK_UIOT_EXPORT_OTA_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "uiot_import.h"
+
+typedef enum {
+
+    OTA_IOCTL_FETCHED_SIZE,     /* 固件已经下载的大小 */
+    OTA_IOCTL_FILE_SIZE,        /* 固件总大小 */
+    OTA_IOCTL_MD5SUM,           /* md5(字符串类型) */
+    OTA_IOCTL_VERSION,          /* 版本号(字符串类型)t */
+    OTA_IOCTL_CHECK_FIRMWARE    /* 对固件进行校验 */
+
+} IOT_OTA_CmdType;
+
+typedef enum {
+
+    OTA_PROGRESS_DOWNLOADING = 1,    /* 版本号(字符串类型)t */
+    OTA_PROGRESS_BURNING = 2         /* 对固件进行校验 */
+
+} IOT_OTA_ProgressState;
+
+typedef enum {
+
+    OTA_ERRCODE_FIRMWARE_NOT_EXIST = -1,      /* 固件文件不存在(URL无法访问) */
+    OTA_ERRCODE_SIGNATURE_EXPIRED = -2,       /* URL签名过期 */
+    OTA_ERRCODE_DOWNLOAD_TIMEOUT = -3,        /* 下载超时 */
+    OTA_ERRCODE_MD5_MISMATCH = -4,            /* MD5不匹配 */
+    OTA_ERRCODE_FIRMWARE_BURN_FAILED = -5,    /* 固件烧录失败 */
+    OTA_ERRCODE_UNDEFINED_ERROR = -6          /* 未定义错误 */
+
+} IOT_OTA_ReportErrCode;
+
+
+/**
+ * @brief 初始化OTA模块和返回句柄
+ *        MQTT客户端必须在调用此接口之前进行初始化
+ *
+ * @param product_sn:   指定产品序列号
+ * @param device_sn:    指定设备序列号
+ * @param ch_signal:    指定的信号通道.
+ *
+ * @retval : 成功则返回句柄,失败返回NULL
+ */
+void *IOT_OTA_Init(const char *product_sn, const char *device_sn, void *ch_signal);
+
+
+/**
+ * @brief 释放OTA相关的资源
+ *        如果在下载之后没有调用重新启动,则须调用该接口以释放资源
+ *
+ * @param handle: 指定OTA模块
+ *
+ * @retval   0 : 成功
+ * @retval < 0 : 失败,返回具体错误码
+ */
+int IOT_OTA_Destroy(void *handle);
+
+
+/**
+ * @brief 向OTA服务器报告固件版本信息。
+ *        NOTE: 进行OTA前请保证先上报一次本地固件的版本信息,以便服务器获取到设备目前的固件信息
+ *
+ * @param handle:   指定OTA模块
+ * @param version:  以字符串格式指定固件版本
+ *
+ * @retval > 0 : 对应publish的packet id
+ * @retval < 0 : 失败,返回具体错误码
+ */
+int IOT_OTA_ReportVersion(void *handle, const char *version);
+
+
+/**
+ * @brief 向OTA服务器报告详细进度
+ *
+ * @param handle:       指定OTA模块
+ * @param progress:     下载或升级进度
+ * @param reportType:   指定当前的OTA状态
+ *
+ * @retval 0 : 成功
+ * @retval < 0 : 失败,返回具体错误码
+ */
+int IOT_OTA_ReportProgress(void *handle, int progress, IOT_OTA_ProgressState state);
+
+
+/**
+ * @brief 向OTA服务器上报升级成功
+ *
+ * @param handle:   指定OTA模块
+ * @param version:  即将升级的固件信息
+ *
+ * @retval > 0 : 对应publish的packet id
+ * @retval < 0 : 失败,返回具体错误码
+ */
+int IOT_OTA_ReportSuccess(void *handle, const char *version);
+
+
+/**
+ * @brief 向OTA服务器上报失败信息
+ *
+ * @param handle:    指定OTA模块
+ * @param err_code:  错误码
+ *
+ * @retval > 0 : 对应publish的packet id
+ * @retval < 0 : 失败,返回具体错误码
+ */
+int IOT_OTA_ReportFail(void *handle, IOT_OTA_ReportErrCode err_code);
+
+/**
+ * @brief 请求固件更新消息。设备离线时,不能接收服务端推送的升级消息。通过MQTT协议接入物联网平台的设备再次上线后,主动请求固件更新消息
+ *
+ * @param handle:   指定OTA模块
+ * @param version:  当前固件版本号
+ *
+ * @retval > 0 : 对应publish的packet id
+ * @retval < 0 : 失败,返回具体错误码
+ */
+int IOT_OTA_RequestFirmware(void *handle, const char *version);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //C_SDK_UIOT_EXPORT_OTA_H_

+ 158 - 0
uiot/sdk-impl/uiot_export_shadow.h

@@ -0,0 +1,158 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+
+#ifndef C_SDK_UIOT_EXPORT_SHADOW_H_
+#define C_SDK_UIOT_EXPORT_SHADOW_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "uiot_import.h"
+#include "shadow_client.h"
+
+/**
+ * @brief 构造ShadowClient
+ *
+ * @param product_sn 产品序列号
+ * @param device_sn 设备序列号
+ * @param ch_signal 与MQTT服务器连接的句柄
+ *
+ * @return 返回NULL: 构造失败
+ */
+void* IOT_Shadow_Construct(const char *product_sn, const char *device_sn, void *ch_signal);
+
+/**
+ * @brief 销毁ShadowClient 关闭设备影子连接
+ *
+ * @param handle ShadowClient对象
+ *
+ * @return 返回SUCCESS, 表示成功
+ */
+int IOT_Shadow_Destroy(void *handle);
+
+/**
+ * @brief            消息接收, 心跳包管理, 超时请求处理
+ *
+ * @param handle     ShadowClient对象
+ * @param timeout_ms 超时时间, 单位:ms
+ * @return           返回SUCCESS, 表示调用成功
+ */
+int IOT_Shadow_Yield(void *handle, uint32_t timeout_ms);
+
+/**
+ * @brief 注册当前设备的设备属性
+ *
+ * @param pClient    ShadowClient对象
+ * @param pProperty  设备属性
+ * @param callback   设备属性更新回调处理函数
+ * @return           返回SUCCESS, 表示请求成功
+ */
+int IOT_Shadow_Register_Property(void *handle, DeviceProperty *pProperty, OnPropRegCallback callback);
+
+/**
+ * @brief 注销当前设备的设备属性
+ *
+ * @param pClient    ShadowClient对象
+ * @param pProperty  设备属性
+ * @return           SUCCESS 请求成功
+ */
+int IOT_Shadow_UnRegister_Property(void *handle, DeviceProperty *pProperty);
+
+/**
+ * @brief 获取设备影子文档并同步设备离线期间设备影子更新的属性值和版本号
+ *
+ * @param pClient           ShadowClient对象
+ * @param request_callback  请求回调函数
+ * @param timeout_sec       请求超时时间, 单位:s
+ * @param user_context      请求回调函数的用户数据
+ * @return                  SUCCESS 请求成功
+ */
+int IOT_Shadow_Get_Sync(void *handle, OnRequestCallback request_callback, uint32_t timeout_sec, void *user_context); 
+
+/**
+ * @brief 设备更新设备影子的属性,变长入参的个数要和property_count的个数保持一致
+ *
+ * @param pClient           ShadowClient对象
+ * @param request_callback  请求回调函数
+ * @param timeout_sec       请求超时时间, 单位:s
+ * @param user_context      请求回调函数的用户数据
+ * @param property_count    变长入参的个数      
+ * @param ...               变长入参设备的属性
+ * @return                  SUCCESS 请求成功
+ */
+int IOT_Shadow_Update(void *handle, OnRequestCallback request_callback, uint32_t timeout_sec, void *user_context, int property_count, ...);
+
+/**
+ * @brief 更新属性并清零设备影子的版本号,变长入参的个数要和property_count的个数保持一致
+ *
+ * @param pClient           ShadowClient对象
+ * @param request_callback  请求回调函数
+ * @param timeout_sec       请求超时时间, 单位:s
+ * @param user_context      请求回调函数的用户数据
+ * @param property_count    变长入参的个数      
+ * @param ...               变长入参设备的属性
+ * @return                  SUCCESS 请求成功
+ */
+int IOT_Shadow_Update_And_Reset_Version(void *handle, OnRequestCallback request_callback, uint32_t timeout_sec, void *user_context, int property_count, ...); 
+
+/**
+ * @brief 设备删除设备影子的属性,变长入参的个数要和property_count的个数保持一致
+ *
+ * @param pClient           ShadowClient对象
+ * @param request_callback  请求回调函数
+ * @param timeout_sec       请求超时时间, 单位:s
+ * @param user_context      请求回调函数的用户数据
+ * @param property_count    变长入参的个数      
+ * @param ...               变长入参设备的属性
+ * @return                  SUCCESS 请求成功
+ */
+int IOT_Shadow_Delete(void *handle, OnRequestCallback request_callback, uint32_t timeout_sec, void *user_context, int property_count, ...); 
+
+/**
+ * @brief 设备删除全部设备影子的属性
+ *
+ * @param pClient           ShadowClient对象
+ * @param request_callback  请求回调函数
+ * @param timeout_sec       请求超时时间, 单位:s
+ * @param user_context      请求回调函数的用户数据
+ * @return                  SUCCESS 请求成功
+ */
+int IOT_Shadow_Delete_All(void *handle, OnRequestCallback request_callback, uint32_t timeout_sec, void *user_context);
+
+/**
+ * @brief 在请求中增加需要修改的属性
+ *
+ * @param pParams    设备影子文档修改请求
+ * @param pProperty  设备属性
+ * @return           返回SUCCESS, 表示请求成功
+ */
+int IOT_Shadow_Request_Add_Delta_Property(void *handle, RequestParams *pParams, DeviceProperty *pProperty);
+
+/**
+ * @brief 使用字符串的属性值直接更新属性值
+ *
+ * @param value         从云服务器设备影子文档Desired字段中解析出的字符串
+ * @param pProperty     设备属性
+ * @return              返回SUCCESS, 表示请求成功
+ */
+int IOT_Shadow_Direct_Update_Value(char *value, DeviceProperty *pProperty);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* C_SDK_UIOT_EXPORT_SHADOW_H_ */

+ 334 - 0
uiot/sdk-impl/uiot_import.h

@@ -0,0 +1,334 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_UIOT_IMPORT_H_
+#define C_SDK_UIOT_IMPORT_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <inttypes.h>
+
+#include "uiot_defs.h"
+#include "HAL_Timer_Platform.h"
+#include "utils_net.h"
+
+/**
+ * @brief 创建互斥量
+ *
+ * @return 创建成功返回Mutex指针,创建失败返回NULL
+ */
+void *HAL_MutexCreate(void);
+
+/**
+ * @brief 销毁互斥量
+ *
+ * @param Mutex指针
+ */
+void HAL_MutexDestroy(_IN_ void *mutex);
+
+/**
+ * @brief 阻塞式加锁。如果互斥量已被另一个线程锁定和拥有,则调用该函数的线程将阻塞,直到该互斥量变为可用为止
+ *
+ * @param Mutex指针
+ */
+void HAL_MutexLock(_IN_ void *mutex);
+
+/**
+ * @brief 非阻塞式加锁。如果mutex参数所指定的互斥锁已经被锁定,调用函数将立即返回FAILURE,不会阻塞当前线程
+ *
+ * @param  Mutex指针
+ * @return 如果成功获取锁,则返回SUCCESS,获取失败返回FAILURE
+ */
+IoT_Error_t HAL_MutexTryLock(_IN_ void *mutex);
+
+/**
+ * @brief 释放互斥量
+ *
+ * @param Mutex指针
+ */
+void HAL_MutexUnlock(_IN_ void *mutex);
+
+/**
+ * @brief 申请内存块
+ *
+ * @param size   申请的内存块大小
+ * @return       申请成功返回指向内存首地址的指针,申请失败返回NULL
+ */
+void *HAL_Malloc(_IN_ uint32_t size);
+
+/**
+ * @brief 释放内存块
+ *
+ * @param ptr   指向要释放的内存块的指针
+ */
+void HAL_Free(_IN_ void *ptr);
+
+/**
+ * @brief 打印函数,向标准输出格式化打印一个字符串
+ *
+ * @param fmt   格式化字符串
+ * @param ...   可变参数列表
+ */
+void HAL_Printf(_IN_ const char *fmt, ...);
+
+/**
+ * @brief 打印函数, 向内存缓冲区格式化打印一个字符串
+ *
+ * @param str   指向字符缓冲区的指针
+ * @param len   缓冲区字符长度
+ * @param fmt   格式化字符串
+ * @param ...   可变参数列表
+ * @return      实际写入缓冲区的字符长度
+ */
+int HAL_Snprintf(_OU_ char *str, _IN_ int len, _IN_ const char *fmt, ...);
+
+/**
+ * @brief 打印函数, 格式化输出字符串到指定buffer中
+ *
+ * @param [out] str: 用于存放写入字符串的buffer
+ * @param [in] len:  允许写入的最大字符串长度
+ * @param [in] fmt:  格式化字符串
+ * @param [in] ap:   可变参数列表
+ * @return 成功写入的字符串长度
+ */
+int HAL_Vsnprintf(_OU_ char *str, _IN_ int len, _IN_ const char *fmt, _IN_ va_list ap);
+
+/**
+ * @brief 检索自系统启动以来已运行的毫秒数.
+ *
+ * @return 返回毫秒数.
+ */
+uint64_t HAL_UptimeMs(void);
+
+/**
+ * @brief 休眠.
+ *
+ * @param ms 休眠的时长, 单位毫秒.
+ */
+void HAL_SleepMs(_IN_ uint32_t ms);
+
+/**
+ * @brief 获取产品序列号。从设备持久化存储(例如FLASH)中读取产品序列号。
+ *
+ * @param productSN  存放ProductSN的字符串缓冲区
+ * @return           返回SUCCESS, 表示获取成功,FAILURE表示获取失败
+ */
+IoT_Error_t HAL_GetProductSN(_OU_ char productSN[IOT_PRODUCT_SN_LEN + 1]);
+
+/**
+ * @brief 获取产品密钥(动态注册)。从设备持久化存储(例如FLASH)中读取产品密钥。
+ *
+ * @param productSecret   存放ProductSecret的字符串缓冲区
+ * @return                返回SUCCESS, 表示获取成功,FAILURE表示获取失败
+ */
+IoT_Error_t HAL_GetProductSecret(_OU_ char productSecret[IOT_PRODUCT_SECRET_LEN + 1]);
+
+/**
+ * @brief 获取设备序列号。从设备持久化存储(例如FLASH)中读取设备序列号。
+ *
+ * @param deviceSN   存放DeviceSN的字符串缓冲区
+ * @return           返回SUCCESS, 表示获取成功,FAILURE表示获取失败
+ */
+IoT_Error_t HAL_GetDeviceSN(_OU_ char deviceSN[IOT_DEVICE_SN_LEN + 1]);
+
+/**
+ * @brief 获取设备密钥。从设备持久化存储(例如FLASH)中读取设备密钥。
+ *
+ * @param deviceSecret  存放DeviceSecret的字符串缓冲区
+ * @return              返回SUCCESS, 表示获取成功,FAILURE表示获取失败
+ */
+IoT_Error_t HAL_GetDeviceSecret(_OU_ char deviceSecret[IOT_DEVICE_SECRET_LEN + 1]);
+
+/**
+ * @brief 设置产品序列号。将产品序列号烧写到设备持久化存储(例如FLASH)中,以备后续使用。
+ *
+ * @param pProductSN  指向待设置的产品序列号的指针
+ * @return            返回SUCCESS, 表示设置成功,FAILURE表示设置失败
+ */
+IoT_Error_t HAL_SetProductSN(_IN_ const char *pProductSN);
+
+/**
+ * @brief 设置产品密钥。将产品密钥烧写到设备持久化存储(例如FLASH)中,以备后续使用。
+ *
+ * @param pProductSecret  指向待设置的产品密钥的指针
+ * @return                返回SUCCESS, 表示设置成功,FAILURE表示设置失败
+ */
+IoT_Error_t HAL_SetProductSecret(_IN_ const char *pProductSecret);
+
+/**
+ * @brief 设置设备序列号。将设备序列号烧写到设备持久化存储(例如FLASH)中,以备后续使用。
+ *
+ * @param pDeviceSN  指向待设置的设备序列号的指针
+ * @return           返回SUCCESS, 表示设置成功,FAILURE表示设置失败
+ */
+IoT_Error_t HAL_SetDeviceSN(_IN_ const char *pDeviceSN);
+
+/**
+ * @brief 设置设备密钥。将设备密钥烧写到设备持久化存储(例如FLASH)中,以备后续使用。
+ *
+ * @param pDeviceSecret  指向待设置的设备密钥的指针
+ * @return               返回SUCCESS, 表示设置成功,FAILURE表示设置失败
+ */
+IoT_Error_t HAL_SetDeviceSecret(_IN_ const char *pDeviceSecret);
+
+/**
+ * 定义特定平台下的一个定时器结构体,需要在特定平台的代码中创建一个名为
+ * HAL_Timer_Platform.h的头文件,在该头文件中定义Timer结构体。
+ */
+typedef struct Timer Timer;
+
+/**
+ * @brief 判断定时器时间是否已经过期
+ *
+ * @param timer     定时器结构体
+ * @return          返回true, 表示定时器已过期
+ */
+bool HAL_Timer_Expired(_IN_ Timer *timer);
+
+/**
+ * @brief 根据timeout时间开启定时器计时, 单位: ms
+ *
+ * @param timer         定时器结构体
+ * @param timeout_ms    超时时间, 单位:ms
+ */
+void HAL_Timer_Countdown_ms(_IN_ Timer *timer, _IN_ uint32_t timeout_ms);
+
+/**
+ * @brief 根据timeout时间开启定时器计时, 单位: s
+ *
+ * @param timer   定时器结构体
+ * @param timeout 超时时间, 单位:s
+ */
+void HAL_Timer_Countdown(_IN_ Timer *timer, _IN_ uint32_t timeout);
+
+/**
+ * @brief 检查给定定时器剩余时间
+ *
+ * @param timer     定时器结构体
+ * @return          定时器剩余时间, 单位: ms
+ */
+uint32_t HAL_Timer_Remain_ms(_IN_ Timer *timer);
+
+/**
+ * @brief 初始化定时器结构体
+ *
+ * @param timer 定时器结构体
+ */
+void HAL_Timer_Init(_IN_ Timer *timer);
+
+/**
+ * @brief 建立TLS连接
+ *
+ * @host        指定的TLS服务器网络地址
+ * @port        指定的TLS服务器端口
+ * @ca_crt      指向X.509证书的指针
+ * @ca_crt_len  证书字节长度
+ * @return      连接成功, 返回TLS连接句柄,连接失败,返回NULL
+ */
+uintptr_t HAL_TLS_Connect(_IN_ const char *host, _IN_ uint16_t port, _IN_ uint16_t authmode, _IN_ const char *ca_crt,
+                          _IN_ size_t ca_crt_len);
+
+/**
+ * @brief 断开TLS连接, 并释放相关对象资源
+ *
+ * @param pParams TLS连接参数
+ * @return        若断开成功返回SUCCESS,否则返回FAILURE
+ */
+int32_t HAL_TLS_Disconnect(_IN_ uintptr_t handle);
+
+/**
+ * @brief 向指定的TLS连接写入数据。此接口为同步接口, 如果在超时时间内写入了参数len指定长度的数据则立即返回, 否则在超时时间到时返回
+ *
+ * @param handle        TLS连接句柄
+ * @param buf           指向数据发送缓冲区的指针
+ * @param len           数据发送缓冲区的字节大小
+ * @param timeout_ms    超时时间, 单位:ms
+ * @return              <0: TLS写入错误; =0: TLS写超时, 且没有写入任何数据; >0: TLS成功写入的字节数
+ */
+int32_t HAL_TLS_Write(_IN_ uintptr_t handle, _IN_ unsigned char *buf, _IN_ size_t len, _IN_ uint32_t timeout_ms);
+
+/**
+ * @brief 通过TLS连接读数据
+ *
+ * @param handle        TLS连接句柄
+ * @param buf           指向数据接收缓冲区的指针
+ * @param len           数据接收缓冲区的字节大小
+ * @param timeout_ms    超时时间, 单位:ms
+ * @return              <0: TLS读取错误; =0: TLS读超时, 且没有读取任何数据; >0: TLS成功读取的字节数
+ */
+int32_t HAL_TLS_Read(_IN_ uintptr_t handle, _OU_ unsigned char *buf, _IN_ size_t len, _IN_ uint32_t timeout_ms);
+
+/**
+ * @brief   建立TCP连接。根据指定的HOST地址, 服务器端口号建立TCP连接, 返回对应的连接句柄。
+ *
+ * @host	指定的TCP服务器网络地址
+ * @port	指定的TCP服务器端口
+ * @return	连接成功, 返回TCP连接句柄,连接失败,返回NULL
+ */
+uintptr_t HAL_TCP_Connect(_IN_ const char *host, _IN_ uint16_t port);
+
+/**
+ * @brief 断开TCP连接, 并释放相关对象资源。
+ *
+ * @param fd  TCP连接句柄
+ * @return	  成功返回SUCCESS,失败返回FAILURE
+ */
+int32_t HAL_TCP_Disconnect(_IN_ uintptr_t fd);
+
+/**
+ * @brief 向指定的TCP连接写入数据。此接口为同步接口, 如果在超时时间内写入了参数len指定长度的数据则立即返回, 否则在超时时间到时返回。
+ *
+ * @param fd				TCP连接句柄
+ * @param buf				指向数据发送缓冲区的指针
+ * @param len				数据发送缓冲区的字节大小
+ * @param timeout_ms		超时时间,单位: ms
+ * @return					<0: TCP写入错误; =0: TCP写超时, 且没有写入任何数据; >0: TCP成功写入的字节数
+ */
+int32_t HAL_TCP_Write(_IN_ uintptr_t fd, _IN_ unsigned char *buf, _IN_ size_t len, _IN_ uint32_t timeout_ms);
+
+/**
+ * @brief 从指定的TCP连接读取数据。此接口为同步接口, 如果在超时时间内读取到参数len指定长度的数据则立即返回, 否则在超时时间到时返回。
+ *
+ * @param fd				TCP连接句柄
+ * @param buf				指向数据接收缓冲区的指针
+ * @param len				数据接收缓冲区的字节大小
+ * @param timeout_ms		超时时间,单位: ms
+ * @return					<0: TCP读取错误; =0: TCP读超时, 且没有读取任何数据; >0: TCP成功读取的字节数
+ */
+int32_t HAL_TCP_Read(_IN_ uintptr_t fd, _OU_ unsigned char *buf, _IN_ size_t len, _IN_ uint32_t timeout_ms);
+
+int HAL_AT_Read(_IN_ utils_network_pt pNetwork, _OU_ unsigned char *buffer, _IN_ size_t len);
+
+int HAL_AT_Write(_IN_ unsigned char *buffer, _IN_ size_t len);
+
+int HAL_AT_TCP_Disconnect();
+
+int HAL_AT_TCP_Connect(_IN_ void * pNetwork, _IN_ const char *host, _IN_ uint16_t port); 
+
+int HAL_AT_Write_Tcp(_IN_ utils_network_pt pNetwork, _IN_ unsigned char *buffer, _IN_ size_t len);
+
+int HAL_AT_Read_Tcp(_IN_ utils_network_pt pNetwork, _IN_ unsigned char *buffer, _IN_ size_t len);
+
+#if defined(__cplusplus)
+}
+#endif
+#endif  /* C_SDK_UIOT_IMPORT_H_ */

+ 61 - 0
uiot/sdk-impl/uiot_internal.h

@@ -0,0 +1,61 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_UIOT_INTERNAL_H_
+#define C_SDK_UIOT_INTERNAL_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include "uiot_export.h"
+#include "uiot_import.h"
+
+#define NUMERIC_VALID_CHECK(num, err) \
+    do { \
+        if (0 == (num)) { \
+            return (err); \
+        } \
+    } while(0)
+
+#define POINTER_VALID_CHECK(ptr, err) \
+    do { \
+        if (NULL == (ptr)) { \
+            return (err); \
+        } \
+    } while(0)
+
+#define POINTER_VALID_CHECK_RTN(ptr) \
+    do { \
+        if (NULL == (ptr)) { \
+            return; \
+        } \
+    } while(0)
+
+#define STRING_PTR_VALID_CHECK(ptr, err) \
+    do { \
+        if (NULL == (ptr)) { \
+            return (err); \
+        } \
+        if (0 == strlen((ptr))) { \
+            return (err); \
+        } \
+    } while(0)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* C_SDK_UIOT_INTERNAL_H_ */

+ 235 - 0
uiot/shadow/include/shadow_client.h

@@ -0,0 +1,235 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef IOT_SHADOW_CLIENT_H_
+#define IOT_SHADOW_CLIENT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+#include "mqtt_client.h"
+
+
+/* 在任意给定时间内, 处于appending状态的请求最大个数 */
+#define MAX_APPENDING_REQUEST_AT_ANY_GIVEN_TIME                     (10)
+
+/* 一个method的最大长度 */
+#define MAX_SIZE_OF_METHOD                                          (10)
+
+/* 一个仅包含method字段的JSON文档的最大长度 */
+#define MAX_SIZE_OF_JSON_WITH_METHOD                                (MAX_SIZE_OF_METHOD + 20)
+
+/* 接收云端返回的JSON文档的buffer大小 */
+#define CLOUD_IOT_JSON_RX_BUF_LEN                                   (UIOT_MQTT_RX_BUF_LEN + 1)
+
+/* 最大等待时间 */
+#define MAX_WAIT_TIME_SEC   1
+#define MAX_WAIT_TIME_MS    1000
+
+/**
+ * @brief 请求响应返回的类型
+ */
+typedef enum {
+    ACK_NONE = -3,      // 请求超时
+    ACK_TIMEOUT = -2,   // 请求超时
+    ACK_REJECTED = -1,  // 请求拒绝
+    ACK_ACCEPTED = 0    // 请求接受
+} RequestAck;
+
+/**
+ * @brief 操作云端设备文档可以使用的三种方式
+ */
+typedef enum {
+    GET,                    // 获取云端设备文档
+    UPDATE,                 // 更新或创建云端设备文档
+    UPDATE_AND_RESET_VER,   // 更新同时重置版本号
+    DELETE,                 // 删除部分云端设备文档
+    DELETE_ALL,             // 删除全部云端设备文档中的属性,不需要一个个添加需要删除的属性
+    REPLY_CONTROL_UPDATE,   // 设备处理完服务端的control消息后回应的update消息
+    REPLY_CONTROL_DELETE,   // 设备处理完服务端的control消息后回应的delete消息
+} Method;
+
+/**
+ * @brief JSON文档中支持的数据类型
+ */
+typedef enum {
+    JINT32,     // 32位有符号整型
+    JINT16,     // 16位有符号整型
+    JINT8,      // 8位有符号整型
+    JUINT32,    // 32位无符号整型
+    JUINT16,    // 16位无符号整型
+    JUINT8,     // 8位无符号整型
+    JFLOAT,     // 单精度浮点型
+    JDOUBLE,    // 双精度浮点型
+    JBOOL,      // 布尔型
+    JSTRING,    // 字符串
+    JOBJECT     // JSON对象
+} JsonDataType;
+
+/**
+ * @brief 定义设备的某个属性, 实际就是一个JSON文档节点
+ */
+typedef struct _JSONNode {
+    char   		 *key;    // 该JSON节点的Key
+    void         *data;   // 该JSON节点的Value
+    JsonDataType type;    // 该JSON节点的数据类型
+} DeviceProperty;
+
+/**
+ * @brief 每次文档请求响应的回调函数
+ *
+ * @param pClient        ShadowClient对象
+ * @param method         文档操作方式
+ * @param requestAck     请求响应类型
+ * @param pJsonDocument  云端响应返回的文档
+ * @param userContext    用户数据
+ *
+ */
+typedef void (*OnRequestCallback)(void *pClient, Method method, RequestAck requestAck, const char *pJsonDocument, void *userContext);
+
+/**
+ * @brief 文档操作请求的参数结构体定义
+ */
+typedef struct _RequestParam {
+    Method               	method;              	// 文档请求方式: GET, UPDATE, DELETE等
+
+    List                    *property_delta_list;   // 该请求需要修改的属性
+
+    uint32_t             	timeout_sec;         	// 请求超时时间, 单位:s
+
+    OnRequestCallback    	request_callback;    	// 请求回调方法
+
+    void                 	*user_context;          // 用户数据, 会通过回调方法OnRequestCallback返回
+
+} RequestParams;
+
+/**
+ * @brief 设备属性处理回调函数
+ *
+ * @param pClient          ShadowClient对象
+ * @param pParams          设备影子文档修改请求
+ * @param pJsonValueBuffer 设备属性值
+ * @param valueLength      设备属性值长度
+ * @param DeviceProperty   设备属性结构体
+ */
+typedef void (*OnPropRegCallback)(void *pClient, RequestParams *pParams, char *pJsonValueBuffer, uint32_t valueLength, DeviceProperty *pProperty);
+
+/**
+ * @brief 该结构体用于保存已登记的设备属性及设备属性处理的回调方法
+ */
+typedef struct {
+
+    void *property;					 // 设备属性
+
+    OnPropRegCallback callback;      // 回调处理函数
+
+} PropertyHandler;
+
+typedef struct _ShadowInnerData {
+    uint32_t version;                   //本地维护的影子文档的版本号
+    List *request_list;                 //影子文档的修改请求
+    List *property_list;                //本地维护的影子文档的属性值,期望值和回调处理函数
+} ShadowInnerData;
+
+typedef struct _Shadow {
+    void *mqtt;
+    const char *product_sn;
+    const char *device_sn;
+    void *request_mutex;
+    void *property_mutex;
+    ShadowInnerData inner_data;
+} UIoT_Shadow;
+
+/**
+ * @brief 设备影子初始化
+ *
+ * @param pShadow       shadow client
+ * @return         		返回SUCCESS, 表示成功
+ */
+int uiot_shadow_init(UIoT_Shadow *pShadow);
+
+/**
+ * @brief 设备影子重置,主要是将设备影子中的队列归零
+ *
+ * @param pClient       shadow client
+ * @return         		返回SUCCESS, 表示成功
+ */
+void uiot_shadow_reset(void *pClient);
+
+/**
+ * @brief 处理请求队列中已经超时的请求
+ * 
+ * @param pShadow   shadow client
+ */
+void _handle_expired_request(UIoT_Shadow *pShadow);
+
+/**
+ * @brief 所有的云端设备文档操作请求, 通过该方法进行中转分发
+ *
+ * @param pShadow       shadow client
+ * @param pParams  		请求参数
+ * @param pJsonDoc 		请求文档
+ * @param sizeOfBuffer 	文档缓冲区大小
+ * @return         		返回SUCCESS, 表示成功
+ */
+int uiot_shadow_make_request(UIoT_Shadow *pShadow,char *pJsonDoc, size_t sizeOfBuffer, RequestParams *pParams);
+
+/**
+ * @brief 订阅设备影子topic
+ *
+ * @param pShadow                   shadow client
+ * @param topicFilter               topic的名称
+ * @param on_message_handler 		topic的消息回调函数
+ * @return         		返回SUCCESS, 表示成功
+ */
+int uiot_shadow_subscribe_topic(UIoT_Shadow *pShadow, char *topicFilter, OnMessageHandler on_message_handler);
+
+/**
+ * @brief 初始化一个修改设备影子的请求
+ * @param handle        ShadowClient对象
+ * @param method        修改类型
+ * @param callback      请求回调函数
+ * @param timeout_sec   超时时间
+ * @return              返回NULL,表示初始化失败
+ */
+void* uiot_shadow_request_init(Method method, OnRequestCallback request_callback, uint32_t timeout_sec, void *user_context);
+
+/**
+ * @brief 从服务端获取设备影子文档
+ *
+ * @param handle        shadow handle
+ * @param message  	    返回的消息
+ * @param pUserdata     跟随回调函数返回
+ */
+void topic_request_result_handler(void *pClient, MQTTMessage *message, void *pUserdata);
+
+/**
+ * @brief 从服务端获取设备影子文档
+ *
+ * @param handle        shadow handle
+ * @param message  	    返回的消息
+ * @param pUserdata     跟随回调函数返回
+ */
+void topic_sync_handler(void *pClient, MQTTMessage *message, void *pUserdata);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IOT_SHADOW_CLIENT_H_ */

+ 92 - 0
uiot/shadow/include/shadow_client_common.h

@@ -0,0 +1,92 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+
+#ifndef IOT_SHADOW_CLIENT_COMMON_H_
+#define IOT_SHADOW_CLIENT_COMMON_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "shadow_client.h"
+
+//设备影子相关topic
+#define SHADOW_PUBLISH_REQUEST_TEMPLATE                 "/$system/%s/%s/shadow/upstream"
+#define SHADOW_SUBSCRIBE_REQUEST_TEMPLATE               "/$system/%s/%s/shadow/downstream"
+#define SHADOW_PUBLISH_SYNC_TEMPLATE                    "/$system/%s/%s/shadow/get"
+#define SHADOW_SUBSCRIBE_SYNC_TEMPLATE                  "/$system/%s/%s/shadow/get_reply"
+#define SHADOW_DOC_TEMPLATE                             "/$system/%s/%s/shadow/document"
+
+/**
+ * @brief 如果没有订阅delta主题, 则进行订阅, 并注册相应设备属性
+ *
+ * @param pShadow   shadow client
+ * @param pProperty 设备属性
+ * @param callback  相应设备属性处理回调函数
+ * @return          返回SUCCESS, 表示成功
+ */
+int shadow_common_register_property_on_delta(UIoT_Shadow *pShadow, DeviceProperty *pProperty, OnPropRegCallback callback);
+
+/**
+ * @brief 更新属性值
+ *
+ * @param pShadow   shadow client
+ * @param pProperty 设备属性
+ * @return          返回SUCCESS, 表示成功
+ */
+int shadow_common_update_property(UIoT_Shadow *pshadow, DeviceProperty *pProperty, Method           method);
+
+/**
+ * @brief 移除注册过的设备属性
+ *
+ * @param pShadow   shadow client
+ * @param pProperty 设备属性
+ * @return          返回SUCCESS, 表示成功
+ */
+int shadow_common_remove_property(UIoT_Shadow *pshadow, DeviceProperty *pProperty);
+
+/**
+ * @brief 检查注册属性是否已经存在
+ *
+ * @param pShadow   shadow client
+ * @param pProperty 设备属性
+ * @return          返回 0, 表示属性不存在
+ */
+int shadow_common_check_property_existence(UIoT_Shadow *pshadow, DeviceProperty *pProperty);
+
+/**
+ * @brief 检查注册属性是否已经存在
+ *
+ * @param pParams   RequestParams
+ * @param pProperty 设备属性
+ * @return          返回 0, 表示修改属性添加成功
+ */
+int request_common_add_delta_property(RequestParams *pParams, DeviceProperty *pProperty);
+
+/**
+ * @brief 检查注册属性是否已经存在
+ *
+ * @param property_handle   PropertyHandler
+ * @param pProperty         设备属性
+ * @return                  返回 0, 表示匹配
+ */
+int shadow_common_check_property_match(void *property_handle, void *pProperty);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //IOT_SHADOW_CLIENT_COMMON_H_

+ 171 - 0
uiot/shadow/include/shadow_client_json.h

@@ -0,0 +1,171 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+
+#ifndef IOT_SHADOW_CLIENT_JSON_H_
+#define IOT_SHADOW_CLIENT_JSON_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stddef.h>
+
+#include "uiot_import.h"
+#include "shadow_client.h"
+
+/* 回复消息中的消息字段 */
+#define METHOD_FIELD	         	        "Method"
+#define PAYLOAD_RESULT_FIELD	            "Payload.RetCode"
+#define PAYLOAD_STATE_REPORTED_FIELD        "Payload.State.Reported"
+#define PAYLOAD_STATE_DESIRED_FIELD         "Payload.State.Desired"
+
+/* 设备影子文档中的字段 */
+#define STATE_FIELD                         "State"
+#define STATE_REPORTED_FIELD                "State.Reported"
+#define STATE_DESIRED_FIELD                 "State.Desired"
+#define METADATA_FIELD                      "Metadata"
+#define METADATA_REPORTED_FIELD             "Metadata.Reported"
+#define METADATA_DESIRED_FIELD              "Metadata.Desired"
+#define VERSION_FIELD                       "Version"
+#define TIMESTAMP_FIELD                     "Timestamp"
+
+/* 消息类型字段 */
+#define METHOD_CONTROL        	            "control"
+#define METHOD_GET				            "get"
+#define METHOD_UPDATE			            "update"
+#define METHOD_DELETE                       "delete"
+#define METHOD_REPLY                        "reply"
+#define METHOD_GET_REPLY                    "get_reply"
+
+/**
+ * @brief 检查函数snprintf的返回值
+ *
+ * @param returnCode       函数snprintf的返回值
+ * @param maxSizeOfWrite   可写最大字节数
+ * @return                 返回ERR_JSON, 表示出错; 返回ERR_JSON_BUFFER_TRUNCATED, 表示截断
+ */
+int _check_snprintf_return(int32_t returnCode, size_t maxSizeOfWrite);
+
+/**
+ * 将一个JSON节点写入到JSON串中
+ *
+ * @param jsonBuffer   	JSON串
+ * @param sizeOfBuffer  可写入大小
+ * @param pKey          JSON节点的key
+ * @param pData         JSON节点的value
+ * @param type          JSON节点value的数据类型
+ * @return              返回SUCCESS, 表示成功
+ */
+int put_json_node(char *jsonBuffer, size_t sizeOfBuffer, const char *pKey, void *pData, JsonDataType type);
+
+/**
+ * @brief 从JSON文档中解析出report字段
+ *
+ * @param pJsonDoc         	待解析的JSON文档
+ * @param pType    			输出tyde字段
+ * @return                 	返回true, 表示解析成功
+ */
+bool parse_shadow_payload_state_reported_state(char *pJsonDoc, char **pState);
+
+
+/**
+ * @brief 从JSON文档中解析出desired字段
+ *
+ * @param pJsonDoc         	待解析的JSON文档
+ * @param pType    			输出tyde字段
+ * @return                 	返回true, 表示解析成功
+ */
+bool parse_shadow_payload_state_desired_state(char *pJsonDoc, char **pState);
+
+/**
+ * @brief 从JSON文档中解析出type字段
+ *
+ * @param pJsonDoc         	待解析的JSON文档
+ * @param pType    			输出tyde字段
+ * @return                 	返回true, 表示解析成功
+ */
+bool parse_shadow_method_type(char *pJsonDoc, char **pType);
+
+/**
+ * @brief 从JSON文档中解析出recode字段
+ *
+ * @param pJsonDoc         	待解析的JSON文档
+ * @param pType    			输出tyde字段
+ * @return                 	返回true, 表示解析成功
+ */
+bool parse_shadow_payload_retcode_type(char *pJsonDoc, uint32_t *pRetCode);
+
+/**
+ * @brief 从JSON文档中解析出version字段
+ *
+ * @param pJsonDoc         	待解析的JSON文档
+ * @param pType    			输出tyde字段
+ * @return                 	返回true, 表示解析成功
+ */
+bool parse_version_num(char *pJsonDoc, uint32_t *pVersionNumber);
+
+/**
+ * @brief 从JSON文档中解析出reported字段
+ *
+ * @param pJsonDoc         	待解析的JSON文档
+ * @param pType    			输出tyde字段
+ * @return                 	返回true, 表示解析成功
+ */
+bool parse_shadow_state_reported_type(char *pJsonDoc, char **pType);
+
+/**
+ * @brief 从JSON文档中解析出desired字段
+ *
+ * @param pJsonDoc         	待解析的JSON文档
+ * @param pType    			输出tyde字段
+ * @return                 	返回true, 表示解析成功
+ */
+bool parse_shadow_state_desired_type(char *pJsonDoc, char **pType);
+
+/**
+ * @brief 从JSON文档中解析出state字段
+ *
+ * @param pJsonDoc         	待解析的JSON文档
+ * @param pType    			输出tyde字段
+ * @return                 	返回true, 表示解析成功
+ */
+bool parse_shadow_state_type(char *pJsonDoc, char **pType);
+
+/**
+ * @brief 为GET和DELETE请求构造一个只带有clientToken字段的JSON文档
+ *
+ * @param tokenNumber   shadow的token值,函数内部每次执行完会自增
+ * @param pJsonBuffer 存储JSON文档的字符串缓冲区
+ */
+void build_empty_json(uint32_t *tokenNumber, char *pJsonBuffer);
+
+/**
+ * @brief 如果JSON文档中的key与某个设备属性的key匹配的话, 则更新该设备属性, 该设备属性的值不能为OBJECT类型
+ *
+ * @param pJsonDoc       JSON文档
+ * @param pProperty      设备属性
+ * @return               返回true, 表示成功
+ */
+char *find_value_if_key_match(char *pJsonDoc, DeviceProperty *pProperty);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //IOT_SHADOW_CLIENT_JSON_H_

+ 418 - 0
uiot/shadow/src/shadow_client.c

@@ -0,0 +1,418 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "uiot_internal.h"
+#include "shadow_client.h"
+#include "lite-utils.h"
+#include "shadow_client_common.h"
+
+int IOT_Shadow_Request_Add_Delta_Property(void *handle, RequestParams *pParams, DeviceProperty *pProperty);
+
+void* IOT_Shadow_Construct(const char *product_sn, const char *device_sn, void *ch_signal)
+{
+    FUNC_ENTRY;
+	POINTER_VALID_CHECK(product_sn, NULL);
+	POINTER_VALID_CHECK(device_sn, NULL);
+	POINTER_VALID_CHECK(ch_signal, NULL);
+
+	int ret;
+	UIoT_Shadow *shadow_client = NULL;
+	if ((shadow_client = (UIoT_Shadow *)HAL_Malloc(sizeof(UIoT_Shadow))) == NULL) {
+		LOG_ERROR("memory not enough to malloc ShadowClient\n");
+        return NULL;
+	}
+
+	UIoT_Client *mqtt_client = (UIoT_Client *)ch_signal;
+
+    mqtt_client->event_handler.context = shadow_client;
+    shadow_client->product_sn = product_sn;
+    shadow_client->device_sn = device_sn;
+	shadow_client->mqtt = mqtt_client;
+	shadow_client->inner_data.version = 0;
+	
+	ret = uiot_shadow_init(shadow_client);	
+	if (ret != SUCCESS_RET) {
+		goto end;
+	}
+
+    /* 订阅更新影子文档必要的topic */
+	ret = uiot_shadow_subscribe_topic(shadow_client, SHADOW_SUBSCRIBE_SYNC_TEMPLATE, topic_sync_handler);
+	if (ret < 0)
+	{
+		LOG_ERROR("Subcribe %s fail!\n",SHADOW_SUBSCRIBE_SYNC_TEMPLATE);
+		goto end;
+	}
+  
+    ret = uiot_shadow_subscribe_topic(shadow_client, SHADOW_SUBSCRIBE_REQUEST_TEMPLATE, topic_request_result_handler);
+	if (ret < 0)
+	{
+		LOG_ERROR("Subcribe %s fail!\n",SHADOW_SUBSCRIBE_SYNC_TEMPLATE);
+		goto end;
+	}
+
+	return shadow_client;
+
+end:
+    HAL_Free(shadow_client);
+	return NULL;
+}
+
+int IOT_Shadow_Destroy(void *handle)
+{
+    FUNC_ENTRY;
+	POINTER_VALID_CHECK(handle, ERR_PARAM_INVALID);
+
+	UIoT_Shadow* shadow_client = (UIoT_Shadow*)handle;
+	uiot_shadow_reset(handle);
+
+	IOT_MQTT_Destroy(&shadow_client->mqtt);
+
+    if (NULL != shadow_client->request_mutex) {
+        HAL_MutexDestroy(shadow_client->request_mutex);
+    }
+
+    if (NULL != shadow_client->property_mutex) {
+        HAL_MutexDestroy(shadow_client->property_mutex);
+    }
+
+    HAL_Free(handle);
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+int IOT_Shadow_Yield(void *handle, uint32_t timeout_ms) 
+{
+    FUNC_ENTRY;
+    int ret;
+
+	POINTER_VALID_CHECK(handle, ERR_PARAM_INVALID);
+	NUMERIC_VALID_CHECK(timeout_ms, ERR_PARAM_INVALID);
+
+	UIoT_Shadow *shadow_client = (UIoT_Shadow *)handle;
+
+    _handle_expired_request(shadow_client);
+
+    ret = IOT_MQTT_Yield(shadow_client->mqtt, timeout_ms);
+
+    FUNC_EXIT_RC(ret);
+}
+
+int IOT_Shadow_Register_Property(void *handle, DeviceProperty *pProperty, OnPropRegCallback callback) 
+{
+    FUNC_ENTRY;
+	POINTER_VALID_CHECK(handle, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pProperty, ERR_PARAM_INVALID);
+
+	UIoT_Shadow* shadow_client = (UIoT_Shadow*)handle;
+
+    if (IOT_MQTT_IsConnected(shadow_client->mqtt) == false) {
+        FUNC_EXIT_RC(ERR_MQTT_NO_CONN);
+    }
+
+    if(shadow_client->inner_data.property_list->len)
+    {
+    	if (shadow_common_check_property_existence(shadow_client, pProperty)) 
+    		FUNC_EXIT_RC(ERR_SHADOW_PROPERTY_EXIST);
+    }
+    
+    int ret = shadow_common_register_property_on_delta(shadow_client, pProperty, callback);
+
+    FUNC_EXIT_RC(ret);
+}
+
+int IOT_Shadow_UnRegister_Property(void *handle, DeviceProperty *pProperty)
+{
+    FUNC_ENTRY;
+
+    POINTER_VALID_CHECK(handle, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pProperty, ERR_PARAM_INVALID);
+
+    UIoT_Shadow* pshadow = (UIoT_Shadow*)handle;
+
+    if (IOT_MQTT_IsConnected(pshadow->mqtt) == false) {
+        FUNC_EXIT_RC(ERR_MQTT_NO_CONN);
+    }
+
+    if (!shadow_common_check_property_existence(pshadow, pProperty)) {
+        FUNC_EXIT_RC(ERR_SHADOW_NOT_PROPERTY_EXIST);
+    }
+
+    int ret =  shadow_common_remove_property(pshadow, pProperty);
+
+    FUNC_EXIT_RC(ret);
+}
+
+
+int IOT_Shadow_Get_Sync(void *handle, OnRequestCallback request_callback, uint32_t timeout_sec, void *user_context) 
+{
+    FUNC_ENTRY;
+	int ret = SUCCESS_RET;
+
+	POINTER_VALID_CHECK(handle, ERR_PARAM_INVALID);
+	NUMERIC_VALID_CHECK(timeout_sec, ERR_PARAM_INVALID);
+
+	UIoT_Shadow* shadow_client = (UIoT_Shadow*)handle;
+	char JsonDoc[UIOT_MQTT_TX_BUF_LEN];
+    size_t sizeOfBuffer = sizeof(JsonDoc) / sizeof(JsonDoc[0]);
+
+    RequestParams *pParams = uiot_shadow_request_init(GET, request_callback, timeout_sec, user_context); 
+        
+	if (IOT_MQTT_IsConnected(shadow_client->mqtt) == false) 
+    {
+		FUNC_EXIT_RC(ERR_MQTT_NO_CONN);
+	}
+
+	ret = uiot_shadow_make_request(shadow_client, JsonDoc, sizeOfBuffer, pParams);
+	if (ret != SUCCESS_RET) {
+        FUNC_EXIT_RC(ret);
+    }
+
+	FUNC_EXIT_RC(ret);
+}
+
+int IOT_Shadow_Update(void *handle, OnRequestCallback request_callback, uint32_t timeout_sec, void *user_context, int property_count, ...) 
+{
+    FUNC_ENTRY;
+	int ret = SUCCESS_RET;
+    int loop = 0;
+
+	POINTER_VALID_CHECK(handle, ERR_PARAM_INVALID);
+	NUMERIC_VALID_CHECK(timeout_sec, ERR_PARAM_INVALID);
+
+	UIoT_Shadow* shadow_client = (UIoT_Shadow*)handle;
+	char JsonDoc[UIOT_MQTT_TX_BUF_LEN];
+    size_t sizeOfBuffer = sizeof(JsonDoc) / sizeof(JsonDoc[0]);
+
+    RequestParams *pParams = uiot_shadow_request_init(UPDATE, request_callback, timeout_sec, user_context); 
+
+	va_list pArgs;
+    va_start(pArgs, property_count);
+
+    for(loop = 0; loop < property_count; loop++)
+    {
+        DeviceProperty *pProperty;
+        pProperty  = va_arg(pArgs, DeviceProperty *);
+        if(NULL != pProperty)
+        {
+            if(SUCCESS_RET != IOT_Shadow_Request_Add_Delta_Property(handle, pParams, pProperty))
+            {
+                va_end(pArgs);                
+                return FAILURE_RET;
+            }
+         }
+    }
+
+    va_end(pArgs);
+    
+	if (IOT_MQTT_IsConnected(shadow_client->mqtt) == false) 
+    {    
+		FUNC_EXIT_RC(ERR_MQTT_NO_CONN);
+	}
+
+	ret = uiot_shadow_make_request(shadow_client, JsonDoc, sizeOfBuffer, pParams);
+	if (ret != SUCCESS_RET) {
+        FUNC_EXIT_RC(ret);
+    }
+    
+	FUNC_EXIT_RC(ret);
+}
+
+int IOT_Shadow_Update_And_Reset_Version(void *handle, OnRequestCallback request_callback, uint32_t timeout_sec, void *user_context, int property_count, ...) 
+{
+    FUNC_ENTRY;
+	int ret = SUCCESS_RET;
+    int loop = 0;
+
+	POINTER_VALID_CHECK(handle, ERR_PARAM_INVALID);
+	NUMERIC_VALID_CHECK(timeout_sec, ERR_PARAM_INVALID);
+
+	UIoT_Shadow* shadow_client = (UIoT_Shadow*)handle;
+	char JsonDoc[UIOT_MQTT_TX_BUF_LEN];
+    size_t sizeOfBuffer = sizeof(JsonDoc) / sizeof(JsonDoc[0]);
+
+    RequestParams *pParams = uiot_shadow_request_init(UPDATE_AND_RESET_VER, request_callback, timeout_sec, user_context); 
+
+	va_list pArgs;
+    va_start(pArgs, property_count);
+
+    for(loop = 0; loop < property_count; loop++)
+    {
+        DeviceProperty *pProperty;
+        pProperty  = va_arg(pArgs, DeviceProperty *);
+        if(NULL != pProperty)
+        {
+            if(SUCCESS_RET != IOT_Shadow_Request_Add_Delta_Property(handle, pParams, pProperty))
+            {
+                va_end(pArgs);
+                return FAILURE_RET;
+            }
+         }
+    }
+
+    va_end(pArgs);
+    
+	if (IOT_MQTT_IsConnected(shadow_client->mqtt) == false) 
+    {
+		FUNC_EXIT_RC(ERR_MQTT_NO_CONN);
+	}
+
+	ret = uiot_shadow_make_request(shadow_client, JsonDoc, sizeOfBuffer, pParams);
+	if (ret != SUCCESS_RET) {
+        FUNC_EXIT_RC(ret);
+    }
+
+	FUNC_EXIT_RC(ret);
+}
+
+int IOT_Shadow_Delete(void *handle, OnRequestCallback request_callback, uint32_t timeout_sec, void *user_context, int property_count, ...) 
+{
+    FUNC_ENTRY;
+	int ret = SUCCESS_RET;
+    int loop = 0;
+
+	POINTER_VALID_CHECK(handle, ERR_PARAM_INVALID);
+	NUMERIC_VALID_CHECK(timeout_sec, ERR_PARAM_INVALID);
+
+	UIoT_Shadow* shadow_client = (UIoT_Shadow*)handle;
+	char JsonDoc[UIOT_MQTT_TX_BUF_LEN];
+    size_t sizeOfBuffer = sizeof(JsonDoc) / sizeof(JsonDoc[0]);
+
+    RequestParams *pParams = uiot_shadow_request_init(DELETE, request_callback, timeout_sec, user_context); 
+
+	va_list pArgs;
+    va_start(pArgs, property_count);
+
+    for(loop = 0; loop < property_count; loop++)
+    {
+        DeviceProperty *pProperty;
+        pProperty  = va_arg(pArgs, DeviceProperty *);
+        if(NULL != pProperty)
+        {
+            if(SUCCESS_RET != IOT_Shadow_Request_Add_Delta_Property(handle, pParams, pProperty))
+            {
+                va_end(pArgs);
+                return FAILURE_RET;
+            }             
+        }
+    }
+
+    va_end(pArgs);
+
+	if (IOT_MQTT_IsConnected(shadow_client->mqtt) == false) 
+    {
+		FUNC_EXIT_RC(ERR_MQTT_NO_CONN);
+	}
+
+	ret = uiot_shadow_make_request(shadow_client, JsonDoc, sizeOfBuffer, pParams);
+	if (ret != SUCCESS_RET) {
+        FUNC_EXIT_RC(ret);
+    }
+
+	FUNC_EXIT_RC(ret);
+}
+
+int IOT_Shadow_Delete_All(void *handle, OnRequestCallback request_callback, uint32_t timeout_sec, void *user_context) 
+{
+    FUNC_ENTRY;
+	int ret = SUCCESS_RET;
+
+	POINTER_VALID_CHECK(handle, ERR_PARAM_INVALID);
+	NUMERIC_VALID_CHECK(timeout_sec, ERR_PARAM_INVALID);
+
+	UIoT_Shadow* shadow_client = (UIoT_Shadow*)handle;
+	char JsonDoc[UIOT_MQTT_TX_BUF_LEN];
+    size_t sizeOfBuffer = sizeof(JsonDoc) / sizeof(JsonDoc[0]);
+
+    RequestParams *pParams = uiot_shadow_request_init(DELETE_ALL, request_callback, timeout_sec, user_context); 
+     
+	if (IOT_MQTT_IsConnected(shadow_client->mqtt) == false) 
+    {
+		FUNC_EXIT_RC(ERR_MQTT_NO_CONN);
+	}
+
+	ret = uiot_shadow_make_request(shadow_client, JsonDoc, sizeOfBuffer, pParams);
+	if (ret != SUCCESS_RET) {
+        FUNC_EXIT_RC(ret);
+    }
+
+	FUNC_EXIT_RC(ret);
+}
+
+int IOT_Shadow_Request_Add_Delta_Property(void *handle, RequestParams *pParams, DeviceProperty *pProperty)
+{
+    FUNC_ENTRY;
+    int ret;
+
+    POINTER_VALID_CHECK(pParams, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pProperty, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pProperty->key, ERR_PARAM_INVALID);
+    
+    ret = request_common_add_delta_property(pParams, pProperty);
+    if(SUCCESS_RET != ret)
+    {
+        LOG_ERROR("request_common_add_delta_property fail\n");        
+        FUNC_EXIT_RC(ret);
+    }
+        
+    FUNC_EXIT_RC(ret);
+}
+
+int IOT_Shadow_Direct_Update_Value(char *value, DeviceProperty *pProperty) {
+    FUNC_ENTRY;
+
+    int ret = SUCCESS_RET;
+
+    if (pProperty->type == JBOOL) {
+        ret = LITE_get_boolean(pProperty->data, value);
+    } else if (pProperty->type == JINT32) {
+        ret = LITE_get_int32(pProperty->data, value);
+    } else if (pProperty->type == JINT16) {
+        ret = LITE_get_int16(pProperty->data, value);
+    } else if (pProperty->type == JINT8) {
+        ret = LITE_get_int8(pProperty->data, value);
+    } else if (pProperty->type == JUINT32) {
+        ret = LITE_get_uint32(pProperty->data, value);
+    } else if (pProperty->type == JUINT16) {
+        ret = LITE_get_uint16(pProperty->data, value);
+    } else if (pProperty->type == JUINT8) {
+        ret = LITE_get_uint8(pProperty->data, value);
+    } else if (pProperty->type == JFLOAT) {
+        ret = LITE_get_float(pProperty->data, value);
+    } else if (pProperty->type == JDOUBLE) {
+        ret = LITE_get_double(pProperty->data, value);
+    }else if(pProperty->type == JSTRING){
+        LOG_DEBUG("string type wait to be deal,%s\n",value);
+    }else if(pProperty->type == JOBJECT){
+        LOG_DEBUG("Json type wait to be deal,%s\n",value);
+    }else{
+        LOG_ERROR("pProperty type unknow,%d\n",pProperty->type);
+    }
+
+    FUNC_EXIT_RC(ret);
+}
+
+#ifdef __cplusplus
+}
+#endif
+

+ 198 - 0
uiot/shadow/src/shadow_client_common.c

@@ -0,0 +1,198 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+#include "shadow_client_common.h"
+#include "uiot_import.h"
+
+/**
+ * @brief 将注册属性的回调函数保存到列表之中
+ */
+static int _add_property_handle_to_list(UIoT_Shadow *pShadow, DeviceProperty *pProperty, OnPropRegCallback callback)
+{
+    FUNC_ENTRY;
+
+    PropertyHandler *property_handle = (PropertyHandler *)HAL_Malloc(sizeof(PropertyHandler));
+    if (NULL == property_handle)
+    {
+        LOG_ERROR("run memory malloc is error!\n");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+
+    property_handle->callback = callback;
+    property_handle->property = pProperty;
+
+    ListNode *node = list_node_new(property_handle);
+    if (NULL == node) 
+    {
+        LOG_ERROR("run list_node_new is error!\n");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+    list_rpush(pShadow->inner_data.property_list, node);
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+int shadow_common_check_property_match(void *pProperty, void *property_handle)
+{
+    FUNC_ENTRY;
+    POINTER_VALID_CHECK(property_handle, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pProperty, ERR_PARAM_INVALID);
+
+    int ret = SUCCESS_RET;
+    PropertyHandler *property_handle_bak = property_handle;
+    DeviceProperty *property_in_handle = (DeviceProperty *)property_handle_bak->property;
+    DeviceProperty *property_bak = (DeviceProperty *)pProperty;
+    
+    LOG_DEBUG("property_in_handle->key:%s, property_bak->key:%s\n",property_in_handle->key,property_bak->key);
+    
+    if(!strcmp(property_in_handle->key, property_bak->key))
+    {
+        ret = true;
+    }
+    else
+    {
+        ret = false;
+    }
+    
+    FUNC_EXIT_RC(ret);
+}
+
+int shadow_common_check_property_existence(UIoT_Shadow *pShadow, DeviceProperty *pProperty)
+{
+    FUNC_ENTRY;
+    
+    ListNode *node;
+
+    HAL_MutexLock(pShadow->property_mutex);
+    node = list_find(pShadow->inner_data.property_list, pProperty);
+    HAL_MutexUnlock(pShadow->property_mutex);
+
+    FUNC_EXIT_RC(NULL != node);
+}
+
+int shadow_common_update_property(UIoT_Shadow *pShadow, DeviceProperty *pProperty, Method           method)
+{
+    FUNC_ENTRY;
+
+    int ret = SUCCESS_RET;
+    ListNode *node;
+    PropertyHandler *property_handle = NULL;
+    DeviceProperty *property_bak =  NULL;
+    
+    HAL_MutexLock(pShadow->property_mutex);
+    node = list_find(pShadow->inner_data.property_list, pProperty);
+    if (NULL == node) 
+    {
+        ret = ERR_SHADOW_NOT_PROPERTY_EXIST;
+        LOG_ERROR("Try to remove a non-existent property.\n");
+    } 
+    else 
+    {
+        property_handle = (PropertyHandler *)node->val;
+        property_bak = (DeviceProperty *)property_handle->property;
+        if((UPDATE == method) || (REPLY_CONTROL_UPDATE == method) || (UPDATE_AND_RESET_VER == method))
+        {
+            property_bak->data = pProperty->data;
+        }
+        else if((DELETE == method) || (REPLY_CONTROL_DELETE == method))
+        {
+            LOG_INFO("delete property\n");
+            property_bak->data = NULL;
+        }
+        else
+        {
+            LOG_ERROR("error method\n");
+            ret = ERR_PARAM_INVALID;
+        }
+    }
+    
+    HAL_MutexUnlock(pShadow->property_mutex);
+    FUNC_EXIT_RC(ret);
+}
+
+
+int shadow_common_remove_property(UIoT_Shadow *pShadow, DeviceProperty *pProperty)
+{
+    FUNC_ENTRY;
+
+    int ret = SUCCESS_RET;
+
+    ListNode *node;
+    HAL_MutexLock(pShadow->property_mutex);
+    node = list_find(pShadow->inner_data.property_list, pProperty);
+    if (NULL == node) 
+    {
+        ret = ERR_SHADOW_NOT_PROPERTY_EXIST;
+        LOG_ERROR("Try to remove a non-existent property.\n");
+    } 
+    else 
+    {
+        list_remove(pShadow->inner_data.property_list, node);
+    }
+    HAL_MutexUnlock(pShadow->property_mutex);
+    
+    FUNC_EXIT_RC(ret);
+}
+
+int shadow_common_register_property_on_delta(UIoT_Shadow *pShadow, DeviceProperty *pProperty, OnPropRegCallback callback)
+{
+    FUNC_ENTRY;
+
+    POINTER_VALID_CHECK(pShadow, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(callback, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pProperty, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pProperty->key, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pProperty->data, ERR_PARAM_INVALID);
+
+    int ret;
+
+    HAL_MutexLock(pShadow->property_mutex);
+    ret = _add_property_handle_to_list(pShadow, pProperty, callback);
+    HAL_MutexUnlock(pShadow->property_mutex);
+
+    FUNC_EXIT_RC(ret);
+}
+
+int request_common_add_delta_property(RequestParams *pParams, DeviceProperty *pProperty)
+{
+    FUNC_ENTRY;
+
+    POINTER_VALID_CHECK(pParams, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pProperty, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pProperty->key, ERR_PARAM_INVALID);
+
+    int ret = SUCCESS_RET;
+    
+    ListNode *node = list_node_new(pProperty);
+    if (NULL == node) 
+    {
+        LOG_ERROR("run list_node_new is error!\n");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+    list_rpush(pParams->property_delta_list, node);
+
+    FUNC_EXIT_RC(ret);
+}
+
+
+#ifdef __cplusplus
+}
+#endif

+ 224 - 0
uiot/shadow/src/shadow_client_json.c

@@ -0,0 +1,224 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "shadow_client_json.h"
+
+#include "shadow_client.h"
+#include "lite-utils.h"
+
+/**
+ * @brief 检查函数snprintf的返回值
+ *
+ * @param returnCode       函数snprintf的返回值
+ * @param maxSizeOfWrite   可写最大字节数
+ * @return                 返回ERR_JSON, 表示出错; 返回ERR_JSON_BUFFER_TRUNCATED, 表示截断
+ */
+int _check_snprintf_return(int32_t returnCode, size_t maxSizeOfWrite) 
+{
+    FUNC_ENTRY;
+
+    if (returnCode >= maxSizeOfWrite) 
+    {
+        FUNC_EXIT_RC(ERR_JSON_BUFFER_TRUNCATED);
+    } 
+    else if (returnCode < 0) 
+    { 
+        FUNC_EXIT_RC(ERR_JSON);
+    }
+
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+int put_json_node(char *jsonBuffer, size_t sizeOfBuffer, const char *pKey, void *pData, JsonDataType type) 
+{
+    FUNC_ENTRY;
+
+    POINTER_VALID_CHECK(pKey, ERR_PARAM_INVALID);
+
+    int ret;
+    int ret_of_snprintf = 0;
+    size_t remain_size = 0;
+
+    if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) 
+    {
+        FUNC_EXIT_RC(ERR_JSON_BUFFER_TOO_SMALL);
+    }
+
+    ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"%s\":", pKey);
+    ret = _check_snprintf_return(ret_of_snprintf, remain_size);
+    if (ret != SUCCESS_RET) 
+    {
+        FUNC_EXIT_RC(ret);
+    }
+
+    if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) 
+    {
+        FUNC_EXIT_RC(ERR_JSON_BUFFER_TOO_SMALL);
+    }
+
+    if (pData == NULL) {
+        ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "null,");
+    } else {
+        if (type == JINT32) {
+            ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%"
+                                      PRIi32
+                                      ",", *(int32_t *) (pData));
+        } else if (type == JINT16) {
+            ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%"
+                                      PRIi16
+                                      ",", *(int16_t *) (pData));
+        } else if (type == JINT8) {
+            ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%"
+                                      PRIi8
+                                      ",", *(int8_t *) (pData));
+        } else if (type == JUINT32) {
+            ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%"
+                                      PRIu32
+                                      ",", *(uint32_t *) (pData));
+        } else if (type == JUINT16) {
+            ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%"
+                                      PRIu16
+                                      ",", *(uint16_t *) (pData));
+        } else if (type == JUINT8) {
+            ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%"
+                                      PRIu8
+                                      ",", *(uint8_t *) (pData));
+        } else if (type == JDOUBLE) {
+            ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%f,", *(double *) (pData));
+        } else if (type == JFLOAT) {
+            ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%f,", *(float *) (pData));
+		} else if (type == JBOOL) {
+            ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%u,",
+                                      *(bool *) (pData) ? 1 : 0);		
+        } else if (type == JSTRING) {
+            ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"%s\",", (char *) (pData));
+        } else if (type == JOBJECT) {
+            ret_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%s,", (char *) (pData));
+        }
+    }
+
+    ret = _check_snprintf_return(ret_of_snprintf, remain_size);
+
+    FUNC_EXIT_RC(ret);
+}
+
+bool parse_version_num(char *pJsonDoc, uint32_t *pVersionNumber) 
+{
+    FUNC_ENTRY;
+    
+	bool ret = false;
+
+	char *version_num = LITE_json_value_of(VERSION_FIELD, pJsonDoc);
+	if (version_num == NULL) FUNC_EXIT_RC(false);
+
+	if (sscanf(version_num, "%" SCNu32, pVersionNumber) != 1) 
+    {
+		LOG_ERROR("parse shadow Version failed, errCode: %d\n", ERR_JSON_PARSE);
+	}
+	else 
+    {
+		ret = true;
+	}
+
+	HAL_Free(version_num);
+
+	FUNC_EXIT_RC(ret);
+}
+
+bool parse_shadow_payload_retcode_type(char *pJsonDoc, uint32_t *pRetCode) 
+{
+    FUNC_ENTRY;
+
+	bool ret = false;
+
+	char *ret_code = LITE_json_value_of(PAYLOAD_RESULT_FIELD, pJsonDoc);
+	if (ret_code == NULL) FUNC_EXIT_RC(false);
+
+	if (sscanf(ret_code, "%" SCNu32, pRetCode) != 1) 
+    {
+		LOG_ERROR("parse RetCode failed, errCode: %d\n", ERR_JSON_PARSE);
+	}
+	else {
+		ret = true;
+	}
+
+	HAL_Free(ret_code);
+
+	FUNC_EXIT_RC(ret);
+}
+
+bool parse_shadow_payload_state_reported_state(char *pJsonDoc, char **pState)
+{
+	*pState = LITE_json_value_of(PAYLOAD_STATE_REPORTED_FIELD, pJsonDoc);
+	return *pState == NULL ? false : true;
+}
+
+bool parse_shadow_payload_state_desired_state(char *pJsonDoc, char **pState)
+{
+	*pState = LITE_json_value_of(PAYLOAD_STATE_DESIRED_FIELD, pJsonDoc);
+	return *pState == NULL ? false : true;
+}
+
+bool parse_shadow_method_type(char *pJsonDoc, char **pType)
+{
+	*pType = LITE_json_value_of(METHOD_FIELD, pJsonDoc);
+	return *pType == NULL ? false : true;
+}
+
+bool parse_shadow_state_reported_type(char *pJsonDoc, char **pType)
+{
+	*pType = LITE_json_value_of(STATE_REPORTED_FIELD, pJsonDoc);
+	return *pType == NULL ? false : true;
+}
+
+bool parse_shadow_state_desired_type(char *pJsonDoc, char **pType)
+{
+	*pType = LITE_json_value_of(STATE_DESIRED_FIELD, pJsonDoc);
+	return *pType == NULL ? false : true;
+}
+
+bool parse_shadow_state_type(char *pJsonDoc, char **pType)
+{
+	*pType = LITE_json_value_of(STATE_FIELD, pJsonDoc);
+	return *pType == NULL ? false : true;
+}
+
+char *find_value_if_key_match(char *pJsonDoc, DeviceProperty *pProperty) 
+{
+	char* property_data = LITE_json_value_of(pProperty->key, pJsonDoc);
+	if ((property_data == NULL) || !(strncmp(property_data, "null", 4))
+		 ||!(strncmp(property_data, "NULL", 4))) {
+		 return NULL;
+	}
+	else {		
+		return property_data;
+	}
+
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 1050 - 0
uiot/shadow/src/shadow_client_manager.c

@@ -0,0 +1,1050 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "shadow_client.h"
+#include "shadow_client_common.h"
+#include "uiot_internal.h"
+#include "uiot_import.h"
+
+#include "shadow_client_json.h"
+#include "utils_list.h"
+
+#define min(a,b) (a) < (b) ? (a) : (b)
+
+/**
+ * @brief 代表一个设备修改设备影子文档的请求
+ */
+typedef struct {
+    Method                 method;                 // 文档操作方式
+    List                   *property_delta_list;   // 该请求需要修改的属性,期望值,时间戳
+    void                   *user_context;          // 用户数据
+    Timer                  timer;                  // 请求超时定时器
+    OnRequestCallback      callback;               // 文档操作请求返回处理函数
+} Request;
+
+static char cloud_rcv_buf[CLOUD_IOT_JSON_RX_BUF_LEN];
+
+static Method cloud_send_method;
+
+typedef void (*TraverseHandle)(UIoT_Shadow *pShadow, ListNode **node, List *list, const char *pType);
+
+static int shadow_json_init(char *pJsonDoc, size_t sizeOfBuffer, RequestParams *pParams);
+
+static int shadow_json_set_content(char *pJsonDoc, size_t sizeOfBuffer, RequestParams *pParams);
+
+static int shadow_json_finalize(UIoT_Shadow *pShadow, char *pJsonDoc, size_t sizeOfBuffer, RequestParams *pParams);
+
+static int uiot_shadow_publish_operation_to_cloud(UIoT_Shadow *pShadow, Method method, char *pJsonDoc);
+
+static int shadow_add_request_to_list(UIoT_Shadow *pShadow, RequestParams *pParams);
+
+static int uiot_shadow_unsubscribe_topic(UIoT_Shadow *pShadow, char *topicFilter);
+
+static void uiot_shadow_request_destory(void *request);
+
+int uiot_shadow_init(UIoT_Shadow *pShadow) 
+{
+    FUNC_ENTRY;
+
+    POINTER_VALID_CHECK(pShadow, ERR_PARAM_INVALID);
+
+    pShadow->inner_data.version = 0;
+
+    pShadow->request_mutex = HAL_MutexCreate();
+    if (pShadow->request_mutex == NULL)
+        FUNC_EXIT_RC(FAILURE_RET);
+
+    pShadow->property_mutex = HAL_MutexCreate();
+    if (pShadow->property_mutex == NULL)
+        FUNC_EXIT_RC(FAILURE_RET);
+
+    pShadow->inner_data.property_list = list_new();
+    if (pShadow->inner_data.property_list)
+    {
+        pShadow->inner_data.property_list->free = HAL_Free;
+        pShadow->inner_data.property_list->match = shadow_common_check_property_match;
+    }
+    else 
+    {
+    	LOG_ERROR("no memory to allocate property_handle_list\n");
+    	FUNC_EXIT_RC(FAILURE_RET);
+    }
+
+	pShadow->inner_data.request_list = list_new();
+	if (pShadow->inner_data.request_list)
+	{
+		pShadow->inner_data.request_list->free = HAL_Free;
+	} 
+    else 
+    {
+		LOG_ERROR("no memory to allocate request_list\n");
+		FUNC_EXIT_RC(FAILURE_RET);
+	}
+
+	FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+
+void uiot_shadow_reset(void *pClient) 
+{
+    FUNC_ENTRY;
+
+    POINTER_VALID_CHECK_RTN(pClient);
+
+    UIoT_Shadow *shadow_client = (UIoT_Shadow *)pClient;
+    if (shadow_client->inner_data.property_list) 
+    {
+        list_destroy(shadow_client->inner_data.property_list);
+    }
+
+    uiot_shadow_unsubscribe_topic(shadow_client,SHADOW_SUBSCRIBE_REQUEST_TEMPLATE);
+    uiot_shadow_unsubscribe_topic(shadow_client,SHADOW_SUBSCRIBE_SYNC_TEMPLATE);
+    
+    if (shadow_client->inner_data.request_list)
+    {
+        list_destroy(shadow_client->inner_data.request_list);
+    }
+}
+
+int uiot_shadow_update_property(UIoT_Shadow *pShadow, RequestParams *pParams)
+{
+    FUNC_ENTRY;
+    
+    POINTER_VALID_CHECK(pShadow, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pShadow->property_mutex, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pParams, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pParams->property_delta_list, ERR_PARAM_INVALID);
+
+    int ret = 0;
+    
+    if ((pParams->property_delta_list->len) && (DELETE_ALL != pParams->method))
+    {
+        ListIterator *iter;
+        ListNode *node = NULL;
+        DeviceProperty *pProperty = NULL;
+    
+        if (NULL == (iter = list_iterator_new(pParams->property_delta_list, LIST_TAIL))) 
+        {   
+            ret = ERR_PARAM_INVALID;
+            LOG_ERROR("property_delta_list is null\n");
+            FUNC_EXIT_RC(ret);
+        }
+    
+        for (;;) 
+        {
+            node = list_iterator_next(iter);
+            if (NULL == node) {
+                break;
+            }
+    
+            pProperty = (DeviceProperty *)(node->val);
+            if (NULL == pProperty) 
+            {
+                LOG_ERROR("node's value is invalid!\n");
+                continue;
+            }
+
+            shadow_common_update_property(pShadow, pProperty, pParams->method);                                         
+        }
+    
+        list_iterator_destroy(iter);
+    }            
+
+    /* 将所有本地属性置为空 */
+    if(DELETE_ALL == pParams->method)
+    {
+        HAL_MutexLock(pShadow->property_mutex);
+        if (pShadow->inner_data.property_list->len) 
+        {
+            ListIterator *shadow_iter;
+            ListNode *shadow_node = NULL;
+            PropertyHandler *property_handle = NULL;
+            DeviceProperty *shadow_property = NULL;
+        
+            if (NULL == (shadow_iter = list_iterator_new(pShadow->inner_data.property_list, LIST_TAIL))) 
+            {   
+                ret = ERR_PARAM_INVALID;
+                LOG_ERROR("property_list is null\n");
+                FUNC_EXIT_RC(ret);
+            }
+        
+            for (;;) 
+            {
+                shadow_node = list_iterator_next(shadow_iter);
+                if (NULL == shadow_node) {
+                    break;
+                }
+        
+                property_handle = (PropertyHandler *)(shadow_node->val);
+                shadow_property = (DeviceProperty *)property_handle->property;
+                if (NULL == shadow_property) 
+                {
+                    LOG_ERROR("node's value is invalid!\n");
+                    continue;
+                }
+                shadow_property->data = NULL;
+            }
+            list_iterator_destroy(shadow_iter);
+        }     
+        HAL_MutexUnlock(pShadow->property_mutex);
+    }
+
+    FUNC_EXIT_RC(ret);
+
+}
+
+int uiot_shadow_make_request(UIoT_Shadow *pShadow,char *pJsonDoc, size_t sizeOfBuffer, RequestParams *pParams)
+{
+    FUNC_ENTRY;
+
+    POINTER_VALID_CHECK(pShadow, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pParams, ERR_PARAM_INVALID);
+
+    //把请求加入设备的请求队列中
+    int ret = SUCCESS_RET;
+    ret = shadow_add_request_to_list(pShadow, pParams);
+
+    ret = shadow_json_init(pJsonDoc, sizeOfBuffer, pParams);
+    if (ret != SUCCESS_RET)
+    {
+		goto end;
+    }
+
+    ret = shadow_json_set_content(pJsonDoc, sizeOfBuffer, pParams);
+    if (ret != SUCCESS_RET)
+    {
+		goto end;
+    }
+
+    ret = shadow_json_finalize(pShadow, pJsonDoc, sizeOfBuffer, pParams);
+    if (ret != SUCCESS_RET)
+    {
+		goto end;
+    }
+
+	LOG_DEBUG("jsonDoc: %s\n", pJsonDoc);
+
+    // 相应的 operation topic 订阅成功或已经订阅
+    ret = uiot_shadow_publish_operation_to_cloud(pShadow, pParams->method, pJsonDoc);
+    if (ret != SUCCESS_RET)
+    {
+		goto end;
+    }
+
+    // 向云平台发送成功更新请求后,根据请求同步更新本地属性
+    ret = uiot_shadow_update_property(pShadow, pParams);
+    if (ret != SUCCESS_RET)
+    {
+		goto end;
+    }
+
+end:
+    uiot_shadow_request_destory(pParams);
+    FUNC_EXIT_RC(ret);
+}
+
+int uiot_shadow_subscribe_topic(UIoT_Shadow *pShadow, char *topicFilter, OnMessageHandler on_message_handler)
+{
+    FUNC_ENTRY;
+    
+    int ret;
+	UIoT_Client *mqtt_client = (UIoT_Client *)pShadow->mqtt;
+
+    char *topic_name = (char *)HAL_Malloc(MAX_SIZE_OF_CLOUD_TOPIC * sizeof(char));
+    if (topic_name == NULL) 
+    {
+        LOG_ERROR("topic_name malloc fail\n");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+    memset(topic_name, 0x0, MAX_SIZE_OF_CLOUD_TOPIC);
+	HAL_Snprintf(topic_name, MAX_SIZE_OF_CLOUD_TOPIC, topicFilter, pShadow->product_sn, pShadow->device_sn);	
+    
+    SubscribeParams subscribe_params = DEFAULT_SUB_PARAMS;
+    subscribe_params.on_message_handler = on_message_handler;
+    subscribe_params.qos = QOS1;
+
+    ret = IOT_MQTT_Subscribe(mqtt_client, topic_name, &subscribe_params);
+    if (ret < 0) 
+    {
+        LOG_ERROR("subscribe topic: %s failed: %d.\n", topicFilter, ret);
+    }
+
+    HAL_Free(topic_name);
+    FUNC_EXIT_RC(ret);
+}
+
+static int uiot_shadow_publish_operation_to_cloud(UIoT_Shadow *pShadow, Method method, char *pJsonDoc)
+{
+    FUNC_ENTRY;
+
+    int ret = SUCCESS_RET;
+
+    char topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0};
+	int size;
+
+    if(GET == method)
+    {
+        size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC, SHADOW_PUBLISH_SYNC_TEMPLATE, pShadow->product_sn, pShadow->device_sn);   
+    }
+    else
+    {
+    	size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC, SHADOW_PUBLISH_REQUEST_TEMPLATE, pShadow->product_sn, pShadow->device_sn);	
+    }
+    
+	if (size < 0 || size > MAX_SIZE_OF_CLOUD_TOPIC - 1)
+    {
+        LOG_ERROR("buf size < topic length!\n");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+
+    cloud_send_method = method;
+    PublishParams pubParams = DEFAULT_PUB_PARAMS;
+    pubParams.qos = QOS1;
+    pubParams.payload_len = strlen(pJsonDoc);
+    pubParams.payload = (char *) pJsonDoc;
+
+    ret = IOT_MQTT_Publish(pShadow->mqtt, topic, &pubParams);
+    if(ret >= 0)
+    {        
+        FUNC_EXIT_RC(SUCCESS_RET);
+    }
+    else
+    {
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+}
+
+static int uiot_shadow_unsubscribe_topic(UIoT_Shadow *pShadow, char *topicFilter)
+{
+    FUNC_ENTRY;
+    POINTER_VALID_CHECK(topicFilter, ERR_PARAM_INVALID);
+    
+    int ret;
+	UIoT_Client *mqtt_client = (UIoT_Client *)pShadow->mqtt;
+
+    char *topic_name = (char *)HAL_Malloc(MAX_SIZE_OF_CLOUD_TOPIC * sizeof(char));
+    if (topic_name == NULL) 
+    {
+        LOG_ERROR("topic_name malloc fail\n");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+    memset(topic_name, 0x0, MAX_SIZE_OF_CLOUD_TOPIC);
+	HAL_Snprintf(topic_name, MAX_SIZE_OF_CLOUD_TOPIC, topicFilter, pShadow->product_sn, pShadow->device_sn);	
+    
+    ret = IOT_MQTT_Unsubscribe(mqtt_client, topic_name);
+    if (ret < 0) 
+    {
+        LOG_ERROR("unsubscribe topic: %s failed: %d.\n", topicFilter, ret);
+    }
+    
+    HAL_Free(topic_name);
+    FUNC_EXIT_RC(ret);
+}
+
+void* uiot_shadow_request_init(Method method, OnRequestCallback request_callback, uint32_t timeout_sec, void *user_context)
+{
+    FUNC_ENTRY;
+
+    RequestParams *pParams = NULL;
+    
+    if((pParams = (RequestParams *) HAL_Malloc (sizeof(RequestParams))) == NULL)
+    {
+        LOG_ERROR("malloc RequestParams error\n");
+        return NULL;
+    }
+    pParams->method = method;    
+    pParams->property_delta_list = list_new();
+    if (pParams->property_delta_list)
+    {
+        pParams->property_delta_list->free = HAL_Free;
+    }
+    else 
+    {
+        LOG_ERROR("no memory to allocate property_delta_list\n");
+        HAL_Free(pParams);
+        return NULL;
+    }
+    pParams->request_callback = request_callback;
+    pParams->timeout_sec = timeout_sec;
+    pParams->user_context = user_context;
+    
+    return pParams;
+}
+
+void uiot_shadow_request_destory(void *request) 
+{
+    FUNC_ENTRY;
+
+    POINTER_VALID_CHECK_RTN(request);
+
+    RequestParams *shadow_request = (RequestParams *)request;
+
+    unsigned int len = shadow_request->property_delta_list->len;
+    ListNode *next;
+    ListNode *curr = shadow_request->property_delta_list->head;
+
+    while (len--) {
+        next = curr->next;
+        HAL_Free(curr);
+        curr = next;
+    }
+
+    HAL_Free(shadow_request->property_delta_list);
+    
+    HAL_Free(request);
+}
+
+/**
+ * @brief 处理注册属性的回调函数
+ * 当订阅的$system/{ProductId}/{DeviceName}/shadow/downstream
+ * 和$system/{ProductId}/{DeviceName}/shadow/getreply返回消息时调用
+ */
+static void _handle_delta(UIoT_Shadow *pShadow, char* delta_str)
+{
+    FUNC_ENTRY;
+
+    char *property_value = NULL;       
+    RequestParams *pParams_property = NULL;    
+	char JsonDoc[CLOUD_IOT_JSON_RX_BUF_LEN];
+    size_t sizeOfBuffer = sizeof(JsonDoc) / sizeof(JsonDoc[0]);
+
+    if((UPDATE == cloud_send_method) 
+        || (GET == cloud_send_method) 
+        || (UPDATE_AND_RESET_VER == cloud_send_method) 
+        || (REPLY_CONTROL_UPDATE == cloud_send_method))
+    {
+        pParams_property = (RequestParams *)uiot_shadow_request_init(REPLY_CONTROL_UPDATE, NULL, MAX_WAIT_TIME_SEC, NULL);
+    }
+    else if((DELETE == cloud_send_method) 
+        || (DELETE_ALL == cloud_send_method) 
+        || (REPLY_CONTROL_DELETE == cloud_send_method))
+    {
+        pParams_property = (RequestParams *)uiot_shadow_request_init(REPLY_CONTROL_DELETE, NULL, MAX_WAIT_TIME_SEC, NULL);
+    }
+    
+    HAL_MutexLock(pShadow->property_mutex);
+    if (pShadow->inner_data.property_list->len) 
+    {
+        ListIterator *iter;
+        ListNode *node = NULL;
+        PropertyHandler *property_handle = NULL;
+
+        if (NULL == (iter = list_iterator_new(pShadow->inner_data.property_list, LIST_TAIL))) 
+        {
+            FUNC_EXIT;
+        }
+
+        for (;;) 
+        {
+            node = list_iterator_next(iter);
+            if (NULL == node) 
+            {
+                break;
+            }
+            
+            property_handle = (PropertyHandler *)(node->val);
+            if (NULL == property_handle) {
+                LOG_ERROR("node's value is invalid!\n");
+                continue;
+            }
+            
+            if (property_handle->property != NULL) 
+            {
+
+                if (NULL != (property_value = find_value_if_key_match(delta_str, property_handle->property)))
+                {   
+                    if (property_handle->callback != NULL)
+                    {
+                        property_handle->callback(pShadow, pParams_property, property_value, strlen(property_value), property_handle->property);
+                    }
+                    node = NULL;
+                }
+            }
+            
+        }
+        
+        list_iterator_destroy(iter);
+    }
+    HAL_MutexUnlock(pShadow->property_mutex);
+    
+    /* 根据回复的设备影子文档中Desired字段的属性值修改完后,把更新完的结果回复服务器 */
+    uiot_shadow_make_request(pShadow, JsonDoc, sizeOfBuffer, pParams_property);
+
+    HAL_Free(property_value);
+    FUNC_EXIT;
+}
+
+/**
+ * @brief 遍历列表, 对列表每个节点都执行一次传入的函数traverseHandle
+ */
+static void _traverse_list(UIoT_Shadow *pShadow, List *list, const char *pType, TraverseHandle traverseHandle)
+{
+    FUNC_ENTRY;
+
+    HAL_MutexLock(pShadow->request_mutex);
+
+    LOG_DEBUG("request list len:%d\n",list->len);
+
+    if (list->len) 
+    {
+        ListIterator *iter;
+        ListNode *node = NULL;
+
+        if (NULL == (iter = list_iterator_new(list, LIST_TAIL))) 
+        {
+            HAL_MutexUnlock(pShadow->request_mutex);
+            FUNC_EXIT;
+        }
+
+        for (;;) 
+        {
+            node = list_iterator_next(iter);
+            if (NULL == node) 
+            {
+                break;
+            }
+
+            if (NULL == node->val) {
+                LOG_DEBUG("node's value is invalid!\n");
+                continue;
+            }
+
+            traverseHandle(pShadow, &node, list, pType);
+        }
+
+        list_iterator_destroy(iter);
+    }
+    HAL_MutexUnlock(pShadow->request_mutex);
+
+    FUNC_EXIT;
+}
+
+/**
+ * @brief 执行设备影子操作的回调函数
+ */
+static void _handle_request_callback(UIoT_Shadow *pShadow, ListNode **node, List *list, const char *pType)
+{
+    FUNC_ENTRY;
+
+    Request *request = (Request *)(*node)->val;
+    if (NULL == request)
+        FUNC_EXIT;
+
+    RequestAck status = ACK_NONE;
+
+    uint32_t result_code = 0;
+    if(!strcmp(pType, METHOD_GET_REPLY))
+    {
+        status = ACK_ACCEPTED;
+    }
+    else if((!strcmp(pType, METHOD_REPLY)) || (!strcmp(pType, METHOD_CONTROL)))
+    {
+        bool parse_success = parse_shadow_payload_retcode_type(cloud_rcv_buf, &result_code);
+        if (parse_success) 
+        {
+        	if (result_code == 0) {
+    			status = ACK_ACCEPTED;
+    		} else {
+    			status = ACK_REJECTED;
+    		}
+        }
+        else 
+        {
+        	LOG_ERROR("parse shadow operation result code failed.\n");
+            status = ACK_REJECTED;
+        }
+    }
+    
+    if (request->callback != NULL) 
+    {
+        request->callback(pShadow, request->method, status, cloud_rcv_buf, request->user_context);
+    }
+    
+    list_remove(list, *node);
+    *node = NULL;
+
+    FUNC_EXIT;
+}
+
+/**
+ * @brief 执行过期的设备影子操作的回调函数
+ */
+static void _handle_expired_request_callback(UIoT_Shadow *pShadow, ListNode **node, List *list, const char *pType)
+{
+    FUNC_ENTRY;
+
+    Request *request = (Request *)(*node)->val;
+    if (NULL == request)
+        FUNC_EXIT;
+
+    if (has_expired(&request->timer))
+    {
+        if (request->callback != NULL) 
+        {
+            request->callback(pShadow, request->method, ACK_TIMEOUT, cloud_rcv_buf, request->user_context);
+        }
+
+        list_remove(list, *node);
+        
+        *node = NULL;
+    }
+
+    FUNC_EXIT;
+}
+
+void _handle_expired_request(UIoT_Shadow *pShadow) 
+{
+    FUNC_ENTRY;
+
+    _traverse_list(pShadow, pShadow->inner_data.request_list, NULL, _handle_expired_request_callback);
+
+    FUNC_EXIT;
+}
+
+/**
+ * @brief 文档操作请求结果的回调函数
+ * 客户端先订阅 $system/${ProductSN}/${DeviceSN}/shadow/downstream, 收到该topic的消息则会调用该回调函数
+ * 在这个回调函数中, 解析出各个设备影子文档操作的结果
+ */
+void topic_request_result_handler(void *pClient, MQTTMessage *message, void *pUserdata)
+{
+    FUNC_ENTRY;
+
+    POINTER_VALID_CHECK_RTN(pClient);
+    POINTER_VALID_CHECK_RTN(message);
+
+    UIoT_Client *mqtt_client = (UIoT_Client *)pClient;
+    UIoT_Shadow *shadow_client = (UIoT_Shadow*)mqtt_client->event_handler.context;
+
+    const char *topic = message->topic;
+    size_t topic_len = message->topic_len;
+    if (NULL == topic || topic_len <= 0) 
+    {
+        FUNC_EXIT;
+    }
+
+    char *method_str = NULL;
+    uint32_t ret_code = 0;
+
+    if (message->payload_len > CLOUD_IOT_JSON_RX_BUF_LEN) 
+    {
+        LOG_ERROR("The length of the received message exceeds the specified length!\n");
+        goto end;
+    }
+
+    int cloud_rcv_len = min(CLOUD_IOT_JSON_RX_BUF_LEN - 1, message->payload_len);
+    memcpy(cloud_rcv_buf, message->payload, cloud_rcv_len + 1);
+    cloud_rcv_buf[cloud_rcv_len] = '\0';    // jsmn_parse relies on a string
+
+    LOG_DEBUG("downstream get message:%s\n",cloud_rcv_buf);
+
+    //解析shadow result topic消息类型
+    if (!parse_shadow_method_type(cloud_rcv_buf, &method_str))
+    {
+        LOG_ERROR("Fail to parse method type!\n");
+        goto end;
+    }
+
+    uint32_t version_num = 0;
+    if (parse_version_num(cloud_rcv_buf, &version_num)) 
+    {
+        shadow_client->inner_data.version = version_num;
+        LOG_DEBUG("update version:%d\n",version_num);
+    }   
+    else
+    {
+        LOG_ERROR("Fail to parse version num!\n");
+        goto end;
+    }
+
+    //属性更新或者删除成功,更新本地维护的版本号
+    if (!strcmp(method_str, METHOD_REPLY)) 
+    {
+        if (!parse_shadow_payload_retcode_type(cloud_rcv_buf, &ret_code))
+        {
+            LOG_ERROR("Fail to parse RetCode!\n");
+            goto end;
+        }    
+
+        if(SUCCESS_RET != ret_code)
+        {
+            LOG_DEBUG("update or delete fail! reply:%s\n",cloud_rcv_buf);
+            goto end;
+        }
+        
+    }
+    else if(!strcmp(method_str, METHOD_CONTROL))     //版本号与影子文档不符,重新同步属性
+    {        
+        char* desired_str = NULL;
+        if (parse_shadow_payload_state_desired_state(cloud_rcv_buf, &desired_str)) 
+        {
+			LOG_DEBUG("desired:%s\n", desired_str);
+            /* desired中的字段不为空 */
+            if(strlen(desired_str) > 2)
+            {
+            	_handle_delta(shadow_client, desired_str);
+            }
+        	HAL_Free(desired_str);
+        }
+        
+    }
+    else
+    {
+        goto end;
+    }
+
+    if (shadow_client != NULL)
+        _traverse_list(shadow_client, shadow_client->inner_data.request_list, method_str, _handle_request_callback);
+end:
+    HAL_Free(method_str);
+
+    FUNC_EXIT;
+}
+
+/**
+ * @brief 文档操作请求结果的回调函数
+ * 客户端先订阅 $system/${ProductSN}/${DeviceSN}/shadow/get_reply,
+    $system/${ProductSN}/${DeviceSN}/shadow/document,收到该topic的消息则会调用该回调函数
+ * 在这个回调函数中, 解析出各个设备影子文档操作的结果
+ */
+void topic_sync_handler(void *pClient, MQTTMessage *message, void *pUserdata)
+{
+    FUNC_ENTRY;
+
+    POINTER_VALID_CHECK_RTN(pClient);
+    POINTER_VALID_CHECK_RTN(message);
+
+    UIoT_Client *mqtt_client = (UIoT_Client *)pClient;
+    UIoT_Shadow *shadow_client = (UIoT_Shadow*)mqtt_client->event_handler.context;
+
+    const char *topic = message->topic;
+    size_t topic_len = message->topic_len;
+    if (NULL == topic || topic_len <= 0) 
+    {
+        FUNC_EXIT;
+    }
+    
+    if (message->payload_len > CLOUD_IOT_JSON_RX_BUF_LEN) 
+    {
+        LOG_ERROR("The length of the received message exceeds the specified length!\n");
+        goto end;
+    }
+
+    int cloud_rcv_len = min(CLOUD_IOT_JSON_RX_BUF_LEN - 1, message->payload_len);
+    memcpy(cloud_rcv_buf, message->payload, cloud_rcv_len + 1);
+    cloud_rcv_buf[cloud_rcv_len] = '\0';    // jsmn_parse relies on a string
+
+    LOG_DEBUG("get_reply:%s\n",cloud_rcv_buf);
+
+    //同步返回消息中的version
+	uint32_t version_num = 0;
+	if (parse_version_num(cloud_rcv_buf, &version_num)) {
+		shadow_client->inner_data.version = version_num;
+	}
+    else
+    {
+        LOG_ERROR("Fail to parse version num!\n");
+        goto end;
+    }
+
+    LOG_DEBUG("version num:%d\n",shadow_client->inner_data.version);
+
+    char* desired_str = NULL;
+    if (parse_shadow_state_desired_type(cloud_rcv_buf, &desired_str)) 
+    {
+		LOG_DEBUG("Desired part:%s\n", desired_str);
+        /* desired中的字段不为空       */
+        if(strlen(desired_str) > 2)
+        {
+        	_handle_delta(shadow_client, desired_str);
+        }
+    	HAL_Free(desired_str);
+    }
+
+    if (shadow_client != NULL)
+        _traverse_list(shadow_client, shadow_client->inner_data.request_list, METHOD_GET_REPLY, _handle_request_callback);
+end:
+
+    FUNC_EXIT;
+}
+
+/**
+ * @brief 根据RequestParams来给json填入type字段
+ */
+static int shadow_json_init(char *pJsonDoc, size_t sizeOfBuffer, RequestParams *pParams)
+{
+    FUNC_ENTRY;
+
+    POINTER_VALID_CHECK(pJsonDoc, ERR_PARAM_INVALID);
+    POINTER_VALID_CHECK(pParams, ERR_PARAM_INVALID);
+    
+    int ret = SUCCESS_RET;
+    char *type_str = NULL;
+    
+    switch (pParams->method) 
+    {
+      case GET:
+        type_str = METHOD_GET;
+        HAL_Snprintf(pJsonDoc, sizeOfBuffer, "{\"Method\":\"%s\"", type_str);
+        break;
+      case UPDATE:
+      case UPDATE_AND_RESET_VER:
+        type_str = METHOD_UPDATE;
+        HAL_Snprintf(pJsonDoc, sizeOfBuffer, "{\"Method\":\"%s\",\"State\":{\"Reported\":{", type_str);
+        break;
+      case REPLY_CONTROL_UPDATE:
+        type_str = METHOD_UPDATE;
+        if (pParams->property_delta_list->len) 
+        {   
+            /* 没有完全按照Desired字段更新属性 */
+            HAL_Snprintf(pJsonDoc, sizeOfBuffer, "{\"Method\":\"%s\",\"State\":{\"Reported\":{", type_str);
+        }
+        else
+        {   
+            /* 完全按照Desired字段更新属性 */
+            HAL_Snprintf(pJsonDoc, sizeOfBuffer, "{\"Method\":\"%s\",\"State\":{", type_str);
+        }
+        break;
+      case DELETE:
+        type_str = METHOD_DELETE;
+        if (pParams->property_delta_list->len) 
+        {   
+            /* 没有完全按照Desired字段更新属性 */
+            HAL_Snprintf(pJsonDoc, sizeOfBuffer, "{\"Method\":\"%s\",\"State\":{\"Reported\":{", type_str);
+        }
+        else
+        {   
+            /* 完全按照Desired字段更新属性 */
+            HAL_Snprintf(pJsonDoc, sizeOfBuffer, "{\"Method\":\"%s\",\"State\":{", type_str);
+        }
+        break;      
+      case REPLY_CONTROL_DELETE:
+        type_str = METHOD_DELETE;
+        if (pParams->property_delta_list->len) 
+        {
+            HAL_Snprintf(pJsonDoc, sizeOfBuffer, "{\"Method\":\"%s\",\"State\":{\"Reported\":{", type_str);
+        }
+        else
+        {
+            HAL_Snprintf(pJsonDoc, sizeOfBuffer, "{\"Method\":\"%s\",\"State\":{", type_str);
+        }
+        break;      
+      case DELETE_ALL:
+        type_str = METHOD_DELETE;
+        HAL_Snprintf(pJsonDoc, sizeOfBuffer, "{\"Method\":\"%s\",\"State\":{\"Reported\":", type_str);
+        break;      
+      default:
+        LOG_ERROR("unexpected method!");
+        ret = ERR_PARAM_INVALID;
+        break;
+    }
+
+    FUNC_EXIT_RC(ret);
+}
+
+/**
+ * @brief 根据RequestParams来给json填入type字段
+ */
+static int shadow_json_set_content(char *pJsonDoc, size_t sizeOfBuffer, RequestParams *pParams)
+{
+    FUNC_ENTRY;
+
+    POINTER_VALID_CHECK(pJsonDoc, ERR_PARAM_INVALID);
+    
+    int ret = SUCCESS_RET;
+    int ret_of_snprintf = 0;
+    size_t json_len = strlen(pJsonDoc);
+    size_t remain_size = sizeOfBuffer - json_len;
+    char delete_str[5] = "null";
+
+    /* GET命令获取完整的影子文档,没有属性需要上报 */
+    if(GET == pParams->method)
+    {
+        FUNC_EXIT_RC(ret);
+    }
+
+    if(DELETE_ALL == pParams->method)
+    {
+        ret_of_snprintf = HAL_Snprintf(pJsonDoc + json_len, remain_size, "%s",delete_str);
+        ret = _check_snprintf_return(ret_of_snprintf, remain_size);
+        FUNC_EXIT_RC(ret);
+    }
+
+    if (pParams->property_delta_list->len) 
+    {
+        ListIterator *iter;
+        ListNode *node = NULL;
+        DeviceProperty *DevProperty = NULL;
+
+        if (NULL == (iter = list_iterator_new(pParams->property_delta_list, LIST_TAIL))) 
+        {   
+            ret = ERR_PARAM_INVALID;
+            LOG_ERROR("property_delta_list is null\n");
+            FUNC_EXIT_RC(ret);
+        }
+
+        for (;;) 
+        {
+            node = list_iterator_next(iter);
+            if (NULL == node) {
+                break;
+            }
+
+            DevProperty = (DeviceProperty *)(node->val);
+            if (NULL == DevProperty) 
+            {
+                LOG_ERROR("node's value is invalid!\n");
+                continue;
+            }
+
+            if (DevProperty->key != NULL) 
+            {
+                if((UPDATE == pParams->method) || (UPDATE_AND_RESET_VER == pParams->method) ||
+                   (REPLY_CONTROL_UPDATE == pParams->method))
+                {
+                    put_json_node(pJsonDoc, remain_size, DevProperty->key, DevProperty->data, DevProperty->type);
+                }
+                else if((DELETE == pParams->method) || (REPLY_CONTROL_DELETE == pParams->method))
+                {
+                    put_json_node(pJsonDoc, remain_size, DevProperty->key, NULL, JSTRING);
+
+                }
+            }
+            json_len = strlen(pJsonDoc);
+            remain_size = sizeOfBuffer - json_len;
+
+        }
+
+        list_iterator_destroy(iter);
+    }
+
+    FUNC_EXIT_RC(ret);
+}
+
+/**
+ * @brief 在JSON文档中添加结尾部分的内容, 包括version字段
+ *
+ */
+static int shadow_json_finalize(UIoT_Shadow *pShadow, char *pJsonDoc, size_t sizeOfBuffer, RequestParams *pParams) 
+{
+	int ret;
+	size_t remain_size = 0;
+	int ret_of_snprintf = 0;
+
+	if (pJsonDoc == NULL) 
+    {
+		return ERR_PARAM_INVALID;
+	}
+
+	if ((remain_size = sizeOfBuffer - strlen(pJsonDoc)) <= 1) 
+    {
+		return ERR_JSON_BUFFER_TOO_SMALL;
+	}
+
+    switch(pParams->method)
+    {
+        case GET:
+            ret_of_snprintf = HAL_Snprintf(pJsonDoc + strlen(pJsonDoc), remain_size, "}");
+            break;
+        case DELETE_ALL:
+            ret_of_snprintf = HAL_Snprintf(pJsonDoc + strlen(pJsonDoc), remain_size, "},\"Version\":%d}", pShadow->inner_data.version);
+            break;
+        case UPDATE_AND_RESET_VER:
+            ret_of_snprintf = HAL_Snprintf(pJsonDoc + strlen(pJsonDoc) - 1, remain_size, "}},\"Version\":-1}");
+            break;
+        case REPLY_CONTROL_UPDATE:            
+        case REPLY_CONTROL_DELETE:            
+            if (pParams->property_delta_list->len) 
+            {   
+                ret_of_snprintf = HAL_Snprintf(pJsonDoc + strlen(pJsonDoc) - 1, remain_size, "},\"Desired\":null},\"Version\":%d}",pShadow->inner_data.version);
+            }
+            else
+            {
+                ret_of_snprintf = HAL_Snprintf(pJsonDoc + strlen(pJsonDoc), remain_size, "\"Desired\":null},\"Version\":%d}",pShadow->inner_data.version);
+            }
+            break;
+        case UPDATE:
+        case DELETE:
+            ret_of_snprintf = HAL_Snprintf(pJsonDoc + strlen(pJsonDoc) - 1, remain_size, "}},\"Version\":%d}", pShadow->inner_data.version);
+            break;
+        default:
+            ret= ERR_PARAM_INVALID;
+            LOG_ERROR("undefined method!\n");
+            break;
+    }
+    ret = _check_snprintf_return(ret_of_snprintf, remain_size);
+
+	return ret;
+}
+
+/**
+ * @brief 将设备影子文档的操作请求保存在列表中
+ */
+static int shadow_add_request_to_list(UIoT_Shadow *pShadow, RequestParams *pParams)
+{
+    FUNC_ENTRY;
+
+    HAL_MutexLock(pShadow->request_mutex);
+    if (pShadow->inner_data.request_list->len >= MAX_APPENDING_REQUEST_AT_ANY_GIVEN_TIME)
+    {
+        HAL_MutexUnlock(pShadow->request_mutex);
+        FUNC_EXIT_RC(ERR_MAX_APPENDING_REQUEST);
+    }
+    
+    Request *request = (Request *)HAL_Malloc(sizeof(Request));
+    if (NULL == request) 
+    {
+        HAL_MutexUnlock(pShadow->request_mutex);
+        LOG_ERROR("run memory malloc is error!\n");
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+    
+    request->callback = pParams->request_callback;
+    request->property_delta_list = pParams->property_delta_list;
+    request->user_context = pParams->user_context;
+    request->method = pParams->method;
+    
+    init_timer(&(request->timer));
+    countdown(&(request->timer), pParams->timeout_sec);
+    
+    ListNode *node = list_node_new(request);
+    if (NULL == node) 
+    {
+        HAL_MutexUnlock(pShadow->request_mutex);
+        LOG_ERROR("run list_node_new is error!\n");
+        HAL_Free(request);
+        FUNC_EXIT_RC(FAILURE_RET);
+    }
+    
+    list_rpush(pShadow->inner_data.request_list, node);
+    
+    HAL_MutexUnlock(pShadow->request_mutex);
+    
+    FUNC_EXIT_RC(SUCCESS_RET);
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 243 - 0
uiot/utils/json_parser.c

@@ -0,0 +1,243 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "json_parser.h"
+
+#define json_debug Log_d
+
+typedef struct JSON_NV {
+    int nLen;
+    int vLen;
+    int vType;
+    char *pN;
+    char *pV;
+} JSON_NV;
+
+char *json_get_object(int type, char *str) {
+    char *pos = 0;
+    char ch = (type == JSOBJECT) ? '{' : '[';
+    while (str != 0 && *str != 0) {
+        if (*str == ' ') {
+            str++;
+            continue;
+        }
+        pos = (*str == ch) ? str : 0;
+        break;
+    }
+    return pos;
+}
+
+char *json_get_next_object(int type, char *str, char **key, int *key_len,
+                           char **val, int *val_len, int *val_type) {
+    char JsonMark[JSTYPEMAX][2] = {{'\"', '\"'},
+                                   {'{',  '}'},
+                                   {'[',  ']'},
+                                   {'0',  ' '}};
+    int iMarkDepth = 0, iValueType = JSNONE, iNameLen = 0, iValueLen = 0;
+    char *p_cName = 0, *p_cValue = 0, *p_cPos = str;
+
+    if (type == JSOBJECT) {
+        /* Get Key */
+        p_cPos = strchr(p_cPos, '"');
+        if (!p_cPos) {
+            return 0;
+        }
+        p_cName = ++p_cPos;
+        p_cPos = strchr(p_cPos, '"');
+        if (!p_cPos) {
+            return 0;
+        }
+        iNameLen = p_cPos - p_cName;
+
+        /* Get Value */
+        p_cPos = strchr(p_cPos, ':');
+    }
+    while (p_cPos && *p_cPos) {
+        if (*p_cPos == '"') {
+            iValueType = JSSTRING;
+            p_cValue = ++p_cPos;
+            break;
+        } else if (*p_cPos == '{') {
+            iValueType = JSOBJECT;
+            p_cValue = p_cPos++;
+            break;
+        } else if (*p_cPos == '[') {
+            iValueType = JSARRAY;
+            p_cValue = p_cPos++;
+            break;
+        } else if ((*p_cPos == '-') || (*p_cPos >= '0' && *p_cPos <= '9')) {
+            iValueType = JSNUMBER;
+            p_cValue = p_cPos++;
+            break;
+        } else if (*p_cPos == 't' || *p_cPos == 'T' || *p_cPos == 'f' || *p_cPos == 'F') {
+            iValueType = JSBOOLEAN;
+            p_cValue = p_cPos;
+            break;
+        } else if (*p_cPos == 'n' || *p_cPos == 'N') {
+            iValueType = JSNULL;
+            p_cValue = p_cPos;
+            break;
+        }
+        p_cPos++;
+    }
+    while (p_cPos && *p_cPos && iValueType > JSNONE) {
+        if (iValueType == JSBOOLEAN) {
+            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 == JSNULL) { //support null/NULL
+            int nlen = strlen(p_cValue);
+
+            if ((*p_cValue == 'n' || *p_cValue == 'N') && nlen >= 4
+                && (!strncmp(p_cValue, "null", 4)
+                    || !strncmp(p_cValue, "NULL", 4))) {
+                iValueLen = 4;
+                p_cPos = p_cValue + iValueLen;
+                break;
+            }
+        } else if (iValueType == JSNUMBER) {
+            //if (*p_cPos < '0' || *p_cPos > '9') {
+            if ((*p_cPos < '0' || *p_cPos > '9') && (*p_cPos != '.')) { //support float
+                iValueLen = p_cPos - p_cValue;
+                break;
+            }
+        } else if (*p_cPos == JsonMark[iValueType][1]) {
+            if (iMarkDepth == 0) {
+                iValueLen = p_cPos - p_cValue + (iValueType == JSSTRING ? 0 : 1);
+                p_cPos++;
+                break;
+            } else {
+                iMarkDepth--;
+            }
+        } else if (*p_cPos == JsonMark[iValueType][0]) {
+            iMarkDepth++;
+        }
+        p_cPos++;
+    }
+
+    if (type == JSOBJECT) {
+        *key = p_cName;
+        *key_len = iNameLen;
+    }
+
+    *val = p_cValue;
+    *val_len = iValueLen;
+    *val_type = iValueType;
+    if (iValueType == JSSTRING) {
+        return p_cValue + iValueLen + 1;
+    } else {
+        return p_cValue + iValueLen;
+    }
+}
+
+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;
+    char last_char = 0;
+    int ret = JSON_RESULT_ERR;
+
+    if (p_cJsonStr == NULL || iStrLen == 0 || pfnCB == NULL) {
+        return ret;
+    }
+
+    if (iStrLen != strlen(p_cJsonStr)) {
+        backup_json_str_last_char(p_cJsonStr, iStrLen, last_char);
+    }
+
+    json_object_for_each_kv(p_cJsonStr, 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;
+            }
+        }
+    }
+
+    if (iStrLen != strlen(p_cJsonStr)) {
+        restore_json_str_last_char(p_cJsonStr, iStrLen, last_char);
+    }
+
+    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;
+
+#if (JSON_DEBUG == 1)
+    int         i;
+
+    if (p_cName) {
+        json_debug("Name:");
+        for (i = 0; i < iNameLen; i++) {
+            json_debug("%c", *(p_cName + i));
+        }
+    }
+
+    if (p_cValue) {
+        json_debug("Value:");
+        for (i = 0; i < iValueLen; i++) {
+            json_debug("%c", *(p_cValue + i));
+        }
+    }
+#endif
+
+    if (!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;
+            if (JSNULL == stNV.vType) {
+                stNV.pV = NULL;
+            }
+        }
+    }
+    return stNV.pV;
+}
+

+ 161 - 0
uiot/utils/json_parser.h

@@ -0,0 +1,161 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef __JSON_PARSER_H__
+#define __JSON_PARSER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+The descriptions of the json value node type
+**/
+enum JSONTYPE {
+	JSNONE = -1,
+	JSSTRING = 0,
+	JSOBJECT,
+	JSARRAY,
+	JSNUMBER,
+	JSBOOLEAN,
+	JSNULL,
+	JSTYPEMAX
+};
+
+/**
+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 JSON object point associate with a given type.
+ *
+ * @param[in] type @n The object type
+ * @param[in] str  @n The 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 *json_get_next_object(int type, char *str, 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]  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, pos, key, klen, val, vlen, vtype) \
+    for (pos = json_get_object(JSOBJECT, str); \
+         pos!=0 && *pos!=0 && (pos=json_get_next_object(JSOBJECT, pos, &key, &klen, &val, &vlen, &vtype))!=0; )
+
+/**
+ * @brief retrieve each entry from the json array
+ *
+ * @param[in]  str   @n Json array to revolve
+ * @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, pos, entry, len, type) \
+    for (pos = json_get_object(JSARRAY, str); \
+         pos!=0 && *pos!=0 && (pos=json_get_next_object(JSARRAY, ++pos, 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;    \
+    }
+
+#ifdef __cplusplus
+}
+#endif
+#endif  /* __JSON_PARSER_H__ */

+ 172 - 0
uiot/utils/json_token.c

@@ -0,0 +1,172 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include "json_parser.h"
+
+#include "lite-utils.h"
+#include "uiot_import.h"
+#include "uiot_defs.h"
+
+
+char *LITE_json_value_of(char *key, char *src)
+{
+    char       *value = NULL;
+    int         value_len = -1;
+    char       *ret = NULL;
+
+    char       *delim = NULL;
+    char       *key_iter;
+    char       *key_next;
+    int         key_len;
+    char       *src_iter;
+
+    src_iter = src;
+    key_iter = key;
+
+    do {
+        if ((delim = strchr(key_iter, '.')) != NULL) {
+            key_len = delim - key_iter;
+            key_next = HAL_Malloc(key_len + 1);
+            strncpy(key_next, key_iter, key_len);
+            key_next[key_len] = '\0';
+            value = json_get_value_by_name(src_iter, strlen(src_iter), key_next, &value_len, 0);
+
+            if (value == NULL) {
+                HAL_Free(key_next);
+                return NULL;
+            }
+
+            src_iter = value;
+            key_iter = delim + 1;
+            HAL_Free(key_next);
+        }
+    } while (delim);
+
+    value = json_get_value_by_name(src_iter, strlen(src_iter), key_iter, &value_len, 0);
+    if (NULL == value) {
+        return NULL;
+    }
+    ret = HAL_Malloc((value_len + 1) * sizeof(char));
+    if (NULL == ret) {
+        return NULL;
+    }
+    HAL_Snprintf(ret, value_len + 1, "%s", value);
+    return ret;
+}
+
+list_head_t *LITE_json_keys_of(char *src, char *prefix)
+{
+    static              LIST_HEAD(keylist);
+
+    char    *pos = 0, *key = 0, *val = 0;
+    int     klen = 0, vlen = 0, vtype = 0;
+
+    if (src == NULL || prefix == NULL) {
+        return NULL;
+    }
+
+    if (!strcmp("", prefix)) {
+        INIT_LIST_HEAD(&keylist);
+    }
+
+    json_object_for_each_kv(src, pos, key, klen, val, vlen, vtype) {
+        if (key && klen && val && vlen) {
+
+            json_key_t     *entry = NULL;
+
+            entry = HAL_Malloc(sizeof(json_key_t));
+            memset(entry, 0, sizeof(json_key_t));
+            entry->key = LITE_format_string("%s%.*s", prefix, klen, key);
+            list_add_tail(&entry->list, &keylist);
+
+            if (JSOBJECT == vtype) {
+                char *iter_val = LITE_format_string("%.*s", vlen, val);
+                char *iter_pre = LITE_format_string("%s%.*s.", prefix, klen, key);
+                LITE_json_keys_of(iter_val, iter_pre);
+                HAL_Free(iter_val);
+                HAL_Free(iter_pre);
+            }
+        }
+    }
+
+    if (!strcmp("", prefix)) {
+        json_key_t     *entry = NULL;
+
+        entry = HAL_Malloc(sizeof(json_key_t));
+        memset(entry, 0, sizeof(json_key_t));
+        list_add_tail(&entry->list, &keylist);
+
+        return &keylist;
+    }
+
+    return NULL;
+}
+
+void LITE_json_keys_release(list_head_t *keylist)
+{
+    json_key_t         *pos, *tmp;
+
+    list_for_each_entry_safe(pos, tmp, keylist, list, json_key_t) {
+        if (pos->key) {
+            HAL_Free(pos->key);
+        }
+        list_del(&pos->list);
+        HAL_Free(pos);
+    }
+}
+
+int LITE_get_int32(int32_t *value, char *src) {
+	return (sscanf(src, "%" SCNi32, value) == 1) ? SUCCESS_RET : FAILURE_RET;
+}
+
+int LITE_get_int16(int16_t *value, char *src) {
+	return (sscanf(src, "%" SCNi16, value) == 1) ? SUCCESS_RET : FAILURE_RET;
+}
+
+int LITE_get_int8(int8_t *value, char *src) {
+	return (sscanf(src, "%" SCNi8, value) == 1) ? SUCCESS_RET : FAILURE_RET;
+}
+
+int LITE_get_uint32(uint32_t *value, char *src) {
+	return (sscanf(src, "%" SCNu32, value) == 1) ? SUCCESS_RET : FAILURE_RET;
+}
+
+int LITE_get_uint16(uint16_t *value, char *src) {
+	return (sscanf(src, "%" SCNu16, value) == 1) ? SUCCESS_RET : FAILURE_RET;
+}
+
+int LITE_get_uint8(uint8_t *value, char *src) {
+	return (sscanf(src, "%" SCNu8, value) == 1) ? SUCCESS_RET : FAILURE_RET;
+}
+
+int LITE_get_float(float *value, char *src) {
+	return (sscanf(src, "%f", value) == 1) ? SUCCESS_RET : FAILURE_RET;
+}
+
+int LITE_get_double(double *value, char *src) {
+	return (sscanf(src, "%lf", value) == 1) ? SUCCESS_RET : FAILURE_RET;
+}
+
+int LITE_get_boolean(bool *value, char *src) {
+	if (!strcmp(src, "0")) {
+		*value = false;
+	}
+	else {
+		*value = true;
+	}
+
+	return SUCCESS_RET;
+}
+

+ 501 - 0
uiot/utils/lite-list.h

@@ -0,0 +1,501 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
+    !defined(inline) && !defined(__cplusplus)
+#define inline __inline
+#endif
+
+typedef struct list_head list_head_t;
+
+struct list_head {
+    struct list_head *next, *prev;
+};
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+    struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+    list->next = list;
+    list->prev = list;
+}
+
+/*
+ * Insert a new_ptr entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new_ptr,
+                              struct list_head *prev,
+                              struct list_head *next)
+{
+    next->prev = new_ptr;
+    new_ptr->next = next;
+    new_ptr->prev = prev;
+    prev->next = new_ptr;
+}
+
+/**
+ * list_add - add a new_ptr entry
+ * @new_ptr: new_ptr entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new_ptr entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new_ptr, struct list_head *head)
+{
+    __list_add(new_ptr, head, head->next);
+}
+
+
+/**
+ * list_add_tail - add a new_ptr entry
+ * @new_ptr: new_ptr entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new_ptr entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new_ptr, struct list_head *head)
+{
+    __list_add(new_ptr, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+    next->prev = prev;
+    prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void __list_del_entry(struct list_head *entry)
+{
+    __list_del(entry->prev, entry->next);
+}
+
+static inline void list_del(struct list_head *entry)
+{
+    __list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_replace - replace old entry by new_ptr one
+ * @old : the element to be replaced
+ * @new_ptr : the new_ptr element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+                                struct list_head *new_ptr)
+{
+    new_ptr->next = old->next;
+    new_ptr->next->prev = new_ptr;
+    new_ptr->prev = old->prev;
+    new_ptr->prev->next = new_ptr;
+}
+
+static inline void list_replace_init(struct list_head *old,
+                                     struct list_head *new_ptr)
+{
+    list_replace(old, new_ptr);
+    INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+    __list_del_entry(entry);
+    INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+    __list_del_entry(list);
+    list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+                                  struct list_head *head)
+{
+    __list_del_entry(list);
+    list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+                               const struct list_head *head)
+{
+    return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+    return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+    struct list_head *next = head->next;
+    return (next == head) && (next == head->prev);
+}
+
+/**
+ * list_rotate_left - rotate the list to the left
+ * @head: the head of the list
+ */
+static inline void list_rotate_left(struct list_head *head)
+{
+    struct list_head *first;
+
+    if (!list_empty(head)) {
+        first = head->next;
+        list_move_tail(first, head);
+    }
+}
+
+/**
+ * list_is_singular - tests whether a list has just one entry.
+ * @head: the list to test.
+ */
+static inline int list_is_singular(const struct list_head *head)
+{
+    return !list_empty(head) && (head->next == head->prev);
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:    the &struct list_head pointer.
+ * @type:   the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+    container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr:    the list head to take the element from.
+ * @type:   the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+    list_entry((ptr)->next, type, member)
+
+/**
+ * list_last_entry - get the last element from a list
+ * @ptr:    the list head to take the element from.
+ * @type:   the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_last_entry(ptr, type, member) \
+    list_entry((ptr)->prev, type, member)
+
+/**
+ * list_first_entry_or_null - get the first element from a list
+ * @ptr:    the list head to take the element from.
+ * @type:   the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note that if the list is empty, it returns NULL.
+ */
+#define list_first_entry_or_null(ptr, type, member) \
+    (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
+
+/**
+ * list_next_entry - get the next element in list
+ * @pos:    the type * to cursor
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_next_entry(pos, member, type) \
+    list_entry((pos)->member.next, type, member)
+
+/**
+ * list_prev_entry - get the prev element in list
+ * @pos:    the type * to cursor
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_prev_entry(pos, member, type) \
+    list_entry((pos)->member.prev, type, member)
+
+/**
+ * list_for_each    -   iterate over a list
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @head:   the head for your list.
+ */
+#define list_for_each(pos, head) \
+    for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * __list_for_each  -   iterate over a list
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @head:   the head for your list.
+ *
+ * This variant doesn't differ from list_for_each() any more.
+ * We don't do prefetching in either case.
+ */
+#define __list_for_each(pos, head) \
+    for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev   -   iterate over a list backwards
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @head:   the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+    for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @n:      another &struct list_head to use as temporary storage
+ * @head:   the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+    for (pos = (head)->next, n = pos->next; pos != (head); \
+         pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @n:      another &struct list_head to use as temporary storage
+ * @head:   the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+    for (pos = (head)->prev, n = pos->prev; \
+         pos != (head); \
+         pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry  -   iterate over list of given type
+ * @pos:    the type * to use as a loop cursor.
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member, type)             \
+    for (pos = list_entry((head)->next, type, member); \
+         &pos->member != (head);    \
+         pos = list_entry(pos->member.next, type, member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:    the type * to use as a loop cursor.
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_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))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos:    the type * to use as a start point
+ * @head:   the head of the list
+ * @member: the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member, type) \
+    ((pos) ? : list_entry(head, type, member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos:    the type * to use as a loop cursor.
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member, type)        \
+    for (pos = list_entry(pos->member.next, type, member); \
+         &pos->member != (head);    \
+         pos = list_entry(pos->member.next, type, member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos:    the type * to use as a loop cursor.
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member, type)        \
+    for (pos = list_entry(pos->member.prev, type, member); \
+         &pos->member != (head);    \
+         pos = list_entry(pos->member.prev, type, member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos:    the type * to use as a loop cursor.
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member, type)            \
+    for (; &pos->member != (head);  \
+         pos = list_entry(pos->member.next, type, member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:    the type * to use as a loop cursor.
+ * @n:      another type * to use as temporary storage
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#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))
+
+/**
+ * list_for_each_entry_safe_continue - continue list iteration safe against removal
+ * @pos:    the type * to use as a loop cursor.
+ * @n:      another type * to use as temporary storage
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member, type)        \
+    for (pos = list_entry(pos->member.next, type, member),         \
+         n = list_entry(pos->member.next, type, member);        \
+         &pos->member != (head);                        \
+         pos = n, n = list_entry(n->member.next, type, member))
+
+/**
+ * list_for_each_entry_safe_from - iterate over list from current point safe against removal
+ * @pos:    the type * to use as a loop cursor.
+ * @n:      another type * to use as temporary storage
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member, type)            \
+    for (n = list_entry(pos->member.next, type, member);       \
+         &pos->member != (head);                        \
+         pos = n, n = list_entry(n->member.next, type, member))
+
+/**
+ * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
+ * @pos:    the type * to use as a loop cursor.
+ * @n:      another type * to use as temporary storage
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member, type)     \
+    for (pos = list_entry((head)->prev, type, member), \
+         n = list_entry(pos->member.prev, type, member);    \
+         &pos->member != (head);                    \
+         pos = n, n = list_entry(n->member.prev, type, member))
+
+/**
+ * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
+ * @pos:    the loop cursor used in the list_for_each_entry_safe loop
+ * @n:      temporary storage used in list_for_each_entry_safe
+ * @member: the name of the list_struct within the struct.
+ *
+ * list_safe_reset_next is not safe to use in general if the list may be
+ * modified concurrently (eg. the lock is dropped in the loop body). An
+ * exception to this is if the cursor element (pos) is pinned in the list,
+ * and list_safe_reset_next is called after re-taking the lock and before
+ * completing the current iteration of the loop body.
+ */
+#define list_safe_reset_next(pos, n, member, type)               \
+    n = list_entry(pos->member.next, type, member)
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 95 - 0
uiot/utils/lite-utils.h

@@ -0,0 +1,95 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef __LITE_UTILS_H__
+#define __LITE_UTILS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#if defined(_PLATFORM_IS_LINUX_)
+#include <assert.h>
+#endif
+
+#include "lite-list.h"
+#include "uiot_import.h"
+
+#define LITE_TRUE                   (1)
+#define LITE_FALSE                  (0)
+
+#ifndef container_of
+#define container_of(ptr, type, member)  \
+    ((type *) ((char *) (ptr) - offsetof(type, member)))
+#endif
+
+#define LITE_MINIMUM(a, b)          (((a) <= (b)) ? (a) : (b))
+#define LITE_MAXIMUM(a, b)          (((a) >= (b)) ? (a) : (b))
+#define LITE_isdigit(c)             (((c) <= '9' && (c) >= '0') ? (LITE_TRUE) : (LITE_FALSE))
+
+#if defined(_PLATFORM_IS_LINUX_)
+#define LITE_ASSERT(expr)           assert(expr)
+#else
+#define LITE_ASSERT(expr) \
+    do { \
+        if (!(expr)) { \
+            HAL_Printf("### %s | %s(%d): ASSERT FAILED ###: %s is FALSE\r\n", \
+                        __FILE__, __func__, __LINE__, #expr); \
+        } \
+    } while(0)
+#endif
+
+char       	   *LITE_strdup(const char *src);
+char       	   *LITE_format_string(const char *fmt, ...);
+char       	   *LITE_format_nstring(const int len, const char *fmt, ...);
+void        	LITE_hexbuf_convert(unsigned char *digest, char *out, int buflen, int uppercase);
+void        	LITE_hexstr_convert(char *hexstr, uint8_t *out_buf, int len);
+void        	LITE_replace_substr(char orig[], char key[], char swap[]);
+
+char           *LITE_json_value_of(char *key, char *src);
+list_head_t    *LITE_json_keys_of(char *src, char *prefix);
+void            LITE_json_keys_release(list_head_t *keylist);
+
+int 			LITE_get_int32(int32_t *value, char *src);
+int 			LITE_get_int16(int16_t *value, char *src);
+int 			LITE_get_int8(int8_t *value, char *src);
+int 			LITE_get_uint32(uint32_t *value, char *src);
+int 			LITE_get_uint16(uint16_t *value, char *src);
+int 			LITE_get_uint8(uint8_t *value, char *src);
+int 			LITE_get_float(float *value, char *src);
+int 			LITE_get_double(double *value, char *src);
+int 			LITE_get_boolean(bool *value, char *src);
+
+typedef struct _json_key_t {
+    char           *key;
+    list_head_t     list;
+} json_key_t;
+
+#define foreach_json_keys_in(src, iter_key, keylist, pos)   \
+    for(keylist = (void *)LITE_json_keys_of((char *)src, ""), \
+        pos = (void *)list_first_entry((list_head_t *)keylist, json_key_t, list), \
+        iter_key = ((json_key_t *)pos)->key; \
+            (iter_key = ((json_key_t *)pos)->key); \
+                pos = list_next_entry((json_key_t *)pos, list, json_key_t))
+#ifdef __cplusplus
+}
+#endif
+#endif  /* __LITE_UTILS_H__ */

+ 166 - 0
uiot/utils/string_utils.c

@@ -0,0 +1,166 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#include "lite-utils.h"
+
+#include "uiot_import.h"
+#include "uiot_defs.h"
+
+char *LITE_strdup(const char *src)
+{
+    int             len = 0;
+    char           *dst = NULL;
+
+    if (!src) {
+        return NULL;
+    }
+    len = strlen(src) + 1;
+    if (len > 1024) {
+        LOG_ERROR("Too long string to duplicate, abort! len = %d", len);
+        return NULL;
+    }
+
+    dst = (char *)HAL_Malloc(sizeof(char) * len);
+    if (!dst) {
+        return NULL;
+    }
+    strncpy(dst, src, len);
+
+    return dst;
+}
+     
+char *LITE_format_string(const char *fmt, ...)
+{
+#define TEMP_STRING_MAXLEN      (512)
+
+    va_list         ap;
+    char           *tmp = NULL;
+    char           *dst;
+    int             rc = -1;
+
+    va_start(ap, fmt);
+    tmp = HAL_Malloc(TEMP_STRING_MAXLEN);
+    memset(tmp, 0, TEMP_STRING_MAXLEN);
+    rc = HAL_Vsnprintf(tmp, TEMP_STRING_MAXLEN, fmt, ap);
+    va_end(ap);
+    LITE_ASSERT(tmp);
+    LITE_ASSERT(rc < 1024);
+
+    dst = LITE_strdup(tmp);
+    HAL_Free(tmp);
+
+    return dst;
+
+#undef TEMP_STRING_MAXLEN
+}
+
+char *LITE_format_nstring(const int len, const char *fmt, ...)
+{
+    va_list         ap;
+    char           *tmp = NULL;
+    char           *dst;
+    int             rc = -1;
+
+    va_start(ap, fmt);
+    tmp = HAL_Malloc(len+2);
+    memset(tmp, 0, len+2);
+    rc = HAL_Vsnprintf(tmp, len+1, fmt, ap);
+    va_end(ap);
+    LITE_ASSERT(tmp);
+    LITE_ASSERT(rc < 1024);
+
+    dst = HAL_Malloc(len + 1);
+    HAL_Snprintf(dst, (len + 1), "%s", tmp);
+    HAL_Free(tmp);
+
+    return dst;
+}
+
+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];
+    }
+}
+
+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 *hexstr, uint8_t *out_buf, int in_len)
+{
+    int             i = 0;
+    uint8_t         ch0, ch1;
+
+    if (in_len % 2 != 0) {
+        LOG_ERROR("hexstr length (%d) is not even", in_len);
+        return;
+    }
+
+    while (i < in_len) {
+        ch0 = _hexval_of_char((char)hexstr[2 * i]);
+        ch1 = _hexval_of_char((char)hexstr[2 * i + 1]);
+        out_buf[i] = (ch0 << 4 | ch1);
+        i++;
+    }
+}
+
+void LITE_replace_substr(char originalString[], char key[], char swap[])
+{
+    int         lengthOfOriginalString, lengthOfKey, lengthOfSwap, i, j, flag;
+    char        tmp[512];
+
+    lengthOfOriginalString = strlen(originalString);
+    lengthOfKey = strlen(key);
+    lengthOfSwap = strlen(swap);
+
+    for (i = 0; i <= lengthOfOriginalString - lengthOfKey; i++) {
+        flag = 1;
+        for (j  = 0; j < lengthOfKey; j++) {
+            if (originalString[i + j] != key[j]) {
+                flag = 0;
+                break;
+            }
+        }
+
+        if (flag) {
+            strcpy(tmp, originalString);
+            strcpy(&tmp[i], swap);
+            strcpy(&tmp[i + lengthOfSwap], &originalString[i  + lengthOfKey]);
+            strcpy(originalString, tmp);
+            i += lengthOfSwap - 1;
+            lengthOfOriginalString = strlen(originalString);
+        }
+    }
+}

+ 572 - 0
uiot/utils/utils_httpc.c

@@ -0,0 +1,572 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "uiot_defs.h"
+#include "utils_httpc.h"
+#include "utils_net.h"
+#include "utils_timer.h"
+#include "utils_md5.h"
+
+#define MIN_TIMEOUT                   (100)
+#define MAX_RETRY_COUNT               (600)
+
+#define HTTP_CLIENT_READ_BUF_SIZE     (1024)          /* read payload */
+#define HTTP_CLIENT_READ_HEAD_SIZE    (32)            /* read header */
+#define HTTP_CLIENT_SEND_BUF_SIZE     (1024)          /* send */
+#define HTTP_CLIENT_REQUEST_BUF_SIZE  (300)           /* send */
+#define HTTP_CLIENT_MAX_URL_LEN       (256)
+#define HTTP_RETRIEVE_MORE_DATA       (1)             /**< More data needs to be retrieved. */
+#define HTTP_CLIENT_CHUNK_SIZE        (1024)
+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;
+    }
+
+    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_RET;
+}
+
+static int _utils_fill_tx_buffer(http_client_t *client, unsigned char *send_buf, int *send_idx, char *buf, uint32_t len) {
+    int ret;
+    int cp_len;
+    int writen_len = 0;
+    int idx = *send_idx;
+
+    if (len == 0) {
+        len = strlen(buf);
+    }
+    do {
+        if ((HTTP_CLIENT_SEND_BUF_SIZE - idx) >= len) {
+            cp_len = len;
+        } else {
+            cp_len = HTTP_CLIENT_SEND_BUF_SIZE - idx;
+        }
+
+        memcpy(send_buf + idx, buf + writen_len, cp_len);
+        idx += cp_len;
+        writen_len += cp_len;
+        len -= cp_len;
+
+        if (idx == HTTP_CLIENT_SEND_BUF_SIZE) {
+            ret = client->net.write(&client->net, send_buf, HTTP_CLIENT_SEND_BUF_SIZE, 5000);
+            if (ret < 0) {
+                return (ret);
+            } else if (ret != HTTP_CLIENT_SEND_BUF_SIZE) {
+                return (ret == 0) ? ERR_HTTP_CLOSED : ERR_HTTP_CONN_ERROR;
+            }
+            idx -= ret;
+        }
+    } while (len);
+
+    *send_idx = idx;
+    return SUCCESS_RET;
+}
+
+static int _http_send_header(http_client_t *client, char *host, const char *path, int method,
+                             http_client_data_t *client_data) {
+    int len;
+    unsigned char send_buf[HTTP_CLIENT_SEND_BUF_SIZE] = {0};
+    char buf[HTTP_CLIENT_REQUEST_BUF_SIZE] = {0};
+    char *pMethod = (method == HTTP_GET) ? "GET" : (method == HTTP_POST) ? "POST" :
+            (method == HTTP_PUT) ? "PUT" : (method == HTTP_DELETE) ? "DELETE" :
+            (method == HTTP_HEAD) ? "HEAD" : "";
+    int ret;
+
+    /* Send request */
+    memset(send_buf, 0, HTTP_CLIENT_SEND_BUF_SIZE);
+    len = 0; /* Reset send buffer */
+
+    HAL_Snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", pMethod, path, host); /* Write request */
+
+    ret = _utils_fill_tx_buffer(client, send_buf, &len, buf, strlen(buf));
+    if (ret < 0) {
+        /* LOG_ERROR("Could not write request"); */
+        return ERR_HTTP_CONN_ERROR;
+    }
+
+    /* 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);
+
+    ret = client->net.write(&client->net, send_buf, len, 5000);
+    if (ret <= 0) {
+        LOG_ERROR("ret = client->net.write() = %d", ret);
+        return (ret == 0) ? ERR_HTTP_CLOSED : ERR_HTTP_CONN_ERROR;
+    }
+
+    return SUCCESS_RET;
+}
+
+int _http_send_user_data(http_client_t *client, http_client_data_t *client_data, uint32_t timeout_ms) {
+    int ret = 0;
+
+    if (client_data->post_buf && client_data->post_buf_len) {
+        ret = client->net.write(&client->net, (unsigned char *) client_data->post_buf, client_data->post_buf_len, timeout_ms);
+        LOG_DEBUG("client_data->post_buf: %s, ret is %d", client_data->post_buf, ret);
+        if (ret <= 0) {
+            return (ret == 0) ? ERR_HTTP_CLOSED : ERR_HTTP_CONN_ERROR; /* Connection was closed by server */
+        }
+    }
+
+    return SUCCESS_RET;
+}
+
+/* 0 on success, err code on failure */
+static int _http_recv(http_client_t *client, unsigned char *buf, int max_len, int *p_read_len,
+                      uint32_t timeout_ms) {
+    int ret = 0;
+    Timer timer;
+
+    init_timer(&timer);
+    countdown_ms(&timer, timeout_ms);
+
+    *p_read_len = 0;
+
+    ret = client->net.read(&client->net, buf, max_len, left_ms(&timer));
+
+    if (ret > 0) {
+        *p_read_len = ret;
+        return 0;
+    } else if (ret == 0) {
+        /* timeout */
+        return FAILURE_RET;
+    } else {
+        return ERR_HTTP_CONN_ERROR;
+    }
+}
+
+
+static int _utils_check_deadloop(int len, Timer *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 indefinite behavior, so we avoid it */
+    if (left_ms(timer) < MIN_TIMEOUT) {
+        (*extend_count)++;
+        countdown_ms(timer, MIN_TIMEOUT);
+    }
+
+    /* if it falls into deadloop before reconnected to internet, we just quit*/
+    if ((0 == len) && (0 == left_ms(timer)) && (FAILURE_RET == ret)) {
+        (*dead_loop_count)++;
+        if (*dead_loop_count > MAX_RETRY_COUNT) {
+            LOG_ERROR("deadloop detected, exit");
+            return ERR_HTTP_CONN_ERROR;
+        }
+    } 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) && (FAILURE_RET == ret)) {
+        LOG_ERROR("extend timer for too many times, exit");
+        return ERR_HTTP_CONN_ERROR;
+    }
+    return SUCCESS_RET;
+}
+
+static int _utils_fill_rx_buf(int *recv_count, int len_to_write_to_response_buf, http_client_data_t *client_data,
+                              unsigned char *data) {
+    int count = *recv_count;
+    if (count + len_to_write_to_response_buf < client_data->response_buf_len - 1) {
+        memcpy(client_data->response_buf + count, data, len_to_write_to_response_buf);
+        count += len_to_write_to_response_buf;
+        client_data->response_buf[count] = '\0';
+        client_data->retrieve_len -= len_to_write_to_response_buf;
+        *recv_count = count;
+        return SUCCESS_RET;
+    } 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(http_client_t *client, unsigned char *data, int data_len_actually_received,
+                                   uint32_t timeout_ms, http_client_data_t *client_data) {
+    int written_response_buf_len = 0;
+    int len_to_write_to_response_buf = 0;
+    Timer timer;
+
+    init_timer(&timer);
+    countdown_ms(&timer, timeout_ms);
+
+    /* Receive data */
+    /* LOG_DEBUG("Current data: %s", data); */
+
+    client_data->is_more = 1;
+
+    /* the header is not received finished */
+    if (client_data->response_content_len == -1 && client_data->is_chunked == 0) {
+        /* can not enter this if */
+        LOG_ERROR("header is not received yet");
+        return ERR_HTTP_CONN_ERROR;
+    }
+
+    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_response_buf = Min(data_len_actually_received, client_data->retrieve_len);
+            res = _utils_fill_rx_buf(&written_response_buf_len, len_to_write_to_response_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 = Min(HTTP_CLIENT_CHUNK_SIZE - 1,
+                                             client_data->response_buf_len - 1 - written_response_buf_len);
+                max_len_to_receive = Min(max_len_to_receive, client_data->retrieve_len);
+
+                ret = _http_recv(client, data, max_len_to_receive, &data_len_actually_received, left_ms(&timer));
+                if (ret == ERR_HTTP_CONN_ERROR) {
+                    return ret;
+                }
+                LOG_DEBUG("Total- remaind Payload: %d Bytes; currently Read: %d Bytes", client_data->retrieve_len,
+                          data_len_actually_received);
+
+                ret = _utils_check_deadloop(data_len_actually_received, &timer, ret, &dead_loop_count,
+                                            &extend_count);
+                if (ERR_HTTP_CONN_ERROR == ret) {
+                    return ret;
+                }
+            }
+        } while (client_data->retrieve_len);
+        client_data->is_more = 0;
+        break;
+    }
+
+    return SUCCESS_RET;
+}
+
+static int _http_parse_response_header(http_client_t *client, char *data, int len, uint32_t timeout_ms,
+                                       http_client_data_t *client_data) {
+    int crlf_pos;
+    Timer timer;
+    char *tmp_ptr, *ptr_body_end;
+    int new_trf_len, ret;
+    char *crlf_ptr;
+
+    init_timer(&timer);
+    countdown_ms(&timer, timeout_ms);
+
+    client_data->response_content_len = -1;
+
+    /* http client response */
+    /* <status-line> HTTP/1.1 200 OK(CRLF)
+
+       <headers> ...(CRLF)
+
+       <blank line> (CRLF)
+
+      [<response-body>] */
+    crlf_ptr = strstr(data, "\r\n");
+    if (crlf_ptr == NULL) {
+        LOG_ERROR("\r\n not found");
+        return ERR_HTTP_UNRESOLVED_DNS;
+    }
+
+    crlf_pos = crlf_ptr - data;
+    data[crlf_pos] = '\0';
+    client->response_code = atoi(data + 9);
+    LOG_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 = 0;
+
+    /*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, (unsigned char *) (data + len), HTTP_CLIENT_READ_HEAD_SIZE, &new_trf_len,
+                         left_ms(&timer));
+        if (ret == ERR_HTTP_CONN_ERROR) {
+            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 {
+        LOG_ERROR("Could not parse header");
+        return ERR_HTTP_CONN_ERROR;
+    }
+
+    /* 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, (unsigned char *) data, len, left_ms(&timer), client_data);
+}
+
+static int _http_connect(http_client_t *client) {
+    int retry_max = 3;
+    int retry_cnt = 1;
+    int retry_interval = 1000;
+    int rc = -1;
+
+    do {
+        client->net.handle = 0;
+        LOG_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);
+            LOG_ERROR("TCP or TLS connect failed, rc = %d", rc);
+            HAL_SleepMs(retry_interval);
+            continue;
+        } else {
+            LOG_DEBUG("rc = client->net.connect() = %d, success @ [%d/%d] iteration", rc, retry_cnt, retry_max);
+            break;
+        }
+    } while (++retry_cnt <= retry_max);
+
+    return SUCCESS_RET;
+}
+
+int _http_send_request(http_client_t *client, const char *url, HTTP_Request_Method method,
+                       http_client_data_t *client_data, uint32_t timeout_ms) {
+    int ret = ERR_HTTP_CONN_ERROR;
+
+    if (0 == client->net.handle) {
+        return -1;
+    }
+
+    int rc;
+    char host[HTTP_CLIENT_MAX_URL_LEN] = {0};
+    char path[HTTP_CLIENT_MAX_URL_LEN] = {0};
+
+    rc = _utils_parse_url(url, host, path);
+    if (rc != SUCCESS_RET) {
+        return rc;
+    }
+
+    ret = _http_send_header(client, host, path, method, client_data);
+    if (ret != 0) {
+        return -2;
+    }
+
+    if (method == HTTP_POST || method == HTTP_PUT) {
+        ret = _http_send_user_data(client, client_data,timeout_ms);
+        if (ret < 0) {
+            ret = -3;
+        }
+    }
+
+    return ret;
+}
+
+static int _http_client_recv_response(http_client_t *client, uint32_t timeout_ms, http_client_data_t *client_data) {
+    int read_len = 0, ret = ERR_HTTP_CONN_ERROR;
+    char buf[HTTP_CLIENT_READ_BUF_SIZE] = {0};
+    Timer timer;
+
+    init_timer(&timer);
+    countdown_ms(&timer, timeout_ms);
+
+    if (0 == client->net.handle) {
+        LOG_ERROR("no connection have been established");
+        return ret;
+    }
+
+    if (client_data->is_more) {
+        client_data->response_buf[0] = '\0';
+        ret = _http_get_response_body(client, (unsigned char *) buf, read_len, left_ms(&timer), client_data);
+    } else {
+        client_data->is_more = 1;
+        /* try to read header */
+        ret = _http_recv(client, (unsigned char *) buf, HTTP_CLIENT_READ_HEAD_SIZE, &read_len, left_ms(&timer));
+        if (ret != 0) {
+            return ret;
+        }
+
+        buf[read_len] = '\0';
+
+        if (read_len) {
+            ret = _http_parse_response_header(client, buf, read_len, left_ms(&timer), client_data);
+        }
+    }
+
+    return ret;
+}
+
+int http_client_connect(http_client_t *client, const char *url, int port, const char *ca_crt) {
+    if (client->net.handle != 0) {
+        LOG_ERROR("http client has connected to host!");
+        return ERR_HTTP_CONN_ERROR;
+    }
+
+    int rc;
+    char host[HTTP_CLIENT_MAX_URL_LEN] = {0};
+    char path[HTTP_CLIENT_MAX_URL_LEN] = {0};
+
+    rc = _utils_parse_url(url, host, path);
+    if (rc != SUCCESS_RET) {
+        return rc;
+    }
+
+    rc = utils_net_init(&client->net, host, port, SSL_CA_VERIFY_REQUIRED, ca_crt);
+    if (rc != SUCCESS_RET) {
+        return rc;
+    }
+
+    rc = _http_connect(client);
+    if (rc != SUCCESS_RET) {
+        LOG_ERROR("_http_connect error, rc = %d", rc);
+        http_client_close(client);
+    } else {
+        LOG_DEBUG("http client connect success");
+    }
+    return rc;
+}
+
+int http_client_common(http_client_t *client, const char *url, int port, const char *ca_crt,
+                       HTTP_Request_Method method, http_client_data_t *client_data, uint32_t timeout_ms) {
+    int rc;
+
+    if (client->net.handle == 0) {
+        rc = http_client_connect(client, url, port, ca_crt);
+        if (rc != SUCCESS_RET) {
+            return rc;
+        }
+    }
+
+    rc = _http_send_request(client, url, method, client_data, timeout_ms);
+    if (rc != SUCCESS_RET) {
+        LOG_ERROR("http_send_request error, rc = %d", rc);
+        http_client_close(client);
+        return rc;
+    }
+
+    return SUCCESS_RET;
+}
+
+int http_client_recv_data(http_client_t *client, uint32_t timeout_ms, http_client_data_t *client_data) {
+    int rc;
+    Timer timer;
+
+    init_timer(&timer);
+    countdown_ms(&timer, (unsigned int) timeout_ms);
+
+    if ((NULL != client_data->response_buf)
+        && (0 != client_data->response_buf_len)) {
+        rc = _http_client_recv_response(client, left_ms(&timer), client_data);
+        if (rc < 0) {
+            LOG_ERROR("_http_client_recv_response is error, rc = %d", rc);
+            http_client_close(client);
+            return rc;
+        }
+    }
+    return SUCCESS_RET;
+}
+
+void http_client_close(http_client_t *client) {
+    if (client->net.handle > 0) {
+        client->net.disconnect(&client->net);
+    }
+    client->net.handle = 0;
+    LOG_INFO("client disconnected");
+}
+
+void http_client_file_md5(char* file_path, char *output)
+{
+    iot_md5_context ctx;
+    
+    utils_md5_init(&ctx);
+    utils_md5_starts(&ctx);
+    
+    char *buffer = (char *)HAL_Malloc(1024);
+    if (NULL == buffer) {
+        return;
+    }
+    memset(buffer,0,1024);
+    uint32_t count = 0;
+    FILE *fp = fopen(file_path, "rb+");
+    if(NULL == fp)
+    {
+        return;
+    }
+
+    while((count = fread(buffer,1,1024,fp))){
+        utils_md5_update(&ctx, (unsigned char *)buffer, count);
+    }
+    utils_md5_finish_hb2hex(&ctx, output);
+    utils_md5_free(&ctx);
+    fclose(fp);
+    HAL_Free(buffer);
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 76 - 0
uiot/utils/utils_httpc.h

@@ -0,0 +1,76 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_UTILS_HTTPC_H_
+#define C_SDK_UTILS_HTTPC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+#include "utils_net.h"
+
+typedef enum {
+    HTTP_GET,
+    HTTP_POST,
+    HTTP_PUT,
+    HTTP_DELETE,
+    HTTP_HEAD
+} HTTP_Request_Method;
+
+/** @brief   This structure defines the http_client_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. */
+} http_client_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. */
+    unsigned char   *post_buf;      /**< User data to be posted. */
+    char   *response_buf;           /**< Buffer to store the response data. */
+} http_client_data_t;
+
+
+int http_client_connect(http_client_t *client, const char *url, int port, const char *ca_crt);
+
+int http_client_common(http_client_t *client, const char *url, int port, const char *ca_crt,
+                       HTTP_Request_Method method, http_client_data_t *client_data, uint32_t timeout_ms);
+
+int http_client_recv_data(http_client_t *client, uint32_t timeout_ms, http_client_data_t *client_data);
+
+void http_client_close(http_client_t *client);
+
+int _http_send_user_data(http_client_t *client, http_client_data_t *client_data, uint32_t timeout_ms);
+
+void http_client_file_md5(char* file_path, char *output);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* C_SDK_UTILS_HTTPC_H_ */

+ 296 - 0
uiot/utils/utils_list.c

@@ -0,0 +1,296 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "utils_list.h"
+
+#include "uiot_import.h"
+
+ /*
+ * 创建List. 失败则返回NULL.
+ */
+List *list_new(void)
+{
+    List *self;
+    self = (List *)HAL_Malloc(sizeof(List));
+    if (!self) {
+        return NULL;
+    }
+    self->head = NULL;
+    self->tail = NULL;
+    self->free = NULL;
+    self->match = NULL;
+    self->len = 0;
+    return self;
+}
+
+/*
+ * 失败List的内存.
+ */
+void list_destroy(List *self)
+{
+    unsigned int len = self->len;
+    ListNode *next;
+    ListNode *curr = self->head;
+
+    while (len--) {
+        next = curr->next;
+        if (self->free) {
+            self->free(curr->val);
+        }
+        HAL_Free(curr);
+        curr = next;
+    }
+
+    HAL_Free(self);
+}
+
+/*
+ * 将给定节点附加到列表并返回该节点,在失败时返回NULL.
+ */
+ListNode *list_rpush(List *self, ListNode *node)
+{
+    if (!node) {
+        return NULL;
+    }
+
+    if (self->len) {
+        node->prev = self->tail;
+        node->next = NULL;
+        self->tail->next = node;
+        self->tail = node;
+    } else {
+        self->head = self->tail = node;
+        node->prev = node->next = NULL;
+    }
+
+    ++self->len;
+    return node;
+}
+
+/*
+ * 弹出列表中的最后一个节点, 失败返回NULL.
+ */
+ListNode *list_rpop(List *self)
+{
+    ListNode *node = NULL;
+    if (!self->len) {
+        return NULL;
+    }
+
+    node = self->tail;
+
+    if (--self->len) {
+        (self->tail = node->prev)->next = NULL;
+    } else {
+        self->tail = self->head = NULL;
+    }
+
+    node->next = node->prev = NULL;
+    return node;
+}
+
+/*
+ * 弹出列表中的首个节点, 失败返回NULL.
+ */
+ListNode *list_lpop(List *self)
+{
+    ListNode *node = NULL;
+    if (!self->len) {
+        return NULL;
+    }
+
+    node = self->head;
+
+    if (--self->len) {
+        (self->head = node->next)->prev = NULL;
+    } else {
+        self->head = self->tail = NULL;
+    }
+
+    node->next = node->prev = NULL;
+    return node;
+}
+
+/*
+ * 预先将给定的节点添加到列表中,并返回该节点,在失败时返回NULL.
+ */
+ListNode *list_lpush(List *self, ListNode *node)
+{
+    if (!node) {
+        return NULL;
+    }
+
+    if (self->len) {
+        node->next = self->head;
+        node->prev = NULL;
+        self->head->prev = node;
+        self->head = node;
+    } else {
+        self->head = self->tail = node;
+        node->prev = node->next = NULL;
+    }
+
+    ++self->len;
+    return node;
+}
+
+/*
+ * 根据val返回对应的节点,没有则返回NULL.
+ */
+ListNode *list_find(List *self, void *val)
+{
+    ListIterator *it;
+    ListNode *node;
+
+    if (NULL == (it = list_iterator_new(self, LIST_HEAD))) {
+        return NULL;
+    }
+    node = list_iterator_next(it);
+    while (node) {
+        if (self->match) {
+            if (self->match(val, node->val)) {
+                list_iterator_destroy(it);
+                return node;
+            }
+        } else {
+            if (val == node->val) {
+                list_iterator_destroy(it);
+                return node;
+            }
+        }
+        node = list_iterator_next(it);
+    }
+
+    list_iterator_destroy(it);
+    return NULL;
+}
+
+/*
+ * 根据index返回对应的节点,没有则返回NULL.
+ */
+ListNode *list_at(List *self, int index)
+{
+    ListDirection direction = LIST_HEAD;
+
+    if (index < 0) {
+        direction = LIST_TAIL;
+        index = ~index;
+    }
+
+    if ((unsigned) index < self->len) {
+        ListIterator *it;
+        ListNode *node;
+
+        if (NULL == (it = list_iterator_new(self, direction))) {
+            return NULL;
+        }
+        node = list_iterator_next(it);
+
+        while (index--) {
+            node = list_iterator_next(it);
+        }
+        list_iterator_destroy(it);
+        return node;
+    }
+
+    return NULL;
+}
+
+/*
+ * 从列表中删除给定的节点,释放它和它的值.
+ */
+void list_remove(List *self, ListNode *node)
+{
+    node->prev ? (node->prev->next = node->next) : (self->head = node->next);
+
+    node->next ? (node->next->prev = node->prev) : (self->tail = node->prev);
+
+    if (self->free) {
+        self->free(node->val);
+    }
+
+    HAL_Free(node);
+    --self->len;
+}
+
+/*
+ * 创建一个新的ListIterator,失败返回NULL, 并且设置其ListDirection.
+ */
+ListIterator *list_iterator_new(List *list, ListDirection direction)
+{
+    ListNode *node = direction == LIST_HEAD ? list->head : list->tail;
+    return list_iterator_new_from_node(node, direction);
+}
+
+/*
+ * 创建一个新的ListIterator, 并设置初始节点. 失败则返回NULL.
+ */
+ListIterator *list_iterator_new_from_node(ListNode *node, ListDirection direction)
+{
+    ListIterator *self;
+    self = HAL_Malloc(sizeof(ListIterator));
+    if (!self) {
+        return NULL;
+    }
+    self->next = node;
+    self->direction = direction;
+    return self;
+}
+
+/*
+ * 返回下一个节点, 如果没有更多的节点则返回NULL.
+ */
+ListNode *list_iterator_next(ListIterator *self)
+{
+    ListNode *curr = self->next;
+    if (curr) {
+        self->next = self->direction == LIST_HEAD ? curr->next : curr->prev;
+    }
+    return curr;
+}
+
+/*
+ * 释放列表迭代器.
+ */
+void list_iterator_destroy(ListIterator *self)
+{
+    HAL_Free(self);
+    self = NULL;
+}
+
+/*
+ * 根据预设值来创建新节点, 失败则返回NULL.
+ */
+ListNode *list_node_new(void *val)
+{
+    ListNode *self;
+    self = HAL_Malloc(sizeof(ListNode));
+    if (!self) {
+        return NULL;
+    }
+
+    self->prev = NULL;
+    self->next = NULL;
+    self->val = val;
+    return self;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 97 - 0
uiot/utils/utils_list.h

@@ -0,0 +1,97 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_UTILS_LIST_H_
+#define C_SDK_UTILS_LIST_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+
+/*
+ * ListNode迭代器的方向.
+ */
+typedef enum {
+    LIST_HEAD,
+    LIST_TAIL
+} ListDirection;
+
+/*
+ * 链表节点定义.
+ */
+typedef struct ListNode {
+    struct ListNode *prev;
+    struct ListNode *next;
+    void *val;
+} ListNode;
+
+/*
+ * 链表.
+ */
+typedef struct {
+    ListNode *head;
+    ListNode *tail;
+    unsigned int len;
+    void (*free)(void *val);
+    int (*match)(void *a, void *b);
+} List;
+
+/*
+ * 迭代器.
+ */
+typedef struct {
+    ListNode *next;
+    ListDirection direction;
+} ListIterator;
+
+
+/* 节点. */
+ListNode *list_node_new(void *val);
+
+/* 链表. */
+List *list_new(void);
+
+ListNode *list_rpush(List *self, ListNode *node);
+
+ListNode *list_lpush(List *self, ListNode *node);
+
+ListNode *list_find(List *self, void *val);
+
+ListNode *list_at(List *self, int index);
+
+ListNode *list_rpop(List *self);
+
+ListNode *list_lpop(List *self);
+
+void list_remove(List *self, ListNode *node);
+
+void list_destroy(List *self);
+
+/* 迭代器. */
+ListIterator *list_iterator_new(List *list, ListDirection direction);
+
+ListIterator *list_iterator_new_from_node(ListNode *node, ListDirection direction);
+
+ListNode *list_iterator_next(ListIterator *self);
+
+void list_iterator_destroy(ListIterator *self);
+
+#ifdef __cplusplus
+}
+#endif
+#endif //C_SDK_UTILS_LIST_H_

+ 330 - 0
uiot/utils/utils_md5.c

@@ -0,0 +1,330 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include "utils_md5.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#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, size_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_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, size_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);
+}
+
+
+int8_t utils_hb2hex(uint8_t hb)
+{
+    hb = hb & 0xF;
+    return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a');
+}
+
+void utils_md5_finish_hb2hex(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] = utils_hb2hex(buf_out[i] >> 4);
+        output_str[i * 2 + 1] = utils_hb2hex(buf_out[i]);
+    }
+    output_str[32] = '\0';
+}
+
+
+#ifdef __cplusplus
+}
+#endif

+ 93 - 0
uiot/utils/utils_md5.h

@@ -0,0 +1,93 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_UTILS_MD5_H_
+#define C_SDK_UTILS_MD5_H_
+
+#include "uiot_import.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 初始化MD5上下文
+ *
+ * @param ctx   MD5上下文指针
+ */
+void utils_md5_init(iot_md5_context *ctx);
+
+/**
+ * @brief 清空MD5上下文
+ *
+ * @param ctx   MD5上下文指针
+ */
+void utils_md5_free(iot_md5_context *ctx);
+
+/**
+ * @brief 拷贝MD5上下文
+ *
+ * @param dst   目标MD5上下文
+ * @param src   源MD5上下文
+ */
+void utils_md5_clone(iot_md5_context *dst,
+                     const iot_md5_context *src);
+
+/**
+ * @brief 设置MD5上下文
+ *
+ * @param ctx   MD5上下文指针
+ */
+void utils_md5_starts(iot_md5_context *ctx);
+
+/**
+ * @brief MD5过程缓冲区
+ *
+ * @param ctx MD5上下文指针
+ * @param input    输入数据
+ * @param ilen     输入数据长度
+ */
+void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, size_t ilen);
+
+/**
+ * @brief          MD5数据
+ *
+ * @param ctx      MD5上下文指针
+ * @param output   MD5校验和结果
+ */
+void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16]);
+
+/* 内部使用 */
+void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64]);
+
+/**
+ * @brief          Output = MD5( input buffer )
+ *
+ * @param input    输入数据
+ * @param ilen     输入数据长度
+ * @param output   MD5校验和结果
+ */
+void utils_md5(const unsigned char *input, size_t ilen, unsigned char output[16]);
+
+
+int8_t utils_hb2hex(uint8_t hb);
+
+void utils_md5_finish_hb2hex(void *md5, char *output_str);
+
+#endif //C_SDK_UTILS_MD5_H_
+

+ 341 - 0
uiot/utils/utils_net.c

@@ -0,0 +1,341 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+//based on Alibaba c-sdk
+/*
+ * Copyright (C) 2015-2018 Alibaba Group Holding Limited
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "uiot_defs.h"
+#include "utils_net.h"
+#include "uiot_import.h"
+
+
+#ifdef SUPPORT_TLS
+
+static int read_ssl(utils_network_pt pNetwork, unsigned char *buffer, size_t len, uint32_t timeout_ms)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    return HAL_TLS_Read((uintptr_t)pNetwork->handle, buffer, len, timeout_ms);
+}
+
+static int write_ssl(utils_network_pt pNetwork, unsigned char *buffer, size_t len, uint32_t timeout_ms)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    return HAL_TLS_Write((uintptr_t)pNetwork->handle, buffer, len, timeout_ms);
+}
+
+static int disconnect_ssl(utils_network_pt pNetwork)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    HAL_TLS_Disconnect((uintptr_t)pNetwork->handle);
+    pNetwork->handle = 0;
+
+    return SUCCESS_RET;
+}
+
+static int connect_ssl(utils_network_pt pNetwork)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    if (0 != (pNetwork->handle = (intptr_t)HAL_TLS_Connect(
+            pNetwork->pHostAddress,
+            pNetwork->port,
+            pNetwork->authmode,
+            pNetwork->ca_crt,
+            pNetwork->ca_crt_len))) {
+        return SUCCESS_RET;
+    }
+    else {
+        return FAILURE_RET;
+    }
+}
+
+/*** TCP connection ***/
+static int read_tcp(utils_network_pt pNetwork, unsigned char *buffer, size_t len, uint32_t timeout_ms)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    return HAL_TCP_Read((uintptr_t)pNetwork->handle, buffer, len, timeout_ms);
+}
+
+
+static int write_tcp(utils_network_pt pNetwork, unsigned char *buffer, size_t len, uint32_t timeout_ms)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    return HAL_TCP_Write((uintptr_t)pNetwork->handle, buffer, len, timeout_ms);
+}
+
+static int disconnect_tcp(utils_network_pt pNetwork)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    HAL_TCP_Disconnect(pNetwork->handle);
+    pNetwork->handle = (uintptr_t)(-1);
+    return SUCCESS_RET;
+}
+
+static int connect_tcp(utils_network_pt pNetwork)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    pNetwork->handle = HAL_TCP_Connect(pNetwork->pHostAddress, pNetwork->port);
+    if (pNetwork->handle == (uintptr_t)(-1)) {
+        return FAILURE_RET;
+    }
+
+    return SUCCESS_RET;
+}
+
+#elif SUPPORT_AT_CMD
+/* connect TCP by AT cmd through uart */
+static int at_read_tcp(utils_network_pt pNetwork, unsigned char *buffer, size_t len, uint32_t timeout_ms)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    return HAL_AT_Read_Tcp(pNetwork, buffer, len);
+}
+
+static int at_write_tcp(utils_network_pt pNetwork, unsigned char *buffer, size_t len, uint32_t timeout_ms)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    return HAL_AT_Write_Tcp(pNetwork, buffer, len);
+}
+
+static int at_disconnect_tcp(utils_network_pt pNetwork)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    return HAL_AT_TCP_Disconnect(pNetwork);
+}
+
+static int at_connect_tcp(utils_network_pt pNetwork)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    return HAL_AT_TCP_Connect(pNetwork,pNetwork->pHostAddress, pNetwork->port);
+}
+
+#else
+/*** TCP connection ***/
+static int read_tcp(utils_network_pt pNetwork, unsigned char *buffer, size_t len, uint32_t timeout_ms)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    return HAL_TCP_Read((uintptr_t)pNetwork->handle, buffer, len, timeout_ms);
+}
+
+
+static int write_tcp(utils_network_pt pNetwork, unsigned char *buffer, size_t len, uint32_t timeout_ms)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    return HAL_TCP_Write((uintptr_t)pNetwork->handle, buffer, len, timeout_ms);
+}
+
+static int disconnect_tcp(utils_network_pt pNetwork)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    HAL_TCP_Disconnect(pNetwork->handle);
+    pNetwork->handle = (uintptr_t)(-1);
+    return SUCCESS_RET;
+}
+
+static int connect_tcp(utils_network_pt pNetwork)
+{
+    if (NULL == pNetwork) {
+        LOG_ERROR("network is null");
+        return FAILURE_RET;
+    }
+
+    pNetwork->handle = HAL_TCP_Connect(pNetwork->pHostAddress, pNetwork->port);
+    if (pNetwork->handle == (uintptr_t)(-1)) {
+        return FAILURE_RET;
+    }
+
+    return SUCCESS_RET;
+}
+#endif  /* #ifdef SUPPORT_TLS */
+
+/****** network interface ******/
+int utils_net_read(utils_network_pt pNetwork, unsigned char *buffer, size_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
+    {
+        ret = read_tcp(pNetwork, buffer, len, timeout_ms);
+    }
+#elif SUPPORT_AT_CMD
+        ret = at_read_tcp(pNetwork, buffer, len, timeout_ms);
+#else
+    if (NULL == pNetwork->ca_crt) {
+        ret = read_tcp(pNetwork, buffer, len, timeout_ms);
+    }   
+#endif
+
+    return ret;
+}
+
+int utils_net_write(utils_network_pt pNetwork,unsigned char *buffer, size_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
+    {
+        ret = write_tcp(pNetwork, buffer, len, timeout_ms);
+    }
+#elif SUPPORT_AT_CMD
+        ret = at_write_tcp(pNetwork, buffer, len, timeout_ms);
+#else
+    if (NULL == pNetwork->ca_crt) {
+        ret = write_tcp(pNetwork, buffer, len, timeout_ms);
+    }
+#endif
+
+    return ret;
+}
+
+int utils_net_disconnect(utils_network_pt pNetwork)
+{
+    int ret = 0;
+#ifdef SUPPORT_TLS
+    if (NULL != pNetwork->ca_crt) {
+        ret = disconnect_ssl(pNetwork);
+    }
+    else
+    {
+        ret = disconnect_tcp(pNetwork);
+    }
+#elif SUPPORT_AT_CMD
+        ret = at_disconnect_tcp(pNetwork);
+#else
+    if (NULL == pNetwork->ca_crt) {
+        ret = disconnect_tcp(pNetwork);
+    }
+#endif
+
+    return  ret;
+}
+
+int utils_net_connect(utils_network_pt pNetwork)
+{
+    int ret = 0;
+#ifdef SUPPORT_TLS
+    if (NULL != pNetwork->ca_crt) {
+        ret = connect_ssl(pNetwork);
+    }
+    else
+    {
+        ret = connect_tcp(pNetwork);
+    }
+#elif SUPPORT_AT_CMD
+        ret = at_connect_tcp(pNetwork);
+#else
+    if (NULL == pNetwork->ca_crt) {
+        ret = connect_tcp(pNetwork);
+    }
+#endif
+
+    return ret;
+}
+
+int utils_net_init(utils_network_pt pNetwork, const char *host, uint16_t port, uint16_t authmode, const char *ca_crt)
+{
+    if (!pNetwork || !host) {
+        LOG_ERROR("parameter error! pNetwork=%p, host = %p", pNetwork, host);
+        return FAILURE_RET;
+    }
+    pNetwork->pHostAddress = host;
+    pNetwork->port = port;
+#ifndef SUPPORT_AT_CMD
+    pNetwork->authmode = authmode;
+    pNetwork->ca_crt = ca_crt;
+
+    if (NULL == ca_crt) {
+        pNetwork->ca_crt_len = 0;
+    } else {
+        pNetwork->ca_crt_len = strlen(ca_crt);
+    }
+#endif 
+
+    pNetwork->handle = 0;
+    pNetwork->read = utils_net_read;
+    pNetwork->write = utils_net_write;
+    pNetwork->disconnect = utils_net_disconnect;
+    pNetwork->connect = utils_net_connect;
+
+    return SUCCESS_RET;
+}
+

+ 107 - 0
uiot/utils/utils_net.h

@@ -0,0 +1,107 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+//based on Alibaba c-sdk
+/*
+ * Copyright (C) 2015-2018 Alibaba Group Holding Limited
+ */
+
+#ifndef C_SDK_UTILS_NET_H_
+#define C_SDK_UTILS_NET_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifdef SUPPORT_AT_CMD
+#include "stm32f7xx_hal.h"
+#include "at_client.h"
+#endif
+
+/**
+ * @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;
+
+typedef enum
+{
+    SSL_CA_VERIFY_NONE = 0,         
+    SSL_CA_VERIFY_OPTIONAL = 1,
+    SSL_CA_VERIFY_REQUIRED = 2,
+    SSL_CA_VERIFY_UNSET = 3, 
+}SSL_AUTH_MODE;
+
+#ifdef SUPPORT_AT_CMD
+struct utils_network {
+    const char *pHostAddress;
+    uint16_t port;
+
+    /**< uart for send at cmd */
+    at_client *pclient;
+
+    uint16_t authmode;
+
+    /**< 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,unsigned char *, size_t, uint32_t);
+
+    /**< Send data to server function pointer. */
+    int (*write)(utils_network_pt,unsigned char *, size_t, uint32_t);
+
+    /**< Disconnect the network */
+    int (*disconnect)(utils_network_pt);
+
+    /**< Establish the network */
+    int (*connect)(utils_network_pt);
+};
+#else
+struct utils_network {
+    const char *pHostAddress;
+    uint16_t port;
+    uint16_t ca_crt_len;
+
+    uint16_t authmode;
+
+    /**< NULL, TCP connection; NOT NULL, SSL connection */
+    const char *ca_crt;
+    /**< 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,unsigned char *, size_t, uint32_t);
+
+    /**< Send data to server function pointer. */
+    int (*write)(utils_network_pt,unsigned char *, size_t, uint32_t);
+
+    /**< Disconnect the network */
+    int (*disconnect)(utils_network_pt);
+
+    /**< Establish the network */
+    int (*connect)(utils_network_pt);
+};
+#endif
+int utils_net_read(utils_network_pt pNetwork, unsigned char *buffer, size_t len, uint32_t timeout_ms);
+int utils_net_write(utils_network_pt pNetwork, unsigned char *buffer, size_t len, uint32_t timeout_ms);
+int utils_net_disconnect(utils_network_pt pNetwork);
+int utils_net_connect(utils_network_pt pNetwork);
+int utils_net_init(utils_network_pt pNetwork, const char *host, uint16_t port, uint16_t authmode, const char *ca_crt);
+
+#endif /* C_SDK_UTILS_NET_H_ */
+
+

+ 331 - 0
uiot/utils/utils_sha2.c

@@ -0,0 +1,331 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#if 0
+#define UNROLL_LOOPS /* Enable loops unrolling */
+#endif
+
+#define INFRA_SHA256_SMALLER
+
+#include <stdlib.h>
+#include <string.h>
+#include "utils_sha2.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 */
+}
+

+ 99 - 0
uiot/utils/utils_sha2.h

@@ -0,0 +1,99 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef _UTILS_SHA2_H
+#define _UTILS_SHA2_H
+
+#include <stdint.h>
+
+#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]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif 
+

+ 44 - 0
uiot/utils/utils_timer.c

@@ -0,0 +1,44 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+#include "utils_timer.h"
+    
+bool has_expired(Timer *timer) {
+    return HAL_Timer_Expired(timer);
+}
+
+void countdown_ms(Timer *timer, unsigned int timeout_ms) {
+    HAL_Timer_Countdown_ms(timer, timeout_ms);
+}
+
+void countdown(Timer *timer, unsigned int timeout) {
+    HAL_Timer_Countdown(timer, timeout);
+}
+
+int left_ms(Timer *timer) {
+    return HAL_Timer_Remain_ms(timer);
+}
+
+void init_timer(Timer *timer) {
+    HAL_Timer_Init(timer);
+}
+    
+#ifdef __cplusplus
+}
+#endif

+ 80 - 0
uiot/utils/utils_timer.h

@@ -0,0 +1,80 @@
+/*
+* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*/
+
+#ifndef C_SDK_UTILS_TIMER_H_
+#define C_SDK_UTILS_TIMER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+// Add the platform specific timer includes to define the Timer struct
+#include "uiot_import.h"
+
+/**
+ * @brief Check if a timer is expired
+ *
+ * Call this function passing in a timer to check if that timer has expired.
+ *
+ * @param timer - pointer to the timer to be checked for expiration
+ * @return bool - true = timer expired, false = timer not expired
+ */
+bool has_expired(Timer *timer);
+
+/**
+ * @brief Create a timer (milliseconds)
+ *
+ * Sets the timer to expire in a specified number of milliseconds.
+ *
+ * @param timer - pointer to the timer to be set to expire in milliseconds
+ * @param timeout_ms - set the timer to expire in this number of milliseconds
+ */
+void countdown_ms(Timer *timer, unsigned int timeout_ms);
+
+/**
+ * @brief Create a timer (seconds)
+ *
+ * Sets the timer to expire in a specified number of seconds.
+ *
+ * @param timer - pointer to the timer to be set to expire in seconds
+ * @param timeout - set the timer to expire in this number of seconds
+ */
+void countdown(Timer *timer, unsigned int timeout);
+
+/**
+ * @brief Check the time remaining on a give timer
+ *
+ * Checks the input timer and returns the number of milliseconds remaining on the timer.
+ *
+ * @param timer - pointer to the timer to be set to checked
+ * @return int - milliseconds left on the countdown timer
+ */
+int left_ms(Timer *timer);
+
+/**
+ * @brief Initialize a timer
+ *
+ * Performs any initialization required to the timer passed in.
+ *
+ * @param timer - pointer to the timer to be initialized
+ */
+void init_timer(Timer *timer);
+    
+#ifdef __cplusplus
+}
+#endif
+
+#endif //C_SDK_UTILS_TIMER_H_
+