diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/BUILD.gn b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..ba123909ef98f82136006caacc8cad84fb451d35 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/BUILD.gn @@ -0,0 +1,124 @@ +# Copyright (C) 2022-2023 Huawei Device Co., Ltd. +# 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. + +if (defined(ohos_lite)) { + import("//build/lite/config/component/lite_component.gni") +} else { + import("//build/ohos.gni") +} + +import("dconnectcaseone_deps.gni") + +dconn_sources = [ + "adapter/src/dconn_sched_yield.c", + "client/src/client.c", + "common/src/dconn_auth.c", + "common/src/dconn_cjson.c", + "common/src/dconn_data.c", + "common/src/dconn_group_auth.c", + "common/src/dconn_group_common.c", + "common/src/dconn_group_manager.c", + "common/src/dconn_handler.c", + "common/src/dconn_log.c", + "common/src/dconn_mbedtls_gcm.c", + "common/src/dconn_msg.c", + "common/src/dconn_peer.c", + "common/src/dconn_send.c", + "common/src/dconn_server_data.c", + "common/src/dconn_syspara.c", + "common/src/dconn_thread.c", + "common/src/recv_thread.c", + "main/dconncaseone.c", + "service/src/service.c", +] + +dconn_include_dirs = [ + "adapter/include", + "interface/include", + "service/include", + "client/include", + "common/include", + "common/src", + "//base/startup/syspara_lite/interfaces/innerkits/native/syspara/include", # should be exported by bundle.json +] + +dconn_ldflags = [ + "-fvisibility=hidden", +] + +dconn_cflags = [ + "-Wall", + "-Wdate-time", + "-Werror", + "-Wextra", + "-Wfloat-equal", + "-Wshadow", + "-Wtrampolines", + "-freg-struct-return", + "-fno-strict-aliasing", + "-fno-common", + "-fsigned-char", + "-pipe", + "-std=c99", + "-Wformat=2", # check format string +] + +if (defined(ohos_lite)) { + if (ohos_kernel_type == "liteos_m") { + static_library("dconnectcaseone") { + sources = dconn_sources + include_dirs = dconn_include_dirs + deps = dconn_mini_deps + defines = [] + cflags = dconn_cflags + ldflags = dconn_ldflags + } + } else { + # ohos_kernel_type == "liteos_a" + dconn_cflags -= [ + "-freg-struct-return", # unsupported option '-fno-reg-struct-return' for target + "-Wtrampolines", # unsupported option '-Wtrampolines' for target + ] + dconn_ldflags += [ + "-fPIC" + ] + shared_library("dconnectcaseone") { + sources = dconn_sources + include_dirs = dconn_include_dirs + deps = dconn_small_deps + defines = [] + cflags = dconn_cflags + ldflags = dconn_ldflags + } + } +} else { + # standard_system + dconn_cflags -= [ + "-freg-struct-return", # unsupported option '-fno-reg-struct-return' for target + "-Wtrampolines", # unsupported option '-Wtrampolines' for target + ] + dconn_ldflags += [ + "-fPIC" + ] + ohos_shared_library("dconnectcaseone") { + sources = dconn_sources + include_dirs = dconn_include_dirs + defines = [] + cflags = dconn_cflags + ldflags = dconn_ldflags + deps = dconn_standrad_deps + part_name = "dconnectcaseone" + subsystem_name = "kits" + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } +} \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/LICENSE b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/LICENSE new file mode 100755 index 0000000000000000000000000000000000000000..4a459866a57c25462afad17f3fe0b50d440da080 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/LICENSE @@ -0,0 +1,177 @@ + + 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 \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/adapter/include/dconn_sched_yield.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/adapter/include/dconn_sched_yield.h new file mode 100755 index 0000000000000000000000000000000000000000..63b210aa8c7a1a3f5d1bee4cd0494d25771b0842 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/adapter/include/dconn_sched_yield.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef DCONN_SCHED_YIELD_H +#define DCONN_SCHED_YIELD_H + +void DConnSchedYield(void); + +#endif // DCONN_SCHED_YIELD_H \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/adapter/src/dconn_sched_yield.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/adapter/src/dconn_sched_yield.c new file mode 100755 index 0000000000000000000000000000000000000000..29ee96d45f29d25425b374b27bce25f9648f7bf6 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/adapter/src/dconn_sched_yield.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_sched_yield.h" + +#ifdef __LITEOS__ +#include +#else +#include +#endif + +void DConnSchedYield(void) +{ +#ifdef __LITEOS__ + sleep(0); // LitsOS POSIX API uses LOS_TaskYield() to implement sleep(0) +#else + sched_yield(); +#endif +} \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/client/include/client.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/client/include/client.h new file mode 100755 index 0000000000000000000000000000000000000000..2f7cb5274808de2f4ae27ad211a333b69447e563 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/client/include/client.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_CLIENT_INCLUE_CLIENT +#define APPLICATIONS_APP_DCONNECTCASEONE_CLIENT_INCLUE_CLIENT + +#include + +/** + * @brief 初始化客户端。按 ipAry 列表顺序初始化,遇到第一个失败的则停止。 + * + * @param ipAry IP地址列表,以半角逗号","分隔 + * @param errorIp 第一个出错的 IP 地址 + * @return uint32_t 错误码 + */ +uint32_t DConnInitClient(const char *ipAry, char *errorIp); + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_CLIENT_INCLUE_CLIENT \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/client/src/client.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/client/src/client.c new file mode 100755 index 0000000000000000000000000000000000000000..c36b888e458664fb5603c2304e0e125091a417ca --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/client/src/client.c @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "client.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cJSON.h" + +#include "dconn_syspara.h" +#include "dconn_data.h" +#include "dconn_peer.h" +#include "dconncaseone_interface.h" +#include "product_limits.h" +#include "dconn_log.h" +#include "dconn_cjson.h" +#include "dconn_group_manager.h" +#include "dconn_send.h" +#include "dconn_msg.h" +#include "dconn_sched_yield.h" + +/** + * @brief 滑动窗口算法。从IP地址列表字符串中获取下一个 IP 地址。若中间存在错误格式的 IP 地址,则会导致后续的 IP + * 地址都无法解析。 + * + * @param ipAry IP 地址列表,以逗号分隔 + * @param idx 字符索引。正常情况下传入时总指向下一个IP地址的开始字符,返回后指向获取到的 IP 地址最后一个字符的下一个字符 + * @param ipAddr 获取到的 IP 地址 + * @return uint32_t 错误码 + */ +static uint32_t GetNextIpAddr(const char *ipAry, uint32_t *idx, char *ipAddr, bool *hasNextIpAddr) +{ + errno_t err = memset_s(ipAddr, DCONN_IP_ADDR_LEN + 1, 0, DCONN_IP_ADDR_LEN + 1); + if (err != EOK) { + DCONN_ERROR("memset_s failed."); + return DC_ERROR; + } + uint32_t ipAddrIdx = 0; + while ((*idx) != strlen(ipAry) + 1) { + char chr = ipAry[*idx]; + if (ipAddrIdx > DCONN_IP_ADDR_LEN + 1) { + return DC_ERR_IP_FORMAT; + } + + if (chr == ',' || chr == '\0') { + // IP 地址需以 "," 或 "\0" 结束 + ipAddr[ipAddrIdx] = '\0'; + (*idx)++; + *hasNextIpAddr = (chr != '\0'); // 最后一个 IP 地址 + return DC_SUCCESS; + } + + ipAddr[ipAddrIdx] = chr; + (*idx)++; + ipAddrIdx++; + } + + return DC_ERR_IP_FORMAT; +} + +static uint32_t IpAddrToInt(int addressFamily, const char *ipAddr, uint32_t *addr) +{ + uint32_t ipValue = DconnIpTransToInt(ipAddr); + unsigned char *ipAddress = (unsigned char *)&ipValue; + if (addressFamily == AF_INET) { + if (inet_pton(AF_INET, ipAddr, (void *)addr) == 0) { + DCONN_ERROR("Invalid IPv4 address: %" IPV4_ANONYMOUS_PLACEHOLDER, ipAddress[3], ipAddress[0]); + return DC_ERR_IP_FORMAT; + } + } else { + if (inet_pton(AF_INET6, ipAddr, (void *)addr) == 0) { + DCONN_ERROR("Invalid IPv6 address: %" IPV6_ANONYMOUS_PLACEHOLDER, ipAddress[0], ipAddress[0]); + return DC_ERR_IP_FORMAT; + } + } + return DC_SUCCESS; +} + +static uint32_t ConnectServer(int addressFamily, const char *ipAddr, uint32_t addr, int *fd) +{ + (void)ipAddr; + uint32_t ipValue = DconnIpTransToInt(ipAddr); + unsigned char *ipAddress = (unsigned char *)&ipValue; + (void)ipAddress; + DCONN_DEBUG("Connect server begin: %" IPV4_ANONYMOUS_PLACEHOLDER, ipAddress[3], ipAddress[0]); + + *fd = socket(addressFamily, SOCK_STREAM, 0); + if (*fd == -1) { + DCONN_ERROR("Client socket init error: %d", errno); + return DC_ERR_IP_FORMAT; + } + + struct sockaddr_in servAddr; + struct sockaddr_in6 servAddr6; + int result = 0; + errno_t err = memset_s(&servAddr, sizeof(servAddr), 0, sizeof(servAddr)); + if (err != EOK) { + DCONN_ERROR("memset_s failed."); + return DC_ERROR; + } + if (addressFamily == AF_INET) { + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = addr; + servAddr.sin_port = htons(DCONN_SERVICE_PORT); + result = connect(*fd, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)); + } else { + servAddr6.sin6_family = AF_INET6; + servAddr.sin_addr.s_addr = addr; + servAddr6.sin6_port = htons(DCONN_SERVICE_PORT); + result = connect(*fd, (struct sockaddr *)&servAddr6, sizeof(struct sockaddr_in6)); + } + + if (result == -1) { + // 若服务端 accept 得到的 IP 地址不合法,则会直接断开连接 + DCONN_ERROR("Client connect to server error: %d", errno); + return DC_ERR_CONNECTION_REFUSED; + } + + DCONN_DEBUG("Server connected: %" IPV4_ANONYMOUS_PLACEHOLDER, ipAddress[3], ipAddress[0]); + return DC_SUCCESS; +} + +static uint32_t BuildDeviceIdMessage(char **deviceIdMessage) +{ + DConnDeviceUdId deviceUdId; + uint32_t ret = DConnGetDeviceUdid(&deviceUdId); + if (ret != 0) { + DCONN_ERROR("Cannot get dev udid: %" PRIu32, ret); + return ret; + } + + cJSON *payloadJson = cJSON_CreateObject(); + if (payloadJson == NULL) { + DCONN_ERROR("Failed to allocate payloadJson memory."); + return DC_ERR_ALLOC_MEMORY; + } + DConnAddStringToJson(payloadJson, "deviceId", deviceUdId.deviceId); + DConnAddStringToJson(payloadJson, "udid", deviceUdId.udid); + *deviceIdMessage = cJSON_PrintUnformatted(payloadJson); + if (*deviceIdMessage == NULL) { + DCONN_ERROR("Failed to pack payloadJson to string."); + cJSON_Delete(payloadJson); + return DC_ERR_INVALID_JSON; + } + cJSON_Delete(payloadJson); + + DCONN_DEBUG("Build deviceIdMessage succeed."); + return DC_SUCCESS; +} + +static uint32_t ClientSendDeviceId(int32_t peerIdx) +{ + char *deviceIdMessage; + uint32_t ret = BuildDeviceIdMessage(&deviceIdMessage); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Build device ID message failed: %" PRIu32, ret); + return ret; + } + + DConnMsgIn in = { + .data = (const uint8_t *)deviceIdMessage, + .dataLen = strlen(deviceIdMessage), + }; + DConnMsgOut out; + ret = DConnEncMsg(DCONN_MSG_TYPE_DEVICE_ID, NULL, &in, &out); + cJSON_free(deviceIdMessage); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Encode device ID message failed: %" PRIu32, ret); + return ret; + } + + ret = SendDataToPeer(peerIdx, out.msg, out.msgLen); + free(out.msg); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Send device ID message failed: %" PRIu32, ret); + return ret; + } + + return DC_SUCCESS; +} + +static bool GetAuthProcess(int32_t peerIdx, uint32_t authStat) +{ + DConnDataParam param; + GetSessionKeyByPeerIdx(peerIdx, ¶m.key, ¶m.keyLen); + bool isAuthFinished = authStat & PEER_AUTH_STAT_END_MASK; + + return !isAuthFinished || (param.keyLen == 0); +} + +static uint32_t WaitForAuthStat(int32_t peerIdx) +{ + time_t start = time(NULL); + DCONN_DEBUG("Client auth start at: %lld", start); + bool inAuthProcess = true; + bool isTimeout = false; + uint32_t stat; + + do { + stat = GetAuthStatByPeerDataIdx(peerIdx); + inAuthProcess = GetAuthProcess(peerIdx, stat); + isTimeout = (time(NULL) - start) > HICHAIN_AUTH_TIMEOUT; + DConnSchedYield(); + } while (inAuthProcess && !isTimeout); + + DCONN_DEBUG("Client auth wait end: isAuthProcess: %s, isTimeout: %s", + inAuthProcess ? "true" : "false", + isTimeout ? "true" : "false"); + return stat; +} + +static uint32_t InitOneClient(int addressFamily, const char *ipAddr, uint32_t addr) +{ + int32_t peerIdx = GetNewPeerDataIdx(PEER_ROLE_SERVICE); + if (peerIdx == -1) { + return DC_ERR_PEER_NUM_EXCEED; + } + + int *socket = GetSocketByPeerDataIdx(peerIdx); + uint32_t ret = ConnectServer(addressFamily, ipAddr, addr, socket); + if (ret != DC_SUCCESS) { + ReleasePeerDataIdx(peerIdx); + return ret; + } + + SetAuthStatByPeerDataIdx(peerIdx, PEER_AUTH_EXPECT_DEVICE_ID); + ret = ClientSendDeviceId(peerIdx); + if (ret != DC_SUCCESS) { + ReleasePeerDataIdx(peerIdx); + return ret; + } + + uint32_t stat = WaitForAuthStat(peerIdx); + if (stat != PEER_AUTH_STAT_AUTHORIZED) { + // Async processes should set the peer auth stat to let client release peer data. + ReleasePeerDataIdx(peerIdx); + uint32_t ipValue = DconnIpTransToInt(ipAddr); + unsigned char *ipAddress = (unsigned char *)&ipValue; + DCONN_ERROR("Client init failed: %" IPV4_ANONYMOUS_PLACEHOLDER ", in stat: %" PRIu32, + ipAddress[3], ipAddress[0], stat); + return DC_ERR_AUTH_FAILED; + } + + SetIpAddrByIdx(peerIdx, addr); + return DC_SUCCESS; +} + +uint32_t DConnInitClient(const char *ipAry, char *errorIp) +{ + uint32_t ret = CreateDeviceAuthGroup(); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Create device auth group failed: %" PRIu32, ret); + return ret; + } + + char ipAddr[DCONN_IP_ADDR_LEN + 1] = {0}; + uint32_t ipIdx = 0; + uint32_t addr = 0; + int addressFamily = AF_INET; + bool hasNextIpAddr = false; + do { + ret = GetNextIpAddr(ipAry, &ipIdx, ipAddr, &hasNextIpAddr); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Next IP address [%" PRId32 "] parse failed: %" PRIu32, ipIdx, ret); + break; + } + + uint32_t ipValue = DconnIpTransToInt(ipAddr); + unsigned char *ipAddress = (unsigned char *)&ipValue; + if (!IS_IPV4_ADDRESS(ipAddr)) { + addressFamily = AF_INET6; + } + ret = IpAddrToInt(addressFamily, ipAddr, &addr); + if (ret != DC_SUCCESS) { + DCONN_ERROR("IP address [%" IPV4_ANONYMOUS_PLACEHOLDER "] Converting failed: %" PRIu32, + ipAddress[3], ipAddress[0], ret); + break; + } + + ret = HasPeerIpAddr(addr); + if (ret == DC_SUCCESS) { + continue; + } + + DCONN_DEBUG("Init next client: %" IPV4_ANONYMOUS_PLACEHOLDER, ipAddress[3], ipAddress[0]); + ret = InitOneClient(addressFamily, ipAddr, addr); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Init one client [%" PRId32 "] failed: %" PRIu32, ipIdx, ret); + break; + } + + DCONN_INFO("Client [%" PRId32 "] init succeed.", ipIdx); + } while (hasNextIpAddr); + + if (ret != DC_SUCCESS) { + DCONN_ERROR("Client init failed: %" PRIu32, ret); + if (strcpy_s(errorIp, DCONN_IP_ADDR_LEN + 1, ipAddr) != EOK) { + DCONN_ERROR("strcpy_s failed."); + } + return ret; + } + + DCONN_INFO("All client init succeed"); + return DC_SUCCESS; +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_auth.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_auth.h new file mode 100755 index 0000000000000000000000000000000000000000..6665921c0f62f792e5fb3dc7ef809af983507b6a --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_auth.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_AUTH +#define APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_AUTH + +#include + +#define HC_CREATE_GROUP_REQUEST_ID 0 // 创建群组 request ID + +/** + * @brief Hichain processData proxy + * + * @param idx 索引 + * @param requestId 请求ID + * @param data 数据 + * @param dataLen 数据长度 + * @return int32_t 错误码 + */ +uint32_t HcProcessData(int32_t idx, int64_t requestId, const uint8_t *data, uint32_t dataLen); + +/** + * @brief Hichain 服务端群组初始化。 + * + * @return int32_t 初始化结果 + */ +uint32_t InitHcService(void); + +/** + * @brief 服务端创建 Hichain 群组 + * + * @return int32_t 创建结果 + */ +uint32_t CreateHcGroup(void); + +/** + * @brief 处理处于接收设备ID状态的对等端 + * + * @param idx 对等端索引 + * @param data 设备ID报文(未校验) + * @param dataLen 设备ID报文长度 + */ +void HandleExpectDeviceIdStat(int32_t idx, const uint8_t *data, uint32_t dataLen); + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_AUTH \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_cjson.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_cjson.h new file mode 100755 index 0000000000000000000000000000000000000000..86f9b910d4ba33f81782304de50ecdedd6fdadbb --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_cjson.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef DCONN_CJSON_H +#define DCONN_CJSON_H + +#include +#include + +#include "cJSON.h" + +const char *DConnGetStringFromCJson(const cJSON *jsonObj, const char *key); +int32_t DConnGetInt64FromJson(const cJSON *jsonObj, const char *key, int64_t *value); + +void DConnAddIntToJson(cJSON *jsonObj, const char *key, int value); +void DConnAddInt64StringToJson(cJSON *jsonObj, const char *key, int64_t value); +void DConnAddStringToJson(cJSON *jsonObj, const char *key, const char *value); +void DConnAddBoolToJson(cJSON *jsonObj, const char *key, bool value); + +#endif // DCONN_CJSON_H \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_data.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_data.h new file mode 100755 index 0000000000000000000000000000000000000000..6b9b38309322e65327b7b2972455f69de56c5031 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_data.h @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_DATA +#define APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_DATA + +#include +#include +#include +#include + +#include "dconncaseone_interface.h" + +/** + * @brief 初始化套件数据模块。可重入,不会重复初始化。 + * + * @return true 初始化成功 + * @return false 初始化失败 + */ +uint32_t InitDConnData(void); + +/** + * @brief 释放全局资源 + * + */ +void DeInitDconnData(void); + +/** + * @brief 检查当前的对等端列表中,是否已经存在输入的 IP 地址 + * + * @param ipAddr IP 地址 + * @return true 存在 + * @return false 不存在 + */ +bool ContainsIpAddr(char *ipAddr); + +/** + * @brief 在系统控制块中获取一个新的对等端数据 + * + * @param role 对等端角色 PeerRole + * @return int32_t 获取成功,返回对等端数据索引。获取失败,返回 -1 + */ +int32_t GetNewPeerDataIdx(uint32_t role); + +/** + * @brief 释放一个对等数据。包括关闭 socket + * + * @param idx 该对等数据的索引 + */ +void ReleasePeerDataIdx(int32_t idx); + +/** + * @brief 获取对等端角色 + * + * @param idx 对等端索引 + * @return uint32_t 角色 PeerRole + */ +uint32_t GetPeerRole(int32_t idx); + +/** + * @brief 根据 peer data 索引获取socket + * + * @param idx peer data 索引 + * @return int* socket fd 指针 + */ +int *GetSocketByPeerDataIdx(int32_t idx); + +/** + * @brief 设置对等端 socket + * + * @param idx 对等端索引 + * @param socket 对等端 socket + */ +void SetSocketByPeerDataIdx(int32_t idx, int socket); + +/** + * @brief 根据 peer data 索引获取认证状态 + * + * @param idx peer data 索引 + * @return uint32_t 认证状态 PeerAuthStat + */ +uint32_t GetAuthStatByPeerDataIdx(int32_t idx); + +/** + * @brief Set the Auth Stat By Peer Data Idx object + * + * @param idx peer data 索引 + * @param sta 认证状态 PeerAuthStat + */ +void SetAuthStatByPeerDataIdx(int32_t idx, uint32_t sta); + +/** + * @brief Get the Request Id By Peer Data Idx object + * + * @param idx 索引 + * @return int64_t 请求ID + */ +int64_t GetRequestIdByPeerDataIdx(int32_t idx); + +/** + * @brief Get the Idx By Request Id object + * + * @param requestId 请求ID + * @return int32_t 索引 + */ +int32_t GetIdxByRequestId(int64_t requestId); + +/** + * @brief Set the Session Key By Peer Idx object + * + * @param idx 索引 + * @param sessionKey 密钥 + * @param sessionKeyLen 密钥长度 + */ +void SetSessionKeyByPeerIdx(int32_t idx, const uint8_t *sessionKey, uint32_t sessionKeyLen); + +/** + * @brief Get the Idx By Device Id object + * + * @param deviceId 设备ID + * @return uint32_t 索引 + */ +int32_t GetIdxByDeviceId(const char *deviceId); + +/** + * @brief Get the Session Key By Peer Idx object + * + * @param idx 索引 + * @param sessionKey 密钥 + * @param keyLength 密钥长度 + */ +void GetSessionKeyByPeerIdx(int32_t idx, uint8_t **sessionKey, uint32_t *keyLength); + +/** + * @brief Set the Request Id By Peer Data Idx object + * + * @param idx 索引 + * @param requestId 请求ID + */ +void SetRequestIdByPeerDataIdx(int32_t idx, int64_t requestId); + +/** + * @brief Get the Device Id By Peer idx + * + * @param idx 对等端索引 + * @return NULL 未找到 + */ +char *GetDeviceIdByPeerIdx(int32_t idx); + +/** + * @brief Set the Device Id For Idx object + * + * @param idx 对等端索引 + * @param deviceId 设备ID + */ +void SetDeviceIdForIdx(int32_t idx, const char *deviceId); + +/** + * @brief Get the UDID By Peer idx + * + * @param idx 对等端索引 + * @return NULL 未找到 + */ +const char *GetUdidByPeerIdx(int32_t idx); + +/** + * @brief Set the UDID For Idx object + * + * @param idx 对等端索引 + * @param udid UDID + */ +void SetUdidForIdx(int32_t idx, const char *udid); + +/** + * @brief Get the Peer Data Idx By Udid object + * + * @param udid UDID + * @return int32_t 对等端索引 + */ +int32_t GetPeerDataIdxByUdid(const char *udid); + +/** + * @brief Get the Peer Fd By Device Id object + * + * @param deviceId 设备 ID + * @param fd 对等端 FD + * @return true 找到 + * @return false 未找到 + */ +bool GetPeerFdByDeviceId(const char *deviceId, int *fd, bool authorized); + +/** + * @brief 获取服务器 socket 指针 + * + * @return int 服务器 socket + */ +int GetServerSocket(void); + +/** + * @brief 设置服务器 socket 指针 + * + * @param fd 服务器 socket + */ +void SetServerSocket(int fd); + +/** + * @brief 获取服务端 socket 地址族 + * + * @return int* AF_INET/AF_INET6 + */ +int *GetServerSocketAddrFamily(void); + +/** + * @brief 获取 IOT SDK回调函数 + * + * @return CallbackParam* 回调函数指针 + */ +CallbackParam *GetIotSdkCallback(void); + +/** + * @brief 初始化 select 列表。仅放入认证成功的对等端 socket + * + * @param readSet 读 fd 列表 + * @param exceptSet 异常 fd 列表 + * @return int 最大 fd 值。若没有任何 fd 被设置,则返回 -1 + */ +int InitSelectFdSet(fd_set *readSet, fd_set *exceptSet); + +/** + * @brief Peer idx Handler + * + */ +typedef void (*PeerIdxHandler)(int32_t fd); + +/** + * @brief Server socket Handler + * + */ +typedef void (*ServerSocketHandler)(void); + +/** + * @brief 处理 fd set + * + * @param fdSet The fd set obj + * @param handler The single peer idx handler + * @param serverHandler The server socket Handler. Leave NULL for unused. + */ +void HandleFdSet(const fd_set *fdSet, PeerIdxHandler handler, ServerSocketHandler serverHandler); + +/** + * @brief 检查IP地址是否在client端记录中 + * + * @param ipAddr IP 地址 + * @return DC_SUCCESS 存在 + * @return DC_ERROR 不存在 + */ +uint32_t HasPeerIpAddr(uint32_t ipAddr); + +/** + * @brief Set the IP address For Idx object + * + * @param idx 对等端索引 + * @param ipAddr IP 地址 + */ +void SetIpAddrByIdx(int32_t idx, uint32_t ipAddr); + +/** + * @brief 检查IP地址是否在server端记录中 + * + * @return DC_SUCCESS 存在 + * @return DC_ERROR 不存在 + */ +uint32_t HasServerIpAddr(void); + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_DATA diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_group_auth.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_group_auth.h new file mode 100755 index 0000000000000000000000000000000000000000..1f0bd38091ae77c602f21733b8caf6ae9f8c7835 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_group_auth.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef DCONN_GROUP_AUTH_H +#define DCONN_GROUP_AUTH_H + +#include + +/** + * @brief 认证设备 + * + * @param idx 对端设备 + * @return uint32_t 错误码 + */ +uint32_t DConnAuthDevice(int32_t idx); + +/** + * @brief 处理 Device Auth 自定义通道传输的数据 + * + * @param requestId Request ID + * @param data 解码后的数据 + * @param dataLen 解码后的数据长度 + * @return uint32_t 错误码 + */ +uint32_t ProcessAuthDeviceData(int64_t requestId, const uint8_t *data, uint32_t dataLen); + +#endif // DCONN_GROUP_AUTH_H \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_group_manager.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_group_manager.h new file mode 100755 index 0000000000000000000000000000000000000000..5fffa41c4bf038206de732e729698d9e45dc1a15 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_group_manager.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef DCONN_GROUP_MANAGER_H +#define DCONN_GROUP_MANAGER_H + +#include + +/** + * @brief 设备认证服务初始化 + * + * @return int32_t 初始化结果 + */ +uint32_t DConnInitDeviceAuthService(void); + +/** + * @brief 服务端创建 设备认证 群组 + * + * @return int32_t 创建结果 + */ +uint32_t CreateDeviceAuthGroup(void); + +/** + * @brief 邀请对端设备加入群组。 + * + * @param idx 对端索引 + * @return uint32_t 错误码 + */ +uint32_t InvitePeerIntoGroup(int32_t idx); + +/** + * @brief 处理 Add Member 自定义通道传输的数据 + * + * @param requestId Request ID + * @param data 解码后的数据 + * @param dataLen 解码后的数据长度 + * @return uint32_t 错误码 + */ +uint32_t ProcessAddMemberData(int64_t requestId, const uint8_t *data, uint32_t dataLen); + +#endif // DCONN_GROUP_MANAGER_H \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_log.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_log.h new file mode 100755 index 0000000000000000000000000000000000000000..73a59cbd25c5c3e168d46506ca5a07a4978318b9 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_log.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_LOG +#define APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_LOG + +#include +#include + +typedef enum { + DCONN_LOG_LEVEL_DEBUG = 0, + DCONN_LOG_LEVEL_INFO, + DCONN_LOG_LEVEL_WARN, + DCONN_LOG_LEVEL_ERROR +} DConnLogLevel; + +#ifdef OHOS_DEBUG +#define DCONN_DEBUG(fmt, ...) (DConnLogPrint(DCONN_LOG_LEVEL_DEBUG, __FUNCTION__, fmt, ##__VA_ARGS__)) +#else +#define DCONN_DEBUG(fmt, ...) +#endif +#define DCONN_INFO(fmt, ...) (DConnLogPrint(DCONN_LOG_LEVEL_INFO, __FUNCTION__, fmt, ##__VA_ARGS__)) +#define DCONN_WARN(fmt, ...) (DConnLogPrint(DCONN_LOG_LEVEL_WARN, __FUNCTION__, fmt, ##__VA_ARGS__)) +#define DCONN_ERROR(fmt, ...) (DConnLogPrint(DCONN_LOG_LEVEL_ERROR, __FUNCTION__, fmt, ##__VA_ARGS__)) + +#define IPV4_ANONYMOUS_PLACEHOLDER PRIu32 ".*.*.%" PRIu32 +#define IPV6_ANONYMOUS_PLACEHOLDER PRIx32 ":*:*:*:*:*:*:%" PRIx32 + +#define IS_IPV4_ADDRESS(ipAddr) (strstr(ipAddr, ":") == NULL && strstr(ipAddr, ".") != NULL) + +void DumpBuf(uint8_t *buf, uint32_t len); +void DConnLogPrint(DConnLogLevel level, const char *funName, const char *fmt, ...); +uint32_t DconnIpTransToInt(const char *ipAddr); + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_LOG diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_msg.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_msg.h new file mode 100755 index 0000000000000000000000000000000000000000..e57f9ac67248847e3f55edc3cad843a3ae5dabe4 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_msg.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_MSG +#define APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_MSG + +#include + +#define DCONN_MAX_MSG_LEN 2048 + +#define DCONN_AUTH_HEADER_LEN 16 +#define DCONN_AUTH_BODY_LEN 2032 // DCONN_MAX_MSG_LEN - DCONN_AUTH_HEADER_LEN +#define DCONN_DEVICE_ID_BODY_LEN 2044 // DCONN_MAX_MSG_LEN - sizeof(DConnMsgCommonHeader) +#define DCONN_MAX_KEY_LEN 32 + +enum DConnMsgType { + DCONN_MSG_TYPE_AUTH = 0, + DCONN_MSG_TYPE_DATA = 1, + DCONN_MSG_TYPE_DEVICE_ID = 2, + DCONN_MSG_TYPE_NOTIFY = 3, +}; + +typedef struct { + uint64_t requestId; // Hichain Request ID +} DConnAuthParam; + +typedef struct { + uint8_t *key; // 密钥 + uint32_t keyLen; // 密钥长度 +} DConnDataParam; + +typedef struct { + const uint8_t *data; + uint32_t dataLen; +} DConnMsgIn; + +typedef struct { + uint8_t *msg; + uint32_t msgLen; +} DConnMsgOut; + +/** + * @brief 编码数据 + * + * @param type 数据类型 DConnMsgType + * @param data 明文数据 + * @param dataLen 明文数据长度 + * @param encParam 编码参数,需要与 type 对应 + * @param msg 编码后的字节流数据,调用者释放 + * @param msgLen 编码后的字节流数据长度 + * @return uint32_t 错误码 + */ +uint32_t DConnEncMsg(uint16_t type, const void *encParam, const DConnMsgIn *in, DConnMsgOut *out); + +/** + * @brief 解码数据 + * + * @param type 数据类型 DConnMsgType + * @param msg 编码后的数据,需要与 type 对应 + * @param decParam 解码参数,需要与 type 对应 + * @param data 明文数据,调用者释放 + * @param dataLen 明文数据长度 + * @return uint32_t 错误码 + */ +uint32_t DConnDecMsg(uint16_t type, void *decParam, const DConnMsgIn *in, DConnMsgOut *out); + +/** + * @brief 从编码的消息中获取消息类型 + * + * @param data 编码的消息 + * @param dataLen 编码的消息长度 + * @param type 消息类型 + * @return uint32_t 错误码 + */ +uint32_t DConnGetMsgType(const uint8_t *data, uint32_t dataLen, uint16_t *type); + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_MSG diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_peer.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_peer.h new file mode 100755 index 0000000000000000000000000000000000000000..a30b2f5f22b2edd7e3bb4096e7734fb0c5cc9b68 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_peer.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_PEER +#define APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_PEER + +#define DCONN_SERVICE_PORT 8888 +#define DCONN_UDID_LEN 64 + +enum PeerAuthStat { + PEER_AUTH_STAT_UNAUTHORIZED = 0b00, + PEER_AUTH_EXPECT_DEVICE_ID = 0b0011, // 等待发送设备 ID + PEER_AUTH_ADD_MEMBER = 0b0001, // 添加设备进群组 + PEER_AUTH_AUTH_DEVICE = 0b0010, // 授权设备 + PEER_AUTH_STAT_AUTHORIZED = 0b0100, // 设备认证完成 + PEER_AUTH_STAT_INVALID = 0b1000, // 无效 +}; + +/** + * @brief 对等端角色 + * + */ +enum PeerRole { + PEER_ROLE_SERVICE = 0, + PEER_ROLE_CLIENT = 1, +}; + +#define PEER_AUTH_STAT_END_MASK 0b1100 // 设备认证结束 + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_PEER diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_send.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_send.h new file mode 100755 index 0000000000000000000000000000000000000000..7775fc316edc92e26bb3af74dd2578622ff39ee2 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_send.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef DCONN_SEND_H +#define DCONN_SEND_H + +#include + +/** + * @brief 将数据发送给对等端 + * + * @param idx 对等端索引 + * @param data 数据 + * @param dataLen 数据长度 + * @return uint32_t 错误码 + */ +uint32_t SendDataToPeer(int32_t idx, uint8_t *data, uint32_t dataLen); + +#endif // DCONN_SEND_H \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_syspara.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_syspara.h new file mode 100755 index 0000000000000000000000000000000000000000..7a385004f5e8b2283075b710143102d2632f4bcb --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_syspara.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + + +#ifndef DCONN_SYSPARA_H +#define DCONN_SYSPARA_H + +#include + +#include "dconn_peer.h" + +typedef struct { + char *deviceId; + char udid[DCONN_UDID_LEN + 1]; +} DConnDeviceUdId; + +uint32_t DConnGetUdid(char *udid); + +uint32_t DConnGetDeviceUdid(DConnDeviceUdId *udid); + +#endif // DCONN_SYSPARA_H \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_thread.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_thread.h new file mode 100755 index 0000000000000000000000000000000000000000..58d5a1718206665be79dad023dbc96273d45e851 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/dconn_thread.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_THREAD +#define APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_THREAD + +#include +#include + +/** + * @brief 套件线程状态。用于正确地结束线程,释放资源 + * + */ +enum DConnThrStat { + THR_STAT_DISABLE = 0, // 去激活态 + THR_STAT_ENABLE, // 激活态 + THR_STAT_EXIT, // 退出态 +}; + +/** + * @brief 使能线程 + * + * @return uint32_t 错误码 + */ +uint32_t EnableTransferThr(void *(*func)(void *)); + +/** + * @brief 检查线程是否为指定状态 + * + * @param stat 指定的线程状态 + * @return true + * @return false + */ +bool IsThreadInStat(uint32_t stat); + +/** + * @brief 设置线程状态 + * + * @param stat 线程状态 + */ +void SetThreadStat(uint32_t stat); + +/** + * @brief 通知线程退出 + * + */ +void ExitTransferThr(void); + +/** + * @brief 等待线程退出 + * + */ +void WaitTransferThrDisabled(void); + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_THREAD diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/product_limits.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/product_limits.h new file mode 100755 index 0000000000000000000000000000000000000000..ac01e9619ff84fbb95d43e96a1e9dec72754e397 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/include/product_limits.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUE_PRODUCT_LIMITS +#define APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUE_PRODUCT_LIMITS + +#define MAX_DEVICES_NUM 100 // 客户端最多允许连接 100 目标设备 +#define SESSION_KEY_LEN 32 // session key 最大长度 +#define HICHAIN_AUTH_TIMEOUT 10 // Hichain 认证超时时间 + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUE_PRODUCT_LIMITS \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_auth.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_auth.c new file mode 100755 index 0000000000000000000000000000000000000000..ca6743837a3376a57727d6e593182f988ed33f13 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_auth.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_auth.h" + +#include +#include +#include +#include +#include +#include + +#include "dconn_auth_impl.h" +#include "dconn_log.h" + +void InitHichainData(DConnHichainData *data) +{ + errno_t err = memset_s(data, sizeof(DConnHichainData), 0, sizeof(DConnHichainData)); + if (err != EOK) { + DCONN_ERROR("InitHichainData failed."); + } +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_auth_defines.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_auth_defines.h new file mode 100755 index 0000000000000000000000000000000000000000..e476ce3f6233dd321b6030481b86962c8666500e --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_auth_defines.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef DCONN_AUTH_DEFINES_H +#define DCONN_AUTH_DEFINES_H + +#define DCONN_AUTH_APPID "dconn_app" +#define DCONN_AUTH_GROUP_NAME "dconn_group" + +#endif // DCONN_AUTH_DEFINES_H \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_auth_impl.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_auth_impl.h new file mode 100755 index 0000000000000000000000000000000000000000..c5fbc8e98a9af8b3783edbd8741d58255c10c0e0 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_auth_impl.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef DCONN_AUTH_IMPL_H +#define DCONN_AUTH_IMPL_H + +#include + +#define HC_GROUP_ID_LEN 64 + +enum HcGroupCreateStat { + HC_GROUP_CREATE_STAT_UNINIT = 0, // 未创建 + HC_GROUP_CREATE_STAT_FAILED = 1, // 创建失败 + HC_GROUP_CREATE_STAT_SUCCEED = 2, // 创建成功 +}; + +/** + * @brief Hichain 认证数据 + * + */ +typedef struct { + char groupId[HC_GROUP_ID_LEN + 1]; + int32_t groupCreateStat; // 群组创建状态 HcGroupCreateStat +} DConnHichainData; + +/** + * @brief 初始化 Hichain 数据 + * + * @param data Hichain 数据 + */ +void InitHichainData(DConnHichainData *data); + +#endif \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_cjson.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_cjson.c new file mode 100755 index 0000000000000000000000000000000000000000..34cdca20aa1196111bce35241fdd7ad63f86e942 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_cjson.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_cjson.h" + +#include +#include + +#include "securec.h" + +#include "dconncaseone_interface.h" + +#define DECIMAL 10 + +const char *DConnGetStringFromCJson(const cJSON *jsonObj, const char *key) +{ + if (jsonObj == NULL || key == NULL) { + return NULL; + } + + cJSON *jsonObjTmp = cJSON_GetObjectItemCaseSensitive(jsonObj, key); + if (jsonObjTmp != NULL && cJSON_IsString(jsonObjTmp)) { + return cJSON_GetStringValue(jsonObjTmp); + } + + return NULL; +} + +static int64_t DConnStringToInt64(const char *cp) +{ + if (cp == NULL) { + return 0; + } + + return strtoll(cp, NULL, DECIMAL); +} + +int32_t DConnGetInt64FromJson(const cJSON *jsonObj, const char *key, int64_t *value) +{ + const char *str = DConnGetStringFromCJson(jsonObj, key); + if (str == NULL) { + return DC_ERR_INVALID_JSON; + } + + *value = DConnStringToInt64(str); + return DC_SUCCESS; +} + +static void DConnCreateJson(cJSON *jsonObj, const char *key, cJSON *tmp) +{ + if (cJSON_ReplaceItemInObjectCaseSensitive(jsonObj, key, tmp) == false) { + cJSON_Delete(tmp); + return; + } +} + +void DConnAddIntToJson(cJSON *jsonObj, const char *key, int value) +{ + if (jsonObj == NULL || key == NULL) { + return; + } + + cJSON *objInJson = cJSON_GetObjectItemCaseSensitive(jsonObj, key); + if (objInJson == NULL) { + if (cJSON_AddNumberToObject(jsonObj, key, value) == NULL) { + return; + } + } else { + cJSON *tmp = cJSON_CreateNumber(value); + if (tmp == NULL) { + return; + } + DConnCreateJson(jsonObj, key, tmp); + } + + return; +} + +void DConnAddInt64StringToJson(cJSON *jsonObj, const char *key, int64_t value) +{ + char buffer[65] = { 0 }; + if (sprintf_s(buffer, sizeof(buffer), "%" PRId64, value) <= 0) { + return; + } + + DConnAddStringToJson(jsonObj, key, buffer); + return; +} + +void DConnAddStringToJson(cJSON *jsonObj, const char *key, const char *value) +{ + if (jsonObj == NULL || key == NULL || value == NULL) { + return; + } + + cJSON *objInJson = cJSON_GetObjectItemCaseSensitive(jsonObj, key); + if (objInJson == NULL) { + if (cJSON_AddStringToObject(jsonObj, key, value) == NULL) { + return; + } + } else { + cJSON *tmp = cJSON_CreateString(value); + if (tmp == NULL) { + return; + } + DConnCreateJson(jsonObj, key, tmp); + } + + return; +} + +void DConnAddBoolToJson(cJSON *jsonObj, const char *key, bool value) +{ + if (jsonObj == NULL || key == NULL) { + return; + } + + cJSON *objInJson = cJSON_GetObjectItemCaseSensitive(jsonObj, key); + if (objInJson == NULL) { + if (cJSON_AddBoolToObject(jsonObj, key, value) == NULL) { + return; + } + } else { + cJSON *tmp = cJSON_CreateBool(value); + if (tmp == NULL) { + return; + } + DConnCreateJson(jsonObj, key, tmp); + } + + return; +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_data.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_data.c new file mode 100755 index 0000000000000000000000000000000000000000..fb93de25912e2b184353715ad1527da50b1cf2b6 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_data.c @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dconn_data.h" +#include "dconn_peer.h" +#include "dconn_log.h" +#include "dconn_data_impl.h" +#include "dconn_server_data.h" +#include "dconn_msg.h" + +#define DCONN_COUNT_THRESHOLD 20 +#define DCONN_SHIFT_32_BITS 32 + +static DConnData *g_dconnData = NULL; +static pthread_mutex_t g_initMutex = PTHREAD_MUTEX_INITIALIZER; // 初始化互斥量,避免并发初始化 +static pthread_mutex_t g_peerDataMutex = PTHREAD_MUTEX_INITIALIZER; +static CallbackParam g_iotSdkCallbackParam; // IOT SDK 回调函数 + +uint32_t InitDConnData(void) +{ + DCONN_DEBUG("Init data begin"); + pthread_mutex_lock(&g_initMutex); + if (g_dconnData != NULL) { + pthread_mutex_unlock(&g_initMutex); + DCONN_DEBUG("Data already inited"); + return DC_SUCCESS; + } + + g_dconnData = (DConnData *)malloc(sizeof(DConnData)); + if (g_dconnData == NULL) { + DCONN_ERROR("Malloc for g_dconnData failed!"); + pthread_mutex_unlock(&g_initMutex); + return DC_ERR_ALLOC_MEMORY; + } + + // 设置初始值 + InitPeerData(g_dconnData->peerDataList); + InitServerData(&g_dconnData->serverData); + InitHichainData(&g_dconnData->hichainData); + + pthread_mutex_unlock(&g_initMutex); + DCONN_DEBUG("init data end"); + return DC_SUCCESS; +} + +void DeInitDconnData(void) +{ + if (g_dconnData == NULL) { + return; + } + + // 释放资源时,需与初始化资源顺序相反 + DeInitServerData(&g_dconnData->serverData); + DeInitPeerData(g_dconnData->peerDataList); + + // 释放全局数据 + free(g_dconnData); + g_dconnData = NULL; +} + +DConnData *GetDConnData(void) +{ + return g_dconnData; +} + +int32_t GetNewPeerDataIdx(uint32_t role) +{ + pthread_mutex_lock(&g_peerDataMutex); + for (uint32_t i = 0; i < MAX_DEVICES_NUM; i++) { + if (g_dconnData->peerDataList[i].stat == PEER_DATA_STAT_USED) { + continue; + } + + // 原则上获取时初始化,释放时不做额外的初始化操作 + errno_t err = memset_s(&g_dconnData->peerDataList[i], sizeof(PeerData), 0, sizeof(PeerData)); + if (err != EOK) { + DCONN_ERROR("memset_s failed."); + pthread_mutex_unlock(&g_peerDataMutex); + return -1; + } + g_dconnData->peerDataList[i].socket = -1; + g_dconnData->peerDataList[i].authStat = PEER_AUTH_STAT_UNAUTHORIZED; + g_dconnData->peerDataList[i].role = role; + g_dconnData->peerDataList[i].authStartTime = time(NULL); + g_dconnData->peerDataList[i].stat = PEER_DATA_STAT_USED; + pthread_mutex_unlock(&g_peerDataMutex); + return i; + } + + pthread_mutex_unlock(&g_peerDataMutex); + return -1; +} + +void ReleasePeerDataIdx(int32_t idx) +{ + pthread_mutex_lock(&g_peerDataMutex); + g_dconnData->peerDataList[idx].stat = PEER_DATA_STAT_UNUSED; + close(g_dconnData->peerDataList[idx].socket); + errno_t err = memset_s(g_dconnData->peerDataList[idx].sessionKey, SESSION_KEY_LEN, 0, SESSION_KEY_LEN); + if (err != EOK) { + DCONN_ERROR("memset_s failed."); + pthread_mutex_unlock(&g_peerDataMutex); + return; + } + DCONN_INFO("Peer data released: %" PRId32, idx); + pthread_mutex_unlock(&g_peerDataMutex); +} + +uint32_t GetPeerRole(int32_t idx) +{ + return g_dconnData->peerDataList[idx].role; +} + +void SetSocketByPeerDataIdx(int32_t idx, int socket) +{ + g_dconnData->peerDataList[idx].socket = socket; +} + +int *GetSocketByPeerDataIdx(int32_t idx) +{ + return &g_dconnData->peerDataList[idx].socket; +} + +int64_t GetRequestIdByPeerDataIdx(int32_t idx) +{ + return g_dconnData->peerDataList[idx].requestId; +} + +void SetAuthStatByPeerDataIdx(int32_t idx, uint32_t sta) +{ + DCONN_DEBUG("Peer idx: %" PRId32 " auth stat changed to: %" PRIu32, idx, sta); + g_dconnData->peerDataList[idx].authStat = sta; +} + +void SetRequestIdByPeerDataIdx(int32_t idx, int64_t requestId) +{ + g_dconnData->peerDataList[idx].requestId = requestId; +} + +uint32_t GetAuthStatByPeerDataIdx(int32_t idx) +{ + return g_dconnData->peerDataList[idx].authStat; +} + +int32_t GetIdxByRequestId(int64_t requestId) +{ + for (uint32_t i = 0; i < MAX_DEVICES_NUM; i++) { + if (g_dconnData->peerDataList[i].stat == PEER_DATA_STAT_UNUSED) { + continue; + } + + if (g_dconnData->peerDataList[i].requestId != requestId) { + continue; + } + + return i; + } + + return -1; +} + +uint32_t GetAuthStatByPeerDataRequestId(int64_t requestId) +{ + for (uint32_t i = 0; i < MAX_DEVICES_NUM; i++) { + if (g_dconnData->peerDataList[i].requestId != requestId) { + continue; + } else { + return i; + } + } + + return -1; +} + +char *GetDeviceIdByPeerIdx(int32_t idx) +{ + if (g_dconnData->peerDataList[idx].stat != PEER_DATA_STAT_USED) { + return NULL; + } + + return g_dconnData->peerDataList[idx].deviceId; +} + +void SetDeviceIdForIdx(int32_t idx, const char *deviceId) +{ + errno_t ret = strcpy_s(g_dconnData->peerDataList[idx].deviceId, DCONN_DEVICE_ID_LEN + 1, deviceId); + if (ret != EOK) { + DCONN_ERROR("strcpy_s failed: %d", ret); + } +} + +const char *GetUdidByPeerIdx(int32_t idx) +{ + if (g_dconnData->peerDataList[idx].stat != PEER_DATA_STAT_USED) { + return NULL; + } + + return g_dconnData->peerDataList[idx].udid; +} + +void SetUdidForIdx(int32_t idx, const char *udid) +{ + errno_t ret = strcpy_s(g_dconnData->peerDataList[idx].udid, DCONN_UDID_LEN + 1, udid); + if (ret != EOK) { + DCONN_ERROR("strcpy_s failed: %d", ret); + } +} + +int32_t GetPeerDataIdxByUdid(const char *udid) +{ + for (uint32_t i = 0; i < MAX_DEVICES_NUM; i++) { + if (g_dconnData->peerDataList[i].stat != PEER_DATA_STAT_USED) { + continue; + } + if (strcmp(g_dconnData->peerDataList[i].udid, udid) != 0) { + continue; + } + + return i; + } + + return -1; +} + +bool GetPeerFdByDeviceId(const char *deviceId, int *fd, bool authorized) +{ + for (uint32_t i = 0; i < MAX_DEVICES_NUM; i++) { + if (strcmp(deviceId, g_dconnData->peerDataList[i].deviceId) != 0) { + continue; + } + + if (g_dconnData->peerDataList[i].stat != PEER_DATA_STAT_USED) { + DCONN_ERROR("invalid peer"); + return false; + } + + if (authorized && g_dconnData->peerDataList[i].authStat != PEER_AUTH_STAT_AUTHORIZED) { + DCONN_ERROR("unauthorized peer"); + return false; + } + + *fd = g_dconnData->peerDataList[i].socket; + return true; + } + + DCONN_ERROR("peer match device ID not found"); + return false; +} + +int GetServerSocket(void) +{ + return g_dconnData->serverData.serverSocket; +} + +void SetServerSocket(int fd) +{ + g_dconnData->serverData.serverSocket = fd; +} + +int *GetServerSocketAddrFamily(void) +{ + return &g_dconnData->serverData.serverAddrFamily; +} + +CallbackParam *GetIotSdkCallback(void) +{ + return &g_iotSdkCallbackParam; +} + +void SetSessionKeyByPeerIdx(int32_t idx, const uint8_t *sessionKey, uint32_t sessionKeyLen) +{ + errno_t err = memcpy_s(g_dconnData->peerDataList[idx].sessionKey, SESSION_KEY_LEN, sessionKey, sessionKeyLen); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + return; + } + g_dconnData->peerDataList[idx].sessionKeyLen = sessionKeyLen; +} + +void GetSessionKeyByPeerIdx(int32_t idx, uint8_t **sessionKey, uint32_t *keyLength) +{ + if (g_dconnData->peerDataList[idx].stat == PEER_DATA_STAT_UNUSED || + g_dconnData->peerDataList[idx].authStat != PEER_AUTH_STAT_AUTHORIZED) { + *keyLength = 0; + return; + } + + *sessionKey = g_dconnData->peerDataList[idx].sessionKey; + *keyLength = g_dconnData->peerDataList[idx].sessionKeyLen; +} + +int32_t GetIdxByDeviceId(const char *deviceId) +{ + for (uint32_t i = 0; i < MAX_DEVICES_NUM; i++) { + if (g_dconnData->peerDataList[i].stat != PEER_DATA_STAT_USED) { + continue; + } + if (strcmp(g_dconnData->peerDataList[i].deviceId, deviceId) != 0) { + continue; + } + + return i; + } + + return -1; +} + +int InitSelectFdSet(fd_set *readSet, fd_set *exceptSet) +{ + int maxFd = -1; + time_t now = time(NULL); + FD_ZERO(readSet); + FD_ZERO(exceptSet); + + for (uint32_t i = 0; i < MAX_DEVICES_NUM; i++) { + if (g_dconnData->peerDataList[i].stat != PEER_DATA_STAT_USED) { + continue; + } + + if ((g_dconnData->peerDataList[i].role == PEER_ROLE_CLIENT) && ( + (g_dconnData->peerDataList[i].authStat == PEER_AUTH_STAT_INVALID) || + ((g_dconnData->peerDataList[i].authStat != PEER_AUTH_STAT_AUTHORIZED) && + (now - g_dconnData->peerDataList[i].authStartTime > HICHAIN_AUTH_TIMEOUT)))) { + // Unlike client, server has no timer to release client peers. + // We should release auth failed or timeout peers here. + DCONN_ERROR("Client peer auth time exceed: %" PRIu32, i); + ReleasePeerDataIdx(i); + continue; + } + + int fd = g_dconnData->peerDataList[i].socket; + if (fd == -1) { + continue; + } + FD_SET(fd, readSet); + FD_SET(fd, exceptSet); + maxFd = (maxFd > fd) ? maxFd : fd; + } + + if (g_dconnData->serverData.serverSocket != -1) { + FD_SET(g_dconnData->serverData.serverSocket, readSet); + FD_SET(g_dconnData->serverData.serverSocket, exceptSet); + maxFd = (maxFd > g_dconnData->serverData.serverSocket) ? maxFd : g_dconnData->serverData.serverSocket; + } + + return maxFd; +} + +void HandleFdSet(const fd_set *fdSet, PeerIdxHandler handler, ServerSocketHandler serverHandler) +{ + if (serverHandler != NULL && g_dconnData->serverData.serverSocket != -1 && + FD_ISSET(g_dconnData->serverData.serverSocket, fdSet)) { + serverHandler(); + } + + for (uint32_t i = 0; i < MAX_DEVICES_NUM; i++) { + if (g_dconnData->peerDataList[i].stat != PEER_DATA_STAT_USED) { + continue; + } + + int fd = g_dconnData->peerDataList[i].socket; + if (fd == -1 || !FD_ISSET(fd, fdSet)) { + continue; + } + + handler(i); + } +} + +uint32_t HasPeerIpAddr(uint32_t ipAddr) +{ + for (uint32_t i = 0; i < MAX_DEVICES_NUM; i++) { + if (g_dconnData->peerDataList[i].stat == PEER_DATA_STAT_UNUSED) { + continue; + } + if (g_dconnData->peerDataList[i].ipAddr == ipAddr) { + return DC_SUCCESS; + } + } + + return DC_ERROR; +} + +void SetIpAddrByIdx(int32_t idx, uint32_t ipAddr) +{ + g_dconnData->peerDataList[idx].ipAddr = ipAddr; +} + +uint32_t HasServerIpAddr(void) +{ + if (g_dconnData->serverData.serverSocket == -1) { + return DC_ERROR; + } + + return DC_SUCCESS; +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_data_impl.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_data_impl.h new file mode 100755 index 0000000000000000000000000000000000000000..2f62d823d66213363d81cde498e5c74b1a6b4989 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_data_impl.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_COMMON_SRC_DCONN_DATA_IMPL +#define APPLICATIONS_APP_DCONNECTCASEONE_COMMON_SRC_DCONN_DATA_IMPL + +#include "dconn_peer_impl.h" +#include "dconn_auth_impl.h" + +typedef struct { + int serverSocket; // 服务器 socket + int serverAddrFamily; // 服务器 socket 绑定的 IP 地址类型 AF_INET/AF_INET6 +} ServerData; + +/** + * @brief 套件根数据结构 + * + */ +typedef struct { + ServerData serverData; // 服务端绑定的 socket 数据 + PeerDataList peerDataList; // 对等端数据 + DConnHichainData hichainData; // hichain 数据 +} DConnData; + +/** + * @brief 获取套件根数据结构 + * + * @return DConnData* 套件跟数据结构指针。使用前务必初始化 + */ +DConnData *GetDConnData(void); + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_COMMON_SRC_DCONN_DATA_IMPL diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_group_auth.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_group_auth.c new file mode 100755 index 0000000000000000000000000000000000000000..1602c67ddbf002c9b52856639748ab1b3fe2c38d --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_group_auth.c @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_group_auth.h" + +#include +#include +#include +#include + +#include "cJSON.h" + +#include "dconn_group_auth.h" +#include "dconn_log.h" +#include "dconn_msg.h" +#include "dconn_peer.h" +#include "dconn_data.h" +#include "dconn_cjson.h" +#include "device_auth.h" +#include "dconn_data_impl.h" +#include "dconn_auth_defines.h" +#include "dconncaseone_interface.h" +#include "dconn_group_common.h" + +static bool OnGaTransmit(int64_t requestId, const uint8_t *data, uint32_t dataLen); +static void OnGaSessionKeyReturned(int64_t requestId, const uint8_t *sessionKey, uint32_t sessionKeyLen); +static void OnGaFinish(int64_t requestId, int operationCode, const char *returnData); +static void OnGaError(int64_t requestId, int operationCode, int errorCode, const char *errorReturn); +static char *OnGaRequest(int64_t authReqId, int authForm, const char *reqParams); + +static const DeviceAuthCallback g_groupAuthCallback = { + .onTransmit = OnGaTransmit, + .onSessionKeyReturned = OnGaSessionKeyReturned, + .onFinish = OnGaFinish, + .onError = OnGaError, + .onRequest = OnGaRequest, +}; + +static bool OnGaTransmit(int64_t requestId, const uint8_t *data, uint32_t dataLen) +{ + DCONN_DEBUG("requestID: %" PRId64 ", datalen: %" PRId32, requestId, dataLen); + return OnCommonTransmit(requestId, data, dataLen); +} + +static void OnGaSessionKeyReturned(int64_t requestId, const uint8_t *sessionKey, uint32_t sessionKeyLen) +{ + int32_t idx = GetIdxByRequestId(requestId); + if (idx < 0) { + DCONN_ERROR("GetIdxByRequestId failed by request ID: %" PRId64, requestId); + return; + } + + SetSessionKeyByPeerIdx(idx, sessionKey, sessionKeyLen); + + uint32_t role = GetPeerRole(idx); + if (role == PEER_ROLE_SERVICE) { + return; + } + + char message[] = DCONN_SESSION_KEY_RETURNED_MESSAGE; + uint32_t ret = SendNotifyMessage(idx, message, sizeof(message)); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Service send session key returned message failed for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + } else { + DCONN_INFO("Service send session key returned message succeed for idx: %" PRId32, idx); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_AUTHORIZED); + } +} + +static void OnGaFinish(int64_t requestId, int operationCode, const char *returnData) +{ + DCONN_DEBUG("Ignored requestID: %" PRId64, requestId); + (void)requestId; + (void)operationCode; + (void)returnData; +} + +static void OnGaError(int64_t requestId, int operationCode, int errorCode, const char *errorReturn) +{ + DCONN_INFO("AuthOnError requestID: %lld, operationCode: %d, errorCode: %d, errorReturn: %s", + requestId, + operationCode, + errorCode, + errorReturn); + + int32_t idx = GetIdxByRequestId(requestId); + if (idx < 0) { + DCONN_INFO("auth error but peer idx not found by request ID: %lld", requestId); + return; + } + + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); +} + +static char *OnGaRequest(int64_t authReqId, int authForm, const char *reqParams) +{ + (void)authForm; + (void)reqParams; + DCONN_DEBUG("authReqId: %lld, authForm: %d, reqParams: %s", authReqId, authForm, reqParams); + int32_t idx = GetIdxByRequestId(authReqId); + if (idx < 0) { + DCONN_ERROR("Cannot find peer by request ID: %" PRId64, authReqId); + return BuildRejectConfirmation(); + } + + const char *udid = GetUdidByPeerIdx(idx); + cJSON *rspJson = cJSON_CreateObject(); + if (rspJson == NULL) { + DCONN_ERROR("Failed to allocate rspJson memory."); + return NULL; + } + DConnAddStringToJson(rspJson, FIELD_SERVICE_PKG_NAME, DCONN_AUTH_APPID); + DConnAddStringToJson(rspJson, FIELD_PEER_CONN_DEVICE_ID, udid); + DConnAddIntToJson(rspJson, FIELD_CONFIRMATION, REQUEST_ACCEPTED); + + char *rspStr = cJSON_PrintUnformatted(rspJson); + if (rspStr == NULL) { + DCONN_ERROR("Failed to pack rspJson to string."); + cJSON_Delete(rspJson); + return NULL; + } + cJSON_Delete(rspJson); + DCONN_DEBUG("Response json: %s", rspStr); + return rspStr; +} + +char *CreateAuthParams(int64_t requestId, const char *peerUdid) +{ + cJSON *addParams = cJSON_CreateObject(); + if (addParams == NULL) { + DCONN_ERROR("Failed to allocate addParams memory."); + return NULL; + } + DConnAddStringToJson(addParams, FIELD_PEER_CONN_DEVICE_ID, peerUdid); + DConnAddInt64StringToJson(addParams, FIELD_PEER_AUTH_ID, requestId); + DConnAddStringToJson(addParams, FIELD_SERVICE_PKG_NAME, DCONN_AUTH_APPID); + DConnAddBoolToJson(addParams, FIELD_IS_CLIENT, true); + char *addParamsStr = cJSON_PrintUnformatted(addParams); + if (addParamsStr == NULL) { + DCONN_ERROR("Failed to pack addParams to string."); + cJSON_Delete(addParams); + return NULL; + } + DCONN_DEBUG("addParams: %s", addParamsStr); + cJSON_Delete(addParams); + return addParamsStr; +} + +uint32_t DConnAuthDevice(int32_t idx) +{ + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_AUTH_DEVICE); + const GroupAuthManager *ga = GetGaInstance(); + if (ga == NULL) { + DCONN_ERROR("GaInstance request failed"); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + return DC_ERR_AUTH_FAILED; + } + + int64_t requestId = GetRequestIdByPeerDataIdx(idx); + const char *peerUdid = GetUdidByPeerIdx(idx); + char *authParams = CreateAuthParams(requestId, peerUdid); + + int32_t ret = ga->authDevice(DEFAULT_OS_ACCOUNT, requestId, authParams, &g_groupAuthCallback); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Auth Device request failed: %" PRId32, ret); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + cJSON_free(authParams); + return DC_ERR_AUTH_FAILED; + } + + cJSON_free(authParams); + return DC_SUCCESS; +} + +uint32_t ProcessAuthDeviceData(int64_t requestId, const uint8_t *data, uint32_t dataLen) +{ + return GetGaInstance()->processData(requestId, data, dataLen, &g_groupAuthCallback); +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_group_common.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_group_common.c new file mode 100755 index 0000000000000000000000000000000000000000..e0135792d3322f2ebe1b30272b3a6bff06c704af --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_group_common.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_group_common.h" + +#include + +#include "cJSON.h" +#include "device_auth.h" + +#include "dconn_log.h" +#include "dconn_msg.h" +#include "dconncaseone_interface.h" +#include "dconn_send.h" +#include "dconn_cjson.h" +#include "dconn_data.h" + +bool OnCommonTransmit(int64_t requestId, const uint8_t *data, uint32_t dataLen) +{ + int32_t idx = GetIdxByRequestId(requestId); + if (idx < 0) { + DCONN_ERROR("will not send hc data: requestId: %" PRId64 ", idx: %" PRId32, requestId, idx); + return false; + } + + DConnAuthParam param = { + .requestId = requestId, + }; + DConnMsgIn in = { + .data = data, + .dataLen = dataLen, + }; + DConnMsgOut out; + uint32_t ret = DConnEncMsg(DCONN_MSG_TYPE_AUTH, ¶m, &in, &out); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Encode failed. Data will not send: %" PRIu32, ret); + return false; + } + + ret = SendDataToPeer(idx, out.msg, out.msgLen); + free(out.msg); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Data trasmit failed: %" PRIu32, ret); + return false; + } + + return true; +} + +char *BuildRejectConfirmation(void) +{ + cJSON *rspJson = cJSON_CreateObject(); + if (rspJson == NULL) { + DCONN_ERROR("Failed to allocate rspJson memory."); + return NULL; + } + DConnAddIntToJson(rspJson, FIELD_CONFIRMATION, REQUEST_REJECTED); + char *rspStr = cJSON_PrintUnformatted(rspJson); + if (rspStr == NULL) { + DCONN_ERROR("Failed to pack rspJson to string."); + cJSON_Delete(rspJson); + return NULL; + } + cJSON_Delete(rspJson); + + return rspStr; +} + +uint32_t SendNotifyMessage(int32_t idx, const char *message, uint32_t messageLen) +{ + DConnMsgIn in = { + .data = (const uint8_t *)message, + .dataLen = messageLen, + }; + DConnMsgOut out; + uint32_t ret = DConnEncMsg(DCONN_MSG_TYPE_NOTIFY, NULL, &in, &out); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Encode notify message failed: %" PRIu32, ret); + return ret; + } + + ret = SendDataToPeer(idx, out.msg, out.msgLen); + free(out.msg); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Send notify message failed: %" PRIu32, ret); + return ret; + } + + return DC_SUCCESS; +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_group_common.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_group_common.h new file mode 100755 index 0000000000000000000000000000000000000000..967077c74909b80a980714c6471cf0567bd58a78 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_group_common.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef DCONN_GROUP_COMMON_H +#define DCONN_GROUP_COMMON_H + +#include +#include + +#define DCONN_SESSION_KEY_RETURNED_MESSAGE "Service at session key returned stat" +#define DCONN_ADD_MEMBER_FINISHED_MESSAGE "Service at add member finished stat" + +bool OnCommonTransmit(int64_t requestId, const uint8_t *data, uint32_t dataLen); +char *BuildRejectConfirmation(void); +uint32_t SendNotifyMessage(int32_t idx, const char *message, uint32_t messageLen); + +#endif // DCONN_GROUP_COMMON_H \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_group_manager.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_group_manager.c new file mode 100755 index 0000000000000000000000000000000000000000..d41553b27eb1dd8d1d8da537e42b896b41af03a1 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_group_manager.c @@ -0,0 +1,529 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_group_manager.h" + +#include +#include +#include +#include +#include + +#include "cJSON.h" + +#include "dconn_group_manager.h" +#include "device_auth.h" +#include "dconn_log.h" +#include "dconn_msg.h" +#include "dconn_data.h" +#include "dconn_peer.h" +#include "dconn_cjson.h" +#include "dconn_data_impl.h" +#include "dconn_auth_impl.h" +#include "dconn_auth_defines.h" +#include "device_auth_defines.h" +#include "dconncaseone_interface.h" +#include "dconn_group_common.h" + +#define DCONN_CREATE_GROUP_REQUEST_ID 256 +#define DCONN_DEVICE_AUTH_P2P_GROUP_TYPE 256 +#define DCONN_WAIT_GROUP_CREATE_THRESHOLD 10 + +static bool OnGmTransmit(int64_t requestId, const uint8_t *data, uint32_t dataLen); +static void OnGmSessionKeyReturned(int64_t requestId, const uint8_t *sessionKey, uint32_t sessionKeyLen); +static void OnGmFinish(int64_t requestId, int operationCode, const char *returnData); +static void OnGmError(int64_t requestId, int operationCode, int errorCode, const char *errorReturn); +static char *OnGmRequest(int64_t requestId, int operationCode, const char *reqParams); + +static const DeviceAuthCallback g_groupManagerCallback = { + .onTransmit = OnGmTransmit, + .onSessionKeyReturned = OnGmSessionKeyReturned, + .onFinish = OnGmFinish, + .onError = OnGmError, + .onRequest = OnGmRequest, +}; + +static bool OnGmTransmit(int64_t requestId, const uint8_t *data, uint32_t dataLen) +{ + DCONN_DEBUG("requestID: %" PRId64 ", datalen: %" PRId32, requestId, dataLen); + return OnCommonTransmit(requestId, data, dataLen); +} + +static void OnGmSessionKeyReturned(int64_t requestId, const uint8_t *sessionKey, uint32_t sessionKeyLen) +{ + DCONN_DEBUG("Ignored requestID: %" PRId64 ", sessionKeyLen: %" PRId32, requestId, sessionKeyLen); + (void)requestId; + (void)sessionKey; + (void)sessionKeyLen; +} + +static void OnGmGroupCreateFinished(const char *returnData) +{ + cJSON *jsonObj = cJSON_Parse(returnData); + if (jsonObj == NULL) { + DCONN_ERROR("Cannot parse json from returnData"); + GetDConnData()->hichainData.groupCreateStat = HC_GROUP_CREATE_STAT_FAILED; + return; + } + + const char *groupId = DConnGetStringFromCJson(jsonObj, "groupId"); + if (groupId == NULL) { + DCONN_ERROR("Cannot get group ID from returnData"); + GetDConnData()->hichainData.groupCreateStat = HC_GROUP_CREATE_STAT_FAILED; + } else { // 保存创建的群组id + errno_t err = strcpy_s(GetDConnData()->hichainData.groupId, HC_GROUP_ID_LEN + 1, groupId); + if (err != EOK) { + DCONN_ERROR("strcpy_s failed."); + GetDConnData()->hichainData.groupCreateStat = HC_GROUP_CREATE_STAT_FAILED; + cJSON_Delete(jsonObj); + return; + } + DCONN_INFO("Group create succeed: %s", groupId); + GetDConnData()->hichainData.groupCreateStat = HC_GROUP_CREATE_STAT_SUCCEED; + } + + cJSON_Delete(jsonObj); +} + +static void OnGmAddMemberFinished(int64_t requestId) +{ + int32_t idx = GetIdxByRequestId(requestId); + if (idx < 0) { + DCONN_ERROR("GetIdxByRequestId failed by request ID: %" PRId64, requestId); + return; + } + + uint32_t role = GetPeerRole(idx); + if (role == PEER_ROLE_SERVICE) { + return; + } + + // Here we are service. + // Service should set auth stat to PEER_AUTH_AUTH_DEVICE. + // Client do that on start auth device. + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_AUTH_DEVICE); + char message[] = DCONN_ADD_MEMBER_FINISHED_MESSAGE; + uint32_t ret = SendNotifyMessage(idx, message, sizeof(message)); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Service send add member finished message failed for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + } + + DCONN_INFO("Service send add member finished message succeed for idx: %" PRId32, idx); +} + +static void OnGmFinish(int64_t requestId, int operationCode, const char *returnData) +{ + (void)operationCode; + (void)returnData; + DCONN_DEBUG("requestId: %" PRId64 ", operationCode: %d, returnData: %s", requestId, operationCode, returnData); + if (requestId == DCONN_CREATE_GROUP_REQUEST_ID) { + OnGmGroupCreateFinished(returnData); + return; + } + + OnGmAddMemberFinished(requestId); + return; +} + +static void OnGmError(int64_t requestId, int operationCode, int errorCode, const char *errorReturn) +{ + (void)operationCode; + (void)errorReturn; + // 设备绑定失败,触发该回调函数 + DCONN_DEBUG("AuthOnError requestID: %" PRId64 ", operationCode: %d, errorCode: %d, errorReturn: %s", + requestId, + operationCode, + errorCode, + errorReturn); + if (requestId == 0) { + DCONN_ERROR("Group create failed: %d", errorCode); + GetDConnData()->hichainData.groupCreateStat = HC_GROUP_CREATE_STAT_FAILED; + return; + } + + int32_t idx = GetIdxByRequestId(requestId); + if (idx < 0) { + DCONN_INFO("auth error but peer idx not found by request ID: %" PRId64, requestId); + return; + } + + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); +} + +typedef struct { + int32_t idx; + char peerDeviceId[DCONN_DEVICE_ID_LEN + 1]; + char localDeviceId[DCONN_DEVICE_ID_LEN + 1]; + char authKey[DCONN_AUTH_KEY_LEN + 1]; +} DConnValidReqParams; + +static uint32_t CheckRequestId(int64_t requestId, DConnValidReqParams *validParam) +{ + int32_t idx = GetIdxByRequestId(requestId); + if (idx < 0) { + DCONN_ERROR("Cannot get peer idx by request ID: %" PRId64, requestId); + return DC_ERR_INVALID_REQUEST_ID; + } + validParam->idx = idx; + + return DC_SUCCESS; +} + +static uint32_t CheckReqParams(const char *reqParams, DConnValidReqParams *validParam) +{ + cJSON *reqJson = cJSON_Parse(reqParams); + if (reqJson == NULL) { + DCONN_ERROR("Cannot create json from reqParams"); + return DC_ERR_INVALID_JSON; + } + + const char *peerDeviceId = DConnGetStringFromCJson(reqJson, "peerDeviceId"); + if (peerDeviceId == NULL || strlen(peerDeviceId) > DCONN_DEVICE_ID_LEN) { + DCONN_ERROR("Peer device ID is invalid."); + cJSON_Delete(reqJson); + return DC_ERR_INVALID_DEVICE_ID; + } + errno_t err = strcpy_s(validParam->peerDeviceId, DCONN_DEVICE_ID_LEN, peerDeviceId); + if (err != EOK) { + DCONN_ERROR("strcpy_s failed."); + cJSON_Delete(reqJson); + return DC_ERROR; + } + + cJSON_Delete(reqJson); + return DC_SUCCESS; +} + +static uint32_t CheckSdkParams(DConnValidReqParams *validParam) +{ + GetDeviceID getDeviceID = GetIotSdkCallback()->getDeviceID; + if (getDeviceID == NULL) { + DCONN_ERROR("Get device ID callback not register."); + return DC_ERR_CB_NOT_REGISTER; + } + const char *localDeviceId = getDeviceID(); + if (localDeviceId == NULL || strlen(localDeviceId) > DCONN_DEVICE_ID_LEN) { + DCONN_ERROR("Local device ID is invalid."); + return DC_ERR_INVALID_DEVICE_ID; + } + errno_t err = strcpy_s(validParam->localDeviceId, DCONN_DEVICE_ID_LEN, localDeviceId); + if (err != EOK) { + DCONN_ERROR("strcpy_s failed."); + return DC_ERROR; + } + + GetAuthKey getAuthKey = GetIotSdkCallback()->getAuthKey; + if (getAuthKey == NULL) { + DCONN_ERROR("Get auth key callback not register."); + return DC_ERR_CB_NOT_REGISTER; + } + const char *pinCode = getAuthKey(validParam->peerDeviceId); + if (pinCode == NULL || strlen(pinCode) > DCONN_AUTH_KEY_LEN) { + DCONN_ERROR("Auth key is invalid."); + return DC_ERR_INVALID_AUTH_KEY; + } + err = strcpy_s(validParam->authKey, DCONN_AUTH_KEY_LEN, pinCode); + if (err != EOK) { + DCONN_ERROR("strcpy_s failed."); + return DC_ERROR; + } + + return DC_SUCCESS; +} + +static uint32_t CheckOnRequestParams(int64_t requestId, const char *reqParams, DConnValidReqParams *validParam) +{ + uint32_t ret = CheckRequestId(requestId, validParam); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Check request ID failed."); + return ret; + } + + ret = CheckReqParams(reqParams, validParam); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Check reqParams failed."); + return ret; + } + + ret = CheckSdkParams(validParam); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Check SDK failed."); + return ret; + } + + return ret; +} + +static char *BuildAcceptedConfirmation(const DConnValidReqParams *validParams) +{ + cJSON *rspJson = cJSON_CreateObject(); + if (rspJson == NULL) { + DCONN_ERROR("Failed to allocate rspJson memory."); + return NULL; + } + DConnAddIntToJson(rspJson, FIELD_CONFIRMATION, REQUEST_ACCEPTED); + DConnAddStringToJson(rspJson, FIELD_PIN_CODE, validParams->authKey); + DConnAddStringToJson(rspJson, FIELD_DEVICE_ID, validParams->localDeviceId); + DConnAddIntToJson(rspJson, FIELD_USER_TYPE, 0); + DConnAddIntToJson(rspJson, FIELD_EXPIRE_TIME, -1); + + char *rspBuffer = cJSON_PrintUnformatted(rspJson); + if (rspBuffer == NULL) { + DCONN_ERROR("Failed to pack rspJson to string."); + cJSON_Delete(rspJson); + return NULL; + } + cJSON_Delete(rspJson); + return rspBuffer; +} + +static char *OnGmRequest(int64_t requestId, int operationCode, const char *reqParams) +{ + (void)operationCode; + DCONN_DEBUG("AuthOnRequest requestId: %" PRId64 ", operationCode: %d, reqParams: %s", requestId, operationCode, + reqParams); + DConnValidReqParams validParams; + uint32_t ret = CheckOnRequestParams(requestId, reqParams, &validParams); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Check on request params failed: %" PRIu32, ret); + return BuildRejectConfirmation(); + } + + // 下发相关信息 + DCONN_INFO("AuthOnRequest of DeviceId: %s", validParams.peerDeviceId); + SetDeviceIdForIdx(validParams.idx, validParams.peerDeviceId); + + return BuildAcceptedConfirmation(&validParams); +} + +uint32_t DConnInitDeviceAuthService(void) +{ + static bool hichainInited = false; + if (hichainInited) { + DCONN_DEBUG("Hichain already initialized."); + return DC_SUCCESS; + } + + // 设置设备认证服务 + int32_t ret = InitDeviceAuthService(); + if (ret != HC_SUCCESS) { + DCONN_ERROR("init hc service failed: %d", ret); + return DC_ERR_AUTH_INIT_FAILED; + } + + // 初始化 gm 实例 + if (GetGmInstance() == NULL) { + DCONN_ERROR("GetGmInstance failed"); + return DC_ERR_AUTH_INIT_FAILED; + } + + // 设置回调函数 + int32_t result = GetGmInstance()->regCallback(DCONN_AUTH_APPID, &g_groupManagerCallback); + if (result != HC_SUCCESS) { + DCONN_ERROR("gm regCallback failed: %" PRIu32, result); + return DC_ERR_REG_HICHAIN_CB; + } + + hichainInited = true; + return DC_SUCCESS; +} + + +static bool IsGmGroupExist(void) +{ + cJSON *queryParams = cJSON_CreateObject(); + if (queryParams == NULL) { + DCONN_ERROR("Failed to allocate queryParams memory."); + return false; + } + DConnAddStringToJson(queryParams, FIELD_GROUP_NAME, DCONN_AUTH_GROUP_NAME); + char *queryParamsStr = cJSON_PrintUnformatted(queryParams); + if (queryParamsStr == NULL) { + DCONN_ERROR("Failed to pack queryParams to string."); + cJSON_Delete(queryParams); + return false; + } + + uint32_t groupNum = 0; + char *returnGroupVec = NULL; + GetGmInstance()->getGroupInfo(DEFAULT_OS_ACCOUNT, DCONN_AUTH_APPID, queryParamsStr, &returnGroupVec, &groupNum); + + cJSON_Delete(queryParams); + cJSON_free(queryParamsStr); + if (groupNum == 0) { + DCONN_INFO("group not exist"); + cJSON_free(returnGroupVec); + return false; + } + + DCONN_INFO("group info: groupNum: %" PRId32 ", returnGroupVec: %s", groupNum, returnGroupVec); + cJSON *groupVecJson = cJSON_Parse(returnGroupVec); + if (groupVecJson == NULL) { + DCONN_ERROR("Cannot parse json from returnGroupVec."); + cJSON_free(returnGroupVec); + return false; + } + cJSON *groupVecJson0 = cJSON_GetArrayItem(groupVecJson, 0); + if (groupVecJson0 == NULL) { + DCONN_ERROR("Failed to get groupInfo."); + cJSON_Delete(groupVecJson); + cJSON_free(returnGroupVec); + return false; + } + const char *groupId = DConnGetStringFromCJson(groupVecJson0, "groupId"); + if (strcpy_s(GetDConnData()->hichainData.groupId, HC_GROUP_ID_LEN + 1, groupId) != EOK) { + DCONN_ERROR("strcpy_s failed."); + cJSON_Delete(groupVecJson); + cJSON_free(returnGroupVec); + return false; + } + GetDConnData()->hichainData.groupCreateStat = HC_GROUP_CREATE_STAT_SUCCEED; + + cJSON_Delete(groupVecJson); + cJSON_free(returnGroupVec); + return true; +} + +int32_t CreateGmGroup(void) +{ + GetDeviceID getDeviceID = GetIotSdkCallback()->getDeviceID; + if (getDeviceID == NULL) { + DCONN_ERROR("Get device ID callback not register."); + return DC_ERR_CB_NOT_REGISTER; + } + const char *localDeviceId = getDeviceID(); + if (localDeviceId == NULL || strlen(localDeviceId) > DCONN_DEVICE_ID_LEN) { + DCONN_INFO("Invalid device ID from IOT SDK."); + return DC_ERR_INVALID_DEVICE_ID; + } + + DCONN_INFO("Get device ID from IOT SDK: %s", localDeviceId); + cJSON *createParam = cJSON_CreateObject(); + if (createParam == NULL) { + DCONN_ERROR("Failed to allocate createParam memory."); + return DC_ERR_ALLOC_MEMORY; + } + DConnAddIntToJson(createParam, FIELD_GROUP_TYPE, DCONN_DEVICE_AUTH_P2P_GROUP_TYPE); + DConnAddStringToJson(createParam, FIELD_DEVICE_ID, localDeviceId); + DConnAddStringToJson(createParam, FIELD_GROUP_NAME, DCONN_AUTH_GROUP_NAME); + DConnAddIntToJson(createParam, FIELD_USER_TYPE, 0); + DConnAddIntToJson(createParam, FIELD_GROUP_VISIBILITY, -1); + DConnAddIntToJson(createParam, FIELD_EXPIRE_TIME, -1); + + char *createParamStr = cJSON_PrintUnformatted(createParam); + if (createParamStr == NULL) { + DCONN_ERROR("Failed to pack createParam to string."); + cJSON_Delete(createParam); + return DC_ERR_INVALID_JSON; + } + int32_t result = GetGmInstance()->createGroup(DEFAULT_OS_ACCOUNT, + DCONN_CREATE_GROUP_REQUEST_ID, DCONN_AUTH_APPID, createParamStr); + cJSON_Delete(createParam); + cJSON_free(createParamStr); + + return result; +} + +uint32_t CreateDeviceAuthGroup(void) +{ + if (GetDConnData()->hichainData.groupCreateStat == HC_GROUP_CREATE_STAT_SUCCEED) { + DCONN_INFO("Hichain group already created in this session"); + return DC_SUCCESS; + } + + if (IsGmGroupExist()) { + // Hichain 有数据库能力,设备再启动时之前创建的群组仍然存在 + DCONN_INFO("Hichain group already exists."); + return DC_SUCCESS; + } + + int32_t result = CreateGmGroup(); + if (result != HC_SUCCESS) { + DCONN_ERROR("create group request failed: %" PRId32, result); + return DC_ERR_CREATE_GROUP; + } + + // 等待群组创建成功回调 + uint32_t count = 0; + while (count < DCONN_WAIT_GROUP_CREATE_THRESHOLD && + GetDConnData()->hichainData.groupCreateStat == HC_GROUP_CREATE_STAT_UNINIT) { + DCONN_DEBUG("waiting for hc create group: %" PRId32, GetDConnData()->hichainData.groupCreateStat); + sleep(1); + count++; + } + + if (GetDConnData()->hichainData.groupCreateStat != HC_GROUP_CREATE_STAT_SUCCEED) { + DCONN_ERROR("create hc group callback failed. count = %" PRIu32, count); + return DC_ERR_CREATE_GROUP; + } + + DCONN_DEBUG("Hichain group create finished: %" PRId32, GetDConnData()->hichainData.groupCreateStat); + return DC_SUCCESS; +} + +uint32_t InvitePeerIntoGroup(int32_t idx) +{ + GetAuthKey getAuthKey = GetIotSdkCallback()->getAuthKey; + if (getAuthKey == NULL) { + DCONN_ERROR("Get auth key callback not register."); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + return DC_ERR_CB_NOT_REGISTER; + } + const char *pinCode = getAuthKey(GetDeviceIdByPeerIdx(idx)); + if (pinCode == NULL || strlen(pinCode) > DCONN_AUTH_KEY_LEN) { + DCONN_ERROR("Invalid auth key."); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + return DC_ERR_INVALID_AUTH_KEY; + } + + // 1. 构造参数 + cJSON *addParams = cJSON_CreateObject(); + if (addParams == NULL) { + DCONN_ERROR("Failed to allocate addParams memory."); + return DC_ERR_ALLOC_MEMORY; + } + DConnAddStringToJson(addParams, FIELD_GROUP_ID, GetDConnData()->hichainData.groupId); + DConnAddIntToJson(addParams, FIELD_GROUP_TYPE, DCONN_DEVICE_AUTH_P2P_GROUP_TYPE); // 点对点群组类型 + DConnAddStringToJson(addParams, FIELD_PIN_CODE, pinCode); + DConnAddBoolToJson(addParams, FIELD_IS_ADMIN, true); + char *addParamsStr = cJSON_PrintUnformatted(addParams); + if (addParamsStr == NULL) { + DCONN_ERROR("Failed to pack addParams to string."); + cJSON_Delete(addParams); + return DC_ERR_INVALID_JSON; + } + + // 2. 异步邀请加入 + int32_t ret = GetGmInstance()->addMemberToGroup( + DEFAULT_OS_ACCOUNT, GetRequestIdByPeerDataIdx(idx), DCONN_AUTH_APPID, addParamsStr); + + // 3. 返回结果,释放资源 + cJSON_Delete(addParams); + cJSON_free(addParamsStr); + if (ret != HC_SUCCESS) { + DCONN_INFO("Invite peer [%" PRId32 "] to group failed: %" PRId32, idx, ret); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + return DC_ERR_ADD_MEMBER; + } + + DCONN_INFO("addMemberToGroup sucess"); + return DC_SUCCESS; +} + +uint32_t ProcessAddMemberData(int64_t requestId, const uint8_t *data, uint32_t dataLen) +{ + return GetGmInstance()->processData(requestId, data, dataLen); +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_handler.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_handler.c new file mode 100755 index 0000000000000000000000000000000000000000..77ac2c26cacfe471a2057611a5717f980c68552e --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_handler.c @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_handler.h" + +#include +#include +#include +#include +#include +#include + +#include "cJSON.h" + +#include "dconn_data.h" +#include "dconn_peer.h" +#include "dconn_log.h" +#include "dconn_mbedtls_gcm.h" +#include "dconn_send.h" +#include "dconn_msg.h" +#include "dconn_group_manager.h" +#include "dconn_cjson.h" +#include "dconn_syspara.h" +#include "dconn_group_auth.h" +#include "dconn_group_common.h" + +static uint32_t SavePeerDeviceId(int32_t idx, const uint8_t *data, uint32_t dataLen, bool shoudSaveRequestId) +{ + DConnMsgIn in = { + .data = data, + .dataLen = dataLen, + }; + DConnMsgOut out; + uint32_t ret = DConnDecMsg(DCONN_MSG_TYPE_DEVICE_ID, NULL, &in, &out); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Cannot decode device ID message for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + return ret; + } + + cJSON *payload = cJSON_Parse((const char *)out.msg); + free(out.msg); + if (payload == NULL) { + DCONN_ERROR("Cannot parse device ID message for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + cJSON_Delete(payload); + return ret; + } + + const char *deviceId = DConnGetStringFromCJson(payload, "deviceId"); + if (deviceId == NULL) { + DCONN_ERROR("Cannot get device ID from message for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + cJSON_Delete(payload); + return ret; + } + SetDeviceIdForIdx(idx, deviceId); + + const char *udid = DConnGetStringFromCJson(payload, "udid"); + if (udid == NULL) { + DCONN_ERROR("Cannot get UDID from message for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + cJSON_Delete(payload); + return ret; + } + SetUdidForIdx(idx, udid); + + if (shoudSaveRequestId) { + int64_t requestId; + int32_t result = DConnGetInt64FromJson(payload, "requestId", &requestId); + if (result != DC_SUCCESS) { + DCONN_ERROR("Cannot get request ID from message for idx: %" PRId32 " ret: %" PRId32, idx, result); + cJSON_Delete(payload); + return result; + } + + SetRequestIdByPeerDataIdx(idx, requestId); + } + + cJSON_Delete(payload); + return DC_SUCCESS; +} + +static uint32_t BuildServiceDeviceIdPayload(int32_t idx, char **payload) +{ + DConnDeviceUdId deviceUdId; + uint32_t ret = DConnGetDeviceUdid(&deviceUdId); + if (ret != 0) { + DCONN_ERROR("Cannot get dev udid: %" PRIu32, ret); + return ret; + } + + int64_t requestId; + ret = DConnGenerateRandom((uint8_t *)&requestId, sizeof(int64_t)); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Cannot generate request ID for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + return ret; + } + + cJSON *payloadJson = cJSON_CreateObject(); + if (payloadJson == NULL) { + DCONN_ERROR("Failed to allocate payloadJson memory."); + return DC_ERR_ALLOC_MEMORY; + } + SetRequestIdByPeerDataIdx(idx, requestId); + DConnAddStringToJson(payloadJson, "deviceId", deviceUdId.deviceId); + DConnAddStringToJson(payloadJson, "udid", deviceUdId.udid); + DConnAddInt64StringToJson(payloadJson, "requestId", requestId); + *payload = cJSON_PrintUnformatted(payloadJson); + if (*payload == NULL) { + DCONN_ERROR("Failed to pack payloadJson to string."); + cJSON_Delete(payloadJson); + return DC_ERR_INVALID_JSON; + } + cJSON_Delete(payloadJson); + DCONN_DEBUG("Service send device ID to client payload."); + return DC_SUCCESS; +} + +static uint32_t DoSendDeviceIdWithRequestIdToPeer(int32_t idx, char *payload) +{ + DConnMsgIn in = { + .data = (const uint8_t *)payload, + .dataLen = strlen(payload) + 1, + }; + DConnMsgOut out; + uint32_t ret = DConnEncMsg(DCONN_MSG_TYPE_DEVICE_ID, NULL, &in, &out); + cJSON_free(payload); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Cannot encode device ID message for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + return ret; + } + + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_ADD_MEMBER); + ret = SendDataToPeer(idx, out.msg, out.msgLen); + free(out.msg); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Cannot send device ID message for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + return ret; + } + + return DC_SUCCESS; +} + +static uint32_t SendDeviceIdWithRequestIdToPeer(int32_t idx) +{ + char *payload; + uint32_t ret = BuildServiceDeviceIdPayload(idx, &payload); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Build service device ID param failed for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + return ret; + } + + return DoSendDeviceIdWithRequestIdToPeer(idx, payload); +} + +static uint32_t ServiceOnDeviceIdReceived(int32_t idx, const uint8_t *data, uint32_t dataLen) +{ + uint32_t ret = SavePeerDeviceId(idx, data, dataLen, false); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Save device ID failed for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + return ret; + } + + ret = SendDeviceIdWithRequestIdToPeer(idx); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Send device ID to peer failed for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + return ret; + } + + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_ADD_MEMBER); + return DC_SUCCESS; +} + +static uint32_t ClientOnDeviceIdReceived(int32_t idx, const uint8_t *data, uint32_t dataLen) +{ + uint32_t ret = SavePeerDeviceId(idx, data, dataLen, true); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Save device ID failed for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + return ret; + } + + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_ADD_MEMBER); + ret = InvitePeerIntoGroup(idx); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Invite member to group failed for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + return ret; + } + + return DC_SUCCESS; +} + +uint32_t DConnOnDeviceIdReceived(int32_t idx, const uint8_t *data, uint32_t dataLen) +{ + // Peer is client, thus local is service. Otherwise. + return GetPeerRole(idx) == PEER_ROLE_CLIENT ? ServiceOnDeviceIdReceived(idx, data, dataLen) + : ClientOnDeviceIdReceived(idx, data, dataLen); +} + +static uint32_t AcceptPeerSocket(int *peerSocket, uint32_t *addr) +{ + // 接受传入的连接 + DCONN_DEBUG("waiting for connection"); + struct sockaddr_in peerAddr; + socklen_t peerSocketLen = sizeof(peerAddr); + + *peerSocket = accept(GetServerSocket(), (struct sockaddr *)&peerAddr, &peerSocketLen); + if (*peerSocket < 0) { + DCONN_ERROR("Accepted an invalid peer: %d", *peerSocket); + return DC_ERR_CONNECTION_REFUSED; + } + + *addr = peerAddr.sin_addr.s_addr; + return DC_SUCCESS; +} + +static uint32_t CheckAddressValid(uint32_t addr) +{ + struct in_addr inAddr = { + .s_addr = addr, + }; + const char *addrStr = inet_ntoa(inAddr); + if (addrStr == NULL) { + DCONN_ERROR("Cannot parse the client address."); + return DC_ERR_CONNECTION_REFUSED; + } + + IsValidIP isValidIp = GetIotSdkCallback()->isValidIP; + if (isValidIp == NULL) { + DCONN_ERROR("IsValidIP callback not registered."); + return DC_ERR_CB_NOT_REGISTER; + } + + uint32_t ipValue = DconnIpTransToInt(addrStr); + unsigned char *ipAddress = (unsigned char *)&ipValue; + if (!isValidIp(addrStr)) { + DCONN_ERROR("Invalid address: %" IPV4_ANONYMOUS_PLACEHOLDER, ipAddress[3], ipAddress[0]); + return DC_ERR_CONNECTION_REFUSED; + } + + DCONN_INFO("Client connection accepted: %" IPV4_ANONYMOUS_PLACEHOLDER, ipAddress[3], ipAddress[0]); + return DC_SUCCESS; +} + +void DConnHandleClientAccess(void) +{ + int peerSocket; + uint32_t peerAddr; + uint32_t ret = AcceptPeerSocket(&peerSocket, &peerAddr); + if (ret != DC_SUCCESS) { + return; + } + + ret = CheckAddressValid(peerAddr); + if (ret != DC_SUCCESS) { + close(peerSocket); + DCONN_ERROR("Check address failed: %" PRIu32, ret); + return; + } + + int32_t idx = GetNewPeerDataIdx(PEER_ROLE_CLIENT); + if (idx < 0) { + DCONN_ERROR("Max peer num exceed. Client access refused."); + close(peerSocket); + return; + } + + SetSocketByPeerDataIdx(idx, peerSocket); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_EXPECT_DEVICE_ID); + return; +} + + +uint32_t DConnOnGmTransmitReceived(int32_t idx, const uint8_t *data, uint32_t dataLen) +{ + DConnMsgIn in = { + .data = data, + .dataLen = dataLen, + }; + DConnAuthParam param; + DConnMsgOut out; + uint32_t ret = DConnDecMsg(DCONN_MSG_TYPE_AUTH, ¶m, &in, &out); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Decode auth message for idx: %" PRId32 " failed: %" PRIu32, idx, ret); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + return ret; + } + + ret = ProcessAddMemberData(param.requestId, out.msg, out.msgLen); + free(out.msg); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Process device auth data for idx: %" PRId32 " failed: %" PRIu32, idx, ret); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + return ret; + } + + return DC_SUCCESS; +} + +uint32_t DConnOnGaTransmitReceived(int32_t idx, const uint8_t *data, uint32_t dataLen) +{ + DConnMsgIn in = { + .data = data, + .dataLen = dataLen, + }; + DConnMsgOut out; + DConnAuthParam param; + uint32_t ret = DConnDecMsg(DCONN_MSG_TYPE_AUTH, ¶m, &in, &out); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Decode auth message for idx: %" PRId32 " failed: %" PRIu32, idx, ret); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + return ret; + } + + ret = ProcessAuthDeviceData(param.requestId, out.msg, out.msgLen); + free(out.msg); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Process device auth data for idx: %" PRId32 " failed: %" PRIu32, idx, ret); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + return ret; + } + + return DC_SUCCESS; +} + +uint32_t DConnOnBizDataReceived(int32_t idx, const uint8_t *data, uint32_t dataLen) +{ + uint8_t *sessionKey; + uint32_t keyLength; + GetSessionKeyByPeerIdx(idx, &sessionKey, &keyLength); + if (keyLength == 0) { + DCONN_ERROR("Cannot find session key for idx %" PRId32, idx); + return DC_ERR_DEVICE_NOT_AUTHORIZED; + } + + const char *deviceId = GetDeviceIdByPeerIdx(idx); + if (deviceId == NULL) { + DCONN_ERROR("Cannot find device ID for idx %" PRId32, idx); + return DC_ERR_DEVICE_NOT_AUTHORIZED; + } + + DConnMsgIn in = { + .data = data, + .dataLen = dataLen, + }; + DConnDataParam param = { + .key = sessionKey, + .keyLen = keyLength, + }; + DConnMsgOut out; + uint32_t ret = DConnDecMsg(DCONN_MSG_TYPE_DATA, ¶m, &in, &out); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Cannot decode data for idx: %" PRId32 " , ret: %" PRIu32, idx, ret); + return ret; + } + + ReceiveDataCallback callback = GetIotSdkCallback()->onReceiveDataCb; + if (callback == NULL) { + DCONN_ERROR("On receive data callback not registered."); + return DC_ERR_CB_NOT_REGISTER; + } + + DCONN_DEBUG("Before call on receive data callback."); + callback(deviceId, (const char *)out.msg, out.msgLen); + DCONN_DEBUG("After call on receive data callback."); + free(out.msg); + return DC_SUCCESS; +} + +uint32_t DConnOnNotifyMessageReceived(int32_t idx, const uint8_t *data, uint32_t dataLen) +{ + (void)dataLen; + DConnMsgIn in = { + .data = data, + .dataLen = dataLen, + }; + DConnMsgOut out; + uint32_t ret = DConnDecMsg(DCONN_MSG_TYPE_NOTIFY, NULL, &in, &out); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Cannot decode notify message for idx: %" PRId32 " ret: %" PRIu32, idx, ret); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + return ret; + } + + if (strncmp((const char*)out.msg, DCONN_SESSION_KEY_RETURNED_MESSAGE, + sizeof(DCONN_SESSION_KEY_RETURNED_MESSAGE)) == 0) { + if (GetAuthStatByPeerDataIdx(idx) == PEER_AUTH_AUTH_DEVICE) { + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_AUTHORIZED); + free(out.msg); + return DC_SUCCESS; + } + } + + if (strncmp((const char*)out.msg, DCONN_ADD_MEMBER_FINISHED_MESSAGE, + sizeof(DCONN_ADD_MEMBER_FINISHED_MESSAGE)) == 0) { + if (GetAuthStatByPeerDataIdx(idx) == PEER_AUTH_ADD_MEMBER) { + DConnAuthDevice(idx); + free(out.msg); + return DC_SUCCESS; + } + } + + free(out.msg); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + return DC_ERR_INVALID_NOTIFY_MESSAGE; +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_handler.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_handler.h new file mode 100755 index 0000000000000000000000000000000000000000..09b56e58b9ea028e30fbe8d52c833820fd40224a --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_handler.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef DCONN_HANDLER_H +#define DCONN_HANDLER_H + +#include + +/** + * @brief 处理接收到 Device ID 时的消息 + * + * @param idx 对等端索引。一定不是 -1 + * @param data 收到的数据。一定不是空指针 + * @param dataLen 收到的数据长度 + * @return uint32_t 错误码 + */ +uint32_t DConnOnDeviceIdReceived(int32_t idx, const uint8_t *data, uint32_t dataLen); + +/** + * @brief 处理对等端接入 + * + */ +void DConnHandleClientAccess(void); + +/** + * @brief 处理收到设备绑定过程,Group Manager自定义通道收到的消息 + * + * @param idx 对等端索引。一定不是 -1 + * @param data 收到的数据。一定不是空指针 + * @param dataLen 收到的数据长度 + * @return uint32_t 错误码 + */ +uint32_t DConnOnGmTransmitReceived(int32_t idx, const uint8_t *data, uint32_t dataLen); + +/** + * @brief 处理收到设备绑定过程,Group Auth自定义通道收到的消息 + * + * @param idx 对等端索引。一定不是 -1 + * @param data 收到的数据。一定不是空指针 + * @param dataLen 收到的数据长度 + * @return uint32_t 错误码 + */ +uint32_t DConnOnGaTransmitReceived(int32_t idx, const uint8_t *data, uint32_t dataLen); + +/** + * @brief 处理收到的业务数据 + * + * @param idx 对等端索引。一定不是 -1 + * @param data 收到的数据。一定不是空指针 + * @param dataLen 收到的数据长度 + * @return uint32_t 错误码 + */ +uint32_t DConnOnBizDataReceived(int32_t idx, const uint8_t *data, uint32_t dataLen); + +/** + * @brief 处理接收到通知消息 + * + * @param idx 对等端索引。一定不是 -1 + * @param data 收到的数据。一定不是空指针 + * @param dataLen 收到的数据长度 + * @return uint32_t 错误码 + */ +uint32_t DConnOnNotifyMessageReceived(int32_t idx, const uint8_t *data, uint32_t dataLen); + +#endif // DCONN_HANDLER_H \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_log.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_log.c new file mode 100755 index 0000000000000000000000000000000000000000..3cb5cab95ac27a996386530478f4654b1d311e99 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_log.c @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_log.h" + +#include +#include "securec.h" +#ifdef __LITEOS__ +#include "log.h" +#else +#include "hilog/log.h" +#endif + +#define HEXDECIMAL 16 +#define LOG_PRINT_MAX_LEN 1024 + +#ifdef __LITEOS__ +#define DCONN_HILOG_TYPE HILOG_MODULE_APP +#else +#define DCONN_HILOG_TYPE LOG_APP +#endif + +void DumpBuf(uint8_t *buf, uint32_t len) +{ +#ifdef OHOS_DEBUG + uint32_t i; + printf("buf:"); + for (i = 0; i < len; i++) { + printf("%s%02X%s", i % HEXDECIMAL == 0 ? "\r\n\t" : " ", buf[i], i == len - 1 ? "\r\n" : ""); + } +#else + (void)buf; + (void)len; +#endif +} + +#define DCONN_LOG_DEBUG(buf) HiLogPrint(LOG_CORE, LOG_DEBUG, LOG_DOMAIN, "[DCONN]", "%{public}s", buf) +#define DCONN_LOG_INFO(buf) HiLogPrint(LOG_CORE, LOG_INFO, LOG_DOMAIN, "[DCONN]", "%{public}s", buf) +#define DCONN_LOG_WARN(buf) HiLogPrint(LOG_CORE, LOG_WARN, LOG_DOMAIN, "[DCONN]", "%{public}s", buf) +#define DCONN_LOG_ERROR(buf) HiLogPrint(LOG_CORE, LOG_ERROR, LOG_DOMAIN, "[DCONN]", "%{public}s", buf) + +static void DConnOutPrint(const char *buf, DConnLogLevel level) +{ +#ifdef OHOS_DEBUG + switch (level) { + case DCONN_LOG_LEVEL_DEBUG: + printf("[D][DCONN]: %s\n", buf); + break; + case DCONN_LOG_LEVEL_INFO: + printf("[I][DCONN]: %s\n", buf); + break; + case DCONN_LOG_LEVEL_WARN: + printf("[W][DCONN]: %s\n", buf); + break; + case DCONN_LOG_LEVEL_ERROR: + printf("[E][DCONN]: %s\n", buf); + break; + default: + break; + } + return; +#else + switch (level) { + case DCONN_LOG_LEVEL_DEBUG: + DCONN_LOG_DEBUG(buf); + break; + case DCONN_LOG_LEVEL_INFO: + DCONN_LOG_INFO(buf); + break; + case DCONN_LOG_LEVEL_WARN: + DCONN_LOG_WARN(buf); + break; + case DCONN_LOG_LEVEL_ERROR: + DCONN_LOG_ERROR(buf); + break; + default: + break; + } +#endif +} + +void DConnLogPrint(DConnLogLevel level, const char *funName, const char *fmt, ...) +{ + size_t ulPos = 0; + char *outStr = malloc(LOG_PRINT_MAX_LEN); + if (outStr == NULL) { + return; + } + int32_t ret = sprintf_s(outStr, LOG_PRINT_MAX_LEN, "%s: ", funName); + if (ret < 0) { + free(outStr); + return; + } + ulPos = strlen(outStr); + va_list arg; + va_start(arg, fmt); + ret = vsprintf_s(&outStr[ulPos], LOG_PRINT_MAX_LEN - ulPos, fmt, arg); + va_end(arg); + if (ret < 0) { + free(outStr); + return; + } + DConnOutPrint(outStr, level); + free(outStr); +} + +uint32_t DconnIpTransToInt(const char *ipAddr) +{ + if (ipAddr == NULL || strstr(ipAddr, ".") == NULL) { + printf("Invalid IP address, convert to int failed.\n"); + return 0; + } + uint32_t ipValue = inet_addr(ipAddr); + return ntohl(ipValue); +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_mbedtls_gcm.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_mbedtls_gcm.c new file mode 100755 index 0000000000000000000000000000000000000000..bca4aee78ca4e6c38f1138b528e2fd44741e658d --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_mbedtls_gcm.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_mbedtls_gcm.h" + +#include + +#include "mbedtls/gcm.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" + +#include "dconn_log.h" +#include "dconncaseone_interface.h" + +#define BITS_IN_BYTE 8 +#define DCONN_GEN_RANDOM_THRESHOLD 200 + +static const uint8_t DCONN_RAMDOM_SEED_CUSTOM[] = {'D', 'C', 'O', 'N', 'N'}; + +static uint32_t DConnCtrDrbgSeed(mbedtls_ctr_drbg_context *ctrDrbg, mbedtls_entropy_context *entropy) +{ + mbedtls_ctr_drbg_init(ctrDrbg); + mbedtls_entropy_init(entropy); + + int ret = mbedtls_ctr_drbg_seed(ctrDrbg, mbedtls_entropy_func, + entropy, DCONN_RAMDOM_SEED_CUSTOM, sizeof(DCONN_RAMDOM_SEED_CUSTOM)); + if (ret != 0) { + DCONN_ERROR("Ctr drbg seed failed! mbedtls ret = %d", ret); + mbedtls_ctr_drbg_free(ctrDrbg); + mbedtls_entropy_free(entropy); + return DC_ERR_MBEDTLS_SEED; + } + + return DC_SUCCESS; +} + +uint32_t DConnGenerateRandom(uint8_t *random, uint32_t len) +{ + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctrDrbg; + uint32_t ret = DConnCtrDrbgSeed(&ctrDrbg, &entropy); + if (ret != DC_SUCCESS) { + return ret; + } + + uint32_t count = 0; + int result = 0; + do { + result = mbedtls_ctr_drbg_random(&ctrDrbg, random, len); + if (result != 0) { + DCONN_ERROR("Mbedtls random failed! mbedtls ret = %d", result); + errno_t err = memset_s(random, len, 0, len); + if (err != EOK) { + DCONN_ERROR("memset_s failed."); + } + count++; + } + } while (result != 0 && count < DCONN_GEN_RANDOM_THRESHOLD); + + if (count >= DCONN_GEN_RANDOM_THRESHOLD) { + DCONN_ERROR("Mbedtls random failed count exceed: %" PRIu32, count); + mbedtls_ctr_drbg_free(&ctrDrbg); + mbedtls_entropy_free(&entropy); + return DC_ERR_MBEDTLS_GEN_RANDOM; + } + + mbedtls_ctr_drbg_free(&ctrDrbg); + mbedtls_entropy_free(&entropy); + return DC_SUCCESS; +} + +uint32_t DConnEncrypt(const DConnGcmAlgIn *in, uint8_t* cryptedText, uint8_t *tag) +{ + mbedtls_gcm_context ctx; + mbedtls_gcm_init(&ctx); + + int ret = mbedtls_gcm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, in->key, in->keyLen * BITS_IN_BYTE); + if (ret != 0) { + DCONN_ERROR("mbedtls_gcm_setkey failed: %d", ret); + mbedtls_gcm_free(&ctx); + return DC_ERR_MBEDTLS_SETKEY; + } + + ret = mbedtls_gcm_crypt_and_tag( + &ctx, MBEDTLS_GCM_ENCRYPT, in->dataLen, in->iv, DCONN_IV_LEN, in->add, DCONN_ADD_LEN, in->data, cryptedText, + DCONN_TAG_LEN, tag); + if (ret != 0) { + DCONN_ERROR("mbedtls_gcm_crypt_and_tag failed: %d", ret); + mbedtls_gcm_free(&ctx); + return DC_ERR_MBEDTLS_ENCRYPT; + } + + mbedtls_gcm_free(&ctx); + return DC_SUCCESS; +} + +uint32_t DConnDecrypt(const DConnGcmAlgIn *in, const uint8_t *tag, uint8_t* plainText) +{ + mbedtls_gcm_context ctx; + mbedtls_gcm_init(&ctx); + int ret = mbedtls_gcm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, in->key, in->keyLen * BITS_IN_BYTE); + if (ret != 0) { + DCONN_ERROR("mbedtls_gcm_setkey failed: %d", ret); + mbedtls_gcm_free(&ctx); + return DC_ERR_MBEDTLS_SETKEY; + } + + ret = mbedtls_gcm_auth_decrypt( + &ctx, in->dataLen, in->iv, DCONN_IV_LEN, in->add, DCONN_ADD_LEN, tag, DCONN_TAG_LEN, in->data, plainText); + if (ret != 0) { + DCONN_ERROR("mbedtls_gcm_auth_decrypt failed: %d", ret); + mbedtls_gcm_free(&ctx); + return DC_ERR_MBEDTLS_DECRYPT; + } + + mbedtls_gcm_free(&ctx); + return DC_SUCCESS; +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_mbedtls_gcm.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_mbedtls_gcm.h new file mode 100755 index 0000000000000000000000000000000000000000..60354220e8780a4591e840c39beab4e4968ee976 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_mbedtls_gcm.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_MBEDTLS_GCM +#define APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_MBEDTLS_GCM + +#include +#include + +#include "product_limits.h" + +#define DCONN_IV_LEN 12 +#define DCONN_ADD_LEN 4 +#define DCONN_TAG_LEN 16 + +/** + * @brief 生成指定长度的随机数 + * + * @param random 随机数 + * @param len 长度 + * @return uint32_t 错误码 + */ +uint32_t DConnGenerateRandom(uint8_t *random, uint32_t len); + +typedef struct { + const uint8_t *data; + uint32_t dataLen; + const uint8_t *key; + uint32_t keyLen; + const uint8_t *iv; + const uint8_t *add; +} DConnGcmAlgIn; + +/** + * @brief AES-GCM 模式加密数据 + * + * @param plainText 明文 + * @param plainTextLen 明文长度 + * @param key 密钥 + * @param keyLen 密钥长度 + * @param iv 初始化向量 + * @param add 额外信息 + * @param cryptedText 密文。密文长度与明文一致。 + * @param tag 验证码 + * @return uint32_t 错误码 + */ +uint32_t DConnEncrypt(const DConnGcmAlgIn *in, uint8_t* cryptedText, uint8_t *tag); + +/** + * @brief AES-GCM 模式解密数据 + * + * @param cryptedText 密文 + * @param cryptedTextLen 密文长度 + * @param key 密钥 + * @param keyLen 密钥长度 + * @param iv 初始化向量 + * @param add 额外信息 + * @param tag 验证码 + * @param plainText 明文。明文长度与密文一致。 + * @return uint32_t 错误码 + */ +uint32_t DConnDecrypt(const DConnGcmAlgIn *in, const uint8_t *tag, uint8_t* plainText); + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_COMMON_INCLUDE_DCONN_MBEDTLS_GSM diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_msg.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_msg.c new file mode 100755 index 0000000000000000000000000000000000000000..cd1f796bb9eba5901eb707c3ccf5f4026016cfdf --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_msg.c @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_msg.h" + +#include +#include +#include +#include + +#include "product_limits.h" +#include "dconn_log.h" +#include "dconncaseone_interface.h" +#include "dconn_mbedtls_gcm.h" + +#define DCONN_HW_LEN 2 +#define DCONN_DWORD_BITS 32 + +#define DCONN_PACK_STRUCT __attribute__((packed)) + +static uint32_t g_additionMessage = 0; // 用于AES-GCM模式加密的额外信息,每次自增防止重放攻击 + +typedef struct { + uint8_t hw[DCONN_HW_LEN]; // 固定字符 HW + uint16_t type; // 消息类型 DConnMsgType +} DCONN_PACK_STRUCT DConnMsgCommonHeader; + +typedef struct { + DConnMsgCommonHeader commonHeader; + uint32_t len; // 可变长数据长度 + uint64_t requestId; // Hichain Request ID +} DCONN_PACK_STRUCT DConnAuthMsg; + +typedef struct { + DConnMsgCommonHeader commonHeader; + uint32_t len; // 可变长数据长度 + uint8_t iv[DCONN_IV_LEN]; // 初始化向量 + uint8_t add[DCONN_ADD_LEN]; // 额外信息 + uint8_t tag[DCONN_TAG_LEN]; // 验证码 +} DCONN_PACK_STRUCT DConnDataMsg; + +static uint64_t HostToNetworkLongLong(uint64_t hostLongLong) +{ + return (((uint64_t) htonl(hostLongLong)) << DCONN_DWORD_BITS) + htonl(hostLongLong >> DCONN_DWORD_BITS); +} + +static uint64_t NetworkToHostLongLong(uint64_t netLongLong) +{ + return (((uint64_t) ntohl(netLongLong)) << DCONN_DWORD_BITS) + ntohl(netLongLong >> DCONN_DWORD_BITS); +} + +static uint32_t DConnEncAuthMsg(const DConnAuthParam *encParam, const DConnMsgIn *in, DConnMsgOut *out) +{ + if (in->dataLen > DCONN_AUTH_BODY_LEN) { + DCONN_ERROR("Auth body len exceed."); + return DC_ERR_HICHAIN_AUTH_MSG_EXCEED; + } + + out->msg = malloc(sizeof(DConnAuthMsg) + in->dataLen); + if (out->msg == NULL) { + DCONN_ERROR("Cannot allocate memory."); + return DC_ERR_ALLOC_MEMORY; + } + + if (in->dataLen > DCONN_AUTH_BODY_LEN) { + DCONN_ERROR("Auth body len exceed."); + free(out->msg); + out->msg = NULL; + return DC_ERR_HICHAIN_AUTH_MSG_EXCEED; + } + + DConnAuthMsg authMsgHeader; + errno_t err = memcpy_s(authMsgHeader.commonHeader.hw, DCONN_HW_LEN, "HW", DCONN_HW_LEN); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + free(out->msg); + out->msg = NULL; + return DC_ERROR; + } + authMsgHeader.commonHeader.type = htons(DCONN_MSG_TYPE_AUTH); + authMsgHeader.len = htonl(in->dataLen); + authMsgHeader.requestId = HostToNetworkLongLong(encParam->requestId); + + err = memcpy_s(out->msg, sizeof(DConnAuthMsg), &authMsgHeader, sizeof(DConnAuthMsg)); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + free(out->msg); + out->msg = NULL; + return DC_ERROR; + } + err = memcpy_s(out->msg + sizeof(DConnAuthMsg), DCONN_AUTH_BODY_LEN, in->data, in->dataLen); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + free(out->msg); + out->msg = NULL; + return DC_ERROR; + } + out->msgLen = sizeof(DConnAuthMsg) + in->dataLen; + return DC_SUCCESS; +} + +static uint32_t DConnEncDataMsg(const DConnDataParam *encParam, const DConnMsgIn *in, DConnMsgOut *out) +{ + out->msgLen = sizeof(DConnDataMsg) + in->dataLen; + out->msg = malloc(out->msgLen); + if (out->msg == NULL) { + return DC_ERR_ALLOC_MEMORY; + } + + DConnDataMsg dataMsgHeader; + errno_t err = memcpy_s(dataMsgHeader.commonHeader.hw, DCONN_HW_LEN, "HW", DCONN_HW_LEN); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + free(out->msg); + out->msg = NULL; + return DC_ERROR; + } + dataMsgHeader.commonHeader.type = htons(DCONN_MSG_TYPE_DATA); + dataMsgHeader.len = htonl(in->dataLen); + + DConnGenerateRandom(dataMsgHeader.iv, DCONN_IV_LEN); + err = memcpy_s(dataMsgHeader.add, DCONN_ADD_LEN, &g_additionMessage, DCONN_ADD_LEN); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + free(out->msg); + out->msg = NULL; + return DC_ERROR; + } + g_additionMessage++; + + DConnGcmAlgIn algIn = { + .data = in->data, + .dataLen = in->dataLen, + .key = encParam->key, + .keyLen = encParam->keyLen, + .iv = dataMsgHeader.iv, + .add = dataMsgHeader.add, + }; + uint32_t ret = DConnEncrypt(&algIn, (out->msg + sizeof(DConnDataMsg)), dataMsgHeader.tag); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Encrypt failed: %" PRIu32, ret); + free(out->msg); + out->msg = NULL; + return ret; + } + + err = memcpy_s(out->msg, sizeof(DConnDataMsg), &dataMsgHeader, sizeof(DConnDataMsg)); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + free(out->msg); + out->msg = NULL; + return DC_ERROR; + } + return ret; +} + +static uint32_t DConnEncRawMsg(uint16_t type, const DConnMsgIn *in, DConnMsgOut *out) +{ + if (in->dataLen > DCONN_DEVICE_ID_BODY_LEN) { + DCONN_ERROR("Raw message body len exceed."); + return DC_ERR_HICHAIN_AUTH_MSG_EXCEED; + } + + out->msg = malloc(sizeof(DConnMsgCommonHeader) + in->dataLen); + if (out->msg == NULL) { + DCONN_ERROR("Cannot allocate memory."); + return DC_ERR_ALLOC_MEMORY; + } + + DConnMsgCommonHeader header; + errno_t err = memcpy_s(header.hw, DCONN_HW_LEN, "HW", DCONN_HW_LEN); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + free(out->msg); + out->msg = NULL; + return DC_ERROR; + } + header.type = htons(type); + + err = memcpy_s(out->msg, sizeof(DConnMsgCommonHeader), &header, sizeof(DConnMsgCommonHeader)); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + free(out->msg); + out->msg = NULL; + return DC_ERROR; + } + err = memcpy_s(out->msg + sizeof(DConnMsgCommonHeader), in->dataLen, in->data, in->dataLen); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + free(out->msg); + out->msg = NULL; + return DC_ERROR; + } + out->msgLen = sizeof(DConnMsgCommonHeader) + in->dataLen; + return DC_SUCCESS; +} + +uint32_t DConnEncMsg(uint16_t type, const void *encParam, const DConnMsgIn *in, DConnMsgOut *out) +{ + if (type == DCONN_MSG_TYPE_AUTH) { + return DConnEncAuthMsg((const DConnAuthParam *)encParam, in, out); + } else if (type == DCONN_MSG_TYPE_DATA) { + return DConnEncDataMsg((const DConnDataParam *)encParam, in, out); + } else if (type == DCONN_MSG_TYPE_DEVICE_ID) { + return DConnEncRawMsg(DCONN_MSG_TYPE_DEVICE_ID, in, out); + } else if (type == DCONN_MSG_TYPE_NOTIFY) { + return DConnEncRawMsg(DCONN_MSG_TYPE_NOTIFY, in, out); + } + + return DC_ERR_BRANCH; +} + +static uint32_t DConnDecAuthMsg(DConnAuthParam *decParam, const DConnMsgIn *in, DConnMsgOut *out) +{ + DConnAuthMsg authMsgHeader; + errno_t err = memcpy_s(&authMsgHeader, sizeof(DConnAuthMsg), in->data, sizeof(DConnAuthMsg)); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + return DC_ERROR; + } + + if (memcmp(authMsgHeader.commonHeader.hw, "HW", DCONN_HW_LEN) != 0) { + DCONN_ERROR( + "Invalid message header HW [%c%c]", *authMsgHeader.commonHeader.hw, *(authMsgHeader.commonHeader.hw + 1)); + return DC_ERR_HEADER_INVALID; + } + + uint16_t type = ntohs(authMsgHeader.commonHeader.type); + if (type != DCONN_MSG_TYPE_AUTH) { + DCONN_ERROR("Invalid message header type [%2" PRIu16 "]", type); + return DC_ERR_HEADER_INVALID; + } + + uint32_t len = ntohl(authMsgHeader.len); + if (len > DCONN_AUTH_BODY_LEN) { + DCONN_ERROR("Invalid message header len [%" PRIu32 "]", len); + return DC_ERR_HEADER_INVALID; + } + + if (len + sizeof(DConnAuthMsg) > (in->dataLen)) { + DCONN_ERROR("Invalid message len [%" PRIu32 "]", (in->dataLen)); + return DC_ERR_HEADER_INVALID; + } + + DCONN_DEBUG("All header check passed."); + decParam->requestId = NetworkToHostLongLong(authMsgHeader.requestId); + out->msg = malloc(len); + if (out->msg == NULL) { + DCONN_ERROR("Cannot allocate memory."); + return DC_ERR_ALLOC_MEMORY; + } + + err = memcpy_s(out->msg, DCONN_AUTH_BODY_LEN, in->data + sizeof(DConnAuthMsg), len); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + free(out->msg); + out->msg = NULL; + return DC_ERROR; + } + out->msgLen = len; + return DC_SUCCESS; +} + +static uint32_t DConnCheckDataBeforeDecode(const DConnDataMsg *dataMsgHeader, const DConnMsgIn *in) +{ + if (memcmp(dataMsgHeader->commonHeader.hw, "HW", DCONN_HW_LEN) != 0) { + DCONN_ERROR("Invalid message header HW [%c%c]", *dataMsgHeader->commonHeader.hw, + *(dataMsgHeader->commonHeader.hw + 1)); + return DC_ERR_HEADER_INVALID; + } + + uint16_t type = ntohs(dataMsgHeader->commonHeader.type); + if (type != DCONN_MSG_TYPE_DATA) { + DCONN_ERROR("Invalid message header type [%2" PRIu16 "]", type); + return DC_ERR_HEADER_INVALID; + } + + uint32_t len = ntohl(dataMsgHeader->len); + if (len > DCONN_DATA_BODY_LEN) { + DCONN_ERROR("Invalid message header len [%" PRIu32 "]", len); + return DC_ERR_HEADER_INVALID; + } + + if (len + sizeof(DConnDataMsg) > in->dataLen) { + DCONN_ERROR("Invalid message len [%" PRIu32 "]", in->dataLen); + return DC_ERR_HEADER_INVALID; + } + + return DC_SUCCESS; +} + +static uint32_t DConnDecDataMsg(DConnDataParam *decParam, const DConnMsgIn *in, DConnMsgOut *out) +{ + DConnDataMsg dataMsgHeader; + errno_t err = memcpy_s(&dataMsgHeader, sizeof(DConnDataMsg), in->data, sizeof(DConnDataMsg)); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + return DC_ERROR; + } + + uint32_t ret = DConnCheckDataBeforeDecode(&dataMsgHeader, in); + if (ret != DC_SUCCESS) { + return ret; + } + + out->msg = malloc(ntohl(dataMsgHeader.len)); + if (out->msg == NULL) { + DCONN_ERROR("Cannot allocate memory."); + return DC_ERR_ALLOC_MEMORY; + } + + out->msgLen = ntohl(dataMsgHeader.len); + DConnGcmAlgIn algIn = { + .data = ((in->data) + sizeof(DConnDataMsg)), + .dataLen = ntohl(dataMsgHeader.len), + .key = decParam->key, + .keyLen = decParam->keyLen, + .iv = dataMsgHeader.iv, + .add = dataMsgHeader.add, + }; + ret = DConnDecrypt(&algIn, dataMsgHeader.tag, out->msg); + if (ret != DC_SUCCESS) { + free(out->msg); + out->msg = NULL; + DCONN_ERROR("Decrypt failed: %" PRIu32, ret); + return ret; + } + + return DC_SUCCESS; +} + +static uint32_t DConnDecRawMsg(uint16_t type, const DConnMsgIn *in, DConnMsgOut *out) +{ + DConnMsgCommonHeader header; + errno_t err = memcpy_s(&header, sizeof(DConnMsgCommonHeader), in->data, sizeof(DConnMsgCommonHeader)); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + return DC_ERROR; + } + + if (memcmp(header.hw, "HW", DCONN_HW_LEN) != 0) { + DCONN_ERROR("Invalid message header HW [%c%c]", *header.hw, *(header.hw + 1)); + return DC_ERR_HEADER_INVALID; + } + + if (ntohs(header.type) != type) { + DCONN_ERROR("Invalid message header type [%2" PRIu16 "]", type); + return DC_ERR_HEADER_INVALID; + } + + DCONN_DEBUG("All header check passed."); + uint32_t len = in->dataLen - sizeof(DConnMsgCommonHeader); + out->msg = malloc(len); + if (out->msg == NULL) { + DCONN_ERROR("Cannot allocate memory."); + return DC_ERR_ALLOC_MEMORY; + } + + err = memcpy_s(out->msg, len, in->data + sizeof(DConnMsgCommonHeader), len); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + free(out->msg); + out->msg = NULL; + return DC_ERROR; + } + out->msgLen = len; + return DC_SUCCESS; +} + +uint32_t DConnDecMsg(uint16_t type, void *decParam, const DConnMsgIn *in, DConnMsgOut *out) +{ + if (type == DCONN_MSG_TYPE_AUTH) { + return DConnDecAuthMsg((DConnAuthParam *)decParam, in, out); + } else if (type == DCONN_MSG_TYPE_DATA) { + return DConnDecDataMsg((DConnDataParam *)decParam, in, out); + } else if (type == DCONN_MSG_TYPE_DEVICE_ID) { + return DConnDecRawMsg(DCONN_MSG_TYPE_DEVICE_ID, in, out); + } else if (type == DCONN_MSG_TYPE_NOTIFY) { + return DConnDecRawMsg(DCONN_MSG_TYPE_NOTIFY, in, out); + } + + return DC_ERR_BRANCH; +} + +uint32_t DConnGetMsgType(const uint8_t *data, uint32_t dataLen, uint16_t *type) +{ + if (dataLen < sizeof(DConnMsgCommonHeader)) { + DCONN_ERROR("Invalid message header. Data has invalid length."); + return DC_ERR_HEADER_INVALID; + } + + DConnMsgCommonHeader header; + errno_t err = memcpy_s(&header, sizeof(DConnMsgCommonHeader), data, sizeof(DConnMsgCommonHeader)); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + return DC_ERROR; + } + *type = ntohs(header.type); + return DC_SUCCESS; +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_peer.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_peer.c new file mode 100755 index 0000000000000000000000000000000000000000..0379cec9b8c48693cd19d55a66908904866b3944 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_peer.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include + +#include "dconn_peer_impl.h" +#include "dconn_peer.h" +#include "dconn_log.h" + +void InitPeerData(PeerDataList peerDataList) +{ + DCONN_DEBUG("init peer data begin"); + for (int i = 0; i < MAX_DEVICES_NUM; i++) { + peerDataList[i].stat = PEER_DATA_STAT_UNUSED; // 设置为未使用 + peerDataList[i].authStat = PEER_AUTH_STAT_UNAUTHORIZED; + peerDataList[i].requestId = 0; + peerDataList[i].authStartTime = 0; + } + DCONN_DEBUG("init peer data end"); +} + +void DeInitPeerData(PeerData * const peerDataList) +{ + for (int i = 0; i < MAX_DEVICES_NUM; i++) { + if (peerDataList[i].stat == PEER_DATA_STAT_UNUSED) { + continue; + } + + if (peerDataList[i].socket != -1) { + close(peerDataList[i].socket); + peerDataList[i].socket = -1; + } + } +} \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_peer_impl.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_peer_impl.h new file mode 100755 index 0000000000000000000000000000000000000000..8999979f895e9c856e0040818cb624ed61e0ca27 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_peer_impl.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_COMMON_SRC_DCONN_PEER_IMPL +#define APPLICATIONS_APP_DCONNECTCASEONE_COMMON_SRC_DCONN_PEER_IMPL + +#include +#include +#include + +#include "product_limits.h" +#include "dconncaseone_interface.h" +#include "dconn_peer.h" + +enum PeerDataStat { + PEER_DATA_STAT_UNUSED = 0, // 未使用 + PEER_DATA_STAT_USED = 1 // 已被使用 +}; + +/** + * @brief 对等端数据结构 + * + */ +typedef struct { + uint32_t stat; // PeerDataStat + uint32_t role; // PeerRole + uint32_t authStat; // PeerAuthStat + time_t authStartTime; + uint32_t sessionKeyLen; + int socket; + uint32_t ipAddr; + int64_t requestId; + uint8_t sessionKey[SESSION_KEY_LEN]; + char deviceId[DCONN_DEVICE_ID_LEN + 1]; + char udid[DCONN_UDID_LEN + 1]; +} PeerData; + +typedef PeerData PeerDataList[MAX_DEVICES_NUM]; + +/** + * @brief 初始化对等端数据 + * + * @param peerDataList 对等端数据指针,内存已申请好 + */ +void InitPeerData(PeerDataList peerDataList); + +/** + * @brief 释放对等端数据 + * + * @param peerDataList 对等端数据指针,此函数不会释放指针 + */ +void DeInitPeerData(PeerData * const peerDataList); + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_COMMON_SRC_DCONN_PEER_IMPL diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_send.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_send.c new file mode 100755 index 0000000000000000000000000000000000000000..cbfc15a2a06e511730ce8b1bc4e53324cf87ffd7 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_send.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_send.h" + +#include +#include +#include + +#include "dconn_data.h" +#include "dconn_log.h" +#include "dconn_peer.h" + +uint32_t SendDataToPeer(int32_t idx, uint8_t *data, uint32_t dataLen) +{ + int *fd = GetSocketByPeerDataIdx(idx); + if (*fd < 0) { + DCONN_ERROR("Invalid socket for idx: %" PRId32, idx); + return DC_ERR_CONNECTION_REFUSED; + } + + uint32_t stat = GetAuthStatByPeerDataIdx(idx); + if (stat == PEER_AUTH_STAT_INVALID) { + DCONN_ERROR("Invalid auth stat for idx: %" PRId32, idx); + return DC_ERR_CONNECTION_REFUSED; + } + + SendDataCallback sendDataCallback = NULL; + const char *targetDeviceId = NULL; + if (stat == PEER_AUTH_STAT_AUTHORIZED) { + sendDataCallback = GetIotSdkCallback()->sendDataResultCb; + if (sendDataCallback == NULL) { + DCONN_ERROR("Send data callback not registerd. Data will not send."); + return DC_ERR_CB_NOT_REGISTER; + } + + targetDeviceId = GetDeviceIdByPeerIdx(idx); + if (targetDeviceId == NULL) { + DCONN_ERROR("Cannot find device ID for idx: %" PRId32, idx); + return DC_ERR_DEVICE_ID_NOT_FOUND; + } + } + + // Return success but callback failed below. + DumpBuf(data, dataLen); + ssize_t ret = send(*fd, data, (size_t)dataLen, 0); + if (ret < 0) { + DCONN_ERROR("Send data failed: %d", errno); + if (sendDataCallback != NULL && targetDeviceId != NULL) { + sendDataCallback(targetDeviceId, DC_ERR_SEND_FAILED); + } + } else { + if (sendDataCallback != NULL && targetDeviceId != NULL) { + sendDataCallback(targetDeviceId, DC_SUCCESS); + } + } + + return DC_SUCCESS; +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_server_data.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_server_data.c new file mode 100755 index 0000000000000000000000000000000000000000..a3d7b1eb83ffdddb5b5a82407e2cef61e0a2e562 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_server_data.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_server_data.h" + +#include + +#include "dconn_log.h" + +void InitServerData(ServerData *data) +{ + DCONN_DEBUG("init server data begin"); + data->serverSocket = -1; + DCONN_DEBUG("init server data end"); +} + +void DeInitServerData(ServerData *data) +{ + if (data->serverSocket != -1) { + close(data->serverSocket); + data->serverSocket = -1; + } +} \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_server_data.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_server_data.h new file mode 100755 index 0000000000000000000000000000000000000000..a0275a7d5dbb9b2d51640dc5daca1dc02ac31047 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_server_data.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_COMMON_SRC_DCONN_SERVER_DATA +#define APPLICATIONS_APP_DCONNECTCASEONE_COMMON_SRC_DCONN_SERVER_DATA + +#include "dconn_data_impl.h" + +/** + * @brief 初始化服务端数据 + * + * @param data 服务端数据指针 + */ +void InitServerData(ServerData *data); + +/** + * @brief 释放服务端数据 + * + * @param data 服务端数据指针。此函数不会释放指针 + */ +void DeInitServerData(ServerData *data); + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_COMMON_SRC_DCONN_SERVER_DATA diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_syspara.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_syspara.c new file mode 100755 index 0000000000000000000000000000000000000000..8db76812036c570fe950272abdf2cca1a1b81d35 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_syspara.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_syspara.h" + +#include +#include +#include + +#include "parameter.h" + +#include "dconn_peer.h" +#include "dconn_log.h" +#include "dconn_data.h" +#include "dconncaseone_interface.h" + +uint32_t DConnGetUdid(char *udid) +{ + errno_t err = memset_s(udid, DCONN_UDID_LEN + 1, 0, DCONN_UDID_LEN + 1); + if (err != EOK) { + DCONN_ERROR("memset_s failed."); + return DC_ERROR; + } + int ret = GetDevUdid(udid, DCONN_UDID_LEN + 1); + if (ret != 0) { + DCONN_ERROR("Cannot get dev udid: %d", ret); + return DC_ERR_CANNOT_GET_UDID; + } + + DCONN_DEBUG("Get UDID succeed."); + return DC_SUCCESS; +} + +uint32_t DConnGetDeviceUdid(DConnDeviceUdId *udid) +{ + GetDeviceID getDeviceId = GetIotSdkCallback()->getDeviceID; + if (getDeviceId == NULL) { + DCONN_ERROR("Get device ID callback not register."); + return DC_ERR_CB_NOT_REGISTER; + } + + udid->deviceId = getDeviceId(); + if (udid->deviceId == NULL || strlen(udid->deviceId) > DCONN_DEVICE_ID_LEN) { + DCONN_ERROR("Get device ID failed from IOT SDK."); + return DC_ERR_INVALID_DEVICE_ID; + } + + uint32_t ret = DConnGetUdid(udid->udid); + if (ret != 0) { + DCONN_ERROR("Cannot get dev udid: %" PRIu32, ret); + return ret; + } + return DC_SUCCESS; +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_thread.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_thread.c new file mode 100755 index 0000000000000000000000000000000000000000..292d8275028eccbc1788a4f4b29ba726a28c046e --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/dconn_thread.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "dconn_thread.h" + +#include +#include +#include +#include +#include + +#include "dconn_data_impl.h" +#include "dconn_log.h" +#include "dconn_sched_yield.h" + +static uint32_t g_transferThreadStat = THR_STAT_DISABLE; +static pthread_t g_tid = 0; + +uint32_t EnableTransferThr(void *(*func)(void *)) +{ + g_transferThreadStat = THR_STAT_ENABLE; + int ret = pthread_create(&g_tid, NULL, func, NULL); + if (ret < 0) { + DCONN_ERROR("Cannot create thread: %d", ret); + return DC_ERR_CREATE_THREAD; + } + + DCONN_INFO("Thread created: %lu", g_tid); + return DC_SUCCESS; +} + +bool IsThreadInStat(uint32_t stat) +{ + if (g_transferThreadStat == stat) { + return true; + } + return false; +} + +void SetThreadStat(uint32_t stat) +{ + g_transferThreadStat = stat; +} + +void ExitTransferThr(void) +{ + g_transferThreadStat = THR_STAT_EXIT; +} + +void WaitTransferThrDisabled(void) +{ + if (g_tid == 0) { + DCONN_ERROR("pthread_t is NULL"); + return; + } + int ret = pthread_join(g_tid, NULL); + DCONN_INFO("Thread exit is finished, ret:%d", ret); +} \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/recv_thread.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/recv_thread.c new file mode 100755 index 0000000000000000000000000000000000000000..a7c46638bd7247852781cac985dcc1bd25f3d6ec --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/recv_thread.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "recv_thread.h" + +#include +#include +#include +#include +#include + +#include "dconn_thread.h" +#include "dconn_data.h" +#include "dconn_log.h" +#include "dconn_msg.h" +#include "dconn_peer.h" +#include "dconn_handler.h" +#include "dconn_sched_yield.h" + +#define DCONN_ANY_CONDITION UINT32_MAX + +typedef uint32_t (*DConnRecvFunc)(int32_t idx, const uint8_t *data, uint32_t dataLen); + +typedef struct { + uint32_t msgType; + uint32_t peerAuthStat; + uint32_t peerRole; + DConnRecvFunc handler; +} DconnRecvHandler; + +static const DconnRecvHandler RECV_HANDLES[] = { + { + .msgType = DCONN_MSG_TYPE_DEVICE_ID, + .peerAuthStat = PEER_AUTH_EXPECT_DEVICE_ID, + .peerRole = DCONN_ANY_CONDITION, + .handler = DConnOnDeviceIdReceived, + }, + { + .msgType = DCONN_MSG_TYPE_AUTH, + .peerAuthStat = PEER_AUTH_ADD_MEMBER, + .peerRole = DCONN_ANY_CONDITION, + .handler = DConnOnGmTransmitReceived, + }, + { + .msgType = DCONN_MSG_TYPE_AUTH, + .peerAuthStat = PEER_AUTH_AUTH_DEVICE, + .peerRole = DCONN_ANY_CONDITION, + .handler = DConnOnGaTransmitReceived, + }, + { + .msgType = DCONN_MSG_TYPE_DATA, + .peerAuthStat = PEER_AUTH_STAT_AUTHORIZED, + .peerRole = DCONN_ANY_CONDITION, + .handler = DConnOnBizDataReceived, + }, + { + .msgType = DCONN_MSG_TYPE_NOTIFY, + .peerAuthStat = DCONN_ANY_CONDITION, + .peerRole = PEER_ROLE_SERVICE, + .handler = DConnOnNotifyMessageReceived, + }, +}; + +static DConnRecvFunc GetHandler(uint16_t type, uint32_t stat, uint32_t role) +{ + for (size_t i = 0; i < (sizeof(RECV_HANDLES) / sizeof(DconnRecvHandler)); i++) { + if (RECV_HANDLES[i].msgType != DCONN_ANY_CONDITION && type != RECV_HANDLES[i].msgType) { + continue; + } + + if (RECV_HANDLES[i].peerAuthStat != DCONN_ANY_CONDITION && stat != RECV_HANDLES[i].peerAuthStat) { + continue; + } + + if (RECV_HANDLES[i].peerRole != DCONN_ANY_CONDITION && role != RECV_HANDLES[i].peerRole) { + continue; + } + + return RECV_HANDLES[i].handler; + } + + return NULL; +} + +static void RecvData(int32_t idx) +{ + int *fd = GetSocketByPeerDataIdx(idx); + uint8_t *data = malloc(DCONN_MAX_MSG_LEN); + if (data == NULL) { + DCONN_ERROR("Cannot alloc memory!"); + return; + } + + errno_t err = memset_s(data, DCONN_MAX_MSG_LEN, 0, DCONN_MAX_MSG_LEN); + if (err != EOK) { + DCONN_ERROR("memset_s failed."); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + free(data); + return; + } + int dataLen = recv(*fd, data, DCONN_MAX_MSG_LEN, 0); + if (dataLen <= 0) { + DCONN_ERROR("Peer close the socket: %" PRId32, idx); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + free(data); + return; + } + + uint16_t type; + uint32_t ret = DConnGetMsgType(data, dataLen, &type); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Cannot get message type: %" PRIu32, ret); + SetAuthStatByPeerDataIdx(idx, PEER_AUTH_STAT_INVALID); + free(data); + return; + } + + uint32_t stat = GetAuthStatByPeerDataIdx(idx); + uint32_t role = GetPeerRole(idx); + DConnRecvFunc handler = GetHandler(type, stat, role); + if (handler == NULL) { + DCONN_ERROR("Cannot find a handler for idx: %" PRId32 " type: %" PRIu32 " stat: %" PRIu32 " role: %" PRIu32, + idx, type, stat, role); + free(data); + return; + } + + DCONN_DEBUG("Before handler for idx: %" PRId32 " type: %" PRIu32 " stat: %" PRIu32 " role: %" PRIu32, + idx, type, stat, role); + ret = handler(idx, data, dataLen); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Handle received message to idx: %" PRId32 " failed: %" PRIu32, idx, ret); + } + + free(data); + return; +} + +void *RecvThread(void *param) +{ + DCONN_DEBUG("Recv data thread begin"); + (void)param; + fd_set readSet; + fd_set exceptfds; + struct timeval timeout = { + .tv_sec = 1, + .tv_usec = 0, + }; // 必须设置超时,否则新加入的对等端可能不会被监听到 + + while (IsThreadInStat(THR_STAT_ENABLE)) { + int maxFd = InitSelectFdSet(&readSet, &exceptfds); + if (maxFd < 0) { + DConnSchedYield(); + continue; + } + + int ret = select(maxFd + 1, &readSet, NULL, &exceptfds, &timeout); + if (ret > 0) { + DCONN_DEBUG("Select succeed. total number of bits: %d", ret); + HandleFdSet(&readSet, RecvData, DConnHandleClientAccess); + } else if (ret == 0) { + DCONN_DEBUG("Select timeout"); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + } else { + DCONN_ERROR("Select error: %d", errno); + HandleFdSet(&exceptfds, ReleasePeerDataIdx, NULL); + } + } + + // 告知线程已退出 + SetThreadStat(THR_STAT_DISABLE); + DCONN_DEBUG("Recv data thread end"); + return NULL; +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/recv_thread.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/recv_thread.h new file mode 100755 index 0000000000000000000000000000000000000000..839a62b0142662c84a47553de980f0aeb520c3e3 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/common/src/recv_thread.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_COMMON_SRC_THREAD_RECV_THREAD +#define APPLICATIONS_APP_DCONNECTCASEONE_COMMON_SRC_THREAD_RECV_THREAD + +/** + * @brief 消息接收线程 + * + */ +void *RecvThread(void *param); + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_COMMON_SRC_THREAD_RECV_THREAD diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/dconnectcaseone_deps.gni b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/dconnectcaseone_deps.gni new file mode 100755 index 0000000000000000000000000000000000000000..8124d7cef6aae63c0da6f45fa99b0db76a2d3785 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/dconnectcaseone_deps.gni @@ -0,0 +1,41 @@ +# Copyright (C) 2022-2023 Huawei Device Co., Ltd. +# 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. + +dconn_deps = [ + "//third_party/mbedtls:mbedtls", +] + +dconn_mini_deps = [ + "//base/hiviewdfx/hilog_lite/frameworks/mini:hilog_lite", + "//base/security/deviceauth:deviceauth_lite", + "//base/security/deviceauth/services:deviceauth", + "//build/lite/config/component/cJSON:cjson_static", + "//base/startup/syspara_lite/frameworks/parameter/src:sysparam", +] +dconn_mini_deps += dconn_deps + +dconn_small_deps = [ + "//base/security/deviceauth/services:deviceauth_sdk", + "//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared", + "//build/lite/config/component/cJSON:cjson_shared", + "//base/startup/syspara_lite/frameworks/parameter/src:sysparam", +] +dconn_small_deps += dconn_deps + +dconn_standrad_deps = [ + "//base/security/deviceauth/services:deviceauth_sdk", + "//utils/native/base:utilsecurec_shared", + "//third_party/cJSON:cjson", + "//base/startup/syspara_lite/interfaces/innerkits/native/syspara:syspara", +] +dconn_standrad_deps += dconn_deps \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/interface/include/dconncaseone_interface.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/interface/include/dconncaseone_interface.h new file mode 100755 index 0000000000000000000000000000000000000000..be336b9b787af68066a5ffab25ad3abb076c9867 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/interface/include/dconncaseone_interface.h @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef __DCONN_CASE_ONE_H__ +#define __DCONN_CASE_ONE_H__ + +#include +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +#if defined(__LINUX__) || defined(_UNIX) +#define DCONN_API_PUBLIC __attribute__((visibility("default"))) +#else +#define DCONN_API_PUBLIC +#endif + +#define INIT_SERVICE (0) // 初始化服务端 +#define INIT_CLIENT (1) // 初始化客户端 + +#define DCONN_DEVICE_ID_LEN 128 // 最大设备ID字符串长度 +#define DCONN_IP_ADDR_LEN 46 // 最大IP地址字符串长度 +#define DCONN_AUTH_KEY_LEN 16 // 最大 Auth Key 长度 +#define DCONN_DATA_BODY_LEN 2008 // 最大报文长度 + +enum { + // Common 0x00000000 ~ 0x00000FFF + DC_SUCCESS = 0x00000000, + DC_ERROR = 0x00000001, + DC_ERR_BRANCH = 0x00000002, + DC_ERR_ALLOC_MEMORY = 0x00000003, + DC_ERR_CREATE_THREAD = 0x00000004, + DC_ERR_THRESHOLD_EXCEED = 0x00000005, + DC_ERR_NULLPTR = 0x00000006, + DC_ERR_INVALID_JSON = 0x00000007, + + // Callback 0x00001000 ~ 0x00001FFF + DC_ERR_INVALID_DEVICE_ID = 0x00001001, + DC_ERR_CB_NOT_REGISTER = 0x00001002, + DC_ERR_INVALID_AUTH_KEY = 0x00001003, + + // mbedtls 0x00002000 ~ 0x00002FFF + DC_ERR_MBEDTLS_SETKEY = 0x00002001, + DC_ERR_MBEDTLS_ENCRYPT = 0x00002002, + DC_ERR_MBEDTLS_SEED = 0x00002003, + DC_ERR_MBEDTLS_GEN_RANDOM = 0x00002004, + DC_ERR_MBEDTLS_DECRYPT = 0x00002005, + + // Encode/Decode message 0x00003000 ~ 0x00003FFF + DC_ERR_HEADER_INVALID = 0x00003001, + + // Network 0x00004000 ~ 0x00004fff + DC_ERR_CONNECTION_REFUSED = 0x00004001, // 网络无法连接 + DC_ERR_BIND_PORT = 0x00004002, // 端口被占用 + DC_ERR_SEND_FAILED = 0x00004003, + + // Parameter 0x00005000 ~ 0x00005fff + DC_ERR_IP_FORMAT = 0x00005001, + DC_ERR_DEVICE_ID_NOT_FOUND = 0x00005002, + DC_ERR_DEVICE_NOT_AUTHORIZED = 0x00005003, + DC_ERR_INVALID_INIT_TYPE = 0x00005004, + DC_ERR_CANNOT_GET_UDID = 0x00005005, + DC_ERR_UDID_NOT_FOUND = 0x00005006, + + // Limit 0x00006000 ~ 0x00006fff + DC_ERR_PEER_NUM_EXCEED = 0x00006001, + DC_ERR_SEND_DATA_EXCEED = 0x00006002, + + // Auth 0x00007000 ~ 0x00007fff + DC_ERR_AUTH_FAILED = 0x00007001, + DC_ERR_AUTH_INIT_FAILED = 0x00007002, + DC_ERR_GET_GROUP_MANAGER = 0x00007003, + DC_ERR_INVALID_AUTH_STAT = 0x00007004, + DC_ERR_PROCESS_AUTH_DATA = 0x00007005, + DC_ERR_CREATE_GROUP = 0x00007006, + DC_ERR_REG_HICHAIN_CB = 0x00007007, + DC_ERR_ADD_MEMBER = 0x00007008, + DC_ERR_INVALID_REQUEST_ID = 0x00007009, + DC_ERR_HICHAIN_AUTH_MSG_EXCEED = 0x0000700a, + DC_ERR_INVALID_NOTIFY_MESSAGE = 0x0000700b, +}; + +/** + * @brief 数据发送回调函数。 + * + */ +typedef void (*SendDataCallback)(const char *deviceId, uint32_t result); + +/** + * @brief 数据接收回调函数。 + * + */ +typedef void (*ReceiveDataCallback)(const char *deviceId, const char *receiveData, uint32_t datelen); + +/** + * @brief 校验当前连接的服务的客户端 IP 地址是否合法 + * + */ +typedef bool (*IsValidIP)(const char *ip); + +/** + * @brief 校验当前连接服务的客户端的设备 ID 是否合法 + * + */ +typedef bool (*IsValidDeviceID)(const char *deviceID); + +/** + * @brief 获取对应设备的 PIN 码 + * + */ +typedef char *(*GetAuthKey)(const char *targetDeviceID); + +/** + * @brief 获取本设备 ID + * + */ +typedef char *(*GetDeviceID)(void); + +/** + * @brief 回调函数结构体 + * + */ +typedef struct { + /** Callback for send data */ + SendDataCallback sendDataResultCb; + /** Callback for receive message */ + ReceiveDataCallback onReceiveDataCb; + + // 依赖 IOT SDK 提供的方法 + IsValidIP isValidIP; + IsValidDeviceID isValidDeviceID; + GetAuthKey getAuthKey; + GetDeviceID getDeviceID; +} CallbackParam; + +/** + * @brief 初始化套件。 + * + * @param type 初始化类型: INIT_SERVICE/INIT_CLIENT + * @param ipAry IP地址字符串。初始化服务端时仅可传入一个 IP 地址,初始化客户端时可传入多个,以半角逗号分隔。 + * @param errorIp 第一个出错的 IP 地址,只有在返回值不为 OK 时有效。内存空间由调用方申请。 + * @return uint32_t 错误码。RESLUT_ENUM。在初始化客户端时,按输入顺序依次初始化,遇到第一个失败的 IP 地址则返回, + * 后续的 IP 地址不会被处理。 + */ +DCONN_API_PUBLIC uint32_t InitDConnCaseOne(uint32_t type, const char *ipAry, char *errorIp); + +/** + * @brief 注册回调函数 + * + * @param callback 回调函数结构体 CallbackParam + */ +DCONN_API_PUBLIC void RegisterCallback(const CallbackParam *callback); + +/** + * @brief 发送数据 + * + * @param targetDeviceId 目标设备 ID + * @param data 待发送数据 + * @param dataLen 数据字节长度 + * @return int 发送结果。此处并不能代表发送成功,请通过回调函数获取结果。 + */ +DCONN_API_PUBLIC uint32_t DConnSendData(const char *targetDeviceId, const char *data, uint32_t dataLen); + +/** + * @brief 取消注册回调函数 + * + */ +DCONN_API_PUBLIC void UnRegisterCallback(void); + +/** + * @brief 卸载套件。 + * + */ +DCONN_API_PUBLIC void CloseDConnCaseOne(void); + +/** + * @brief 获取套件版本号 + * + * @return const* 字符串格式的版本号 + */ +DCONN_API_PUBLIC const char *GetDConnVersion(void); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __DCONN_CASE_ONE_H__ */ diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/main/dconncaseone.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/main/dconncaseone.c new file mode 100755 index 0000000000000000000000000000000000000000..b97693e69f0fc3fc52a780f0cd88cd971038dc96 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/main/dconncaseone.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include +#include +#include +#include +#include + +#include "dconncaseone_interface.h" +#include "dconn_data.h" +#include "service.h" +#include "client.h" +#include "dconn_thread.h" +#include "dconn_log.h" +#include "dconn_msg.h" +#include "dconn_group_manager.h" +#include "recv_thread.h" +#include "dconn_send.h" + +// 大特性版本号 +#define MAJOR_VERSION "1" +// 芯片版本号 +#ifdef __MIPSEL__ +#define CHIP_VERSION "1" +#elif __ARMEL__ +#define CHIP_VERSION "2" +#endif +// 特性版本号 +#define FEATURE_VERSION "0" +// 小版本号 +// 0~199开发版本号 +// 200~299 外部联调版本号 +// 300 以上,对外商用发布版本号 +#define MINOR_VERSION "0" + +uint32_t InitDConnCaseOne(uint32_t type, const char *ipAry, char *errorIp) +{ + if (ipAry == NULL || errorIp == NULL) { + DCONN_ERROR("Address array or errorIp pointer is null."); + return DC_ERR_NULLPTR; + } + + // 初始化数据 + uint32_t ret = InitDConnData(); + if (ret != DC_SUCCESS) { + return ret; + } + + // 使能数据传输线程 + ret = EnableTransferThr(RecvThread); + if (ret != DC_SUCCESS) { + return ret; + } + + // 初始化设备认证服务 + ret = DConnInitDeviceAuthService(); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Init device auth service failed: %" PRIu32, ret); + return ret; + } + + if (type == INIT_SERVICE) { + ret = DConnInitService(ipAry); + if (ret != DC_SUCCESS) { + // 服务端初始化失败,IP肯定只有一个 + errno_t err = strcpy_s(errorIp, DCONN_IP_ADDR_LEN + 1, ipAry); + if (err != EOK) { + DCONN_ERROR("strcpy_s failed."); + } + } + } else if (type == INIT_CLIENT) { + ret = DConnInitClient(ipAry, errorIp); + } else { + ret = DC_ERR_INVALID_INIT_TYPE; + } + + return ret; +} + +void RegisterCallback(const CallbackParam *callback) +{ + if (callback == NULL) { + return; + } + + errno_t err = memcpy_s(GetIotSdkCallback(), sizeof(CallbackParam), callback, sizeof(CallbackParam)); + if (err != EOK) { + DCONN_ERROR("memcpy_s failed."); + return; + } +} + +uint32_t DConnSendData(const char *targetDeviceId, const char *data, uint32_t dataLen) +{ + if (targetDeviceId == NULL || data == NULL) { + DCONN_ERROR("targetDeviceId or data pointer is null."); + return DC_ERR_NULLPTR; + } + + if (dataLen > DCONN_DATA_BODY_LEN) { + DCONN_ERROR("Send data len exceed: %" PRIu32, dataLen); + return DC_ERR_SEND_DATA_EXCEED; + } + + int32_t idx = GetIdxByDeviceId(targetDeviceId); + if (idx < 0) { + DCONN_ERROR("Device ID not found: %s", targetDeviceId); + return DC_ERR_DEVICE_ID_NOT_FOUND; + } + + DConnDataParam param; + GetSessionKeyByPeerIdx(idx, ¶m.key, ¶m.keyLen); + if (param.keyLen == 0) { + DCONN_ERROR("Device not authorized: %s", targetDeviceId); + return DC_ERR_DEVICE_NOT_AUTHORIZED; + } + + DConnMsgIn in = { + .data = (const uint8_t *)data, + .dataLen = dataLen, + }; + DConnMsgOut out; + uint32_t ret = DConnEncMsg(DCONN_MSG_TYPE_DATA, ¶m, &in, &out); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Encode message failed"); + return ret; + } + + ret = SendDataToPeer(idx, out.msg, out.msgLen); + free(out.msg); + if (ret != DC_SUCCESS) { + DCONN_ERROR("Send data to peer idx: %" PRId32 " failed. Data will not send: %" PRIu32, idx, ret); + return ret; + } + + return DC_SUCCESS; +} + +void UnRegisterCallback(void) +{ + if (GetIotSdkCallback() == NULL) { + return; + } + + errno_t err = memset_s(GetIotSdkCallback(), sizeof(CallbackParam), 0, sizeof(CallbackParam)); + if (err != EOK) { + DCONN_ERROR("memset_s failed."); + return; + } +} + +void CloseDConnCaseOne(void) +{ + // 通知数据传输线程退出 + (void)ExitTransferThr(); + + // 等待所有线程退出 + WaitTransferThrDisabled(); + + // 释放全局数据 + DeInitDconnData(); +} + +const char *GetDConnVersion(void) +{ + return MAJOR_VERSION "." CHIP_VERSION "." FEATURE_VERSION "." MINOR_VERSION; +} diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/service/include/service.h b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/service/include/service.h new file mode 100755 index 0000000000000000000000000000000000000000..34ee4b376801171e053b90f7847b76d0aff7ce2e --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/service/include/service.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef APPLICATIONS_APP_DCONNECTCASEONE_SERVICE_INCLUE_SERVICE +#define APPLICATIONS_APP_DCONNECTCASEONE_SERVICE_INCLUE_SERVICE + +#include + +/** + * @brief 初始化服务端 + * + * @details 服务端初始化到启动监听阶段即会返回。 + * 第一次初始化服务端后会创建线程接收客户端的认证,或处理已认证的客户端的消息。 + * 此方法可重入。重复调用时若与前一次的 IP 地址一致则不处理,不一致则会关闭前一次的连接,重新创建服务端。 + * @param ipAry 服务端 IP 地址。一个 IPv4 或 IPv6 地址字符串 + * @return int 初始化结果 + */ +uint32_t DConnInitService(const char *ipAry); + +#endif // APPLICATIONS_APP_DCONNECTCASEONE_SERVICE_INCLUE_SERVICE \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/service/src/service.c b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/service/src/service.c new file mode 100755 index 0000000000000000000000000000000000000000..6ffd36df798676f5eed7041c00eb842ec4824461 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/dconnectcaseone/service/src/service.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "service.h" + +#include +#include +#include +#include +#include +#include + +#include "dconn_data.h" +#include "dconncaseone_interface.h" +#include "dconn_log.h" +#include "dconn_peer.h" + +#define DCONN_LISTEN_QUEUE_LEN 10 + +static uint32_t BindSocket(int addressFamily, const char *ipAry, int *fd) +{ + struct sockaddr_in servAddr; + struct sockaddr_in6 servAddr6; + + uint32_t ipValue = DconnIpTransToInt(ipAry); + unsigned char *ipAddress = (unsigned char *)&ipValue; + int result = -1; + if (addressFamily == AF_INET) { + errno_t err = memset_s(&servAddr, sizeof(servAddr), 0, sizeof(servAddr)); + if (err != EOK) { + DCONN_ERROR("memset_s failed."); + return DC_ERROR; + } + servAddr.sin_family = AF_INET; + if (inet_pton(AF_INET, ipAry, (void *)&servAddr.sin_addr) == 0) { + DCONN_ERROR("Invalid IPv4 address: %" IPV4_ANONYMOUS_PLACEHOLDER, ipAddress[3], ipAddress[0]); + return DC_ERR_IP_FORMAT; + } + servAddr.sin_port = htons(DCONN_SERVICE_PORT); + result = bind(*fd, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)); + } else { + servAddr6.sin6_family = AF_INET6; + if (inet_pton(AF_INET6, ipAry, (void *)&servAddr6.sin6_addr) == 0) { + DCONN_ERROR("Invalid IPv6 address: %" IPV6_ANONYMOUS_PLACEHOLDER, ipAddress[0], ipAddress[0]); + return DC_ERR_IP_FORMAT; + } + servAddr6.sin6_port = htons(DCONN_SERVICE_PORT); + result = bind(*fd, (struct sockaddr *)&servAddr6, sizeof(struct sockaddr_in6)); + } + + if (result < 0) { + DCONN_ERROR("Socket bind error: %d", errno); + return DC_ERR_BIND_PORT; + } + + result = listen(*fd, DCONN_LISTEN_QUEUE_LEN); + if (result < 0) { + DCONN_ERROR("Socket listen error: %d", errno); + return DC_ERR_CONNECTION_REFUSED; + } + + DCONN_INFO("Socket bind succeed."); + return DC_SUCCESS; +} + +uint32_t DConnInitService(const char *ipAry) +{ + uint32_t ipValue = DconnIpTransToInt(ipAry); + unsigned char *ipAddress = (unsigned char *)&ipValue; + (void)ipAddress; + DCONN_DEBUG("Init service at TCP: %" IPV4_ANONYMOUS_PLACEHOLDER ":%d", + ipAddress[3], ipAddress[0], DCONN_SERVICE_PORT); + + int addressFamily = AF_INET; + if (strstr(ipAry, ".") == NULL) { + addressFamily = AF_INET6; + DCONN_INFO("IPv6 address detected."); + } + *GetServerSocketAddrFamily() = addressFamily; + + uint32_t ret = HasServerIpAddr(); + if (ret == DC_SUCCESS) { + DCONN_DEBUG("Ip address is already exists"); + return DC_SUCCESS; + } + + int fd = socket(addressFamily, SOCK_STREAM, 0); + if (fd == -1) { + DCONN_ERROR("Socket init error: %d", errno); + return DC_ERR_CONNECTION_REFUSED; + } + + ret = BindSocket(addressFamily, ipAry, &fd); + if (ret != DC_SUCCESS) { + close(fd); + return ret; + } + SetServerSocket(fd); + + return DC_SUCCESS; +} diff --git "a/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\345\217\257\344\277\241\350\256\244\350\257\201.png" "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\345\217\257\344\277\241\350\256\244\350\257\201.png" new file mode 100755 index 0000000000000000000000000000000000000000..090805e4520a0ab13fb6ad594e1e3d703d7aafe3 Binary files /dev/null and "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\345\217\257\344\277\241\350\256\244\350\257\201.png" differ diff --git "a/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\345\256\242\346\210\267\347\253\257\345\210\235\345\247\213\345\214\226.png" "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\345\256\242\346\210\267\347\253\257\345\210\235\345\247\213\345\214\226.png" new file mode 100755 index 0000000000000000000000000000000000000000..07c49368531947f800697cd15c0ef9f4f21b33a3 Binary files /dev/null and "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\345\256\242\346\210\267\347\253\257\345\210\235\345\247\213\345\214\226.png" differ diff --git "a/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\345\272\224\347\224\250\345\234\272\346\231\257.png" "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\345\272\224\347\224\250\345\234\272\346\231\257.png" new file mode 100755 index 0000000000000000000000000000000000000000..c2fac7156a68fc0a03c81ea9e7328828ecd9a5d7 Binary files /dev/null and "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\345\272\224\347\224\250\345\234\272\346\231\257.png" differ diff --git "a/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\224\266\345\217\221\346\225\260\346\215\256.png" "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\224\266\345\217\221\346\225\260\346\215\256.png" new file mode 100755 index 0000000000000000000000000000000000000000..d7b5e66e0fb0286c8ca7044ecd4ead819ddfe913 Binary files /dev/null and "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\224\266\345\217\221\346\225\260\346\215\256.png" differ diff --git "a/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\234\215\345\212\241\347\253\257\345\210\235\345\247\213\345\214\226.png" "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\234\215\345\212\241\347\253\257\345\210\235\345\247\213\345\214\226.png" new file mode 100755 index 0000000000000000000000000000000000000000..bcbeb4de65fec945acc3d727376384174efbea4b Binary files /dev/null and "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\234\215\345\212\241\347\253\257\345\210\235\345\247\213\345\214\226.png" differ diff --git "a/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\237\245\347\234\213\350\256\276\345\244\207\345\272\217\345\210\227\345\217\267.png" "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\237\245\347\234\213\350\256\276\345\244\207\345\272\217\345\210\227\345\217\267.png" new file mode 100755 index 0000000000000000000000000000000000000000..e16501fe8179ce64a032b67d1c18b3f47f3afd21 Binary files /dev/null and "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\237\245\347\234\213\350\256\276\345\244\207\345\272\217\345\210\227\345\217\267.png" differ diff --git "a/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\243\200\346\237\245\344\270\232\345\212\241demo.png" "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\243\200\346\237\245\344\270\232\345\212\241demo.png" new file mode 100755 index 0000000000000000000000000000000000000000..5178508195ce3e68d60b9c02de47555ac966fcce Binary files /dev/null and "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\243\200\346\237\245\344\270\232\345\212\241demo.png" differ diff --git "a/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\243\200\346\237\245\346\240\267\344\276\213\345\257\271\345\272\224\347\232\204so.png" "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\243\200\346\237\245\346\240\267\344\276\213\345\257\271\345\272\224\347\232\204so.png" new file mode 100755 index 0000000000000000000000000000000000000000..fb4da7466945ebff8a423de1846b14b1495c1769 Binary files /dev/null and "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\346\243\200\346\237\245\346\240\267\344\276\213\345\257\271\345\272\224\347\232\204so.png" differ diff --git "a/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\351\205\215\347\275\256HDC\347\216\257\345\242\2031.png" "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\351\205\215\347\275\256HDC\347\216\257\345\242\2031.png" new file mode 100755 index 0000000000000000000000000000000000000000..cb7fa3bddbaf77baff806e1ed258301b49a865e2 Binary files /dev/null and "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\351\205\215\347\275\256HDC\347\216\257\345\242\2031.png" differ diff --git "a/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\351\205\215\347\275\256HDC\347\216\257\345\242\2032.png" "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\351\205\215\347\275\256HDC\347\216\257\345\242\2032.png" new file mode 100755 index 0000000000000000000000000000000000000000..02aecb186a4b3dbee3cd6bec34440f43706e3d8f Binary files /dev/null and "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\351\205\215\347\275\256HDC\347\216\257\345\242\2032.png" differ diff --git "a/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\351\232\247\351\201\223\345\234\272\346\231\257.png" "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\351\232\247\351\201\223\345\234\272\346\231\257.png" new file mode 100755 index 0000000000000000000000000000000000000000..1f33487df481d3a96c6c8c10ee82b500a37c46a8 Binary files /dev/null and "b/demo/hihope_rk3568_dconnectcaseone/00_src/figures/\351\232\247\351\201\223\345\234\272\346\231\257.png" differ diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/ohos.build b/demo/hihope_rk3568_dconnectcaseone/00_src/ohos.build new file mode 100755 index 0000000000000000000000000000000000000000..49e36daa350fb4525ac86c5e98b0c96e6354ae88 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/ohos.build @@ -0,0 +1,29 @@ +{ + "subsystem": "kits", + "parts": { + "dconnectcaseone":{ + "module_list":[ + "//vendor/kits/dconnectcaseone:dconnectcaseone" + ], + "inner_kits": [ + { + "name": "//vendor/kits/dconnectcaseone:dconnectcaseone", + "header": { + "header_files": [ + "dconncaseone_interface.h" + ], + "header_base": "//vendor/kits/dconnectcaseone/interface/include" + } + } + ], + "test_list": [] + }, + "test": { + "module_list": [ + "//vendor/kits/test:demo" + ], + "inner_kits": [], + "test_list": [] + } + } +} \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/readme.md b/demo/hihope_rk3568_dconnectcaseone/00_src/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..03ae3e28c618914027a693fd38ca3d03006acbfa --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/readme.md @@ -0,0 +1,8 @@ +# 简介 + +| 目录 | 功能说明 | +| --------------- | ------------------------------------------------------------ | +| dconnectcaseone | 基于openharmony安全子系统deviceauth组件开发的分布式安全通信样例,可用于多个设备间基于预先定义的关系网完成可信认证与连接,构建安全的数据传输通道 | +| test | 用于验证样例功能可用的业务程序示例代码,使用者可以参考该代码定制自己的业务程序 | +| figures | 用于存放readme文件中的图片资源 | + diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/test/BUILD.gn b/demo/hihope_rk3568_dconnectcaseone/00_src/test/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..6202d2b1af15567e61373e40349f38e343aefb39 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/test/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright (C) 2022-2023 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +ohos_executable("demo") { + install_enable = true + sources = [ "main.c" ] + include_dirs = [ + "//vendor/kits/dconnectcaseone/interface/include", + ] + deps = [ + "//utils/native/base:utilsecurec_shared", + "//vendor/kits/dconnectcaseone:dconnectcaseone", + ] + part_name = "test" + subsystem_name = "kits" +} \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/test/LICENSE b/demo/hihope_rk3568_dconnectcaseone/00_src/test/LICENSE new file mode 100755 index 0000000000000000000000000000000000000000..4a459866a57c25462afad17f3fe0b50d440da080 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/test/LICENSE @@ -0,0 +1,177 @@ + + 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 \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/00_src/test/main.c b/demo/hihope_rk3568_dconnectcaseone/00_src/test/main.c new file mode 100755 index 0000000000000000000000000000000000000000..955230b8ca2c2452bb5792366792e456254bb65f --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/00_src/test/main.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2022-2023 Huawei Device Co., Ltd. + * 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. + */ + +#include +#include +#include +#include + +#include "dconncaseone_interface.h" + +static uint32_t g_initType; +static char g_deviceId[64] = {0}; + +void SendDataToDeviceCb(const char *deviceId, uint32_t result) +{ + printf("Data sent to [%s] result: %u\n", deviceId, result); +} + +void ReceiveDataFromDeviceCb(const char *deviceId, const char *receiveData, uint32_t datelen) +{ + printf("Data received from device [%s]. Datalen: %u, Data: %s\n", deviceId, datelen, receiveData); +} + +bool IsValidIPCb(const char *ip) +{ + printf("IsValidIPCb: %s\n", ip); + return true; +} + +bool IsValidDeviceIDCb(const char *deviceID) +{ + printf("IsValidDeviceIDCb: %s\n", deviceID); + return true; +} + +char *GetAuthKeyCb(const char *targetDeviceID) +{ + printf("GetAuthKeyCb: %s\n", targetDeviceID); + static char authKey[] = "123456"; + return authKey; +} + +char *GetDeviceIDCb(void) +{ + return g_deviceId; +} + +void SendDataLoop() +{ + while (1) { + int shouldClose; + printf("Do you want to close dconnect case one? 1 for yes, 0 for no: \n"); + if (scanf_s("%d", &shouldClose) <= 0) { + printf("Input parameter error.\n"); + continue; + } + if (shouldClose == 1) { + printf("Closing...\n"); + CloseDConnCaseOne(); + printf("Closed.\n"); + return; + } + + char targetDeviceId[64]; + char data[64]; + printf("Please input device ID you want to send: \n"); + if (scanf_s("%s", targetDeviceId, 64) <= 0) { + printf("Input parameter error.\n"); + continue; + } + printf("Please input data you want to send: \n"); + if (scanf_s("%s", data, 64) <= 0) { + printf("Input parameter error.\n"); + continue; + } + + uint32_t datalen = strlen(data) + 1; + uint32_t result = DConnSendData(targetDeviceId, data, datalen); + printf("Send %u data result: %u\n", datalen, result); + } +} + +int main(void) +{ + CallbackParam param = { + .sendDataResultCb = SendDataToDeviceCb, + .onReceiveDataCb = ReceiveDataFromDeviceCb, + .isValidIP = IsValidIPCb, + .isValidDeviceID = IsValidDeviceIDCb, + .getAuthKey = GetAuthKeyCb, + .getDeviceID = GetDeviceIDCb, + }; + RegisterCallback(¶m); + + printf("Distributed Connect Case One Ver. %s \n", GetDConnVersion()); + printf("Please input init type. 0 for service, 1 for client: \n"); + char ipAry[64]; + char errorIp[64]; + + if (scanf_s("%u", &g_initType) <= 0) { + printf("Input parameter error.\n"); + return 0; + } + if (g_initType == INIT_SERVICE) { + printf("init as service \n"); + } else if (g_initType == INIT_CLIENT) { + printf("init as client \n"); + } else { + return 0; + } + + printf("Please input device ID: \n"); + if (scanf_s("%s", g_deviceId, 64) <= 0) { + printf("Input parameter error.\n"); + return 0; + } + + printf("Please input IP address: \n"); + if (scanf_s("%s", ipAry, 64) <= 0) { + printf("Input parameter error.\n"); + return 0; + } + uint32_t ret = InitDConnCaseOne(g_initType, ipAry, errorIp); + printf("Init ret: %u\n", ret); + if (ret != DC_SUCCESS) { + return 0; + } + + SendDataLoop(); + return 0; +} \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/01_tools/readme.md b/demo/hihope_rk3568_dconnectcaseone/01_tools/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..86b226c29caffd55a20dc18aa56d129a84482579 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/01_tools/readme.md @@ -0,0 +1,6 @@ +# 镜像烧录工具 + +rk3568开发板的镜像烧录工具请从如下地址获取: + +https://gitee.com/hihope_iot/docs/tree/master/HiHope_DAYU200/%E7%83%A7%E5%86%99%E5%B7%A5%E5%85%B7%E5%8F%8A%E6%8C%87%E5%8D%97 + diff --git a/demo/hihope_rk3568_dconnectcaseone/02_codebuild/readme.md b/demo/hihope_rk3568_dconnectcaseone/02_codebuild/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..4673e2f3f98be6ac2bcd6c8c49204ae0bd207a05 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/02_codebuild/readme.md @@ -0,0 +1,165 @@ +# 简介 + +本文档介绍如何将样例集成到rk3568开发板的openharmony镜像中。 + +# 环境准备 + +## 硬件准备 + +安装windows 10及以上操作系统的PC主机 + +两台rk3568开发板 + +## 构建环境 + +首先需要在PC主机上安装Ubuntu操作系统,以提供基础的编译环境,安装方法可参考:https://developer.huawei.com/consumer/cn/training/course/video/C101639987816176315 + +然后完成基础环境的配置,可参考:https://developer.huawei.com/consumer/cn/training/course/video/C101639988048536240 + +下载源码前先执行如下指令安装所需的工具: + +``` +sudo apt-get update && sudo apt-get install binutils git git-lfs gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip m4 bc gnutls-bin python3.8 python3-pip ruby genext2fs liblz4-tool libssl-dev libtinfo5 openjdk-17-jre-headless libc6 libstdc++6 default-jdk u-boot-tools mtools mtd-utils scons gcc-arm-linux-gnueabi +``` + +该样例适配的源码版本为:Openharmony-3.1-Release,请确保下载代码时分支选择正确。 + +源码获取方式可参考开源社区文档 http://www.openharmony.cn/download ,选择第一种获取方式,并使用以下命令替换文档中的下载命令: + +``` +repo init -u https://gitee.com/openharmony/manifest.git -b refs/tags/OpenHarmony-v3.1-Release --no-repo-verify +repo sync -c +repo forall -c 'git lfs pull' +``` + +## 编译验证 + +下载源码后,需要先编译rk3568版本通过,以确保编译环境正常可用。 + +切换到源码根目录,执行如下命令,安装编译器及二进制工具: + +``` +bash build/prebuilts_download.sh +``` + +接着执行如下命令进行版本编译: + +``` +./build.sh --product-name rk3568 –ccache +``` + +编译完成后,日志中显示如下,则表示编译成功: + +``` +=====build rk3568 successful. +``` + +编译生成的镜像文件在 out/rk3568/packages/phone/images/ 目录下。 + +# 集成样例 + +## 样例源码介绍 + +样例源码存放在00_src目录下,各个目录中的文件功能如下表: + +| 目录 | 功能说明 | +| --------------- | ------------------------------------------------------------ | +| dconnectcaseone | 基于openharmony安全子系统deviceauth组件开发的分布式安全通信样例,可用于多个设备间基于预先定义的关系网完成可信认证与连接,构建安全的数据传输通道 | +| test | 用于验证样例功能可用的业务程序示例代码,使用者可以参考该代码定制自己的业务程序 | +| figures | 用于存放readme文件中的图片资源 | + +## 修改社区源码 + +基于rk3568设备集成编译该样例时,需要按照如下步骤修改源码(+表示增加行,-表示删除行): + +- 修改base/security/deviceauth/common_lib/impl/src/clib_types.c文件内容: + + ```c + void *ClibMalloc(uint32_t size, char val) + { + - if (size == 0 || size > CLIB_MAX_MALLOC_SIZE) { + + if (size == 0) { + return NULL; + } + void* addr = malloc(size); + ``` + +- 修改base/security/deviceauth/common_lib/interfaces/clib_types.h文件内容: + + ```c + #define NULL 0 + #endif + + -#define CLIB_MAX_MALLOC_SIZE 4096 /* 4K */ + - + #ifdef __cplusplus + extern "C" { + #endif + ``` + +- 修改build/prebuilts_download.sh文件内容: + + ``` + -node_js_ver=v12.18.4 + +node_js_ver='v12.18.4' + node_js_name=node-${node_js_ver}-${host_platform}-x64 + node_js_pkg=${node_js_name}.tar.gz + ``` + +- 修改third_party/jsframework/package.json文件内容: + + ``` + "sinon": "^9.2.2", + "ts-node": "^9.0.0", + "tslib": "^2.0.3", + - "typescript": "^4.1.2" + + "typescript": "4.1.3" + } + } + ``` + +接着按照如下流程将样例集成到rk3568产品版本中: + +- 在社区源码的vendor目录下新建目录,名称可自定义,如vendor/kits,并将00_src目录下的所有文件放到kits目录下。 + +- 修改build/subsystem_config.json文件,增加如下内容,新增一个subsystem: + + ``` + "kits": { + "path": "vendor/kits", + "name": "kits" + }, + ``` + +- 修改productdefine/common/products/rk3568.json文件,在parts中新增kits中的两个部件: + + ``` + "type": "standard", + "product_build_path": "device/hihope/build", + "parts":{ + "kits:dconnectcaseone":{}, + "kits:test":{}, + "ace:ace_engine_standard":{}, + ``` + +## 编译镜像 + +切换到源码根目录,执行如下命令,进行编译构建: + +``` +./build.sh --product-name rk3568 --ccache +``` + +编译成功后,在 /out/rk3568 目录中通过如下指令检查是否包含本样例: + +``` +find ./out/rk3568 -name "libdconnectcaseone.z.so" +``` + +通过如下指令检查是否包含测试用业务程序: + +``` +find ./out/rk3568/kits -name "demo" +``` + +如果找不到样例对应的so文件,请检查00_src目录下的文件是否全部放到了kits目录下(请注意:ohos.build文件也是必需的)。 diff --git a/demo/hihope_rk3568_dconnectcaseone/03_codeburn/readme.md b/demo/hihope_rk3568_dconnectcaseone/03_codeburn/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..41f6eb2d08460cfb6c091b46c47c0a0d594e48f8 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/03_codeburn/readme.md @@ -0,0 +1,57 @@ +# 简介 + +本文档介绍如何将集成了样例的openharmony镜像烧录到rk3568开发板中。 + +# 环境准备 + +## 硬件准备 + +安装windows 10及以上操作系统的PC主机 + +至少两台rk3568开发板 + +# 烧录镜像 + +## 环境准备 + +从 out/rk3568/packages/phone/images/ 目录下复制编译成功的rk3568镜像文件到PC的windows环境中。 + +然后按照如下流程配置PC的HDC环境: + +- 切换到Ubuntu环境中的源码根目录,执行如下命令,编译ohos-sdk包: + + ``` + ./build.sh --product-name ohos-sdk --ccache + ``` + +- 编译完成后,从out/ohos-sdk/windows/ 目录下将toolchains目录整个复制出来,放到D盘根目录下。 + +- 将toolchains目录中的hdc_std.exe文件重命名为hdc.exe,方便后续使用,如下图所示: + + ![配置HDC环境1](../00_src/figures/配置HDC环境1.png) + +- 在环境变量-系统变量-Path中新建一项,值设置为D:\toolchains,之后可以在cmd窗口中直接使用HDC指令: + + ![配置HDC环境2](../00_src/figures/配置HDC环境2.png) + +## 烧录指导 + +参考如下链接进行烧录: + +[https://gitee.com/hihope_iot/docs/blob/master/HiHope_DAYU200/docs/%E7%83%A7%E5%BD%95%E6%8C%87%E5%AF%BC%E6%96%87%E6%A1%A3.md](https://gitee.com/hihope_iot/docs/blob/master/HiHope_DAYU200/docs/烧录指导文档.md) + +## 烧录验证 + +烧录完成后,开发板正常启动进入桌面(若未正常启动,需检查烧录是否失败)。 + +保持USB线仍为连接状态,在PC上开启一个cmd窗口,执行 hdc list targets,可以看到对应设备的序列号,如下图: + +![查看设备序列号](../00_src/figures/查看设备序列号.png) + +接着按下图所示指令执行,可以看到输出libdconnectcaseone.z.so的详细信息,则表示烧录成功: + +![检查样例对应的so](../00_src/figures/检查样例对应的so.png) + +另外,业务程序对应的可执行文件可通过如下方式找到: + +![检查业务demo](../00_src/figures/检查业务demo.png) diff --git a/demo/hihope_rk3568_dconnectcaseone/04_cicuit/readme.md b/demo/hihope_rk3568_dconnectcaseone/04_cicuit/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..7409ea934cff35ca013b56e18e4b8779b23ef2b8 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/04_cicuit/readme.md @@ -0,0 +1,5 @@ +# 开发板硬件介绍 + +rk3568开发板的硬件介绍可参考如下链接: + +https://gitee.com/openharmony/device_board_hihope/blob/master/rk3568/README_zh.md \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/05_other/readme.md b/demo/hihope_rk3568_dconnectcaseone/05_other/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..39abdc3151221394ecf5ca9847d71d03e20aef4f --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/05_other/readme.md @@ -0,0 +1,3 @@ +# 其他说明 + +无 \ No newline at end of file diff --git a/demo/hihope_rk3568_dconnectcaseone/readme.md b/demo/hihope_rk3568_dconnectcaseone/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..33b3c603d3396f38bd983b7e7edecdefdf9f42c0 --- /dev/null +++ b/demo/hihope_rk3568_dconnectcaseone/readme.md @@ -0,0 +1,308 @@ +# 分布式安全通信样例使用指导 + +## 样例介绍 + +本样例基于rk3568开发板,通过封装openharmony安全子系统deviceauth组件提供的能力,实现了一组可用于设备间快速建立可信认证和连接的接口,通过预先定义关系网,在设备初始化阶段完成端端设备间的认证,构建安全的数据传输通道。 + +## 场景介绍 + +本样例可以作为一个SDK集成到设备版本中,供上层业务APP或IOT SDK使用,具体应用场景可参考下图: + +![应用场景](00_src/figures/应用场景.png) + +在智慧隧道场景中,当设备与云端失联时,隧道里面的设备将处于完全失控的状态,因此可以通过openharmony的近端分布式通信能力,实现在云出现异常的情况下设备的自动运行,避免产生二次伤害。例如:隧道内的气体检测仪检测到浓度超标,但是设备与云端失联,导致信息无法及时上传至云,风机的启动指令不能及时下发,导致有毒有害气体无法排出,造成人员伤亡。 + +基于该场景,产生了如下需求:近端设备间实现安全的组网和通信,能够自发进行联动。 + +本样例以rk3568开发板作为载体,实现设备的近端安全互联与通信,可以应用于上述场景,有效解决该场景中存在的问题。 + +![隧道场景](00_src/figures/隧道场景.png) + +样例实现的功能包括: + +- 同局域网设备间的互联 + +- 获取设备预置的PIN码 + +- 基于PIN码和deviceauth模块实现设备互信认证 + +- 点对点设备间数据安全传输 + +本样例可以配合IOT SDK一起使用,IOT SDK主要承担设备注册与PIN码管理的功能,使用者也可以根据自身的实际情况选择用业务APP代替。 + +**IOT SDK源码当前暂未发布到社区**,如有需要可联系 王兵(bing.wang@huawei.com) 获取。 + +## 约束与限制 + +### 特别说明 + +- 本样例仅适用于端端设备间需要保持长连接的场景,除非本端业务主动断开与对端设备的连接,样例本身不会自动超时断开。 + +- 设备间连接断开后,当再次连接时会重新进行设备认证,因此会获得新的会话密钥。 + +- 保持长连接可以保障设备间数据传输的及时性,但也存在一些安全隐患,比如会话密钥不会进行更新,时间太长就存在泄露的风险,如果对该安全风险比较敏感,请勿使用本样例。 + +### 硬件说明 + +通过测试,rk3568开发板在作为服务端时,最多可连接100台客户端,在作为客户端时,最多可连接100台服务端。 + +本样例仅选取两块rk3568开发板进行介绍与演示,其中一块作为服务端,一块作为客户端。 + +## 环境准备 + +### 硬件准备 + +安装windows 10及以上操作系统的PC主机 + +两台rk3568开发板 + +### 构建环境 + +首先需要在PC主机上安装Ubuntu操作系统,以提供基础的编译环境,安装方法可参考:https://developer.huawei.com/consumer/cn/training/course/video/C101639987816176315 + +然后完成Ubuntu基础环境的配置,可参考:https://developer.huawei.com/consumer/cn/training/course/video/C101639988048536240 + +在Ubuntu系统中下载源码前请先执行如下指令安装所需的工具: + +``` +sudo apt-get update && sudo apt-get install binutils git git-lfs gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip m4 bc gnutls-bin python3.8 python3-pip ruby genext2fs liblz4-tool libssl-dev libtinfo-dev libtinfo5 openjdk-17-jre-headless libc6 libstdc++6 default-jdk u-boot-tools mtools mtd-utils scons gcc-arm-linux-gnueabi +``` + +该样例适配的源码版本为:Openharmony-3.1-Release,请确保下载代码时分支选择正确。 + +源码获取方式可参考开源社区文档 http://www.openharmony.cn/download ,选择第一种获取方式,并使用以下命令替换文档中的下载命令: + +``` +repo init -u https://gitee.com/openharmony/manifest.git -b refs/tags/OpenHarmony-v3.1-Release --no-repo-verify +repo sync -c +repo forall -c 'git lfs pull' +``` + +### 编译验证 + +下载源码后,需要先编译rk3568版本通过,以确保编译环境正常可用。 + +切换到源码根目录,执行如下命令,安装编译器及二进制工具: + +``` +bash build/prebuilts_download.sh +``` + +接着执行如下命令进行版本编译: + +``` +./build.sh --product-name rk3568 --ccache +``` + +编译完成后,日志中显示如下,则表示编译成功: + +``` +=====build rk3568 successful. +``` + +编译生成的镜像文件在 out/rk3568/packages/phone/images/ 目录下。 + +## 集成样例 + +### 样例源码介绍 + +样例源码存放在00_src目录下,各个目录中的文件功能如下表: + +| 目录 | 功能说明 | +| --------------- | ------------------------------------------------------------ | +| dconnectcaseone | 基于openharmony安全子系统deviceauth组件开发的分布式安全通信样例,可用于多个设备间基于预先定义的关系网完成可信认证与连接,构建安全的数据传输通道 | +| test | 用于验证样例功能可用的业务程序示例代码,使用者可以参考该代码定制自己的业务程序 | +| figures | 用于存放readme文件中的图片资源 | + +### 修改社区源码 + +基于rk3568设备集成编译该样例时,需要按照如下步骤修改源码(+表示增加行,-表示删除行): + +- 修改base/security/deviceauth/common_lib/impl/src/clib_types.c文件内容: + + ```c + void *ClibMalloc(uint32_t size, char val) + { + - if (size == 0 || size > CLIB_MAX_MALLOC_SIZE) { + + if (size == 0) { + return NULL; + } + void* addr = malloc(size); + ``` + +- 修改base/security/deviceauth/common_lib/interfaces/clib_types.h文件内容: + + ```c + #define NULL 0 + #endif + + -#define CLIB_MAX_MALLOC_SIZE 4096 /* 4K */ + - + #ifdef __cplusplus + extern "C" { + #endif + ``` + +- 修改build/prebuilts_download.sh文件内容: + + ``` + -node_js_ver=v12.18.4 + +node_js_ver='v12.18.4' + node_js_name=node-${node_js_ver}-${host_platform}-x64 + node_js_pkg=${node_js_name}.tar.gz + ``` + +- 修改third_party/jsframework/package.json文件内容: + + ``` + "sinon": "^9.2.2", + "ts-node": "^9.0.0", + "tslib": "^2.0.3", + - "typescript": "^4.1.2" + + "typescript": "4.1.3" + } + } + ``` + +接着按照如下流程将样例集成到rk3568产品版本中: + +- 在社区源码的vendor目录下新建目录kits,并将00_src目录下的所有文件放到kits目录下。 + +- 修改build/subsystem_config.json文件,增加如下内容,新增一个subsystem: + + ``` + "kits": { + "path": "vendor/kits", + "name": "kits" + }, + ``` + +- 修改productdefine/common/products/rk3568.json文件,在parts中新增kits中的两个部件: + + ``` + "type": "standard", + "product_build_path": "device/hihope/build", + "parts":{ + "kits:dconnectcaseone":{}, + "kits:test":{}, + "ace:ace_engine_standard":{}, + ``` + +### 编译镜像 + +切换到源码根目录,执行如下命令,进行编译构建: + +``` +./build.sh --product-name rk3568 --ccache +``` + +编译成功后,在 /out/rk3568 目录中通过如下指令检查是否包含本样例: + +``` +find ./out/rk3568 -name "libdconnectcaseone.z.so" +``` + +通过如下指令检查是否包含测试用业务程序: + +``` +find ./out/rk3568/kits -name "demo" +``` + +如果找不到样例对应的so文件,请检查00_src目录下的文件是否全部放到了kits目录下(请注意:ohos.build文件也是必需的)。 + +## 烧录镜像 + +### 环境准备 + +从 out/rk3568/packages/phone/images/ 目录下复制编译成功的rk3568镜像文件到PC的windows环境中。 + +然后按照如下流程配置PC的HDC环境: + +- 切换到Ubuntu环境中的源码根目录,执行如下命令,编译ohos-sdk包: + + ``` + ./build.sh --product-name ohos-sdk --ccache + ``` + +- 编译完成后,从out/sdk/ohos-sdk/windows/ 目录下将toolchains目录整个复制出来,放到D盘根目录下。 + +- 将toolchains目录中的hdc_std.exe文件重命名为hdc.exe,方便后续使用,如下图所示: + + ![配置HDC环境1](00_src/figures/配置HDC环境1.png) + +- 在环境变量-系统变量-Path中新建一项,值设置为D:\toolchains,之后可以在cmd窗口中直接使用HDC指令: + + ![配置HDC环境2](00_src/figures/配置HDC环境2.png) + +### 烧录指导 + +请参考如下链接进行烧录: + +[https://gitee.com/hihope_iot/docs/blob/master/HiHope_DAYU200/docs/%E7%83%A7%E5%BD%95%E6%8C%87%E5%AF%BC%E6%96%87%E6%A1%A3.md](https://gitee.com/hihope_iot/docs/blob/master/HiHope_DAYU200/docs/烧录指导文档.md) + +### 烧录验证 + +烧录完成后,开发板正常启动进入桌面(若未正常启动,需检查烧录是否失败)。 + +保持USB线仍为连接状态,在PC上开启一个cmd窗口,执行 hdc list targets,可以看到对应设备的序列号,如下图: + +![查看设备序列号](00_src/figures/查看设备序列号.png) + +接着按下图所示指令执行,可以看到输出libdconnectcaseone.z.so的详细信息,则表示烧录成功: + +![检查样例对应的so](00_src/figures/检查样例对应的so.png) + +另外,业务程序对应的可执行文件可通过如下方式找到: + +![检查业务demo](00_src/figures/检查业务demo.png) + +## 使用说明 + +开发板烧录镜像完成后,可以通过HDC指令进入设备的shell界面,切换到/system/bin目录下,通过ls -l demo指令可以看到可执行文件demo,就是我们的测试用业务程序。 + +将两台设备连接网络,通过ifconfig指令查看设备的IP地址,按照下图所示的操作将其中一台设备初始化为服务端,另一台初始化为客户端,在执行客户端初始化时两端设备会自动进行绑定和认证,可以新开一个shell窗口查看认证过程中的日志。 + +服务端初始化(上边为初始化操作指令,下边为样例打印的日志): + +![服务端初始化](00_src/figures/服务端初始化.png) + +客户端初始化(上边为初始化操作指令,下边为样例打印的日志): + +![客户端初始化](00_src/figures/客户端初始化.png) + +可信认证(左侧为服务端,右侧为客户端,认证会在初始化客户端时自动触发): + +![可信认证](00_src/figures/可信认证.png) + +收发数据(左侧为服务端,右侧为客户端): + +![收发数据](00_src/figures/收发数据.png) + +## 接口列表 + +本样例将枚举及宏定义、回调函数、对外接口的定义内容放置于下面的头文件中: + +dconnectcaseone/interface/include/dconncaseone_interface.h + +### 回调函数 + +| 接口名 | 描述 | +| ------------------------------------------------------------ | ------------------------------------------------ | +| typedef void (*SendDataCallback)(const char *device, uint32_t result) | 数据发送回调函数 | +| typedef void (*ReceiveDataCallback)(const char *deviceId, const char *receiveData, uint32_t datelen) | 数据接收回调函数 | +| typedef bool (*IsValidIP)(const char *ip) | 校验当前连接服务端的
客户端IP地址是否合法 | +| typedef bool (*IsValidDeviceID)(const char *deviceID) | 校验当前连接服务端的
客户端的设备ID是否合法 | +| typedef char *( *GetAuthKey)(const char *targetDeviceID) | 获取对应设备的PIN码 | +| typedef char *( *GetDeviceID)() | 获取本设备ID | + +### 样例接口 + +| 接口名 | 描述 | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| DCONN_API_PUBLIC uint32_t InitDConnCaseOne(uint32_t type, const char *ipAry, char *errorIp); | 初始化样例。初始化类型:INIT_SERVICE/INIT_CLIENT
ipAry:IP地址字符串
初始化服务端时仅可传入一个 IP 地址
初始化客户端时可传入多个,以半角逗号分隔 | +| DCONN_API_PUBLIC void RegisterCallback(const CallbackParam *callback); | 注册回调函数 | +| DCONN_API_PUBLIC uint32_t DConnSendData(const char *targetDeviceId, const char *data, uint32_t dataLen); | 发送数据 | +| DCONN_API_PUBLIC void UnRegisterCallback(); | 取消注册回调函数 | +| DCONN_API_PUBLIC void CloseDConnCaseOne(); | 关闭样例 | +| DCONN_API_PUBLIC const char *GetDConnVersion(); | 获取样例版本号 | +