1 /** 2 * @file aiot_http_api.h 3 * @brief HTTP模块头文件, 提供用HTTP协议向阿里云物联网平台上报数据的能力 4 * @date 2019-12-27 5 * 6 * @copyright Copyright (C) 2015-2018 Alibaba Group Holding Limited 7 * 8 */ 9 10 #ifndef _AIOT_HTTP_API_H_ 11 #define _AIOT_HTTP_API_H_ 12 13 #if defined(__cplusplus) 14 extern "C" { 15 #endif 16 17 #include "core_stdinc.h" 18 19 /** 20 * @brief 服务器返回的业务错误码 21 * 22 * @details 23 * 24 * 从云平台对上报消息回应的报文JSON中解析 25 */ 26 typedef enum { 27 /** 28 * @brief 0, 服务端成功接收到上报的消息 29 */ 30 AIOT_HTTP_RSPCODE_SUCCESS = 0, 31 /** 32 * @brief 10000, 服务端返回未知错误 33 */ 34 AIOT_HTTP_RSPCODE_COMMON_ERROR = 10000, 35 /** 36 * @brief 10001, 请求参数错误 37 */ 38 AIOT_HTTP_RSPCODE_PARAM_ERROR = 10001, 39 /** 40 * @brief 20001, token过期, 请调用 @ref aiot_http_auth 进行鉴权, 获取新token 41 */ 42 AIOT_HTTP_RSPCODE_TOKEN_EXPIRED = 20001, 43 /** 44 * @brief 20002, 请求的header中无token可表明设备端合法, 请调用 @ref aiot_http_auth 进行鉴权, 获取新token 45 */ 46 AIOT_HTTP_RSPCODE_TOKEN_NULL = 20002, 47 /** 48 * @brief 20003, token错误, 请调用 @ref aiot_http_auth 进行鉴权, 获取新token 49 */ 50 AIOT_HTTP_RSPCODE_TOKEN_CHECK_ERROR = 20003, 51 /** 52 * @brief 30001, 消息上报失败 53 */ 54 AIOT_HTTP_RSPCODE_PUBLISH_MESSAGE_ERROR = 30001, 55 /** 56 * @brief 40000, 设备端上报过于频繁, 触发服务端限流 57 */ 58 AIOT_HTTP_RSPCODE_REQUEST_TOO_MANY = 40000, 59 } aiot_http_response_code_t; 60 61 /** 62 * @brief @ref aiot_http_setopt 函数的 option 参数, 对于下文每一个选项中的数据类型, 指的是 @ref aiot_mqtt_setopt 中的data参数的数据类型 63 * 64 */ 65 typedef enum { 66 /** 67 * @brief HTTP 服务器的域名地址或者ip地址 68 * 69 * @details 70 * 71 * 阿里云物联网平台域名地址列表: (tcp使用80端口, tls使用443端口) 72 * 73 * | 域名地址 | 区域 | 端口号 | 74 * |---------------------------------------|---------|--------| 75 * | iot-as-http.cn-shanghai.aliyuncs.com | 上海 | 443 | 76 * 77 * 数据类型: (char *) 78 */ 79 AIOT_HTTPOPT_HOST, 80 /** 81 * @brief HTTP 服务器的端口号 82 * 83 * @details 84 * 85 * 连接阿里云物联网平台时: 86 * 87 * 1.如果使用的是tcp, 端口号设置为80 88 * 89 * 2. 如果使用的是tls, 端口号设置为443 90 * 91 * 数据类型: (uint16_t *) 92 */ 93 AIOT_HTTPOPT_PORT, 94 /** 95 * @brief HTTP建联时, 网络使用的安全凭据 96 * 97 * @details 98 * 99 * 该配置项用于为底层网络配置 @ref aiot_sysdep_network_cred_t 安全凭据数据 100 * 101 * 1. 若该选项不配置, 那么MQTT将以tcp方式直接建联 102 * 103 * 2. 若 @ref aiot_sysdep_network_cred_t 中option配置为 @ref AIOT_SYSDEP_NETWORK_CRED_NONE , HTTP将以tcp方式直接建联 104 * 105 * 3. 若 @ref aiot_sysdep_network_cred_t 中option配置为 @ref AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA , HTTP将以tls方式建联 106 * 107 * 数据类型: (aiot_sysdep_network_cred_t *) 108 */ 109 AIOT_HTTPOPT_NETWORK_CRED, 110 /** 111 * @brief HTTP建联时, 建立网络连接的超时时间 112 * 113 * @details 114 * 115 * 指建立socket连接的超时时间 116 * 117 * 数据类型: (uint32_t *) 默认值: (5 *1000) ms 118 * 119 */ 120 AIOT_HTTPOPT_CONNECT_TIMEOUT_MS, 121 /** 122 * @brief HTTP发送数据时, 在协议栈花费的最长时间 123 * 124 * @details 125 * 126 * 数据类型: (uint32_t *) 默认值: (5 * 1000) ms 127 */ 128 AIOT_HTTPOPT_SEND_TIMEOUT_MS, 129 /** 130 * @brief HTTP接收数据时, 在协议栈花费的最长时间 131 * 132 * @details 133 * 134 * 数据类型: (uint32_t *) 默认值: (5 * 1000) ms 135 */ 136 AIOT_HTTPOPT_RECV_TIMEOUT_MS, 137 /** 138 * @brief 销毁HTTP实例时, 等待其他api执行完毕的时间 139 * 140 * @details 141 * 142 * 当调用 @ref aiot_http_deinit 销毁HTTP实例时, 若继续调用其他 aiot_http_xxx API, API会返回STATE_USER_INPUT_EXEC_DISABLED 错误 143 * 144 * 此时, 用户应该停止调用其他 aiot_http_xxx API 145 * 146 * 数据类型: (uint32_t *) 默认值: (2 * 1000) ms 147 */ 148 AIOT_HTTPOPT_DEINIT_TIMEOUT_MS, 149 /** 150 * @brief 当接收服务器返回的http报文时, 单行http header的最大长度 151 * 152 * @details 153 * 154 * 当单行http header设置过短时, @ref aiot_http_recv 会返回 @ref STATE_HTTP_HEADER_BUFFER_TOO_SHORT 状态码 155 * 156 * 数据类型: (uint32_t *) 默认值: 128 157 */ 158 AIOT_HTTPOPT_HEADER_BUFFER_LEN, 159 /** 160 * @brief 当接收服务器返回的http报文时, 每次从 @ref aiot_http_recv_handler_t 回调函数中给出的body最大长度 161 * 162 * @details 163 * 164 * 数据类型: (uint32_t *) 默认值: 128 165 */ 166 AIOT_HTTPOPT_BODY_BUFFER_LEN, 167 /** 168 * @brief HTTP 内部事件回调函数 169 * 170 * @details 171 * 172 * 数据类型: (aiot_http_event_handler_t) 173 */ 174 AIOT_HTTPOPT_EVENT_HANDLER, 175 176 /* 以上选项配置的数据与 CORE_HTTPOPT_XXX 共用 */ 177 178 /** 179 * @brief 用户需要SDK暂存的上下文 180 * 181 * @details 182 * 183 * 1. 当接收到HTTP数据时, 该上下文会从 @ref aiot_http_recv_handler_t 的 userdata 参数给出 184 * 185 * 2. 当HTTP内部有事件发生时, 该上下文会从 @ref aiot_http_event_handler_t 的 userdata 参数给出 186 * 187 * 数据类型: (void *) 188 */ 189 AIOT_HTTPOPT_USERDATA, 190 /** 191 * @brief HTTP 数据接收回调函数 192 * 193 * @details 194 * 195 * 数据类型: (aiot_http_recv_handler_t) 196 */ 197 AIOT_HTTPOPT_RECV_HANDLER, 198 /** 199 * @brief 设备的product key, 可从<a href="http://iot.console.aliyun.com/">阿里云物联网平台控制台</a>获取 200 * 201 * @details 202 * 203 * 数据类型: (char *) 204 */ 205 AIOT_HTTPOPT_PRODUCT_KEY, 206 /** 207 * @brief 设备的device name, 可从<a href="http://iot.console.aliyun.com/">阿里云物联网平台控制台</a>获取 208 * 209 * @details 210 * 211 * 数据类型: (char *) 212 */ 213 AIOT_HTTPOPT_DEVICE_NAME, 214 /** 215 * @brief 设备的device secret, 可从<a href="http://iot.console.aliyun.com/">阿里云物联网平台控制台</a>获取 216 * 217 * @details 218 * 219 * 数据类型: (char *) 220 */ 221 AIOT_HTTPOPT_DEVICE_SECRET, 222 /** 223 * @brief 上报设备的扩展信息, 比如模组商ID和模组ID 224 * 225 * @details 226 * 227 * 1. 模组商ID: 格式为pid=xxx 228 * 229 * 2. 模组ID: 格式为mid=xxx 230 * 231 * 如果需要同时上报多个信息, 那么它们之间用&连接, 例如: pid=xxx&mid=xxx 232 * 233 * 数据类型: (char *) 234 */ 235 AIOT_HTTPOPT_EXTEND_DEVINFO, 236 /** 237 * @brief 使用 @ref aiot_http_auth 进行认证并获取token的超时时间 238 * 239 * @details 240 * 241 * 数据类型: (uint32_t *) 默认值: (5 * 1000) ms 242 */ 243 AIOT_HTTPOPT_AUTH_TIMEOUT_MS, 244 /** 245 * @brief 是否使用http长连接 246 * 247 * @details 248 * 249 * 若该配置的值为0, 则每次使用 @ref aiot_http_auth 和 @ref aiot_http_send 时, SDK会重新与 HTTP 服务器建立简介 250 * 251 * 数据类型: (uint8_t *) 默认值: (5 * 1000) ms 252 */ 253 AIOT_HTTPOPT_LONG_CONNECTION, 254 255 AIOT_HTTPOPT_MAX 256 } aiot_http_option_t; 257 258 /** 259 * @brief SDK收到HTTP报文, 传递给用户数据回调函数时, 对报文类型的描述 260 */ 261 typedef enum { 262 /** 263 * @brief 获取到HTTP Status Code 264 */ 265 AIOT_HTTPRECV_STATUS_CODE, 266 /** 267 * @brief 获取到HTTP Header, 每次返回Header中的一组键值对 268 */ 269 AIOT_HTTPRECV_HEADER, 270 /** 271 * @brief 获取到HTTP Body, 返回完整的Body内容 272 */ 273 AIOT_HTTPRECV_BODY 274 } aiot_http_recv_type_t; 275 276 /** 277 * @brief SDK收到HTTP报文, 传递给用户数据回调函数时, 对报文内容的描述 278 */ 279 typedef struct { 280 /** 281 * @brief HTTP 消息类型, 更多信息请参考 @ref aiot_http_recv_type_t 282 */ 283 aiot_http_recv_type_t type; 284 union { 285 /** 286 * @brief HTTP 消息类型为 @ref AIOT_HTTPRECV_STATUS_CODE 时的数据 287 */ 288 struct { 289 /** 290 * @brief HTTP Status Code 291 */ 292 uint32_t code; 293 } status_code; 294 /** 295 * @brief HTTP 消息类型为 @ref AIOT_HTTPRECV_HEADER 时的数据 296 */ 297 struct { 298 /** 299 * @brief 单行 HTTP Header 的 key 300 */ 301 char *key; 302 /** 303 * @brief 单行 HTTP Header 的 value 304 */ 305 char *value; 306 } header; 307 /** 308 * @brief HTTP 消息类型为 @ref AIOT_HTTPRECV_BODY 时的数据 309 */ 310 struct { 311 /** 312 * @brief HTTP Body 的内容 313 */ 314 uint8_t *buffer; 315 /** 316 * @brief HTTP Body 的长度 317 */ 318 uint32_t len; 319 } body; 320 } data; 321 } aiot_http_recv_t; 322 323 /** 324 * @brief HTTP 消息接收回调函数原型, 可以通过 @ref aiot_http_setopt 接口的 @ref AIOT_HTTPOPT_RECV_HANDLER 参数指定 325 * 326 * @details 327 * 328 * 当SDK收到 HTTP 服务器的应答数据时, 通过此回调函数输出 329 * 330 * @param[out] handle HTTP 句柄 331 * @param[out] packet 从 HTTP 服务器接收到的数据 332 * @param[out] userdata 用户通过 @ref AIOT_HTTPOPT_USERDATA 交由SDK暂存的上下文 333 * 334 * @return void 335 */ 336 typedef void (*aiot_http_recv_handler_t)(void *handle, const aiot_http_recv_t *packet, void *userdata); 337 338 /** 339 * @brief SDK内部发生状态变化, 通过用户事件回调函数通知用户时, 对事件类型的描述 340 */ 341 typedef enum { 342 /** 343 * @brief token无效事件, 此时用户应该调用 @ref aiot_http_auth 获取新的token 344 */ 345 AIOT_HTTPEVT_TOKEN_INVALID 346 } aiot_http_event_type_t; 347 348 /** 349 * @brief SDK内部发生状态变化, 通过用户事件回调函数通知用户时, 对事件内容的描述 350 */ 351 typedef struct { 352 aiot_http_event_type_t type; 353 } aiot_http_event_t; 354 355 /** 356 * @brief HTTP 事件回调函数原型, 可以通过 @ref aiot_http_setopt 接口的 @ref AIOT_HTTPOPT_EVENT_HANDLER 参数指定 357 * 358 * @param[out] handle HTTP句柄 359 * @param[out] event 事件结构体 360 * @param[out] user_data 指向用户上下文数据的指针, 由 @ref aiot_http_setopt 的 @ref AIOT_HTTPOPT_USERDATA 选项设置 361 */ 362 typedef void (* aiot_http_event_handler_t)(void *handle, const aiot_http_event_t *event, void *userdata); 363 364 /** 365 * @brief 创建一个HTTP上云实例 366 * 367 * @return void* 368 * 369 * @retval 非NULL, HTTP 实例句柄 370 * @retval NULL,初始化 HTTP 实例失败 371 */ 372 void *aiot_http_init(void); 373 374 /** 375 * @brief 设置HTTP实例参数 376 * 377 * @param[in] handle HTTP句柄 378 * @param[in] option 配置选项, 更多信息请参考 @ref aiot_http_option_t 379 * @param[in] data 配置数据, 更多信息请参考 @ref aiot_http_option_t 380 * 381 * @return int32_t 382 * 383 * @retval STATE_SUCCESS, 成功 384 * @retval STATE_HTTP_HANDLE_IS_NULL, HTTP句柄为NULL 385 * @retval STATE_USER_INPUT_OUT_RANGE, 用户输入参数无效 386 * @retval STATE_SYS_DEPEND_MALLOC_FAILED, 内存分配失败 387 */ 388 int32_t aiot_http_setopt(void *handle, aiot_http_option_t option, void *data); 389 390 /** 391 * @brief 向服务器发送认证请求, 获取token 392 * 393 * @param[in] handle HTTP句柄 394 * 395 * @return int32_t 396 * 397 * @retval STATE_SUCCESS, 认证成功 398 * @retval STATE_HTTP_HANDLE_IS_NULL, HTTP句柄为NULL 399 * @retval STATE_USER_INPUT_MISSING_PRODUCT_KEY, 未设置必要选项ProductKey 400 * @retval STATE_USER_INPUT_MISSING_DEVICE_NAME, 未设置必要选项DeviceName 401 * @retval STATE_USER_INPUT_MISSING_DEVICE_SECRET, 未设置必要选项DeviceSecret 402 * @retval STATE_HTTP_TOKEN_LEN_ERROR, token长度错误 403 * @retval STATE_HTTP_GET_TOKEN_FAILED, 获取token失败 404 */ 405 int32_t aiot_http_auth(void *handle); 406 407 /** 408 * @brief 上报数据到物联网平台 409 * 410 * @param[in] handle HTTP句柄 411 * @param[in] topic 上报的目标topic, 在物联网平台控制的产品详情页面有设备的完整topic列表 412 * @param[in] payload 指向上报数据的指针 413 * @param[in] payload_len 上报数据的长度 414 * 415 * @return int32_t 416 * 417 * @retval STATE_SUCCESS, 上报成功 418 * @retval STATE_HTTP_HANDLE_IS_NULL, HTTP句柄为NULL 419 * @retval STATE_USER_INPUT_OUT_RANGE, 用户输入参数无效 420 * @retval STATE_HTTP_NOT_AUTH, 设备未认证 421 */ 422 int32_t aiot_http_send(void *handle, char *topic, uint8_t *payload, uint32_t payload_len); 423 424 /** 425 * 服务器响应数据格式为 426 * { 427 * "code": 0, // 业务状态码 428 * "message": "success", // 业务信息 429 * "info": { 430 * "messageId": 892687627916247040, 431 * } 432 * } 433 */ 434 435 /** 436 * @brief 接受HTTP应答数据, 数据会从用户设置的 @ref aiot_http_event_handler_t 回调函数输出 437 * 438 * @param[in] handle HTTP句柄 439 * 440 * @return int32_t 441 * 442 * @retval >= 0, 接受到的HTTP body数据长度 443 * @retval STATE_HTTP_HANDLE_IS_NULL, HTTP句柄为NULL 444 * @retval STATE_USER_INPUT_NULL_POINTER, 用户输入参数为NULL 445 * @retval STATE_USER_INPUT_OUT_RANGE, buffer_len为0 446 * @retval STATE_HTTP_RSP_MSG_ERROR, 服务器应答消息错误 447 * @retval STATE_SYS_DEPEND_NWK_CLOSED, 网络连接已关闭 448 * @retval STATE_SYS_DEPEND_NWK_READ_OVERTIME, 网络接收超时 449 * @retval STATE_HTTP_RECV_LINE_TOO_LONG, HTTP单行数据过长, 内部无法解析 450 * @retval STATE_HTTP_PARSE_STATUS_LINE_FAILED, 无法解析状态码 451 * @retval STATE_HTTP_GET_CONTENT_LEN_FAILED, 获取Content-Length失败 452 */ 453 int32_t aiot_http_recv(void *handle); 454 455 /** 456 * @brief 销毁参数p_handle所指定的HTTP实例 457 * 458 * @param[in] p_handle 指向HTTP句柄的指针 459 * 460 * @return int32_t 461 * 462 * @retval STATE_SUCCESS 成功 463 * @retval STATE_USER_INPUT_NULL_POINTER 参数p_handle为NULL或者p_handle指向的句柄为NULL 464 */ 465 int32_t aiot_http_deinit(void **p_handle); 466 467 468 #if defined(__cplusplus) 469 } 470 #endif 471 472 #endif /* #ifndef _AIOT_HTTP_API_H_ */ 473 474