diff --git a/frameworks/ets/ani/connection/BUILD.gn b/frameworks/ets/ani/connection/BUILD.gn index d2c8426155fd7322216d321d31b02ede6547cafb..46bf7f864e743771595751a8d494f41fa5945f6b 100644 --- a/frameworks/ets/ani/connection/BUILD.gn +++ b/frameworks/ets/ani/connection/BUILD.gn @@ -69,6 +69,7 @@ ohos_rust_shared_library("connection_ani") { external_deps = [ "runtime_core:ani", "hilog:hilog_rust", + "hilog:libhilog", "ipc:ipc_rust", ] diff --git a/frameworks/ets/ani/connection/ets/@ohos.net.connection.ets b/frameworks/ets/ani/connection/ets/@ohos.net.connection.ets index 07da3a1620beef0c7faf34deae11d0984a192684..d5a4fbc70c22924a22d38e0b6bbe49e6351e1a0c 100644 --- a/frameworks/ets/ani/connection/ets/@ohos.net.connection.ets +++ b/frameworks/ets/ani/connection/ets/@ohos.net.connection.ets @@ -300,14 +300,14 @@ export default namespace connection { export native function reportNetDisconnectedSync(netHandle: NetHandle): void; - export function getAddressesByName(host: string, callback: AsyncCallback>): void{ + export function getAddressesByName(host: string, callback: AsyncCallback>): void { let p1 = taskpool.execute((): Array => { return getAddressesByNameSync(host); }) p1.then((content: NullishType) => { callback(new BusinessError(), content as Array); }, (err: Error): void => { - callback(err as BusinessError, new Array); + callback(err as BusinessError, undefined); }); } @@ -640,9 +640,9 @@ export default namespace connection { // bindSocket(socketParam: TCPSocket | UDPSocket): Promise; - // getAddressesByName(host: string, callback: AsyncCallback>): void; + getAddressesByName(host: string, callback: AsyncCallback>): void; - // getAddressesByName(host: string): Promise>; + getAddressesByName(host: string): Promise>; getAddressByName(host: string, callback: AsyncCallback): void; @@ -653,11 +653,11 @@ export default namespace connection { netId: int; static { loadLibrary("connection_ani") } - native getAddressByNameSync(host:string): NetAddress; + native getAddressByNameSyncWithHandle(host:string): NetAddress; getAddressByName(host: string, callback: AsyncCallback): void { let p1 = taskpool.execute((): NetAddress => { - return this.getAddressByNameSync(host); + return this.getAddressByNameSyncWithHandle(host); }) p1.then((content: NullishType) => { callback(new BusinessError(), content as NetAddress); @@ -669,13 +669,38 @@ export default namespace connection { getAddressByName(host: string): Promise { return new Promise((resolve, reject) => { taskpool.execute((): NetAddress => { - return this.getAddressByNameSync(host); + return this.getAddressByNameSyncWithHandle(host); }).then((content: NullishType) => { resolve(content as NetAddress); }, (err: Error): void => { reject(err as BusinessError); }); - }); + }); + } + + native getAddressesByNameSyncWithHandle(host:string): Array; + + getAddressesByName(host: string, callback: AsyncCallback>): void { + let p1 = taskpool.execute((): Array => { + return this.getAddressesByNameSyncWithHandle(host); + }) + p1.then((content: NullishType) => { + callback(new BusinessError(), content as Array); + }, (err: Error): void => { + callback(err as BusinessError, undefined); + }); + } + + getAddressesByName(host: string): Promise> { + return new Promise>((resolve, reject) => { + taskpool.execute((): Array => { + return this.getAddressesByNameSyncWithHandle(host); + }).then((content: NullishType) => { + resolve(content as Array); + }, (err: Error): void => { + reject(err as BusinessError); + }); + }); } } diff --git a/frameworks/ets/ani/connection/include/connection_ani.h b/frameworks/ets/ani/connection/include/connection_ani.h index d863669b5ef4264c695d9bc0df64478e41d16edf..9ab872401c544fe62e743baf4a197276d6faa7da 100644 --- a/frameworks/ets/ani/connection/include/connection_ani.h +++ b/frameworks/ets/ani/connection/include/connection_ani.h @@ -38,6 +38,17 @@ struct NetBlockStatusInfo; struct NetCapabilityInfo; struct NetConnectionPropertyInfo; +static constexpr size_t MAX_IPV4_STR_LEN = 16; +static constexpr size_t MAX_IPV6_STR_LEN = 64; +static constexpr int32_t NO_PERMISSION_CODE = 1; +static constexpr int32_t PERMISSION_DENIED_CODE = 13; +static constexpr int32_t NET_UNREACHABLE_CODE = 101; + +enum Family { + IPv4 = 1, + IPv6 = 2, +}; + NetHandle GetDefaultNetHandle(int32_t &ret); rust::vec GetAllNets(int32_t &ret); diff --git a/frameworks/ets/ani/connection/src/connection.rs b/frameworks/ets/ani/connection/src/connection.rs index 2269c28f74ff2e7a8706947d9d6293e271f88341..6bb7cd057c6ed56add0eaefcafe84c4e8353ca98 100644 --- a/frameworks/ets/ani/connection/src/connection.rs +++ b/frameworks/ets/ani/connection/src/connection.rs @@ -113,19 +113,25 @@ pub(crate) fn get_connection_properties( #[ani_rs::native] pub(crate) fn get_addresses_by_name(host: String) -> Result, BusinessError> { - let net_handle = NetConnClient::get_default_net_handle().map_err(convert_to_business_error)?; - NetConnClient::get_addresses_by_name(&host, net_handle.net_id) - .map_err(convert_to_business_error) + NetConnClient::get_addresses_by_name(&host, 0).map_err(convert_to_business_error) } #[ani_rs::native] -pub(crate) fn get_address_by_name( +pub(crate) fn get_address_by_name_with_handle( this: NetHandle, host: String, ) -> Result { NetConnClient::get_address_by_name(&host, this.net_id).map_err(convert_to_business_error) } +#[ani_rs::native] +pub(crate) fn get_addresses_by_name_with_handle( + this: NetHandle, + host: String, +) -> Result, BusinessError> { + NetConnClient::get_addresses_by_name(&host, this.net_id).map_err(convert_to_business_error) +} + #[ani_rs::native] pub(crate) fn set_global_http_proxy(proxy: HttpProxy) -> Result<(), BusinessError> { NetConnClient::set_global_http_proxy(proxy).map_err(convert_to_business_error) diff --git a/frameworks/ets/ani/connection/src/cxx/connection_ani.cpp b/frameworks/ets/ani/connection/src/cxx/connection_ani.cpp index 368ce0adea21486099e8ca1f58041bf676cb0042..472057fdd50aa7d98d43e9c238d0065dff5a3e6a 100644 --- a/frameworks/ets/ani/connection/src/cxx/connection_ani.cpp +++ b/frameworks/ets/ani/connection/src/cxx/connection_ani.cpp @@ -13,6 +13,10 @@ * limitations under the License. */ +#include +#include +#include +#include #include "connection_ani.h" #include "access_token.h" #include "accesstoken_kit.h" @@ -27,9 +31,9 @@ #include "tokenid_kit.h" #include "wrapper.rs.h" #include "net_manager_constants.h" +#include "netmanager_base_log.h" #include "errorcode_convertor.h" -#include -#include + namespace OHOS { namespace NetManagerAni { using namespace Security::AccessToken; @@ -248,38 +252,119 @@ ConnectionProperties GetConnectionProperties(int32_t net_id, int32_t &ret) return ConvertConnectionProperties(info); } +static int32_t TransErrorCode(int32_t error) +{ + switch (error) { + case NO_PERMISSION_CODE: + return NetManagerStandard::NETMANAGER_ERR_PERMISSION_DENIED; + case PERMISSION_DENIED_CODE: + return NetManagerStandard::NETMANAGER_ERR_PERMISSION_DENIED; + case NET_UNREACHABLE_CODE: + return NetManagerStandard::NETMANAGER_ERR_INTERNAL; + default: + return NetManagerStandard::NETMANAGER_ERR_OPERATION_FAILED; + } +} + +static void SetAddressInfo(const std::string &host, addrinfo *info, NetAddress &address) +{ + address.address = rust::String(host); + if (info->ai_addr->sa_family == AF_INET) { + address.family = Family::IPv4; + auto addr4 = reinterpret_cast(info->ai_addr); + address.port = addr4->sin_port; + } else if (info->ai_addr->sa_family == AF_INET6) { + address.family = Family::IPv6; + auto addr6 = reinterpret_cast(info->ai_addr); + address.port = addr6->sin6_port; + } +} + rust::vec GetAddressesByName(const std::string &host, int32_t netId, int32_t &ret) { - std::vector addrList; + addrinfo *res = nullptr; + queryparam param; + param.qp_type = QEURY_TYPE_NORMAL; + param.qp_netid = netId; rust::vec addresses; - ret = NetManagerStandard::NetConnClient::GetInstance().GetAddressesByName(host, netId, addrList); - if (ret != 0) { + if (host.empty()) { + NETMANAGER_BASE_LOGE("host is empty!"); + ret = NetManagerStandard::NETMANAGER_ERR_INVALID_PARAMETER; return addresses; } - for (const auto &addr : addrList) { - NetAddress address{ - .address = addr.address_, - .family = addr.family_, - .port = addr.port_, - }; + int status = getaddrinfo_ext(host.c_str(), nullptr, nullptr, &res, ¶m); + if (status < 0) { + NETMANAGER_BASE_LOGE("getaddrinfo errno %{public}d %{public}s, status: %{public}d", errno, strerror(errno), + status); + ret = TransErrorCode(errno); + return addresses; + } + + for (addrinfo *tmp = res; tmp != nullptr; tmp = tmp->ai_next) { + std::string addrHost; + if (tmp->ai_family == AF_INET) { + auto addr = reinterpret_cast(tmp->ai_addr); + char ip[MAX_IPV4_STR_LEN] = {0}; + inet_ntop(AF_INET, &addr->sin_addr, ip, sizeof(ip)); + addrHost = ip; + } else if (tmp->ai_family == AF_INET6) { + auto addr = reinterpret_cast(tmp->ai_addr); + char ip[MAX_IPV6_STR_LEN] = {0}; + inet_ntop(AF_INET6, &addr->sin6_addr, ip, sizeof(ip)); + addrHost = ip; + } + + NetAddress address; + SetAddressInfo(addrHost, tmp, address); addresses.push_back(address); } + freeaddrinfo(res); return addresses; } NetAddress GetAddressByName(const std::string &host, int32_t netId, int32_t &ret) { - NetManagerStandard::INetAddr addr; - ret = NetManagerStandard::NetConnClient::GetInstance().GetAddressByName(host, netId, addr); - if (ret != 0) { + addrinfo *res = nullptr; + queryparam param; + param.qp_type = QEURY_TYPE_NORMAL; + param.qp_netid = netId; + if (host.empty()) { + NETMANAGER_BASE_LOGE("host is empty!"); + ret = NetManagerStandard::NETMANAGER_ERR_INVALID_PARAMETER; return NetAddress{}; } - return NetAddress{ - .address = addr.address_, - .family = addr.family_, - .port = addr.port_, - }; + + int status = getaddrinfo_ext(host.c_str(), nullptr, nullptr, &res, ¶m); + if (status < 0) { + NETMANAGER_BASE_LOGE("getaddrinfo errno %{public}d %{public}s, status: %{public}d", errno, strerror(errno), + status); + ret = TransErrorCode(errno); + return NetAddress{}; + } + if (res == nullptr) { + NETMANAGER_BASE_LOGE("addrinfo is nullptr!"); + return NetAddress{}; + } + + std::string addrHost; + if (res->ai_family == AF_INET) { + auto addr = reinterpret_cast(res->ai_addr); + char ip[MAX_IPV4_STR_LEN] = {0}; + inet_ntop(AF_INET, &addr->sin_addr, ip, sizeof(ip)); + addrHost = ip; + } else if (res->ai_family == AF_INET6) { + auto addr = reinterpret_cast(res->ai_addr); + char ip[MAX_IPV6_STR_LEN] = {0}; + inet_ntop(AF_INET6, &addr->sin6_addr, ip, sizeof(ip)); + addrHost = ip; + } + + NetAddress address; + SetAddressInfo(addrHost, res, address); + + freeaddrinfo(res); + return address; } void NetDetection(int32_t netId, int32_t &ret) diff --git a/frameworks/ets/ani/connection/src/lib.rs b/frameworks/ets/ani/connection/src/lib.rs index 05813a34062e8e21519bf96ba21a9d7adae3b710..328dcccd9c366d2911514db729edfae3e0eca673 100644 --- a/frameworks/ets/ani/connection/src/lib.rs +++ b/frameworks/ets/ani/connection/src/lib.rs @@ -16,6 +16,7 @@ mod bridge; mod connection; mod error_code; +mod log; pub mod wrapper; use ani_rs::ani_constructor; @@ -50,7 +51,8 @@ ani_constructor!( ] class "L@ohos/net/connection/connection/NetHandleInner" [ - "getAddressByNameSync" : connection::get_address_by_name, + "getAddressByNameSyncWithHandle" : connection::get_address_by_name_with_handle, + "getAddressesByNameSyncWithHandle": connection::get_addresses_by_name_with_handle, ] class "L@ohos/net/connection/connection/NetConnectionInner" [ @@ -68,3 +70,21 @@ ani_constructor!( "clean" : connection::connection_clean, ] ); + +const LOG_LABEL: hilog_rust::HiLogLabel = hilog_rust::HiLogLabel { + log_type: hilog_rust::LogType::LogCore, + domain: 0xD0015B0, + tag: "NetMgrSubSystem", +}; + +#[used] +#[link_section = ".init_array"] +static G_CONNECTION_PANIC_HOOK: extern "C" fn() = { + #[link_section = ".text.startup"] + extern "C" fn init() { + std::panic::set_hook(Box::new(|info| { + connection_error!("Panic occurred: {:?}", info); + })); + } + init +}; diff --git a/frameworks/ets/ani/connection/src/log.rs b/frameworks/ets/ani/connection/src/log.rs new file mode 100644 index 0000000000000000000000000000000000000000..782633eb04083127978e5df2195086b401ada43f --- /dev/null +++ b/frameworks/ets/ani/connection/src/log.rs @@ -0,0 +1,43 @@ +// Copyright (C) 2025 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. + +#[macro_export] +macro_rules! connection_debug { + ($fmt: literal $(, $args:expr)* $(,)?) => {{ + use hilog_rust::hilog; + use std::ffi::{c_char, CString}; + use crate::LOG_LABEL; + hilog_rust::debug!(LOG_LABEL, $fmt $(, @public($args))*); + }} +} + +#[macro_export] +macro_rules! connection_info { + ($fmt: literal $(, $args:expr)* $(,)?) => {{ + use hilog_rust::hilog; + use std::ffi::{c_char, CString}; + use crate::LOG_LABEL; + + hilog_rust::info!(LOG_LABEL, $fmt $(, @public($args))*); + }} +} +#[macro_export] +macro_rules! connection_error { + ($fmt: literal $(, $args:expr)* $(,)?) => {{ + use hilog_rust::hilog; + use std::ffi::{c_char, CString}; + use crate::LOG_LABEL; + + hilog_rust::error!(LOG_LABEL, $fmt $(, @public($args))*); + }} +} \ No newline at end of file