From 357c68630679323bb8aab64df6de4583873c77eb Mon Sep 17 00:00:00 2001 From: zhf Date: Sat, 18 Dec 2021 10:58:48 +0800 Subject: [PATCH] zhanghaifeng11@huawei.com Signed-off-by: zhf --- LICENSE | 177 ++++++ README.en.md | 2 +- README.md | 112 +++- figures/net_conn_manager_arch_zh.png | Bin 0 -> 18703 bytes figures/net_manager_arch_zh.png | Bin 0 -> 41997 bytes figures/net_policy_manager_arch_zh.png | Bin 0 -> 24591 bytes figures/net_stats_manager_arch_zh.png | Bin 0 -> 28642 bytes .../dnsresolvermanager/src/dns_addr_info.cpp | 67 +++ .../src/dns_resolver_client.cpp | 154 +++++ .../ethernetmanager/src/ethernet_client.cpp | 120 ++++ .../src/interface_configuration.cpp | 53 ++ .../src/static_configuration.cpp | 105 ++++ .../netconnmanager/src/inet_addr.cpp | 136 +++++ .../src/ipc/net_conn_callback_stub.cpp | 67 +++ .../src/net_conn_callback_info.cpp | 91 +++ .../netconnmanager/src/net_conn_client.cpp | 183 ++++++ .../netconnmanager/src/net_link_info.cpp | 207 +++++++ .../netconnmanager/src/net_specifier.cpp | 98 ++++ .../netconnmanager/src/net_supplier_info.cpp | 113 ++++ .../netconnmanager/src/route.cpp | 117 ++++ .../src/net_policy_client.cpp | 136 +++++ frameworks/js/common/napi_common.cpp | 72 +++ frameworks/js/common/napi_common.h | 70 +++ frameworks/js/dnsresolver/BUILD.gn | 57 ++ .../dnsresolver/include/napi_dns_resolver.h | 52 ++ .../js/dnsresolver/src/napi_dns_resolver.cpp | 158 +++++ frameworks/js/ethernet/BUILD.gn | 62 ++ .../js/ethernet/include/napi_ethernet.h | 86 +++ frameworks/js/ethernet/src/napi_ethernet.cpp | 470 +++++++++++++++ frameworks/js/netpolicy/BUILD.gn | 55 ++ .../js/netpolicy/include/napi_net_policy.h | 73 +++ .../js/netpolicy/src/napi_net_policy.cpp | 442 ++++++++++++++ .../native/dnsresolvermanager/BUILD.gn | 77 +++ .../include/dns_addr_info.h | 39 ++ .../include/dns_resolver_client.h | 123 ++++ .../include/dns_resolver_constants.h | 27 + .../innerkits/native/ethernetmanager/BUILD.gn | 80 +++ .../ethernetmanager/include/ethernet_client.h | 86 +++ .../include/ethernet_constants.h | 27 + .../include/interface_configuration.h | 36 ++ .../include/static_configuration.h | 40 ++ .../native/include/netmanager_constants.h | 67 +++ .../innerkits/native/netconnmanager/BUILD.gn | 83 +++ .../native/netconnmanager/include/inet_addr.h | 48 ++ .../include/ipc/i_net_conn_callback.h | 41 ++ .../include/ipc/net_conn_callback_stub.h | 46 ++ .../include/net_conn_callback_info.h | 36 ++ .../netconnmanager/include/net_conn_client.h | 71 +++ .../include/net_conn_constants.h | 34 ++ .../netconnmanager/include/net_link_info.h | 42 ++ .../netconnmanager/include/net_specifier.h | 56 ++ .../include/net_supplier_info.h | 38 ++ .../native/netconnmanager/include/route.h | 39 ++ .../native/netpolicymanager/BUILD.gn | 75 +++ .../include/net_policy_client.h | 61 ++ .../include/net_policy_constants.h | 38 ++ netmanager_base_config.gni | 32 ++ ohos.build | 62 ++ prebuilts/librarys/netd/BUILD.gn | 36 ++ .../netd/arm/libnet_manager_native.z.so | Bin 0 -> 194960 bytes .../netd/arm64/libnet_manager_native.z.so | Bin 0 -> 269728 bytes .../include/common/include/blocking_queue.h | 76 +++ .../netd/include/common/include/job.h | 39 ++ .../netd/include/common/include/net_utils.h | 539 ++++++++++++++++++ .../include/common/include/server_socket.h | 37 ++ .../include/common/include/server_template.h | 54 ++ .../netd/include/common/include/socket_base.h | 76 +++ .../netd/include/common/include/thread_pool.h | 57 ++ .../include/common/include/warning_disable.h | 46 ++ .../net_mgr_native/include/dnsresolv.h | 218 +++++++ .../include/dnsresolv_controller.h | 46 ++ .../include/dnsresolv_service.h | 79 +++ .../net_mgr_native/include/event_reporter.h | 48 ++ .../net_mgr_native/include/fwmark_server.h | 53 ++ .../include/interface_controller.h | 67 +++ .../include/net_manager_native.h | 127 +++++ .../net_mgr_native/include/netlink_event.h | 75 +++ .../net_mgr_native/include/netlink_handler.h | 59 ++ .../net_mgr_native/include/netlink_listener.h | 44 ++ .../net_mgr_native/include/netlink_manager.h | 72 +++ .../net_mgr_native/include/netlink_socket.h | 79 +++ .../include/netnative_log_wrapper.h | 40 ++ .../include/network_controller.h | 64 +++ .../net_mgr_native/include/nmd_network.h | 73 +++ .../net_mgr_native/include/route_controller.h | 62 ++ .../include/traffic_controller.h | 89 +++ sa_profile/1151.xml | 27 + sa_profile/1152.xml | 27 + sa_profile/1156.xml | 27 + sa_profile/1157.xml | 27 + sa_profile/BUILD.gn | 25 + services/common/include/broadcast_manager.h | 49 ++ services/common/include/netd_controller.h | 243 ++++++++ services/common/include/timer.h | 97 ++++ services/common/src/broadcast_manager.cpp | 75 +++ services/common/src/netd_controller.cpp | 430 ++++++++++++++ services/dnsresolvermanager/BUILD.gn | 69 +++ .../include/dns_resolver_service.h | 61 ++ .../include/ipc/dns_resolver_service_proxy.h | 47 ++ .../include/ipc/dns_resolver_service_stub.h | 47 ++ .../include/ipc/i_dns_resolver_service.h | 57 ++ .../src/dns_resolver_service.cpp | 253 ++++++++ .../src/ipc/dns_resolver_service_proxy.cpp | 294 ++++++++++ .../src/ipc/dns_resolver_service_stub.cpp | 242 ++++++++ services/dnsresolvermanager/test/BUILD.gn | 20 + .../dns_resolver_manager_test/BUILD.gn | 63 ++ .../dns_resolver_manager_test.cpp | 170 ++++++ services/etc/init/BUILD.gn | 39 ++ services/etc/init/netd.cfg | 10 + services/etc/init/netd.rc | 19 + services/etc/init/netmanager_base.cfg | 17 + services/etc/init/netmanager_base.rc | 19 + services/ethernetmanager/BUILD.gn | 76 +++ .../include/dev_interface_state.h | 86 +++ .../include/ethernet_management.h | 70 +++ .../include/ethernet_service.h | 57 ++ .../include/ipc/ethernet_service_proxy.h | 42 ++ .../include/ipc/ethernet_service_stub.h | 46 ++ .../include/ipc/i_ethernet_service.h | 48 ++ .../ethernetmanager/include/netLink_rtnl.h | 67 +++ .../include/nlk_event_handle.h | 36 ++ .../src/dev_interface_state.cpp | 263 +++++++++ .../src/ethernet_management.cpp | 222 ++++++++ .../ethernetmanager/src/ethernet_service.cpp | 114 ++++ .../src/ipc/ethernet_service_proxy.cpp | 150 +++++ .../src/ipc/ethernet_service_stub.cpp | 122 ++++ services/ethernetmanager/src/netLink_rtnl.cpp | 342 +++++++++++ services/ethernetmanager/test/BUILD.gn | 20 + .../unittest/ethernet_manager_test/BUILD.gn | 63 ++ .../ethernet_manager_test.cpp | 135 +++++ services/netconnmanager/BUILD.gn | 77 +++ .../include/ipc/i_net_conn_service.h | 65 +++ .../include/ipc/net_conn_callback_proxy.h | 41 ++ .../include/ipc/net_conn_service_proxy.h | 50 ++ .../include/ipc/net_conn_service_stub.h | 58 ++ .../netconnmanager/include/net_conn_service.h | 176 ++++++ .../netconnmanager/include/net_conn_types.h | 46 ++ .../include/net_controller/i_net_controller.h | 31 + .../net_controller/net_controller_factory.h | 35 ++ .../net_controller/telephony_controller.h | 52 ++ .../netconnmanager/include/net_id_manager.h | 46 ++ services/netconnmanager/include/net_service.h | 110 ++++ .../netconnmanager/include/net_supplier.h | 59 ++ services/netconnmanager/include/network.h | 69 +++ .../src/ipc/net_conn_callback_proxy.cpp | 64 +++ .../src/ipc/net_conn_service_proxy.cpp | 352 ++++++++++++ .../src/ipc/net_conn_service_stub.cpp | 285 +++++++++ .../netconnmanager/src/net_conn_service.cpp | 494 ++++++++++++++++ .../net_controller/net_controller_factory.cpp | 57 ++ .../net_controller/telephony_controller.cpp | 36 ++ .../netconnmanager/src/net_id_manager.cpp | 50 ++ services/netconnmanager/src/net_service.cpp | 301 ++++++++++ services/netconnmanager/src/net_supplier.cpp | 136 +++++ services/netconnmanager/src/network.cpp | 224 ++++++++ services/netconnmanager/test/BUILD.gn | 20 + services/netconnmanager/test/mock/BUILD.gn | 13 + .../unittest/net_conn_manager_test/BUILD.gn | 70 +++ .../net_conn_callback_test.cpp | 56 ++ .../net_conn_callback_test.h | 47 ++ .../net_conn_manager_test.cpp | 258 +++++++++ services/netpolicymanager/BUILD.gn | 69 +++ .../include/ipc/i_net_policy_service.h | 46 ++ .../include/ipc/net_policy_service_proxy.h | 44 ++ .../include/ipc/net_policy_service_stub.h | 50 ++ .../include/net_policy_define.h | 44 ++ .../include/net_policy_file.h | 65 +++ .../include/net_policy_service.h | 69 +++ .../include/net_policy_traffic.h | 41 ++ .../src/ipc/net_policy_service_proxy.cpp | 202 +++++++ .../src/ipc/net_policy_service_stub.cpp | 140 +++++ .../netpolicymanager/src/net_policy_file.cpp | 223 ++++++++ .../src/net_policy_service.cpp | 146 +++++ .../src/net_policy_traffic.cpp | 109 ++++ services/netpolicymanager/test/BUILD.gn | 20 + .../unittest/net_policy_manager_test/BUILD.gn | 64 +++ .../net_policy_manager_test.cpp | 103 ++++ utils/BUILD.gn | 60 ++ utils/log/include/net_mgr_log_wrapper.h | 73 +++ utils/log/src/net_mgr_log_wrapper.cpp | 47 ++ 179 files changed, 16571 insertions(+), 29 deletions(-) create mode 100755 LICENSE mode change 100644 => 100755 README.en.md mode change 100644 => 100755 README.md create mode 100755 figures/net_conn_manager_arch_zh.png create mode 100755 figures/net_manager_arch_zh.png create mode 100755 figures/net_policy_manager_arch_zh.png create mode 100755 figures/net_stats_manager_arch_zh.png create mode 100755 frameworks/innerkitsimpl/dnsresolvermanager/src/dns_addr_info.cpp create mode 100755 frameworks/innerkitsimpl/dnsresolvermanager/src/dns_resolver_client.cpp create mode 100755 frameworks/innerkitsimpl/ethernetmanager/src/ethernet_client.cpp create mode 100755 frameworks/innerkitsimpl/ethernetmanager/src/interface_configuration.cpp create mode 100755 frameworks/innerkitsimpl/ethernetmanager/src/static_configuration.cpp create mode 100755 frameworks/innerkitsimpl/netconnmanager/src/inet_addr.cpp create mode 100755 frameworks/innerkitsimpl/netconnmanager/src/ipc/net_conn_callback_stub.cpp create mode 100755 frameworks/innerkitsimpl/netconnmanager/src/net_conn_callback_info.cpp create mode 100755 frameworks/innerkitsimpl/netconnmanager/src/net_conn_client.cpp create mode 100755 frameworks/innerkitsimpl/netconnmanager/src/net_link_info.cpp create mode 100755 frameworks/innerkitsimpl/netconnmanager/src/net_specifier.cpp create mode 100755 frameworks/innerkitsimpl/netconnmanager/src/net_supplier_info.cpp create mode 100755 frameworks/innerkitsimpl/netconnmanager/src/route.cpp create mode 100755 frameworks/innerkitsimpl/netpolicymanager/src/net_policy_client.cpp create mode 100755 frameworks/js/common/napi_common.cpp create mode 100755 frameworks/js/common/napi_common.h create mode 100755 frameworks/js/dnsresolver/BUILD.gn create mode 100755 frameworks/js/dnsresolver/include/napi_dns_resolver.h create mode 100755 frameworks/js/dnsresolver/src/napi_dns_resolver.cpp create mode 100755 frameworks/js/ethernet/BUILD.gn create mode 100755 frameworks/js/ethernet/include/napi_ethernet.h create mode 100755 frameworks/js/ethernet/src/napi_ethernet.cpp create mode 100755 frameworks/js/netpolicy/BUILD.gn create mode 100755 frameworks/js/netpolicy/include/napi_net_policy.h create mode 100755 frameworks/js/netpolicy/src/napi_net_policy.cpp create mode 100755 interfaces/innerkits/native/dnsresolvermanager/BUILD.gn create mode 100755 interfaces/innerkits/native/dnsresolvermanager/include/dns_addr_info.h create mode 100755 interfaces/innerkits/native/dnsresolvermanager/include/dns_resolver_client.h create mode 100755 interfaces/innerkits/native/dnsresolvermanager/include/dns_resolver_constants.h create mode 100755 interfaces/innerkits/native/ethernetmanager/BUILD.gn create mode 100755 interfaces/innerkits/native/ethernetmanager/include/ethernet_client.h create mode 100755 interfaces/innerkits/native/ethernetmanager/include/ethernet_constants.h create mode 100755 interfaces/innerkits/native/ethernetmanager/include/interface_configuration.h create mode 100755 interfaces/innerkits/native/ethernetmanager/include/static_configuration.h create mode 100755 interfaces/innerkits/native/include/netmanager_constants.h create mode 100755 interfaces/innerkits/native/netconnmanager/BUILD.gn create mode 100755 interfaces/innerkits/native/netconnmanager/include/inet_addr.h create mode 100755 interfaces/innerkits/native/netconnmanager/include/ipc/i_net_conn_callback.h create mode 100755 interfaces/innerkits/native/netconnmanager/include/ipc/net_conn_callback_stub.h create mode 100755 interfaces/innerkits/native/netconnmanager/include/net_conn_callback_info.h create mode 100755 interfaces/innerkits/native/netconnmanager/include/net_conn_client.h create mode 100755 interfaces/innerkits/native/netconnmanager/include/net_conn_constants.h create mode 100755 interfaces/innerkits/native/netconnmanager/include/net_link_info.h create mode 100755 interfaces/innerkits/native/netconnmanager/include/net_specifier.h create mode 100755 interfaces/innerkits/native/netconnmanager/include/net_supplier_info.h create mode 100755 interfaces/innerkits/native/netconnmanager/include/route.h create mode 100755 interfaces/innerkits/native/netpolicymanager/BUILD.gn create mode 100755 interfaces/innerkits/native/netpolicymanager/include/net_policy_client.h create mode 100755 interfaces/innerkits/native/netpolicymanager/include/net_policy_constants.h create mode 100755 netmanager_base_config.gni create mode 100755 ohos.build create mode 100755 prebuilts/librarys/netd/BUILD.gn create mode 100755 prebuilts/librarys/netd/arm/libnet_manager_native.z.so create mode 100755 prebuilts/librarys/netd/arm64/libnet_manager_native.z.so create mode 100755 prebuilts/librarys/netd/include/common/include/blocking_queue.h create mode 100755 prebuilts/librarys/netd/include/common/include/job.h create mode 100755 prebuilts/librarys/netd/include/common/include/net_utils.h create mode 100755 prebuilts/librarys/netd/include/common/include/server_socket.h create mode 100755 prebuilts/librarys/netd/include/common/include/server_template.h create mode 100755 prebuilts/librarys/netd/include/common/include/socket_base.h create mode 100755 prebuilts/librarys/netd/include/common/include/thread_pool.h create mode 100755 prebuilts/librarys/netd/include/common/include/warning_disable.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/dnsresolv.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/dnsresolv_controller.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/dnsresolv_service.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/event_reporter.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/fwmark_server.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/interface_controller.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/net_manager_native.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/netlink_event.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/netlink_handler.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/netlink_listener.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/netlink_manager.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/netlink_socket.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/netnative_log_wrapper.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/network_controller.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/nmd_network.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/route_controller.h create mode 100755 prebuilts/librarys/netd/include/net_mgr_native/include/traffic_controller.h create mode 100755 sa_profile/1151.xml create mode 100755 sa_profile/1152.xml create mode 100755 sa_profile/1156.xml create mode 100755 sa_profile/1157.xml create mode 100755 sa_profile/BUILD.gn create mode 100755 services/common/include/broadcast_manager.h create mode 100755 services/common/include/netd_controller.h create mode 100755 services/common/include/timer.h create mode 100755 services/common/src/broadcast_manager.cpp create mode 100755 services/common/src/netd_controller.cpp create mode 100755 services/dnsresolvermanager/BUILD.gn create mode 100755 services/dnsresolvermanager/include/dns_resolver_service.h create mode 100755 services/dnsresolvermanager/include/ipc/dns_resolver_service_proxy.h create mode 100755 services/dnsresolvermanager/include/ipc/dns_resolver_service_stub.h create mode 100755 services/dnsresolvermanager/include/ipc/i_dns_resolver_service.h create mode 100755 services/dnsresolvermanager/src/dns_resolver_service.cpp create mode 100755 services/dnsresolvermanager/src/ipc/dns_resolver_service_proxy.cpp create mode 100755 services/dnsresolvermanager/src/ipc/dns_resolver_service_stub.cpp create mode 100755 services/dnsresolvermanager/test/BUILD.gn create mode 100755 services/dnsresolvermanager/test/unittest/dns_resolver_manager_test/BUILD.gn create mode 100755 services/dnsresolvermanager/test/unittest/dns_resolver_manager_test/dns_resolver_manager_test.cpp create mode 100755 services/etc/init/BUILD.gn create mode 100755 services/etc/init/netd.cfg create mode 100755 services/etc/init/netd.rc create mode 100755 services/etc/init/netmanager_base.cfg create mode 100755 services/etc/init/netmanager_base.rc create mode 100755 services/ethernetmanager/BUILD.gn create mode 100755 services/ethernetmanager/include/dev_interface_state.h create mode 100755 services/ethernetmanager/include/ethernet_management.h create mode 100755 services/ethernetmanager/include/ethernet_service.h create mode 100755 services/ethernetmanager/include/ipc/ethernet_service_proxy.h create mode 100755 services/ethernetmanager/include/ipc/ethernet_service_stub.h create mode 100755 services/ethernetmanager/include/ipc/i_ethernet_service.h create mode 100755 services/ethernetmanager/include/netLink_rtnl.h create mode 100755 services/ethernetmanager/include/nlk_event_handle.h create mode 100755 services/ethernetmanager/src/dev_interface_state.cpp create mode 100755 services/ethernetmanager/src/ethernet_management.cpp create mode 100755 services/ethernetmanager/src/ethernet_service.cpp create mode 100755 services/ethernetmanager/src/ipc/ethernet_service_proxy.cpp create mode 100755 services/ethernetmanager/src/ipc/ethernet_service_stub.cpp create mode 100755 services/ethernetmanager/src/netLink_rtnl.cpp create mode 100755 services/ethernetmanager/test/BUILD.gn create mode 100755 services/ethernetmanager/test/unittest/ethernet_manager_test/BUILD.gn create mode 100755 services/ethernetmanager/test/unittest/ethernet_manager_test/ethernet_manager_test.cpp create mode 100755 services/netconnmanager/BUILD.gn create mode 100755 services/netconnmanager/include/ipc/i_net_conn_service.h create mode 100755 services/netconnmanager/include/ipc/net_conn_callback_proxy.h create mode 100755 services/netconnmanager/include/ipc/net_conn_service_proxy.h create mode 100755 services/netconnmanager/include/ipc/net_conn_service_stub.h create mode 100755 services/netconnmanager/include/net_conn_service.h create mode 100755 services/netconnmanager/include/net_conn_types.h create mode 100755 services/netconnmanager/include/net_controller/i_net_controller.h create mode 100755 services/netconnmanager/include/net_controller/net_controller_factory.h create mode 100755 services/netconnmanager/include/net_controller/telephony_controller.h create mode 100755 services/netconnmanager/include/net_id_manager.h create mode 100755 services/netconnmanager/include/net_service.h create mode 100755 services/netconnmanager/include/net_supplier.h create mode 100755 services/netconnmanager/include/network.h create mode 100755 services/netconnmanager/src/ipc/net_conn_callback_proxy.cpp create mode 100755 services/netconnmanager/src/ipc/net_conn_service_proxy.cpp create mode 100755 services/netconnmanager/src/ipc/net_conn_service_stub.cpp create mode 100755 services/netconnmanager/src/net_conn_service.cpp create mode 100755 services/netconnmanager/src/net_controller/net_controller_factory.cpp create mode 100755 services/netconnmanager/src/net_controller/telephony_controller.cpp create mode 100755 services/netconnmanager/src/net_id_manager.cpp create mode 100755 services/netconnmanager/src/net_service.cpp create mode 100755 services/netconnmanager/src/net_supplier.cpp create mode 100755 services/netconnmanager/src/network.cpp create mode 100755 services/netconnmanager/test/BUILD.gn create mode 100755 services/netconnmanager/test/mock/BUILD.gn create mode 100755 services/netconnmanager/test/unittest/net_conn_manager_test/BUILD.gn create mode 100755 services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_callback_test.cpp create mode 100755 services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_callback_test.h create mode 100755 services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_manager_test.cpp create mode 100755 services/netpolicymanager/BUILD.gn create mode 100755 services/netpolicymanager/include/ipc/i_net_policy_service.h create mode 100755 services/netpolicymanager/include/ipc/net_policy_service_proxy.h create mode 100755 services/netpolicymanager/include/ipc/net_policy_service_stub.h create mode 100755 services/netpolicymanager/include/net_policy_define.h create mode 100755 services/netpolicymanager/include/net_policy_file.h create mode 100755 services/netpolicymanager/include/net_policy_service.h create mode 100755 services/netpolicymanager/include/net_policy_traffic.h create mode 100755 services/netpolicymanager/src/ipc/net_policy_service_proxy.cpp create mode 100755 services/netpolicymanager/src/ipc/net_policy_service_stub.cpp create mode 100755 services/netpolicymanager/src/net_policy_file.cpp create mode 100755 services/netpolicymanager/src/net_policy_service.cpp create mode 100755 services/netpolicymanager/src/net_policy_traffic.cpp create mode 100755 services/netpolicymanager/test/BUILD.gn create mode 100755 services/netpolicymanager/test/unittest/net_policy_manager_test/BUILD.gn create mode 100755 services/netpolicymanager/test/unittest/net_policy_manager_test/net_policy_manager_test.cpp create mode 100755 utils/BUILD.gn create mode 100755 utils/log/include/net_mgr_log_wrapper.h create mode 100755 utils/log/src/net_mgr_log_wrapper.cpp diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..4947287 --- /dev/null +++ b/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/README.en.md b/README.en.md old mode 100644 new mode 100755 index 0471c0c..efe9ea6 --- a/README.en.md +++ b/README.en.md @@ -1,4 +1,4 @@ -# communication_netmanager_standard +# communication_netmanager_base #### Description {**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 1165ef4..6a43c1c --- a/README.md +++ b/README.md @@ -1,39 +1,95 @@ -# communication_netmanager_standard +# Net Manager -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} - -#### 软件架构 -软件架构说明 +- [简介](#section112mcpsimp) +- [目录](#section125mcpsimp) +- [约束](#section133mcpsimp) +- [相关仓](#section155mcpsimp) -#### 安装教程 -1. xxxx -2. xxxx -3. xxxx +## 简介 -#### 使用说明 +网络管理介绍: -1. xxxx -2. xxxx -3. xxxx +​ 网络管理模块作为电话子系统可裁剪部件,依赖于蜂窝数据管理,主要分为连接管理、策略管理、流量管理、网络共享、VPN管理五大模块;如图1:网络管理架构图; -#### 参与贡献 +**图 1** 网络管理架构图 -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +![](figures/net_manager_arch_zh.png) +连接管理介绍: -#### 特技 +​ 负责与蜂窝数据交互,请求到IP后,再与Netd交互并将路由参数设置到内核,使得蜂窝数据连接且可用,最终实现上网,如图2:网络连接架构图; + +**图 2** 网络连接架构图 + +![](figures/net_conn_manager_arch_zh.png) + +**图 3** 网络策略架构图 + +![](figures\net_policy_manager_arch_zh.png) + +## 目录 + +``` +/foundation/communication/netmanager_standard/netmanager_standard/ +├── frameworks # 框架代码 +│   ├── innerkitsimpl # 内部接口实现 +│   │   └── netconnmanager +│   │   │ └── src +│   │   └── netpolicymanager +│   │   └── src +│   └── js # JS接口实现 +│   └── napi +│   ├── http +│   ├── socket +│   └── websocket +├── interfaces # 接口代码 +│   ├── innerkits # 内部接口 +│   │   └── native +│   │   └── netconnmanager +│   │   │ └── include +│   │   └── netpolicymanager +│   │   └── include +│   └── kits # 外部接口 +│   └── js +├── sa_profile # 服务配置文件 +├── services # 核心服务代码目录 +│   ├── common # 网络管理公共组件 +│   ├── etc # 网络管理进程配置脚本 +│   │   └── init +│   ├── netconnmanager # 网络连接管理代码 +│   │   ├── include # 头文件 +│   │   │   ├── ipc # IPC通信头文件 +│   │   │   ├── net_controller # 网络控制 +│   │   ├── src # 源文件目录 +│   │   │   ├── ipc # IPC通信源文件 +│   │   │   ├── net_controller # 网络控制实现 +│   │   └── test # 单元测试代码 +│   ├── netpolicymanager # 网络策略管理代码 +│   │   ├── include # 头文件 +│   │   │   └── ipc # IPC通信头文件 +│   │   ├── src # 源文件目录 +│   │   │   └── ipc # IPC通信源文件 +│   │   └── test # 单元测试代码 +│   ├── netmanagernative # Netd代码 +│   └── prebuild # 预编译库文件 +└── utils # 公共功能实现 +| └── log # 日志实现 +└── ohos.build # 编译文件 +``` + +## 约束 + +- 开发语言:C++ +- 软件层,需要以下子系统和服务配合使用:蜂窝数据、安全子系统、软总线子系统、USB子系统、电源管理子系统等; +- 硬件层,需要搭载的设备支持以下硬件:可以进行独立蜂窝通信的Modem以及SIM卡; + +## 相关仓 + +[netmanager_standard](https://gitee.com/openharmony/communication_netmanager_standard/blob/master/README.md) + +[电话服务子系统](https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/%E7%94%B5%E8%AF%9D%E6%9C%8D%E5%8A%A1%E5%AD%90%E7%B3%BB%E7%BB%9F.md) + +[ telephony_cellular_data](https://gitee.com/openharmony/telephony_cellular_data/blob/master/README.md) -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/figures/net_conn_manager_arch_zh.png b/figures/net_conn_manager_arch_zh.png new file mode 100755 index 0000000000000000000000000000000000000000..bef52c52dda63cd5746a3e0b737bfdef5f9010e2 GIT binary patch literal 18703 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 literal 0 HcmV?d00001 diff --git a/figures/net_manager_arch_zh.png b/figures/net_manager_arch_zh.png new file mode 100755 index 0000000000000000000000000000000000000000..5c247ab20cd8ca8afc0605e104cc8f33720563b4 GIT binary patch literal 41997 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 literal 0 HcmV?d00001 diff --git a/figures/net_policy_manager_arch_zh.png b/figures/net_policy_manager_arch_zh.png new file mode 100755 index 0000000000000000000000000000000000000000..bc88209c913c5e2b5175ae3f67ce217da5e88bff GIT binary patch literal 24591 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 literal 0 HcmV?d00001 diff --git a/frameworks/innerkitsimpl/dnsresolvermanager/src/dns_addr_info.cpp b/frameworks/innerkitsimpl/dnsresolvermanager/src/dns_addr_info.cpp new file mode 100755 index 0000000..70fadb2 --- /dev/null +++ b/frameworks/innerkitsimpl/dnsresolvermanager/src/dns_addr_info.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 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 "dns_addr_info.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +bool DnsAddrInfo::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteInt32(flags_)) { + return false; + } + if (!parcel.WriteInt32(family_)) { + return false; + } + if (!parcel.WriteInt32(sockType_)) { + return false; + } + if (!parcel.WriteInt32(protocol_)) { + return false; + } + if (!parcel.WriteString(addr_)) { + return false; + } + return true; +} + +sptr DnsAddrInfo::Unmarshalling(Parcel &parcel) +{ + sptr ptr = (std::make_unique()).release(); + if (ptr == nullptr) { + NETMGR_LOGE("create DnsAddrInfo failed"); + return nullptr; + } + if (!parcel.ReadInt32(ptr->flags_)) { + return nullptr; + } + if (!parcel.ReadInt32(ptr->family_)) { + return nullptr; + } + if (!parcel.ReadInt32(ptr->sockType_)) { + return nullptr; + } + if (!parcel.ReadInt32(ptr->protocol_)) { + return nullptr; + } + if (!parcel.ReadString(ptr->addr_)) { + return nullptr; + } + return ptr; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/dnsresolvermanager/src/dns_resolver_client.cpp b/frameworks/innerkitsimpl/dnsresolvermanager/src/dns_resolver_client.cpp new file mode 100755 index 0000000..ab9edfd --- /dev/null +++ b/frameworks/innerkitsimpl/dnsresolvermanager/src/dns_resolver_client.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2021 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 "dns_resolver_client.h" + +#include "iservice_registry.h" +#include "system_ability_definition.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +DnsResolverClient::DnsResolverClient() : dnsResolverService_(nullptr), deathRecipient_(nullptr) {} + +DnsResolverClient::~DnsResolverClient() {} + +int32_t DnsResolverClient::GetAddressesByName(const std::string &hostName, std::vector &addrInfo) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->GetAddressesByName(hostName, addrInfo); +} + +int32_t DnsResolverClient::GetAddrInfo(const std::string &hostName, const std::string &server, + const sptr &hints, std::vector> &dnsAddrInfo) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->GetAddrInfo(hostName, server, hints, dnsAddrInfo); +} + +int32_t DnsResolverClient::CreateNetworkCache(uint16_t netId) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->CreateNetworkCache(netId); +} + +int32_t DnsResolverClient::DestoryNetworkCache(uint16_t netId) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->DestoryNetworkCache(netId); +} + +int32_t DnsResolverClient::FlushNetworkCache(uint16_t netId) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->FlushNetworkCache(netId); +} + +int32_t DnsResolverClient::SetResolverConfig(uint16_t netId, uint16_t baseTimeoutMsec, uint8_t retryCount, + const std::vector &servers, const std::vector &domains) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->SetResolverConfig(netId, baseTimeoutMsec, retryCount, servers, domains); +} + +int32_t DnsResolverClient::GetResolverInfo(uint16_t netId, std::vector &servers, + std::vector &domains, uint16_t &baseTimeoutMsec, uint8_t &retryCount) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->GetResolverInfo(netId, servers, domains, baseTimeoutMsec, retryCount); +} + +sptr DnsResolverClient::GetProxy() +{ + std::lock_guard lock(mutex_); + if (dnsResolverService_) { + NETMGR_LOGI("get proxy is ok"); + return dnsResolverService_; + } + NETMGR_LOGI("execute GetSystemAbilityManager"); + sptr sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (sam == nullptr) { + NETMGR_LOGE("GetProxy, get SystemAbilityManager failed"); + return nullptr; + } + sptr remote = sam->CheckSystemAbility(COMM_DNS_MANAGER_SYS_ABILITY_ID); + if (remote == nullptr) { + NETMGR_LOGE("get Remote service failed"); + return nullptr; + } + deathRecipient_ = (std::make_unique(*this)).release(); + if ((remote->IsProxyObject()) && (!remote->AddDeathRecipient(deathRecipient_))) { + NETMGR_LOGE("add death recipient failed"); + return nullptr; + } + dnsResolverService_ = iface_cast(remote); + if (dnsResolverService_ == nullptr) { + NETMGR_LOGE("get Remote service proxy failed"); + return nullptr; + } + return dnsResolverService_; +} + +void DnsResolverClient::OnRemoteDied(const wptr &remote) +{ + NETMGR_LOGI("on remote died"); + if (remote == nullptr) { + NETMGR_LOGE("remote object is nullptr"); + return; + } + std::lock_guard lock(mutex_); + if (dnsResolverService_ == nullptr) { + NETMGR_LOGE("dnsResolverService_ is nullptr"); + return; + } + sptr local = dnsResolverService_->AsObject(); + if (local != remote.promote()) { + NETMGR_LOGE("proxy and stub is not same remote object"); + return; + } + local->RemoveDeathRecipient(deathRecipient_); + dnsResolverService_ = nullptr; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/ethernetmanager/src/ethernet_client.cpp b/frameworks/innerkitsimpl/ethernetmanager/src/ethernet_client.cpp new file mode 100755 index 0000000..0395477 --- /dev/null +++ b/frameworks/innerkitsimpl/ethernetmanager/src/ethernet_client.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2021 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 "ethernet_client.h" + +#include "iservice_registry.h" +#include "system_ability_definition.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +EthernetClient::EthernetClient() : ethernetService_(nullptr), deathRecipient_(nullptr) {} + +EthernetClient::~EthernetClient() {} + +int32_t EthernetClient::SetIfaceConfig(const std::string &iface, sptr &ic) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->SetIfaceConfig(iface, ic); +} + +sptr EthernetClient::GetIfaceConfig(const std::string &iface) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return nullptr; + } + return proxy->GetIfaceConfig(iface); +} +int32_t EthernetClient::IsActivate(const std::string &iface) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->IsActivate(iface); +} + +std::vector EthernetClient::GetActivateInterfaces() +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return {}; + } + return proxy->GetActivateInterfaces(); +} + +sptr EthernetClient::GetProxy() +{ + std::lock_guard lock(mutex_); + if (ethernetService_) { + NETMGR_LOGI("get proxy is ok"); + return ethernetService_; + } + NETMGR_LOGI("execute GetSystemAbilityManager"); + sptr sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (sam == nullptr) { + NETMGR_LOGE("GetProxy, get SystemAbilityManager failed"); + return nullptr; + } + sptr remote = sam->CheckSystemAbility(COMM_ETHERNET_MANAGER_SYS_ABILITY_ID); + if (remote == nullptr) { + NETMGR_LOGE("get Remote service failed"); + return nullptr; + } + deathRecipient_ = (std::make_unique(*this)).release(); + if ((remote->IsProxyObject()) && (!remote->AddDeathRecipient(deathRecipient_))) { + NETMGR_LOGE("add death recipient failed"); + return nullptr; + } + ethernetService_ = iface_cast(remote); + if (ethernetService_ == nullptr) { + NETMGR_LOGE("get Remote service proxy failed"); + return nullptr; + } + return ethernetService_; +} + +void EthernetClient::OnRemoteDied(const wptr &remote) +{ + NETMGR_LOGI("on remote died"); + if (remote == nullptr) { + NETMGR_LOGE("remote object is nullptr"); + return; + } + std::lock_guard lock(mutex_); + if (ethernetService_ == nullptr) { + NETMGR_LOGE("ethernetService_ is nullptr"); + return; + } + sptr local = ethernetService_->AsObject(); + if (local != remote.promote()) { + NETMGR_LOGE("proxy and stub is not same remote object"); + return; + } + local->RemoveDeathRecipient(deathRecipient_); + ethernetService_ = nullptr; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/ethernetmanager/src/interface_configuration.cpp b/frameworks/innerkitsimpl/ethernetmanager/src/interface_configuration.cpp new file mode 100755 index 0000000..b744bc9 --- /dev/null +++ b/frameworks/innerkitsimpl/ethernetmanager/src/interface_configuration.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 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 "interface_configuration.h" +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +bool InterfaceConfiguration::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteInt32(static_cast(mode_))) { + return false; + } + if (!ipStatic_.Marshalling(parcel)) { + NETMGR_LOGE("write ipStatic_ to parcel failed"); + return false; + } + return true; +} + +sptr InterfaceConfiguration::Unmarshalling(Parcel &parcel) +{ + sptr ptr = (std::make_unique()).release(); + if (ptr == nullptr) { + return nullptr; + } + int32_t mode = 0; + if (!parcel.ReadInt32(mode)) { + return nullptr; + } + ptr->mode_ = static_cast(mode); + sptr sc = StaticConfiguration::Unmarshalling(parcel); + if (sc == nullptr) { + NETMGR_LOGE("sc is null"); + return nullptr; + } + ptr->ipStatic_ = *sc; + return ptr; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/ethernetmanager/src/static_configuration.cpp b/frameworks/innerkitsimpl/ethernetmanager/src/static_configuration.cpp new file mode 100755 index 0000000..cce72d0 --- /dev/null +++ b/frameworks/innerkitsimpl/ethernetmanager/src/static_configuration.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2021 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 "static_configuration.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +bool StaticConfiguration::Marshalling(Parcel &parcel) const +{ + if (!ipAddr_.Marshalling(parcel)) { + NETMGR_LOGE("write ipAddr_ to parcel failed"); + return false; + } + if (!route_.Marshalling(parcel)) { + NETMGR_LOGE("write route_ to parcel failed"); + return false; + } + if (!gate_.Marshalling(parcel)) { + NETMGR_LOGE("write gate_ to parcel failed"); + return false; + } + if (!netMask_.Marshalling(parcel)) { + NETMGR_LOGE("write netMask_ to parcel failed"); + return false; + } + if (!parcel.WriteUint32(dnsServers_.size())) { + NETMGR_LOGE("write dnsServers_ size to parcel failed"); + return false; + } + for (auto it = dnsServers_.begin(); it != dnsServers_.end(); ++it) { + if (!it->Marshalling(parcel)) { + NETMGR_LOGE("write dnsServers_ to parcel failed"); + return false; + } + } + if (!parcel.WriteString(domain_)) { + NETMGR_LOGE("write domain_ to parcel failed"); + return false; + } + return true; +} + +sptr StaticConfiguration::Unmarshalling(Parcel &parcel) +{ + sptr ptr = (std::make_unique()).release(); + if (ptr == nullptr) { + return nullptr; + } + sptr ipAddr = INetAddr::Unmarshalling(parcel); + if (ipAddr == nullptr) { + NETMGR_LOGE("ipAddr_ is null"); + return nullptr; + } + ptr->ipAddr_ = *ipAddr; + sptr route = INetAddr::Unmarshalling(parcel); + if (route == nullptr) { + NETMGR_LOGE("route_ is null"); + return nullptr; + } + ptr->route_ = *route; + sptr gate = INetAddr::Unmarshalling(parcel); + if (gate == nullptr) { + NETMGR_LOGE("gate_ is null"); + return nullptr; + } + ptr->gate_ = *gate; + sptr netMask = INetAddr::Unmarshalling(parcel); + if (netMask == nullptr) { + NETMGR_LOGE("netMask_ is null"); + return nullptr; + } + ptr->netMask_ = *netMask; + uint32_t size = 0; + if (!parcel.ReadUint32(size)) { + return nullptr; + } + for (uint32_t i = 0; i < size; i++) { + sptr netAddr = INetAddr::Unmarshalling(parcel); + if (netAddr == nullptr) { + NETMGR_LOGE("netAddr is null"); + return nullptr; + } + ptr->dnsServers_.push_back(*netAddr); + } + if (!parcel.ReadString(ptr->domain_)) { + return nullptr; + } + return ptr; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/netconnmanager/src/inet_addr.cpp b/frameworks/innerkitsimpl/netconnmanager/src/inet_addr.cpp new file mode 100755 index 0000000..ea08d61 --- /dev/null +++ b/frameworks/innerkitsimpl/netconnmanager/src/inet_addr.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2021 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 "inet_addr.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +bool INetAddr::operator==(const INetAddr &obj) const +{ + bool out = true; + out = out && (type_ == obj.type_); + out = out && (family_ == obj.family_); + out = out && (prefixlen_ == obj.prefixlen_); + out = out && (address_ == obj.address_); + out = out && (netMask_ == obj.netMask_); + out = out && (hostName_ == obj.hostName_); + return out; +} + +bool INetAddr::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteUint8(type_)) { + return false; + } + if (!parcel.WriteUint8(family_)) { + return false; + } + if (!parcel.WriteUint8(prefixlen_)) { + return false; + } + if (!parcel.WriteString(address_)) { + return false; + } + if (!parcel.WriteString(netMask_)) { + return false; + } + if (!parcel.WriteString(hostName_)) { + return false; + } + return true; +} + +sptr INetAddr::Unmarshalling(Parcel &parcel) +{ + sptr ptr = (std::make_unique()).release(); + if (ptr == nullptr) { + NETMGR_LOGE("create INetAddr failed"); + return nullptr; + } + if (!parcel.ReadUint8(ptr->type_)) { + return nullptr; + } + if (!parcel.ReadUint8(ptr->family_)) { + return nullptr; + } + if (!parcel.ReadUint8(ptr->prefixlen_)) { + return nullptr; + } + if (!parcel.ReadString(ptr->address_)) { + return nullptr; + } + if (!parcel.ReadString(ptr->netMask_)) { + return nullptr; + } + if (!parcel.ReadString(ptr->hostName_)) { + return nullptr; + } + return ptr; +} + +bool INetAddr::Marshalling(Parcel &parcel, const sptr &object) +{ + if (object == nullptr) { + NETMGR_LOGE("INetAddr object ptr is nullptr"); + return false; + } + if (!parcel.WriteUint8(object->type_)) { + return false; + } + if (!parcel.WriteUint8(object->family_)) { + return false; + } + if (!parcel.WriteUint8(object->prefixlen_)) { + return false; + } + if (!parcel.WriteString(object->address_)) { + return false; + } + if (!parcel.WriteString(object->netMask_)) { + return false; + } + if (!parcel.WriteString(object->hostName_)) { + return false; + } + return true; +} + +std::string INetAddr::ToString(const std::string tab) const +{ + std::string familyStr = std::to_string(family_); + std::string prefixlenStr = std::to_string(prefixlen_); + std::string jsonStr = "{"; + jsonStr += "\"family_\""; + jsonStr += ":"; + jsonStr += "\"" + familyStr + "\","; + + jsonStr += "\"prefixlen_\""; + jsonStr += ":"; + jsonStr += "\"" + prefixlenStr + "\","; + + jsonStr += "\"address_\""; + jsonStr += ":"; + jsonStr += "\"" + address_ + "\","; + + jsonStr += "\"netMask_\""; + jsonStr += ":"; + jsonStr += "\"" + netMask_ + "\""; + jsonStr += "}"; + return jsonStr; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/netconnmanager/src/ipc/net_conn_callback_stub.cpp b/frameworks/innerkitsimpl/netconnmanager/src/ipc/net_conn_callback_stub.cpp new file mode 100755 index 0000000..644ee7c --- /dev/null +++ b/frameworks/innerkitsimpl/netconnmanager/src/ipc/net_conn_callback_stub.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 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 "net_conn_callback_stub.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +NetConnCallbackStub::NetConnCallbackStub() +{ + memberFuncMap_[NET_CONN_STATE_CHANGED] = &NetConnCallbackStub::OnNetConnStateChanged; +} + +NetConnCallbackStub::~NetConnCallbackStub() {} + +int32_t NetConnCallbackStub::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + NETMGR_LOGI("Stub call start, code:[%{public}d]", code); + std::u16string myDescripter = NetConnCallbackStub::GetDescriptor(); + std::u16string remoteDescripter = data.ReadInterfaceToken(); + if (myDescripter != remoteDescripter) { + NETMGR_LOGE("Descriptor checked failed"); + return ERR_FLATTEN_OBJECT; + } + + auto itFunc = memberFuncMap_.find(code); + if (itFunc != memberFuncMap_.end()) { + auto requestFunc = itFunc->second; + if (requestFunc != nullptr) { + return (this->*requestFunc)(data, reply); + } + } + + NETMGR_LOGI("Stub default case, need check"); + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} + +int32_t NetConnCallbackStub::OnNetConnStateChanged(MessageParcel &data, MessageParcel &reply) +{ + if (!data.ContainFileDescriptors()) { + NETMGR_LOGE("Execute ContainFileDescriptors failed"); + } + + sptr info = NetConnCallbackInfo::Unmarshalling(data); + int32_t result = NetConnStateChanged(info); + if (!reply.WriteInt32(result)) { + NETMGR_LOGE("Write parcel failed"); + return result; + } + + return ERR_NONE; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/netconnmanager/src/net_conn_callback_info.cpp b/frameworks/innerkitsimpl/netconnmanager/src/net_conn_callback_info.cpp new file mode 100755 index 0000000..d50771a --- /dev/null +++ b/frameworks/innerkitsimpl/netconnmanager/src/net_conn_callback_info.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2021 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 "net_conn_callback_info.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +bool NetConnCallbackInfo::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteInt32(netState_)) { + return false; + } + if (!parcel.WriteUint32(netType_)) { + return false; + } + + return true; +} + +sptr NetConnCallbackInfo::Unmarshalling(Parcel &parcel) +{ + sptr ptr = (std::make_unique()).release(); + if (ptr == nullptr) { + NETMGR_LOGE("The parameter of ptr is nullptr"); + return nullptr; + } + + if (!parcel.ReadInt32(ptr->netState_)) { + return nullptr; + } + if (!parcel.ReadUint32(ptr->netType_)) { + return nullptr; + } + + return ptr; +} + +bool NetConnCallbackInfo::Marshalling(Parcel &parcel, const sptr &object) +{ + if (object == nullptr) { + NETMGR_LOGE("NetConnCallbackInfo object is nullptr"); + return false; + } + + if (!parcel.WriteInt32(object->netState_)) { + NETMGR_LOGE("Write netState_ failed"); + return false; + } + if (!parcel.WriteUint32(object->netType_)) { + NETMGR_LOGE("Write netType_ failed"); + return false; + } + + return true; +} + +std::string NetConnCallbackInfo::ToString(const std::string &tab) const +{ + std::string str; + str.append("\n"); + str.append(tab); + str.append("[NetConnCallbackInfo]"); + + str.append("\n"); + str.append(tab); + str.append("netState_ = "); + str.append(std::to_string(netState_)); + + str.append("\n"); + str.append(tab); + str.append("netType_ = "); + str.append(std::to_string(netType_)); + + return str; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/netconnmanager/src/net_conn_client.cpp b/frameworks/innerkitsimpl/netconnmanager/src/net_conn_client.cpp new file mode 100755 index 0000000..5d7f67e --- /dev/null +++ b/frameworks/innerkitsimpl/netconnmanager/src/net_conn_client.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2021 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 "net_conn_client.h" + +#include "iservice_registry.h" +#include "system_ability_definition.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +NetConnClient::NetConnClient() : NetConnService_(nullptr), deathRecipient_(nullptr) {} + +NetConnClient::~NetConnClient() {} + +int32_t NetConnClient::SystemReady() +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->SystemReady(); +} + +int32_t NetConnClient::RegisterNetSupplier(uint32_t netType, const std::string &ident, uint64_t netCapabilities) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->RegisterNetSupplier(netType, ident, netCapabilities); +} + +int32_t NetConnClient::UnregisterNetSupplier(uint32_t supplierId) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->UnregisterNetSupplier(supplierId); +} + +int32_t NetConnClient::RegisterNetConnCallback(const sptr &callback) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("The parameter of proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->RegisterNetConnCallback(callback); +} + +int32_t NetConnClient::RegisterNetConnCallback(const sptr &netSpecifier, + const sptr &callback) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("The parameter of proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->RegisterNetConnCallback(netSpecifier, callback); +} + +int32_t NetConnClient::UnregisterNetConnCallback(const sptr &callback) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->UnregisterNetConnCallback(callback); +} + +int32_t NetConnClient::UnregisterNetConnCallback(const sptr &netSpecifier, + const sptr &callback) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->UnregisterNetConnCallback(netSpecifier, callback); +} + +int32_t NetConnClient::UpdateNetSupplierInfo(uint32_t supplierId, const sptr &netSupplierInfo) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->UpdateNetSupplierInfo(supplierId, netSupplierInfo); +} + +int32_t NetConnClient::UpdateNetCapabilities(uint32_t supplierId, uint64_t netCapabilities) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->UpdateNetCapabilities(supplierId, netCapabilities); +} + +int32_t NetConnClient::UpdateNetLinkInfo(uint32_t supplierId, const sptr &netLinkInfo) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + return proxy->UpdateNetLinkInfo(supplierId, netLinkInfo); +} + +sptr NetConnClient::GetProxy() +{ + std::lock_guard lock(mutex_); + if (NetConnService_) { + NETMGR_LOGI("get proxy is ok"); + return NetConnService_; + } + NETMGR_LOGI("execute GetSystemAbilityManager"); + sptr sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (sam == nullptr) { + NETMGR_LOGE("GetProxy, get SystemAbilityManager failed"); + return nullptr; + } + sptr remote = sam->CheckSystemAbility(COMM_NET_CONN_MANAGER_SYS_ABILITY_ID); + if (remote == nullptr) { + NETMGR_LOGE("get Remote service failed"); + return nullptr; + } + deathRecipient_ = (std::make_unique(*this)).release(); + if ((remote->IsProxyObject()) && (!remote->AddDeathRecipient(deathRecipient_))) { + NETMGR_LOGE("add death recipient failed"); + return nullptr; + } + NetConnService_ = iface_cast(remote); + if (NetConnService_ == nullptr) { + NETMGR_LOGE("get Remote service proxy failed"); + return nullptr; + } + return NetConnService_; +} + +void NetConnClient::OnRemoteDied(const wptr &remote) +{ + NETMGR_LOGI("on remote died"); + if (remote == nullptr) { + NETMGR_LOGE("remote object is nullptr"); + return; + } + std::lock_guard lock(mutex_); + if (NetConnService_ == nullptr) { + NETMGR_LOGE("OnRemoteDied NetConnService_ is nullptr"); + return; + } + sptr local = NetConnService_->AsObject(); + if (local != remote.promote()) { + NETMGR_LOGE("OnRemoteDied proxy and stub is not same remote object"); + return; + } + local->RemoveDeathRecipient(deathRecipient_); + NetConnService_ = nullptr; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/netconnmanager/src/net_link_info.cpp b/frameworks/innerkitsimpl/netconnmanager/src/net_link_info.cpp new file mode 100755 index 0000000..c3f874a --- /dev/null +++ b/frameworks/innerkitsimpl/netconnmanager/src/net_link_info.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2021 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 "net_link_info.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +bool NetLinkInfo::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteString(ifaceName_)) { + return false; + } + if (!parcel.WriteString(domain_)) { + return false; + } + if (!parcel.WriteUint32(netAddrList_.size())) { + return false; + } + for (auto it = netAddrList_.begin(); it != netAddrList_.end(); it++) { + if (!it->Marshalling(parcel)) { + NETMGR_LOGE("write net address to parcel failed"); + return false; + } + } + if (!parcel.WriteUint32(dnsList_.size())) { + return false; + } + for (auto it = dnsList_.begin(); it != dnsList_.end(); it++) { + if (!it->Marshalling(parcel)) { + NETMGR_LOGE("write dns to parcel failed"); + return false; + } + } + if (!parcel.WriteUint32(routeList_.size())) { + return false; + } + for (auto it = routeList_.begin(); it != routeList_.end(); it++) { + if (!it->Marshalling(parcel)) { + NETMGR_LOGE("write route to parcel failed"); + return false; + } + } + if (!parcel.WriteUint16(mtu_)) { + return false; + } + return true; +} + +sptr NetLinkInfo::Unmarshalling(Parcel &parcel) +{ + sptr ptr = (std::make_unique()).release(); + if (ptr == nullptr) { + return nullptr; + } + if (!parcel.ReadString(ptr->ifaceName_)) { + return nullptr; + } + if (!parcel.ReadString(ptr->domain_)) { + return nullptr; + } + uint32_t size = 0; + if (!parcel.ReadUint32(size)) { + return nullptr; + } + sptr netAddr; + for (uint32_t i = 0; i < size; i++) { + netAddr = INetAddr::Unmarshalling(parcel); + if (netAddr == nullptr) { + NETMGR_LOGE("INetAddr::Unmarshalling(parcel) is null"); + return nullptr; + } + ptr->netAddrList_.push_back(*netAddr); + } + if (!parcel.ReadUint32(size)) { + return nullptr; + } + for (uint32_t i = 0; i < size; i++) { + netAddr = INetAddr::Unmarshalling(parcel); + if (netAddr == nullptr) { + NETMGR_LOGE("INetAddr::Unmarshalling(parcel) is null"); + return nullptr; + } + ptr->dnsList_.push_back(*netAddr); + } + if (!parcel.ReadUint32(size)) { + return nullptr; + } + sptr route; + for (uint32_t i = 0; i < size; i++) { + route = Route::Unmarshalling(parcel); + if (route == nullptr) { + NETMGR_LOGE("Route::Unmarshalling(parcel) is null"); + return nullptr; + } + ptr->routeList_.push_back(*route); + } + if (!parcel.ReadUint16(ptr->mtu_)) { + return nullptr; + } + return ptr; +} + +bool NetLinkInfo::Marshalling(Parcel &parcel, const sptr &object) +{ + if (object == nullptr) { + NETMGR_LOGE("NetLinkInfo object ptr is nullptr"); + return false; + } + if (!parcel.WriteString(object->ifaceName_)) { + return false; + } + if (!parcel.WriteString(object->domain_)) { + return false; + } + if (!parcel.WriteUint32(object->netAddrList_.size())) { + return false; + } + for (auto it = object->netAddrList_.begin(); it != object->netAddrList_.end(); it++) { + if (!it->Marshalling(parcel)) { + NETMGR_LOGE("write objects net address to parcel failed"); + return false; + } + } + if (!parcel.WriteUint32(object->dnsList_.size())) { + return false; + } + for (auto it = object->dnsList_.begin(); it != object->dnsList_.end(); it++) { + if (!it->Marshalling(parcel)) { + NETMGR_LOGE("write objects dns to parcel failed"); + return false; + } + } + if (!parcel.WriteUint32(object->routeList_.size())) { + return false; + } + for (auto it = object->routeList_.begin(); it != object->routeList_.end(); it++) { + if (!it->Marshalling(parcel)) { + NETMGR_LOGE("write objects route to parcel failed"); + return false; + } + } + if (!parcel.WriteUint16(object->mtu_)) { + return false; + } + return true; +} + +std::string NetLinkInfo::ToString(const std::string &tab) const +{ + std::string str; + str.append("\n"); + str.append(tab); + str.append("[NetLinkInfo]"); + + str.append("\n"); + str.append(tab); + str.append("ifaceName_ = "); + str.append(ifaceName_); + + str.append("\n"); + str.append(tab); + str.append("domain_ = "); + str.append(domain_); + + str.append("\n"); + str.append(tab); + str.append("netAddrList_ = "); + for (auto it = netAddrList_.begin(); it != netAddrList_.end(); it++) { + str.append(it->ToString(tab + " ")); + } + + str.append("\n"); + str.append(tab); + str.append("dnsList_ = "); + for (auto it = dnsList_.begin(); it != dnsList_.end(); it++) { + str.append(it->ToString(tab + " ")); + } + + str.append("\n"); + str.append(tab); + str.append("routeList_ = "); + for (auto it = routeList_.begin(); it != routeList_.end(); it++) { + str.append(it->ToString(tab + " ")); + } + + str.append("\n"); + str.append(tab); + str.append("mtu_ = "); + str.append(std::to_string(mtu_)); + return str; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/netconnmanager/src/net_specifier.cpp b/frameworks/innerkitsimpl/netconnmanager/src/net_specifier.cpp new file mode 100755 index 0000000..ae3f326 --- /dev/null +++ b/frameworks/innerkitsimpl/netconnmanager/src/net_specifier.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021 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 "net_specifier.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +bool NetSpecifier::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteString(ident_)) { + return false; + } + if (!parcel.WriteUint32(netType_)) { + return false; + } + if (!parcel.WriteUint64(netCapabilities_)) { + return false; + } + return true; +} + +sptr NetSpecifier::Unmarshalling(Parcel &parcel) +{ + sptr ptr = (std::make_unique()).release(); + if (ptr == nullptr) { + NETMGR_LOGE("make_unique() failed"); + return nullptr; + } + if (!parcel.ReadString(ptr->ident_)) { + return nullptr; + } + if (!parcel.ReadUint32(ptr->netType_)) { + return nullptr; + } + if (!parcel.ReadUint64(ptr->netCapabilities_)) { + return nullptr; + } + return ptr; +} + +bool NetSpecifier::Marshalling(Parcel &parcel, const sptr &object) +{ + if (object == nullptr) { + NETMGR_LOGE("NetSpecifier object ptr is nullptr"); + return false; + } + if (!parcel.WriteString(object->ident_)) { + return false; + } + if (!parcel.WriteUint32(object->netType_)) { + return false; + } + if (!parcel.WriteUint64(object->netCapabilities_)) { + return false; + } + return true; +} + +std::string NetSpecifier::ToString(const std::string &tab) const +{ + std::string str; + str.append("\n"); + str.append(tab); + str.append("[NetSpecifier]"); + + str.append("\n"); + str.append(tab); + str.append("ident_ = "); + str.append(ident_); + + str.append("\n"); + str.append(tab); + str.append("netType_ = "); + str.append(std::to_string(netType_)); + + str.append("\n"); + str.append(tab); + str.append("netCapabilities_ = "); + str.append(std::to_string(netCapabilities_)); + + return str; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/netconnmanager/src/net_supplier_info.cpp b/frameworks/innerkitsimpl/netconnmanager/src/net_supplier_info.cpp new file mode 100755 index 0000000..0bfa3f1 --- /dev/null +++ b/frameworks/innerkitsimpl/netconnmanager/src/net_supplier_info.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2021 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 "net_supplier_info.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +bool NetSupplierInfo::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteBool(isAvailable_)) { + return false; + } + if (!parcel.WriteBool(isRoaming_)) { + return false; + } + if (!parcel.WriteUint8(strength_)) { + return false; + } + if (!parcel.WriteUint32(frequency_)) { + return false; + } + return true; +} + +sptr NetSupplierInfo::Unmarshalling(Parcel &parcel) +{ + sptr ptr = (std::make_unique()).release(); + if (ptr == nullptr) { + NETMGR_LOGE("make_unique() failed"); + return nullptr; + } + if (!parcel.ReadBool(ptr->isAvailable_)) { + return nullptr; + } + if (!parcel.ReadBool(ptr->isRoaming_)) { + return nullptr; + } + if (!parcel.ReadUint8(ptr->strength_)) { + NETMGR_LOGE("read strength_ from parcel failed"); + return nullptr; + } + if (!parcel.ReadUint32(ptr->frequency_)) { + return nullptr; + } + return ptr; +} + +bool NetSupplierInfo::Marshalling(Parcel &parcel, const sptr &object) +{ + if (object == nullptr) { + NETMGR_LOGE("NetSupplierInfo object ptr is nullptr"); + return false; + } + if (!parcel.WriteBool(object->isAvailable_)) { + return false; + } + if (!parcel.WriteBool(object->isRoaming_)) { + return false; + } + if (!parcel.WriteUint8(object->strength_)) { + return false; + } + if (!parcel.WriteUint32(object->frequency_)) { + return false; + } + return true; +} + +std::string NetSupplierInfo::ToString(const std::string &tab) const +{ + std::string str; + str.append("\n"); + str.append(tab); + str.append("[NetSupplierInfo]"); + + str.append("\n"); + str.append(tab); + str.append("isAvailable_ = "); + str.append(std::to_string(isAvailable_)); + + str.append("\n"); + str.append(tab); + str.append("isRoaming_ = "); + str.append(std::to_string(isRoaming_)); + + str.append("\n"); + str.append(tab); + str.append("strength_ = "); + str.append(std::to_string(strength_)); + + str.append("\n"); + str.append(tab); + str.append("frequency_ = "); + str.append(std::to_string(frequency_)); + + return str; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/netconnmanager/src/route.cpp b/frameworks/innerkitsimpl/netconnmanager/src/route.cpp new file mode 100755 index 0000000..9287b95 --- /dev/null +++ b/frameworks/innerkitsimpl/netconnmanager/src/route.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2021 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 "route.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +bool Route::operator==(const Route &obj) const +{ + bool out = true; + out = out && (iface_ == obj.iface_); + out = out && (destination_ == obj.destination_); + out = out && (gateway_ == obj.gateway_); + return out; +} + +bool Route::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteString(iface_)) { + return false; + } + if (!destination_.Marshalling(parcel)) { + NETMGR_LOGE("write destination_ to parcel failed"); + return false; + } + if (!gateway_.Marshalling(parcel)) { + NETMGR_LOGE("write gateway_ to parcel failed"); + return false; + } + return true; +} + +sptr Route::Unmarshalling(Parcel &parcel) +{ + sptr ptr = (std::make_unique()).release(); + if (ptr == nullptr) { + NETMGR_LOGE("make_unique() failed"); + return nullptr; + } + if (!parcel.ReadString(ptr->iface_)) { + return nullptr; + } + sptr destination = INetAddr::Unmarshalling(parcel); + if (destination == nullptr) { + NETMGR_LOGE("read destination from parcel failed"); + return nullptr; + } + ptr->destination_ = *destination; + sptr gateway = INetAddr::Unmarshalling(parcel); + if (gateway == nullptr) { + NETMGR_LOGE("read gateway from parcel failed"); + return nullptr; + } + ptr->gateway_ = *gateway; + return ptr; +} + +bool Route::Marshalling(Parcel &parcel, const sptr &object) +{ + if (object == nullptr) { + NETMGR_LOGE("Route object ptr is nullptr"); + return false; + } + if (!parcel.WriteString(object->iface_)) { + return false; + } + if (!object->destination_.Marshalling(parcel)) { + NETMGR_LOGE("write object->destination_ to parcel failed"); + return false; + } + if (!object->gateway_.Marshalling(parcel)) { + NETMGR_LOGE("write object->gateway_ to parcel failed"); + return false; + } + return true; +} + +std::string Route::ToString(const std::string &tab) const +{ + std::string str; + str.append("\n"); + str.append(tab); + str.append("[Route]"); + + str.append("\n"); + str.append(tab); + str.append("iface_ = "); + str.append(iface_); + + str.append("\n"); + str.append(tab); + str.append("destination_ = "); + str.append(destination_.ToString(tab + " ")); + + str.append("\n"); + str.append(tab); + str.append("gateway_ = "); + str.append(gateway_.ToString(tab + " ")); + + return str; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/netpolicymanager/src/net_policy_client.cpp b/frameworks/innerkitsimpl/netpolicymanager/src/net_policy_client.cpp new file mode 100755 index 0000000..834e4ce --- /dev/null +++ b/frameworks/innerkitsimpl/netpolicymanager/src/net_policy_client.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2021 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 "net_policy_client.h" + +#include "iservice_registry.h" +#include "system_ability_definition.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +NetPolicyClient::NetPolicyClient() : netPolicyService_(nullptr), deathRecipient_(nullptr) {} + +NetPolicyClient::~NetPolicyClient() {} + +NetPolicyResultCode NetPolicyClient::SetUidPolicy(uint32_t uid, NetUidPolicy policy) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return NetPolicyResultCode::ERR_INTERNAL_ERROR; + } + return proxy->SetUidPolicy(uid, policy); +} + +NetUidPolicy NetPolicyClient::GetUidPolicy(uint32_t uid) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return NetUidPolicy::NET_POLICY_NONE; + } + return proxy->GetUidPolicy(uid); +} + +std::vector NetPolicyClient::GetUids(NetUidPolicy policy) +{ + std::vector uids; + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return uids; + } + uids = proxy->GetUids(policy); + return uids; +} + +bool NetPolicyClient::IsUidNetAccess(uint32_t uid, bool metered) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return false; + } + return proxy->IsUidNetAccess(uid, metered); +} + +bool NetPolicyClient::IsUidNetAccess(uint32_t uid, const std::string &ifaceName) +{ + sptr proxy = GetProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return false; + } + return proxy->IsUidNetAccess(uid, ifaceName); +} + +sptr NetPolicyClient::GetProxy() +{ + std::lock_guard lock(mutex_); + if (netPolicyService_ != nullptr) { + return netPolicyService_; + } + + sptr sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (sam == nullptr) { + NETMGR_LOGE("GetProxy, get SystemAbilityManager failed"); + return nullptr; + } + + sptr remote = sam->CheckSystemAbility(COMM_NET_POLICY_MANAGER_SYS_ABILITY_ID); + if (remote == nullptr) { + NETMGR_LOGE("get Remote service failed"); + return nullptr; + } + + deathRecipient_ = (std::make_unique(*this)).release(); + if ((remote->IsProxyObject()) && (!remote->AddDeathRecipient(deathRecipient_))) { + NETMGR_LOGE("add death recipient failed"); + return nullptr; + } + + netPolicyService_ = iface_cast(remote); + if (netPolicyService_ == nullptr) { + NETMGR_LOGE("get Remote service proxy failed"); + return nullptr; + } + return netPolicyService_; +} + +void NetPolicyClient::OnRemoteDied(const wptr &remote) +{ + NETMGR_LOGI("on remote died"); + if (remote == nullptr) { + NETMGR_LOGE("remote object is nullptr"); + return; + } + + std::lock_guard lock(mutex_); + if (netPolicyService_ == nullptr) { + NETMGR_LOGE("netPolicyService_ is nullptr"); + return; + } + + sptr local = netPolicyService_->AsObject(); + if (local != remote.promote()) { + NETMGR_LOGE("proxy and stub is not same remote object"); + return; + } + local->RemoveDeathRecipient(deathRecipient_); + netPolicyService_ = nullptr; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/frameworks/js/common/napi_common.cpp b/frameworks/js/common/napi_common.cpp new file mode 100755 index 0000000..b2aecb2 --- /dev/null +++ b/frameworks/js/common/napi_common.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 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 "napi_common.h" + +namespace OHOS { +namespace NetManagerStandard { +napi_value NpiCommon::CreateCodeMessage(napi_env env, const std::string &msg, int32_t code) +{ + napi_value messageCodeInfo = nullptr; + napi_value messageInfo = nullptr; + napi_value codeInfo = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, msg.c_str(), msg.length(), &messageInfo)); + NAPI_CALL(env, napi_create_string_utf8( + env, std::to_string(code).c_str(), std::to_string(code).length(), &codeInfo)); + NAPI_CALL(env, napi_create_error(env, codeInfo, messageInfo, &messageCodeInfo)); + return messageCodeInfo; +} + +void NpiCommon::SetPropertyInt32(napi_env env, napi_value object, const std::string &propertyName, int32_t property) +{ + napi_value propertyDest = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, property, &propertyDest)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, object, propertyName.c_str(), propertyDest)); +} + +void NpiCommon::SetPropertyString( + napi_env env, napi_value object, const std::string &propertyName, const std::string &property) +{ + napi_value propertyDest = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, property.c_str(), property.length(), &propertyDest)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, object, propertyName.c_str(), propertyDest)); +} + +void NpiCommon::GetPropertyString( + napi_env env, napi_value object, const std::string &propertyName, std::string &property) +{ + napi_value value = nullptr; + char propertyBuffer[PROPERTY_MAX_BYTE] = {0}; + size_t realByte= 0; + NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, object, propertyName.c_str(), &value)); + NAPI_CALL_RETURN_VOID(env, napi_get_value_string_utf8(env, value, propertyBuffer, PROPERTY_MAX_BYTE, &realByte)); + property = propertyBuffer; +} + +void NpiCommon::GetPropertyInt32(napi_env env, napi_value object, const std::string &propertyName, int32_t &property) +{ + napi_value value = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_named_property(env, object, propertyName.c_str(), &value)); + NAPI_CALL_RETURN_VOID(env, napi_get_value_int32(env, value, &property)); +} + +napi_value NpiCommon::NapiValueByInt32(napi_env env, int32_t property) +{ + napi_value value = nullptr; + NAPI_CALL(env, napi_create_int32(env, property, &value)); + return value; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/frameworks/js/common/napi_common.h b/frameworks/js/common/napi_common.h new file mode 100755 index 0000000..bce9aea --- /dev/null +++ b/frameworks/js/common/napi_common.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2021 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 NAPI_COMMON_H +#define NAPI_COMMON_H + +#include +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace NetManagerStandard { +// define callback ref count +constexpr uint32_t CALLBACK_REF_CNT = 1; +// define property max bytes +constexpr uint32_t PROPERTY_MAX_BYTE = 128; +// define constant of 64 bytes +constexpr uint32_t BUFFER_BYTE = 64; + +enum JS_CALLBACK_ARGV { + CALLBACK_ARGV_INDEX_0 = 0, + CALLBACK_ARGV_INDEX_1, + CALLBACK_ARGV_CNT, +}; + +enum JS_ARGV_NUM { + ARGV_NUM_0 = 0, + ARGV_NUM_1, + ARGV_NUM_2, + ARGV_NUM_3, + ARGV_NUM_4, + ARGV_NUM_5, +}; + +enum JS_ARGV_INDEX { + ARGV_INDEX_0 = 0, + ARGV_INDEX_1, + ARGV_INDEX_2, + ARGV_INDEX_3, + ARGV_INDEX_4, +}; + +class NpiCommon { +public: + static napi_value CreateCodeMessage(napi_env env, const std::string &msg, int32_t code); + static napi_value NapiValueByInt32(napi_env env, int32_t property); + static void SetPropertyInt32(napi_env env, napi_value object, const std::string &propertyName, int32_t property); + static void SetPropertyString(napi_env env, napi_value object, const std::string &propertyName, + const std::string &property); + static void GetPropertyString(napi_env env, napi_value object, const std::string &propertyName, + std::string &property); + static void GetPropertyInt32(napi_env env, napi_value object, const std::string &propertyName, int32_t &property); +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NAPI_COMMON_H + diff --git a/frameworks/js/dnsresolver/BUILD.gn b/frameworks/js/dnsresolver/BUILD.gn new file mode 100755 index 0000000..5cd5ca5 --- /dev/null +++ b/frameworks/js/dnsresolver/BUILD.gn @@ -0,0 +1,57 @@ +# Copyright (c) 2021 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") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +SUBSYSTEM_DIR = "//foundation/communication" +NETMANAGER_NAPI_ROOT = "$SUBSYSTEM_DIR/netmanager_standard/frameworks/js/" + +ohos_shared_library("dnsresolver") { + include_dirs = [ + "//third_party/node/src", + "$NETMANAGER_NAPI_ROOT/dnsresolver/include", + "$NETMANAGER_NAPI_ROOT/common", + "$NETMANAGER_BASE_ROOT/utils/log/include", + "$DNSRESOLVERMANAGER_SOURCE_DIR/include", + "$DNSRESOLVERMANAGER_SOURCE_DIR/include/ipc", + "$INNERKITS_ROOT/native/netconnmanager/include", + ] + + sources = [ + "$NETMANAGER_NAPI_ROOT/common/napi_common.cpp", + "$NETMANAGER_NAPI_ROOT/dnsresolver/src/napi_dns_resolver.cpp", + ] + + defines = [ "NETMGR_DEBUG" ] + + deps = [ + "$INNERKITS_ROOT/native/dnsresolvermanager:dns_resolver_manager_if", + "$INNERKITS_ROOT/native/netconnmanager:net_conn_manager_if", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/ace/napi/:ace_napi", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_standard:samgr_proxy", + ] + + relative_install_dir = "module" + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/frameworks/js/dnsresolver/include/napi_dns_resolver.h b/frameworks/js/dnsresolver/include/napi_dns_resolver.h new file mode 100755 index 0000000..0f3a2d4 --- /dev/null +++ b/frameworks/js/dnsresolver/include/napi_dns_resolver.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 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 NAPI_DNS_RESOLVER_H +#define NAPI_DNS_RESOLVER_H + +#include +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace NetManagerStandard { +constexpr int32_t HOST_MAX_BYTES = 256; + +// dns resolver async context +struct DnsResolverAsyncContext { + napi_async_work work = nullptr; + napi_deferred deferred = nullptr; + napi_ref callbackRef = nullptr; + // Data context + char host[HOST_MAX_BYTES] = {0}; + size_t hostRealBytes = 0; + std::vector hostAddress; +}; + +class NapiDnsResolver { +public: + NapiDnsResolver(); + ~NapiDnsResolver() = default; + static napi_value DeclareNapiDnsResolverInterface(napi_env env, napi_value exports); + static napi_value RegisterDnsResolverInterface(napi_env env, napi_value exports); + static void ExecDnsResolverCallback(napi_env env, void *data); + static void CompleteDnsResolverCallback(napi_env env, napi_status status, void *data); + // declare napi interface for JS + static napi_value GetAddressesByName(napi_env env, napi_callback_info info); +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NAPI_DNS_RESOLVER_H diff --git a/frameworks/js/dnsresolver/src/napi_dns_resolver.cpp b/frameworks/js/dnsresolver/src/napi_dns_resolver.cpp new file mode 100755 index 0000000..8b4271d --- /dev/null +++ b/frameworks/js/dnsresolver/src/napi_dns_resolver.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2021 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 "napi_dns_resolver.h" +#include "system_ability_definition.h" +#include "iservice_registry.h" +#include "net_mgr_log_wrapper.h" +#include "i_dns_resolver_service.h" +#include "dns_resolver_client.h" +#include "napi_common.h" + +namespace OHOS { +namespace NetManagerStandard { +NapiDnsResolver::NapiDnsResolver() {} + +void NapiDnsResolver::ExecDnsResolverCallback(napi_env env, void *data) +{ + DnsResolverAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + std::string hostName = context->host; + std::vector addrInfo; + NETMGR_LOGI("ExecDnsResolverCallback [%{public}s]", hostName.c_str()); + DelayedSingleton::GetInstance()->GetAddressesByName(hostName, addrInfo); + NETMGR_LOGI("ExecDnsResolverCallback, addrInfo.size = [%{public}d]", static_cast(addrInfo.size())); + std::string tap; + for (auto it = addrInfo.begin(); it != addrInfo.end(); ++it) { + context->hostAddress.push_back(it->ToString(tap)); + } +} + +void NapiDnsResolver::CompleteDnsResolverCallback(napi_env env, napi_status status, void *data) +{ + NETMGR_LOGI("CompleteDnsResolverCallback"); + DnsResolverAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + // creat function return + napi_value infoAttay = nullptr; + napi_value info = nullptr; + napi_create_string_utf8(env, "fail", NAPI_AUTO_LENGTH, &info); + napi_create_array_with_length(env, context->hostAddress.size(), &infoAttay); + for (size_t index = 0; index < context->hostAddress.size(); index++) { + napi_create_string_utf8(env, context->hostAddress[index].c_str(), NAPI_AUTO_LENGTH, &info); + napi_set_element(env, infoAttay, index, info); + } + if (context->callbackRef == nullptr) { + // promiss return + if (context->hostAddress.size() > 0) { + NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context->deferred, infoAttay)); + } else { + NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, context->deferred, info)); + } + } else { + // call back return + napi_value callbackValues[CALLBACK_ARGV_CNT] = {nullptr, nullptr}; + napi_value recv = nullptr; + napi_value result = nullptr; + napi_value callbackFunc = nullptr; + napi_get_undefined(env, &recv); + napi_get_reference_value(env, context->callbackRef, &callbackFunc); + if (context->hostAddress.size() > 0) { + callbackValues[CALLBACK_ARGV_INDEX_1] = infoAttay; + } else { + callbackValues[CALLBACK_ARGV_INDEX_0] = info; + } + napi_call_function(env, recv, callbackFunc, std::size(callbackValues), callbackValues, &result); + napi_delete_reference(env, context->callbackRef); + } + napi_delete_async_work(env, context->work); + delete context; + context = nullptr; +} + +napi_value NapiDnsResolver::GetAddressesByName(napi_env env, napi_callback_info info) +{ + NETMGR_LOGI("NapiDnsResolver GetAddressesByName"); + size_t argc = ARGV_NUM_2; + napi_value argv[] = {nullptr, nullptr} ; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + DnsResolverAsyncContext* context = std::make_unique().release(); + NAPI_CALL(env, napi_get_value_string_utf8( + env, argv[ARGV_INDEX_0], context->host, HOST_MAX_BYTES, &(context->hostRealBytes))); + NETMGR_LOGI("GetAddressesByName = [%{public}s]", context->host); + NETMGR_LOGI("GetAddressesByName argc = [%{public}d]", static_cast(argc)); + napi_value result = nullptr; + if (argc == ARGV_NUM_1) { + if (context->callbackRef == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + } else if (argc == ARGV_NUM_2) { + NAPI_CALL(env, napi_create_reference(env, argv[ARGV_INDEX_1], CALLBACK_REF_CNT, &context->callbackRef)); + } else { + NETMGR_LOGE("GetAddressesByName exception"); + } + // creat async work + napi_value resource = nullptr; + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_get_undefined(env, &resource)); + NAPI_CALL(env, napi_create_string_utf8(env, "GetAddressesByName", NAPI_AUTO_LENGTH, &resourceName)); + NAPI_CALL(env, napi_create_async_work(env, resource, resourceName, + ExecDnsResolverCallback, + CompleteDnsResolverCallback, + (void *)context, + &context->work)); + NAPI_CALL(env, napi_queue_async_work(env, context->work)); + return result; +} + +napi_value NapiDnsResolver::DeclareNapiDnsResolverInterface(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("getAddressesByName", GetAddressesByName), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + return exports; +} + +napi_value NapiDnsResolver::RegisterDnsResolverInterface(napi_env env, napi_value exports) +{ + DeclareNapiDnsResolverInterface(env, exports); + return nullptr; +} + +static napi_module _dnsResolverModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = NapiDnsResolver::RegisterDnsResolverInterface, + .nm_modname = "netmanager.dnsresolver", + .nm_priv = ((void *)0), + .reserved = {0}, +}; + +extern "C" __attribute__((constructor)) void RegisterDnsResolverModule(void) +{ + napi_module_register(&_dnsResolverModule); +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/frameworks/js/ethernet/BUILD.gn b/frameworks/js/ethernet/BUILD.gn new file mode 100755 index 0000000..e0f098b --- /dev/null +++ b/frameworks/js/ethernet/BUILD.gn @@ -0,0 +1,62 @@ +# Copyright (c) 2021 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") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +SUBSYSTEM_DIR = "//foundation/communication" +NETMANAGER_NAPI_ROOT = "$SUBSYSTEM_DIR/netmanager_standard/frameworks/js/" + +ohos_shared_library("ethernet") { + include_dirs = [ + "//third_party/node/src", + "$NETMANAGER_NAPI_ROOT/ethernet/include", + "$NETMANAGER_NAPI_ROOT/common", + "$NETMANAGER_BASE_ROOT/utils/log/include", + "$ETHERNETMANAGER_SOURCE_DIR/include", + "$ETHERNETMANAGER_SOURCE_DIR/include/ipc", + "$INNERKITS_ROOT/native/ethernetmanager/include", + "//foundation/communication/netmanager_standard/interfaces/innerkits/native/ethernetmanager/include", + "//foundation/communication/wifi/services/wifi_standard/wifi_framework/dhcp_manage/mgr_service/include", + "//foundation/communication/wifi/services/wifi_standard/wifi_framework/dhcp_manage/mgr_service/interfaces", + ] + + sources = [ + "$NETMANAGER_NAPI_ROOT/common/napi_common.cpp", + "$NETMANAGER_NAPI_ROOT/ethernet/src/napi_ethernet.cpp", + ] + + defines = [ "NETMGR_DEBUG" ] + + deps = [ + "$INNERKITS_ROOT/native/ethernetmanager:ethernet_manager_if", + "$INNERKITS_ROOT/native/netconnmanager:net_conn_manager_if", + "$NETMANAGER_PREBUILTS_DIR/librarys/netd:libnet_manager_native", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/ace/napi/:ace_napi", + "//foundation/communication/wifi/services/wifi_standard/wifi_framework/dhcp_manage/mgr_service:dhcp_manager_service", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_standard:samgr_proxy", + ] + + relative_install_dir = "module" + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/frameworks/js/ethernet/include/napi_ethernet.h b/frameworks/js/ethernet/include/napi_ethernet.h new file mode 100755 index 0000000..19f35c8 --- /dev/null +++ b/frameworks/js/ethernet/include/napi_ethernet.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 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 NAPI_ETHERNET_H +#define NAPI_ETHERNET_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include +#include + +namespace OHOS { +namespace NetManagerStandard { +// ethernet name max bytes +constexpr int32_t ETHERNET_NAME_MAX_BYTE = 32; +// ip address max bytes +constexpr int32_t IP_ADDR_MAX_BYTE = 128; +// ip address type [static] +const std::string STATIC_IP = "static"; +// ip address type [dynamic] +const std::string DYNAMIC_IP = "dynamic"; + +struct EthernetAsyncContext { + napi_async_work work = nullptr; + napi_deferred deferred = nullptr; + napi_ref callbackRef = nullptr; + // Data context + char ethernetName[ETHERNET_NAME_MAX_BYTE] = {0}; + size_t ethernetNameRealBytes = 0; + int32_t ifActivate = 0; + // get all ethernetName + std::vector ethernetNameList; + // [0] static, [1] dhcp + int32_t ipMode = 0; + // ip address info + std::string ipAddrInfo; + // route address info + std::string routeAddrInfo; + // gate address info + std::string gateAddrInfo; + // mask address info + std::string maskAddrInfo; + // dns0 address info + std::string dns0AddrInfo; + // dns1 address info + std::string dns1AddrInfo; + int32_t result = 0; +}; + +class NapiEthernet { +public: + NapiEthernet(); + ~NapiEthernet() = default; + static napi_value RegisterEthernetInterface(napi_env env, napi_value exports); + static napi_value DeclareEthernetInterface(napi_env env, napi_value exports); + static napi_value DeclareEthernetData(napi_env env, napi_value exports); + + static void ExecSetIfaceConfig(napi_env env, void *data); + static void CompleteSetIfaceConfig(napi_env env, napi_status status, void *data); + static void ExecGetIfaceConfig(napi_env env, void *data); + static void CompleteGetIfaceConfig(napi_env env, napi_status status, void *data); + static void ExecIsActivate(napi_env env, void *data); + static void CompleteIsActivate(napi_env env, napi_status status, void *data); + static void ExecGetActivateInterfaces(napi_env env, void *data); + static void CompleteGetActivateInterfaces(napi_env env, napi_status status, void *data); + // define napi interface for JS + static napi_value SetIfaceConfig(napi_env env, napi_callback_info info); + static napi_value GetIfaceConfig(napi_env env, napi_callback_info info); + static napi_value IsActivate(napi_env env, napi_callback_info info); + static napi_value GetActivateInterfaces(napi_env env, napi_callback_info info); +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NAPI_ETHERNET_H diff --git a/frameworks/js/ethernet/src/napi_ethernet.cpp b/frameworks/js/ethernet/src/napi_ethernet.cpp new file mode 100755 index 0000000..847ea02 --- /dev/null +++ b/frameworks/js/ethernet/src/napi_ethernet.cpp @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2021 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 "napi_ethernet.h" +#include +#include "system_ability_definition.h" +#include "iservice_registry.h" +#include "net_mgr_log_wrapper.h" +#include "i_ethernet_service.h" +#include "ethernet_client.h" +#include "napi_common.h" + +namespace OHOS { +namespace NetManagerStandard { +NapiEthernet::NapiEthernet() {} + +void NapiEthernet::ExecSetIfaceConfig(napi_env env, void *data) +{ + NETMGR_LOGI("ExecSetIfaceConfig"); + EthernetAsyncContext *context = (EthernetAsyncContext *)data; + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + INetAddr addr0, addr1; + sptr config = std::make_unique().release(); + if (config == nullptr) { + NETMGR_LOGE("config == nullptr"); + return; + } + addr0.address_ = context->dns0AddrInfo; + addr1.address_ = context->dns1AddrInfo; + config->mode_ = static_cast(context->ipMode); + config->ipStatic_.ipAddr_.address_ = context->ipAddrInfo; + config->ipStatic_.route_.address_ = context->routeAddrInfo; + config->ipStatic_.gate_.address_ = context->gateAddrInfo; + config->ipStatic_.netMask_.address_ = context->maskAddrInfo; + config->ipStatic_.dnsServers_.push_back(addr0); + config->ipStatic_.dnsServers_.push_back(addr1); + context->result = DelayedSingleton::GetInstance()->SetIfaceConfig( + context->ethernetName, config); + NETMGR_LOGI("ExecSetIfaceConfig result =[%{public}d]", context->result); +} + +void NapiEthernet::CompleteSetIfaceConfig(napi_env env, napi_status status, void *data) +{ + NETMGR_LOGI("CompleteSetIfaceConfig"); + EthernetAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + napi_value info = nullptr; + napi_create_int32(env, context->result, &info); + if (context->callbackRef == nullptr) { + // promiss return + if (context->result != ERR_NONE) { + NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, context->deferred, info)); + } else { + NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context->deferred, info)); + } + } else { + // call back return + napi_value callbackValues[CALLBACK_ARGV_CNT] = {nullptr, nullptr}; + napi_value recv = nullptr; + napi_value result = nullptr; + napi_value callbackFunc = nullptr; + napi_get_undefined(env, &recv); + napi_get_reference_value(env, context->callbackRef, &callbackFunc); + if (context->result != ERR_NONE) { + callbackValues[CALLBACK_ARGV_INDEX_0] = info; + } else { + callbackValues[CALLBACK_ARGV_INDEX_1] = info; + } + napi_call_function(env, recv, callbackFunc, std::size(callbackValues), callbackValues, &result); + napi_delete_reference(env, context->callbackRef); + } + napi_delete_async_work(env, context->work); + delete context; + context = nullptr; +} + +void NapiEthernet::ExecGetIfaceConfig(napi_env env, void *data) +{ + NETMGR_LOGI("ExecGetIfaceConfig"); + EthernetAsyncContext *context = (EthernetAsyncContext *)data; + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + sptr config = + DelayedSingleton::GetInstance()->GetIfaceConfig(context->ethernetName); + if (config != nullptr) { + context->ifActivate = 1; + std::string tap; + context->ipMode = config->mode_; + NETMGR_LOGI("config->mode_ = [%{public}d]", config->mode_); + context->ipAddrInfo = config->ipStatic_.ipAddr_.ToString(tap); + NETMGR_LOGI("config->ipAddr_ = [%{public}s]", config->ipStatic_.ipAddr_.ToString(tap).c_str()); + context->routeAddrInfo = config->ipStatic_.route_.ToString(tap); + NETMGR_LOGI("config->route_ = [%{public}s]", config->ipStatic_.route_.ToString(tap).c_str()); + context->gateAddrInfo = config->ipStatic_.gate_.ToString(tap); + NETMGR_LOGI("config->gate_ = [%{public}s]", config->ipStatic_.gate_.ToString(tap).c_str()); + context->maskAddrInfo = config->ipStatic_.netMask_.ToString(tap); + NETMGR_LOGI("config->netMask_ = [%{public}s]", config->ipStatic_.netMask_.ToString(tap).c_str()); + for (auto it = config->ipStatic_.dnsServers_.begin(); it != config->ipStatic_.dnsServers_.end(); ++it) { + context->dns0AddrInfo = it->ToString(tap); + context->dns1AddrInfo = it->ToString(tap); + NETMGR_LOGI("config->dnsServers_ = [%{public}s]", it->ToString(tap).c_str()); + } + } else { + context->ifActivate = -1; + } +} + +void NapiEthernet::CompleteGetIfaceConfig(napi_env env, napi_status status, void *data) +{ + NETMGR_LOGI("CompleteGetIfaceConfig"); + EthernetAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + napi_value info = nullptr; + napi_value infoFail = nullptr; + napi_create_object(env, &info); + napi_create_string_utf8(env, "fail", NAPI_AUTO_LENGTH, &infoFail); + NpiCommon::SetPropertyInt32(env, info, "mode", context->ipMode); + NpiCommon::SetPropertyString(env, info, "ipAddr", context->ipAddrInfo); + NpiCommon::SetPropertyString(env, info, "routeAddr", context->routeAddrInfo); + NpiCommon::SetPropertyString(env, info, "gateAddr", context->gateAddrInfo); + NpiCommon::SetPropertyString(env, info, "maskAddr", context->maskAddrInfo); + NpiCommon::SetPropertyString(env, info, "dns0Addr", context->dns0AddrInfo); + NpiCommon::SetPropertyString(env, info, "dns1Addr", context->dns1AddrInfo); + if (context->callbackRef == nullptr) { + if (context->ifActivate == -1) { + NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, context->deferred, infoFail)); + } else { + NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context->deferred, info)); + } + } else { + napi_value callbackValues[CALLBACK_ARGV_CNT] = {nullptr, nullptr}; + napi_value recv = nullptr; + napi_value result = nullptr; + napi_value callbackFunc = nullptr; + napi_get_undefined(env, &recv); + napi_get_reference_value(env, context->callbackRef, &callbackFunc); + if (context->ifActivate == 0) { + callbackValues[ARGV_INDEX_0] = infoFail; + } else { + callbackValues[ARGV_INDEX_1] = info; + } + napi_call_function(env, recv, callbackFunc, std::size(callbackValues), callbackValues, &result); + napi_delete_reference(env, context->callbackRef); + } + napi_delete_async_work(env, context->work); + delete context; + context = nullptr; +} + +void NapiEthernet::ExecIsActivate(napi_env env, void *data) +{ + NETMGR_LOGI("ExecIsActivate"); + EthernetAsyncContext *context = (EthernetAsyncContext *)data; + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + context->ifActivate = DelayedSingleton::GetInstance()->IsActivate(context->ethernetName); + NETMGR_LOGI("ifActivate == [%{public}d]", context->ifActivate); +} + +void NapiEthernet::CompleteIsActivate(napi_env env, napi_status status, void *data) +{ + NETMGR_LOGI("CompleteIsActivate"); + EthernetAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + napi_value info = nullptr; + napi_create_int32(env, context->ifActivate, &info); + if (context->callbackRef == nullptr) { + if (context->ifActivate == -1) { + NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, context->deferred, info)); + } else { + NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context->deferred, info)); + } + } else { + napi_value callbackValues[CALLBACK_ARGV_CNT] = {nullptr, nullptr}; + napi_value recv = nullptr; + napi_value result = nullptr; + napi_value callbackFunc = nullptr; + napi_get_undefined(env, &recv); + napi_get_reference_value(env, context->callbackRef, &callbackFunc); + if (context->ifActivate == -1) { + callbackValues[ARGV_INDEX_0] = info; + } else { + callbackValues[ARGV_INDEX_1] = info; + } + napi_call_function(env, recv, callbackFunc, std::size(callbackValues), callbackValues, &result); + napi_delete_reference(env, context->callbackRef); + } + napi_delete_async_work(env, context->work); + delete context; + context = nullptr; +} + +void NapiEthernet::ExecGetActivateInterfaces(napi_env env, void *data) +{ + NETMGR_LOGI("ExecGetActivateInterfaces"); + EthernetAsyncContext *context = (EthernetAsyncContext *)data; + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + context->ethernetNameList = DelayedSingleton::GetInstance()->GetActivateInterfaces(); +} + +void NapiEthernet::CompleteGetActivateInterfaces(napi_env env, napi_status status, void *data) +{ + NETMGR_LOGI("CompleteGetActivateInterfaces"); + EthernetAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + // creat function return + napi_value infoAttay = nullptr; + napi_value info = nullptr; + napi_create_array_with_length(env, context->ethernetNameList.size(), &infoAttay); + for (size_t index = 0; index < context->ethernetNameList.size(); index++) { + napi_create_string_utf8(env, context->ethernetNameList[index].c_str(), NAPI_AUTO_LENGTH, &info); + napi_set_element(env, infoAttay, index, info); + } + if (context->callbackRef == nullptr) { + NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context->deferred, infoAttay)); + } else { + napi_value callbackValues[CALLBACK_ARGV_CNT] = {nullptr, nullptr}; + napi_value recv = nullptr; + napi_value result = nullptr; + napi_value callbackFunc = nullptr; + napi_get_undefined(env, &recv); + napi_get_reference_value(env, context->callbackRef, &callbackFunc); + callbackValues[CALLBACK_ARGV_INDEX_1] = infoAttay; + napi_call_function(env, recv, callbackFunc, std::size(callbackValues), callbackValues, &result); + napi_delete_reference(env, context->callbackRef); + } + napi_delete_async_work(env, context->work); + delete context; + context = nullptr; +} + +napi_value NapiEthernet::SetIfaceConfig(napi_env env, napi_callback_info info) +{ + NETMGR_LOGI("SetIfaceConfig"); + size_t argc = ARGV_NUM_4; + napi_value argv[] = {nullptr, nullptr, nullptr, nullptr} ; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + NETMGR_LOGI("SetIfaceConfig agvc = [%{public}d]", static_cast(argc)); + EthernetAsyncContext* context = std::make_unique().release(); + // Parse Js argv + NAPI_CALL(env, napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], + context->ethernetName, ETHERNET_NAME_MAX_BYTE, &(context->ethernetNameRealBytes))); + NETMGR_LOGI("SetIfaceConfig ethernetName = [%{public}s]", context->ethernetName); + // Parse Js object [ip] + NAPI_CALL(env, napi_get_value_int32(env, argv[ARGV_INDEX_1], &context->ipMode)); + NETMGR_LOGI("SetIfaceConfig mode = [%{public}d]", context->ipMode); + if (context->ipMode == IPSetMode::STATIC) { + NpiCommon::GetPropertyString(env, argv[ARGV_INDEX_2], "ipAddr", context->ipAddrInfo); + NpiCommon::GetPropertyString(env, argv[ARGV_INDEX_2], "routeAddr", context->routeAddrInfo); + NpiCommon::GetPropertyString(env, argv[ARGV_INDEX_2], "gateAddr", context->gateAddrInfo); + NpiCommon::GetPropertyString(env, argv[ARGV_INDEX_2], "maskAddr", context->maskAddrInfo); + NpiCommon::GetPropertyString(env, argv[ARGV_INDEX_2], "dnsAddr0", context->dns0AddrInfo); + NpiCommon::GetPropertyString(env, argv[ARGV_INDEX_2], "dnsAddr1", context->dns1AddrInfo); + } + napi_value result = nullptr; + if ((argc == ARGV_NUM_2) || (argc == ARGV_NUM_3 && context->ipMode == IPSetMode::STATIC)) { + if (context->callbackRef == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + } else if ((argc == ARGV_NUM_4) || (argc == ARGV_NUM_3 && context->ipMode == IPSetMode::DHCP)) { + NAPI_CALL(env, napi_create_reference(env, argv[argc - 1], CALLBACK_REF_CNT, &context->callbackRef)); + } else { + NETMGR_LOGE("SetIfaceConfig exception"); + } + // creat async work + napi_value resource = nullptr; + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_get_undefined(env, &resource)); + NAPI_CALL(env, napi_create_string_utf8(env, "SetIfaceConfig", NAPI_AUTO_LENGTH, &resourceName)); + NAPI_CALL(env, napi_create_async_work(env, resource, resourceName, + ExecSetIfaceConfig, + CompleteSetIfaceConfig, + (void *)context, + &context->work)); + NAPI_CALL(env, napi_queue_async_work(env, context->work)); + return result; +} + +napi_value NapiEthernet::GetIfaceConfig(napi_env env, napi_callback_info info) +{ + NETMGR_LOGI("GetIfaceConfig"); + size_t argc = ARGV_NUM_2; + napi_value argv[] = {nullptr, nullptr} ; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + NETMGR_LOGI("GetIfaceConfig agvc = [%{public}d]", static_cast(argc)); + EthernetAsyncContext* context = std::make_unique().release(); + // Parse Js argv + NAPI_CALL(env, napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], + context->ethernetName, ETHERNET_NAME_MAX_BYTE, &(context->ethernetNameRealBytes))); + NETMGR_LOGI("GetIfaceConfig [%{public}s]", context->ethernetName); + napi_value result = nullptr; + if (argc == ARGV_NUM_1) { + if (context->callbackRef == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + } else if (argc == ARGV_NUM_2) { + NAPI_CALL(env, napi_create_reference(env, argv[ARGV_INDEX_1], CALLBACK_REF_CNT, &context->callbackRef)); + } else { + NETMGR_LOGE("GetIfaceConfig exception"); + } + // creat async work + napi_value resource = nullptr; + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_get_undefined(env, &resource)); + NAPI_CALL(env, napi_create_string_utf8(env, "GetIfaceConfig", NAPI_AUTO_LENGTH, &resourceName)); + NAPI_CALL(env, napi_create_async_work(env, resource, resourceName, + ExecGetIfaceConfig, + CompleteGetIfaceConfig, + (void *)context, + &context->work)); + NAPI_CALL(env, napi_queue_async_work(env, context->work)); + return result; +} + +napi_value NapiEthernet::IsActivate(napi_env env, napi_callback_info info) +{ + NETMGR_LOGI("IsActivate"); + size_t argc = ARGV_NUM_2; + napi_value argv[] = {nullptr, nullptr} ; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + NETMGR_LOGI("IsActivate agvc = [%{public}d]", static_cast(argc)); + EthernetAsyncContext* context = std::make_unique().release(); + // Parse Js argv + NAPI_CALL(env, napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], + context->ethernetName, ETHERNET_NAME_MAX_BYTE, &(context->ethernetNameRealBytes))); + NETMGR_LOGI("IsActivate [%{public}s]", context->ethernetName); + napi_value result = nullptr; + if (argc == ARGV_NUM_1) { + if (context->callbackRef == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + } else if (argc == ARGV_NUM_2) { + NAPI_CALL(env, napi_create_reference(env, argv[ARGV_INDEX_1], CALLBACK_REF_CNT, &context->callbackRef)); + } else { + NETMGR_LOGE("IsActivate exception"); + } + // creat async work + napi_value resource = nullptr; + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_get_undefined(env, &resource)); + NAPI_CALL(env, napi_create_string_utf8(env, "IsActivate", NAPI_AUTO_LENGTH, &resourceName)); + NAPI_CALL(env, napi_create_async_work(env, resource, resourceName, + ExecIsActivate, + CompleteIsActivate, + (void *)context, + &context->work)); + NAPI_CALL(env, napi_queue_async_work(env, context->work)); + return result; +} + +napi_value NapiEthernet::GetActivateInterfaces(napi_env env, napi_callback_info info) +{ + size_t argc = ARGV_NUM_1; + napi_value argv[] = {nullptr} ; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + NETMGR_LOGI("GetActivateInterfaces agvc = [%{public}d]", static_cast(argc)); + EthernetAsyncContext* context = std::make_unique().release(); + napi_value result = nullptr; + if (argc == ARGV_NUM_0) { + if (context->callbackRef == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + } else if (argc == ARGV_NUM_1) { + NAPI_CALL(env, napi_create_reference(env, argv[ARGV_INDEX_0], CALLBACK_REF_CNT, &context->callbackRef)); + } else { + NETMGR_LOGE("GetActivateInterfaces exception"); + } + // creat async work + napi_value resource = nullptr; + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_get_undefined(env, &resource)); + NAPI_CALL(env, napi_create_string_utf8(env, "GetActivateInterfaces", NAPI_AUTO_LENGTH, &resourceName)); + NAPI_CALL(env, napi_create_async_work(env, resource, resourceName, + ExecGetActivateInterfaces, + CompleteGetActivateInterfaces, + (void *)context, + &context->work)); + NAPI_CALL(env, napi_queue_async_work(env, context->work)); + return result; +} + +napi_value NapiEthernet::DeclareEthernetData(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_STATIC_PROPERTY("STATIC", + NpiCommon::NapiValueByInt32(env, static_cast(IPSetMode::STATIC))), + DECLARE_NAPI_STATIC_PROPERTY("DHCP", + NpiCommon::NapiValueByInt32(env, static_cast(IPSetMode::DHCP))), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + return exports; +} + +napi_value NapiEthernet::DeclareEthernetInterface(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("setIfaceConfig", SetIfaceConfig), + DECLARE_NAPI_FUNCTION("getIfaceConfig", GetIfaceConfig), + DECLARE_NAPI_FUNCTION("isActivate", IsActivate), + DECLARE_NAPI_FUNCTION("getActivateInterfaces", GetActivateInterfaces), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + return exports; +} + +napi_value NapiEthernet::RegisterEthernetInterface(napi_env env, napi_value exports) +{ + DeclareEthernetInterface(env, exports); + DeclareEthernetData(env, exports); + return nullptr; +} + +static napi_module _ethernetModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = NapiEthernet::RegisterEthernetInterface, + .nm_modname = "netmanager.ethernet", + .nm_priv = ((void *)0), + .reserved = {0}, +}; + +extern "C" __attribute__((constructor)) void RegisterEthernetModule(void) +{ + napi_module_register(&_ethernetModule); +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/frameworks/js/netpolicy/BUILD.gn b/frameworks/js/netpolicy/BUILD.gn new file mode 100755 index 0000000..d504eed --- /dev/null +++ b/frameworks/js/netpolicy/BUILD.gn @@ -0,0 +1,55 @@ +# Copyright (c) 2021 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") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +NETMANAGER_NAPI_ROOT = "$SUBSYSTEM_DIR/netmanager_standard/frameworks/js/" + +ohos_shared_library("netpolicy") { + include_dirs = [ + "//third_party/node/src", + "$NETMANAGER_NAPI_ROOT/netpolicy/include", + "$NETMANAGER_NAPI_ROOT/common", + "$NETMANAGER_BASE_ROOT/utils/log/include", + "$NETPOLICYMANAGER_SOURCE_DIR/include", + "$NETPOLICYMANAGER_SOURCE_DIR/include/ipc", + ] + + sources = [ + "$NETMANAGER_NAPI_ROOT/common/napi_common.cpp", + "$NETMANAGER_NAPI_ROOT/netpolicy/src/napi_net_policy.cpp", + ] + + defines = [ "NETMGR_DEBUG" ] + + deps = [ + "$INNERKITS_ROOT/native/netconnmanager:net_conn_manager_if", + "$INNERKITS_ROOT/native/netpolicymanager:net_policy_manager_if", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/ace/napi/:ace_napi", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_standard:samgr_proxy", + ] + + relative_install_dir = "module" + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/frameworks/js/netpolicy/include/napi_net_policy.h b/frameworks/js/netpolicy/include/napi_net_policy.h new file mode 100755 index 0000000..fc33b51 --- /dev/null +++ b/frameworks/js/netpolicy/include/napi_net_policy.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 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 NAPI_NET_POLICY_H +#define NAPI_NET_POLICY_H + +#include +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "net_policy_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +// net policy async context +struct NetPolicyAsyncContext { + napi_async_work work = nullptr; + napi_deferred deferred = nullptr; + napi_ref callbackRef = nullptr; + // uid + uint32_t uid = 0; + // policy + uint32_t policy = 0; + // result of policy napi + int32_t policyResult = 0; + // vector of uid + std::vector uidTogether; + // result of bool type + bool result = false; + // metered + bool metered = false; + // interface name + std::string interfaceName; +}; + +class NapiNetPolicy { +public: + NapiNetPolicy(); + ~NapiNetPolicy() = default; + static napi_value RegisterNetPolicyInterface(napi_env env, napi_value exports); + static napi_value DeclareNapiNetPolicyInterface(napi_env env, napi_value exports); + static napi_value DeclareNapiNetPolicyData(napi_env env, napi_value exports); + static napi_value DeclareNapiNetPolicyResultData(napi_env env, napi_value exports); + + static void ExecSetUidPolicy(napi_env env, void *data); + static void ExecGetUids(napi_env env, void *data); + static void ExecGetUidPolicy(napi_env env, void *data); + static void ExecIsUidNetAccess(napi_env env, void *data); + static void CompleteSetUidPolicy(napi_env env, napi_status status, void *data); + static void CompleteGetUids(napi_env env, napi_status status, void *data); + static void CompleteGetUidPolicy(napi_env env, napi_status status, void *data); + static void CompleteIsUidNetAccess(napi_env env, napi_status status, void *data); + // Declare napi interfaces for JS + static napi_value SetUidPolicy(napi_env env, napi_callback_info info); + static napi_value GetUidPolicy(napi_env env, napi_callback_info info); + static napi_value GetUids(napi_env env, napi_callback_info info); + static napi_value IsUidNetAccess(napi_env env, napi_callback_info info); +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NAPI_NET_POLICY_H diff --git a/frameworks/js/netpolicy/src/napi_net_policy.cpp b/frameworks/js/netpolicy/src/napi_net_policy.cpp new file mode 100755 index 0000000..e7831cb --- /dev/null +++ b/frameworks/js/netpolicy/src/napi_net_policy.cpp @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2021 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 "napi_net_policy.h" +#include +#include "system_ability_definition.h" +#include "iservice_registry.h" +#include "net_mgr_log_wrapper.h" +#include "i_net_policy_service.h" +#include "net_conn_constants.h" +#include "net_policy_client.h" +#include "napi_common.h" + +namespace OHOS { +namespace NetManagerStandard { +void NapiNetPolicy::ExecSetUidPolicy(napi_env env, void *data) +{ + NetPolicyAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + NetUidPolicy policy = static_cast(context->policy); + context->policyResult = + static_cast(DelayedSingleton::GetInstance()->SetUidPolicy(context->uid, policy)); + NETMGR_LOGI("ExecSetUidPolicy, policy = [%{public}d], policyResult = [%{public}d]", + context->policy, context->policyResult); +} + +void NapiNetPolicy::ExecGetUids(napi_env env, void *data) +{ + NetPolicyAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + NetUidPolicy policy = static_cast(context->policy); + context->uidTogether = DelayedSingleton::GetInstance()->GetUids(policy); + NETMGR_LOGI("ExecGetUids, policy = [%{public}d], res.length = [%{public}d]", + context->policy, static_cast(context->uidTogether.size())); +} + +void NapiNetPolicy::ExecGetUidPolicy(napi_env env, void *data) +{ + NetPolicyAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + context->policyResult = + static_cast(DelayedSingleton::GetInstance()->GetUidPolicy(context->uid)); + NETMGR_LOGI("ExecGetUidPolicy, uid = [%{public}d], policyResult = [%{public}d]", + context->uid, context->policyResult); +} + +void NapiNetPolicy::ExecIsUidNetAccess(napi_env env, void *data) +{ + NetPolicyAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + if (context->interfaceName.length() > 0) { + context->result = + DelayedSingleton::GetInstance()->IsUidNetAccess(context->uid, context->interfaceName); + } else { + context->result = + DelayedSingleton::GetInstance()->IsUidNetAccess(context->uid, context->metered); + } +} +void NapiNetPolicy::CompleteSetUidPolicy(napi_env env, napi_status status, void *data) +{ + NetPolicyAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + napi_value info = nullptr; + napi_create_int32(env, context->policyResult, &info); + if (context->callbackRef == nullptr) { + // promiss return + if (context->policyResult != static_cast(NetPolicyResultCode::ERR_NONE)) { + NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, context->deferred, info)); + } else { + NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context->deferred, info)); + } + } else { + // call back + napi_value callbackValues[CALLBACK_ARGV_CNT] = {nullptr, nullptr}; + napi_value recv = nullptr; + napi_value result = nullptr; + napi_value callbackFunc = nullptr; + napi_get_undefined(env, &recv); + napi_get_reference_value(env, context->callbackRef, &callbackFunc); + if (context->policyResult != static_cast(NetPolicyResultCode::ERR_NONE)) { + callbackValues[CALLBACK_ARGV_INDEX_0] = info; + } else { + callbackValues[CALLBACK_ARGV_INDEX_1] = info; + } + napi_call_function(env, recv, callbackFunc, std::size(callbackValues), callbackValues, &result); + napi_delete_reference(env, context->callbackRef); + } + napi_delete_async_work(env, context->work); + delete context; + context = nullptr; +} + +void NapiNetPolicy::CompleteGetUids(napi_env env, napi_status status, void *data) +{ + NetPolicyAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + napi_value info = nullptr; + std::vector& res = context->uidTogether; + napi_create_array(env, &info); + for (unsigned int i = 0; i < res.size(); i++) { + napi_value num; + napi_create_uint32(env, res[i], &num); + napi_set_element(env, info, i, num); + } + if (!context->callbackRef) { + NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context->deferred, info)); + } else { + napi_value callbackValues[CALLBACK_ARGV_CNT] = {nullptr, nullptr}; + napi_value recv = nullptr; + napi_value result = nullptr; + napi_value callbackFunc = nullptr; + napi_get_undefined(env, &recv); + napi_get_reference_value(env, context->callbackRef, &callbackFunc); + callbackValues[CALLBACK_ARGV_INDEX_1] = info; + napi_call_function(env, recv, callbackFunc, std::size(callbackValues), callbackValues, &result); + napi_delete_reference(env, context->callbackRef); + } + napi_delete_async_work(env, context->work); + delete context; + context = nullptr; +} + +void NapiNetPolicy::CompleteGetUidPolicy(napi_env env, napi_status status, void *data) +{ + NetPolicyAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + napi_value info = nullptr; + napi_create_int32(env, context->policyResult, &info); + if (!context->callbackRef) { + NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context->deferred, info)); + } else { + napi_value callbackValues[CALLBACK_ARGV_CNT] = {nullptr, nullptr}; + napi_value recv = nullptr; + napi_value result = nullptr; + napi_value callbackFunc = nullptr; + napi_get_undefined(env, &recv); + napi_get_reference_value(env, context->callbackRef, &callbackFunc); + callbackValues[CALLBACK_ARGV_INDEX_1] = info; + napi_call_function(env, recv, callbackFunc, std::size(callbackValues), callbackValues, &result); + napi_delete_reference(env, context->callbackRef); + } + napi_delete_async_work(env, context->work); + delete context; + context = nullptr; +} + +void NapiNetPolicy::CompleteIsUidNetAccess(napi_env env, napi_status status, void *data) +{ + NetPolicyAsyncContext* context = static_cast(data); + if (context == nullptr) { + NETMGR_LOGE("context == nullptr"); + return; + } + napi_value info = nullptr; + napi_create_int32(env, context->result, &info); + if (!context->callbackRef) { + if (context->result == 0) { + NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, context->deferred, info)); + } else { + NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context->deferred, info)); + } + } else { + napi_value callbackValues[CALLBACK_ARGV_CNT] = {nullptr, nullptr}; + napi_value recv = nullptr; + napi_value result = nullptr; + napi_value callbackFunc = nullptr; + napi_get_undefined(env, &recv); + napi_get_reference_value(env, context->callbackRef, &callbackFunc); + if (context->result == 0) { + callbackValues[CALLBACK_ARGV_INDEX_0] = info; + } else { + callbackValues[CALLBACK_ARGV_INDEX_1] = info; + } + napi_call_function(env, recv, callbackFunc, std::size(callbackValues), callbackValues, &result); + napi_delete_reference(env, context->callbackRef); + } + napi_delete_async_work(env, context->work); + delete context; + context = nullptr; +} + +napi_value NapiNetPolicy::DeclareNapiNetPolicyData(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_STATIC_PROPERTY("NET_POLICY_NONE", + NpiCommon::NapiValueByInt32(env, static_cast(NetUidPolicy::NET_POLICY_NONE))), + DECLARE_NAPI_STATIC_PROPERTY("NET_POLICY_ALLOW_METERED_BACKGROUND", + NpiCommon::NapiValueByInt32(env, static_cast(NetUidPolicy::NET_POLICY_ALLOW_METERED_BACKGROUND))), + DECLARE_NAPI_STATIC_PROPERTY("NET_POLICY_TEMPORARY_ALLOW_METERED", + NpiCommon::NapiValueByInt32(env, static_cast(NetUidPolicy::NET_POLICY_TEMPORARY_ALLOW_METERED))), + DECLARE_NAPI_STATIC_PROPERTY("NET_POLICY_REJECT_METERED_BACKGROUND", + NpiCommon::NapiValueByInt32(env, static_cast(NetUidPolicy::NET_POLICY_REJECT_METERED_BACKGROUND))), + DECLARE_NAPI_STATIC_PROPERTY("NET_POLICY_ALLOW_ALL", + NpiCommon::NapiValueByInt32(env, static_cast(NetUidPolicy::NET_POLICY_ALLOW_ALL))), + DECLARE_NAPI_STATIC_PROPERTY("NET_POLICY_REJECT_ALL", + NpiCommon::NapiValueByInt32(env, static_cast(NetUidPolicy::NET_POLICY_REJECT_ALL))), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + return exports; +} + +napi_value NapiNetPolicy::DeclareNapiNetPolicyResultData(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_STATIC_PROPERTY("ERR_NONE", + NpiCommon::NapiValueByInt32(env, static_cast(NetPolicyResultCode::ERR_NONE))), + DECLARE_NAPI_STATIC_PROPERTY("ERR_INTERNAL_ERROR", + NpiCommon::NapiValueByInt32(env, static_cast(NetPolicyResultCode::ERR_INTERNAL_ERROR))), + DECLARE_NAPI_STATIC_PROPERTY("ERR_INVALID_UID", + NpiCommon::NapiValueByInt32(env, static_cast(NetPolicyResultCode::ERR_INVALID_UID))), + DECLARE_NAPI_STATIC_PROPERTY("ERR_INVALID_POLICY", + NpiCommon::NapiValueByInt32(env, static_cast(NetPolicyResultCode::ERR_INVALID_POLICY))), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + return exports; +} + +napi_value NapiNetPolicy::DeclareNapiNetPolicyInterface(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("setUidPolicy", SetUidPolicy), + DECLARE_NAPI_FUNCTION("getUidPolicy", GetUidPolicy), + DECLARE_NAPI_FUNCTION("getUids", GetUids), + DECLARE_NAPI_FUNCTION("isUidNetAccess", IsUidNetAccess), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + return exports; +} + +napi_value NapiNetPolicy::SetUidPolicy(napi_env env, napi_callback_info info) +{ + size_t argc = ARGV_NUM_3; + napi_value argv[] = {nullptr, nullptr, nullptr}; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + NetPolicyAsyncContext* context = std::make_unique().release(); + NAPI_CALL(env, napi_get_value_uint32(env, argv[ARGV_INDEX_0], &context->uid)); + NAPI_CALL(env, napi_get_value_uint32(env, argv[ARGV_INDEX_1], &context->policy)); + NETMGR_LOGI("JS agvc count = [%{public}d], argv[ARGV_INDEX_0] = [%{public}d], argv[ARGV_INDEX_1] = [%{public}d]", + static_cast(argc), context->uid, context->policy); + napi_value result = nullptr; + if (argc == ARGV_INDEX_2) { + if (context->callbackRef == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + } else if (argc == ARGV_INDEX_3) { + NAPI_CALL(env, napi_create_reference(env, argv[ARGV_INDEX_2], CALLBACK_REF_CNT, &context->callbackRef)); + } else { + NETMGR_LOGE("SetUidPolicy exception"); + } + // creat async work + napi_value resource = nullptr; + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_get_undefined(env, &resource)); + NAPI_CALL(env, napi_create_string_utf8(env, "SetUidPolicy", NAPI_AUTO_LENGTH, &resourceName)); + NAPI_CALL(env, napi_create_async_work(env, resource, resourceName, + ExecSetUidPolicy, + CompleteSetUidPolicy, + (void *)context, + &context->work)); + NAPI_CALL(env, napi_queue_async_work(env, context->work)); + return result; +} + +napi_value NapiNetPolicy::GetUidPolicy(napi_env env, napi_callback_info info) +{ + size_t argc = ARGV_INDEX_2; + napi_value argv[] = {nullptr, nullptr}; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + NetPolicyAsyncContext* context = std::make_unique().release(); + NAPI_CALL(env, napi_get_value_uint32(env, argv[ARGV_INDEX_0], &context->uid)); + NETMGR_LOGE("JS agvc count = [%{public}d], argv[0] = [%{public}d]", + static_cast(argc), context->uid); + // Get and verify parameter[js] + napi_value result = nullptr; + if (argc == ARGV_INDEX_1) { + if (!context->callbackRef) { + NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + } else if (argc == ARGV_INDEX_2) { + NAPI_CALL(env, napi_create_reference(env, argv[ARGV_INDEX_1], CALLBACK_REF_CNT, &context->callbackRef)); + } else { + NETMGR_LOGE("GetUidPolicy exception"); + } + // creat async work + napi_value resource = nullptr; + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_get_undefined(env, &resource)); + NAPI_CALL(env, napi_create_string_utf8(env, "getUids", NAPI_AUTO_LENGTH, &resourceName)); + NAPI_CALL(env, napi_create_async_work(env, resource, resourceName, + ExecGetUidPolicy, + CompleteGetUidPolicy, + (void *)context, + &context->work)); + NAPI_CALL(env, napi_queue_async_work(env, context->work)); + return result; +} + +napi_value NapiNetPolicy::GetUids(napi_env env, napi_callback_info info) +{ + size_t argc = ARGV_INDEX_2; + napi_value argv[] = {nullptr, nullptr} ; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + NetPolicyAsyncContext* context = std::make_unique().release(); + NAPI_CALL(env, napi_get_value_uint32(env, argv[ARGV_INDEX_0], &context->policy)); + NETMGR_LOGE("JS agvc count = [%{public}d], argv[0] = [%{public}d]", + static_cast(argc), context->policy); + // Get and verify parameter[js] + napi_value result = nullptr; + if (argc == ARGV_INDEX_1) { + if (!context->callbackRef) { + NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + } else if (argc == ARGV_INDEX_2) { + NAPI_CALL(env, napi_create_reference(env, argv[ARGV_INDEX_1], CALLBACK_REF_CNT, &context->callbackRef)); + } else { + NETMGR_LOGE("GetUids exception"); + } + // creat async work + napi_value resource = nullptr; + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_get_undefined(env, &resource)); + NAPI_CALL(env, napi_create_string_utf8(env, "getUids", NAPI_AUTO_LENGTH, &resourceName)); + NAPI_CALL(env, napi_create_async_work(env, resource, resourceName, + ExecGetUids, + CompleteGetUids, + (void *)context, + &context->work)); + NAPI_CALL(env, napi_queue_async_work(env, context->work)); + return result; +} + +napi_value NapiNetPolicy::IsUidNetAccess(napi_env env, napi_callback_info info) +{ + napi_valuetype valueType = napi_undefined; + size_t argc = ARGV_NUM_3; + napi_value argv[] = {nullptr, nullptr, nullptr}; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + NetPolicyAsyncContext* context = std::make_unique().release(); + NAPI_CALL(env, napi_get_value_uint32(env, argv[ARGV_NUM_0], &context->uid)); + napi_typeof(env, argv[ARGV_NUM_1], &valueType); + if (napi_valuetype::napi_boolean == valueType) { + NAPI_CALL(env, napi_get_value_bool(env, argv[ARGV_NUM_1], &context->metered)); + } + if (napi_valuetype::napi_string == valueType) { + char buf[BUFFER_BYTE] = {0}; + size_t typeLen = 0; + napi_get_value_string_utf8(env, argv[ARGV_NUM_1], buf, sizeof(buf), &typeLen); + context->interfaceName = buf; + NETMGR_LOGE("interfaceName = [%{public}s].\n", context->interfaceName.c_str()); + } + NETMGR_LOGI("JS agvc count = [%{public}d], argv[0] = [%{public}d], argv[1] = [%{public}d]", + static_cast(argc), context->uid, context->metered); + napi_value result = nullptr; + if (argc == ARGV_NUM_2) { + if (!context->callbackRef) { + NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + } else if (argc == ARGV_NUM_3) { + NAPI_CALL(env, napi_create_reference(env, argv[ARGV_NUM_2], CALLBACK_REF_CNT, &context->callbackRef)); + } else { + NETMGR_LOGE("IsUidNetAccess exception"); + } + // creat async work + napi_value resource = nullptr; + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_get_undefined(env, &resource)); + NAPI_CALL(env, napi_create_string_utf8(env, "IsUidNetAccess", NAPI_AUTO_LENGTH, &resourceName)); + NAPI_CALL(env, napi_create_async_work(env, resource, resourceName, + ExecIsUidNetAccess, + CompleteIsUidNetAccess, + (void *)context, + &context->work)); + NAPI_CALL(env, napi_queue_async_work(env, context->work)); + return result; +} + +napi_value NapiNetPolicy::RegisterNetPolicyInterface(napi_env env, napi_value exports) +{ + NETMGR_LOGI("RegisterNetPolicyInterface"); + DeclareNapiNetPolicyInterface(env, exports); + DeclareNapiNetPolicyData(env, exports); + DeclareNapiNetPolicyResultData(env, exports); + return nullptr; +} + +static napi_module _netPolicyModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = NapiNetPolicy::RegisterNetPolicyInterface, + .nm_modname = "netmanager.netpolicy", + .nm_priv = ((void *)0), + .reserved = {0}, +}; + +extern "C" __attribute__((constructor)) void RegisterNetPolicyModule(void) +{ + napi_module_register(&_netPolicyModule); +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/interfaces/innerkits/native/dnsresolvermanager/BUILD.gn b/interfaces/innerkits/native/dnsresolvermanager/BUILD.gn new file mode 100755 index 0000000..874b156 --- /dev/null +++ b/interfaces/innerkits/native/dnsresolvermanager/BUILD.gn @@ -0,0 +1,77 @@ +# Copyright (c) 2021 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") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +config("net_conn_manager_if_config") { + # header file path + include_dirs = [ + "$DNSRESOLVERMANAGER_SOURCE_DIR/include/ipc/", + "$INNERKITS_ROOT/native/dnsresolvermanager/include", + "$INNERKITS_ROOT/native/netconnmanager/include", + "$INNERKITS_ROOT/native/include", + ] + + cflags = [] + if (is_double_framework) { + cflags = [ "-DCONFIG_DUAL_FRAMEWORK" ] + } + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + if (is_standard_system) { + cflags += [ "-DCONFIG_STANDARD_SYSTEM" ] + } + if (defined(build_public_version) && build_public_version) { + cflags += [ "-DBUILD_PUBLIC_VERSION" ] + } +} + +ohos_shared_library("dns_resolver_manager_if") { + sources = [ + "$DNSRESOLVERMANAGER_INNERKITS_SOURCE_DIR/src/dns_addr_info.cpp", + "$DNSRESOLVERMANAGER_INNERKITS_SOURCE_DIR/src/dns_resolver_client.cpp", + "$DNSRESOLVERMANAGER_SOURCE_DIR/src/ipc/dns_resolver_service_proxy.cpp", + ] + + include_dirs = [ "$DNSRESOLVERMANAGER_SOURCE_DIR/include/" ] + + public_configs = [ ":net_conn_manager_if_config" ] + + deps = [ + "$INNERKITS_ROOT/native/netconnmanager:net_conn_manager_if", + "$NETMANAGER_BASE_ROOT/utils:net_manager_common", + ] + + external_deps = [ + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_standard:samgr_proxy", + ] + + defines = [ + "NETMGR_LOG_TAG = \"DnsResolverManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/interfaces/innerkits/native/dnsresolvermanager/include/dns_addr_info.h b/interfaces/innerkits/native/dnsresolvermanager/include/dns_addr_info.h new file mode 100755 index 0000000..b955b00 --- /dev/null +++ b/interfaces/innerkits/native/dnsresolvermanager/include/dns_addr_info.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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 DNS_ADDR_INFO_H +#define DNS_ADDR_INFO_H + +#include +#include + +#include "parcel.h" + +namespace OHOS { +namespace NetManagerStandard { +struct DnsAddrInfo : public Parcelable { + int32_t flags_ = 0; + int32_t family_ = 0; + int32_t sockType_ = 0; + int32_t protocol_ = 0; + std::string addr_; + std::string canonName_; + + bool Marshalling(Parcel &parcel) const override; + static sptr Unmarshalling(Parcel &parcel); +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/innerkits/native/dnsresolvermanager/include/dns_resolver_client.h b/interfaces/innerkits/native/dnsresolvermanager/include/dns_resolver_client.h new file mode 100755 index 0000000..e461d60 --- /dev/null +++ b/interfaces/innerkits/native/dnsresolvermanager/include/dns_resolver_client.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2021 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 DNS_RESOLVER_MANAGER_H +#define DNS_RESOLVER_MANAGER_H + +#include + +#include "parcel.h" +#include "singleton.h" + +#include "i_dns_resolver_service.h" + +namespace OHOS { +namespace NetManagerStandard { +class DnsResolverClient { + DECLARE_DELAYED_SINGLETON(DnsResolverClient) + +public: + /** + * @brief Get Addresses By domain Name + * + * @param The domain name + * @param The address information is parsed successfully + * @return Returns 0 as success, other values as failure + */ + int32_t GetAddressesByName(const std::string &hostName, std::vector &addrInfo); + /** + * @brief Get Addresses By domain Name + * + * @param DNS server address + * @param DNS server address + * @param Address information structure + * @param The address information is parsed successfully + * @return Returns 0 as success, other values as failure + */ + int32_t GetAddrInfo(const std::string &hostName, const std::string &server, + const sptr &hints, std::vector> &dnsAddrInfo); + /** + * @brief Create a network cache and netId mapping + * + * @param netId + * @return Returns 0 as success, other values as failure + */ + int32_t CreateNetworkCache(uint16_t netId); + /** + * @brief Delete the network cache and remove the mapping with netId + * + * @param netId + * @return Returns 0 as success, other values as failure + */ + int32_t DestoryNetworkCache(uint16_t netId); + /** + * @brief Clear the network cache information + * + * @param netId + * @return Returns 0 as success, other values as failure + */ + int32_t FlushNetworkCache(uint16_t netId); + /** + * @brief Bind the DNS server address to netId + * + * @param netId + * @param Timeout of domain name request + * @param Number of Domain name Requests + * @param DNS server address information + * @param The domain name + * @return Returns 0 as success, other values as failure + */ + int32_t SetResolverConfig(uint16_t netId, uint16_t baseTimeoutMsec, uint8_t retryCount, + const std::vector &servers, const std::vector &domains); + /** + * @brief Obtain domain name resolution configuration information + * + * @param netId + * @param DNS server address information + * @param The domain name + * @param Timeout of domain name request + * @param Number of Domain name Requests + * @return Returns 0 as success, other values as failure + */ + int32_t GetResolverInfo(uint16_t netId, std::vector &servers, + std::vector &domains, uint16_t &baseTimeoutMsec, uint8_t &retryCount); + +private: + class DnsResolverDeathRecipient : public IRemoteObject::DeathRecipient { + public: + explicit DnsResolverDeathRecipient(DnsResolverClient &client) : client_(client) {} + ~DnsResolverDeathRecipient() override = default; + void OnRemoteDied(const wptr &remote) override + { + client_.OnRemoteDied(remote); + } + + private: + DnsResolverClient &client_; + }; + +private: + sptr GetProxy(); + void OnRemoteDied(const wptr &remote); + +private: + std::mutex mutex_; + sptr dnsResolverService_; + sptr deathRecipient_; +}; +} // namespace NetManagerStandard +} // namespace OHOS + +#endif // DNS_RESOLVER_MANAGER_H \ No newline at end of file diff --git a/interfaces/innerkits/native/dnsresolvermanager/include/dns_resolver_constants.h b/interfaces/innerkits/native/dnsresolvermanager/include/dns_resolver_constants.h new file mode 100755 index 0000000..31fed08 --- /dev/null +++ b/interfaces/innerkits/native/dnsresolvermanager/include/dns_resolver_constants.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 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 DNS_RESOLVER_CONSTANTS_H +#define DNS_RESOLVER_CONSTANTS_H + +#include "netmanager_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +constexpr int DNS_ERROR = -1; +constexpr int DNS_SUCCESS = 0; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // DNS_RESOLVER_CONSTANTS_H \ No newline at end of file diff --git a/interfaces/innerkits/native/ethernetmanager/BUILD.gn b/interfaces/innerkits/native/ethernetmanager/BUILD.gn new file mode 100755 index 0000000..5265e86 --- /dev/null +++ b/interfaces/innerkits/native/ethernetmanager/BUILD.gn @@ -0,0 +1,80 @@ +# Copyright (c) 2021 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") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") +config("net_conn_manager_if_config") { + # header file path + include_dirs = [ + "$ETHERNETMANAGER_SOURCE_DIR/include/ipc/", + "$INNERKITS_ROOT/native/ethernetmanager/include", + "$INNERKITS_ROOT/native/netconnmanager/include", + "$INNERKITS_ROOT/native/include", + ] + + cflags = [] + if (is_double_framework) { + cflags = [ "-DCONFIG_DUAL_FRAMEWORK" ] + } + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + if (is_standard_system) { + cflags += [ "-DCONFIG_STANDARD_SYSTEM" ] + } + if (defined(build_public_version) && build_public_version) { + cflags += [ "-DBUILD_PUBLIC_VERSION" ] + } +} + +ohos_shared_library("ethernet_manager_if") { + sources = [ + "$ETHERNETMANAGER_INNERKITS_SOURCE_DIR/src/ethernet_client.cpp", + "$ETHERNETMANAGER_INNERKITS_SOURCE_DIR/src/interface_configuration.cpp", + "$ETHERNETMANAGER_INNERKITS_SOURCE_DIR/src/static_configuration.cpp", + "$ETHERNETMANAGER_SOURCE_DIR/src/ipc/ethernet_service_proxy.cpp", + ] + + include_dirs = [ "$ETHERNETMANAGER_SOURCE_DIR/include/" ] + + public_configs = [ ":net_conn_manager_if_config" ] + + deps = [ + "$INNERKITS_ROOT/native/netconnmanager:net_conn_manager_if", + "$NETMANAGER_BASE_ROOT/utils:net_manager_common", + ] + + external_deps = [ + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_standard:samgr_proxy", + ] + + defines = [ + "NETMGR_LOG_TAG = \"EthernetManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (enable_netmgr_debug) { + defines += [ "NETMGR_DEBUG" ] + } + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/interfaces/innerkits/native/ethernetmanager/include/ethernet_client.h b/interfaces/innerkits/native/ethernetmanager/include/ethernet_client.h new file mode 100755 index 0000000..db6729c --- /dev/null +++ b/interfaces/innerkits/native/ethernetmanager/include/ethernet_client.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021 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 ETHERNET_MANAGER_H +#define ETHERNET_MANAGER_H + +#include + +#include "parcel.h" +#include "singleton.h" + +#include "i_ethernet_service.h" + +namespace OHOS { +namespace NetManagerStandard { +class EthernetClient { + DECLARE_DELAYED_SINGLETON(EthernetClient) + +public: + /** + * @brief Set the network interface configuration + * + * @param Network interface name + * @param Network interface parameters + * @return Returns 0 as success, other values as failure + */ + int32_t SetIfaceConfig(const std::string &iface, sptr &ic); + /** + * @brief Gets the network interface configuration parameters + * + * @param Network interface name + * @return Parameter is returned on success, null on failure + */ + sptr GetIfaceConfig(const std::string &iface); + /** + * @brief Gets the network interface configuration parameters + * + * @param Network interface name + * @return Returns 1 for device open (active), 0 for device closed (inactive), and -1 for failure + */ + int32_t IsActivate(const std::string &iface); + /** + * @brief Gets the list of active devices + * + * @return Return to device List + */ + std::vector GetActivateInterfaces(); + +private: + class EthernetDeathRecipient : public IRemoteObject::DeathRecipient { + public: + explicit EthernetDeathRecipient(EthernetClient &client) : client_(client) {} + ~EthernetDeathRecipient() override = default; + void OnRemoteDied(const wptr &remote) override + { + client_.OnRemoteDied(remote); + } + + private: + EthernetClient &client_; + }; + +private: + sptr GetProxy(); + void OnRemoteDied(const wptr &remote); + +private: + std::mutex mutex_; + sptr ethernetService_; + sptr deathRecipient_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // ETHERNET_MANAGER_H \ No newline at end of file diff --git a/interfaces/innerkits/native/ethernetmanager/include/ethernet_constants.h b/interfaces/innerkits/native/ethernetmanager/include/ethernet_constants.h new file mode 100755 index 0000000..3c42533 --- /dev/null +++ b/interfaces/innerkits/native/ethernetmanager/include/ethernet_constants.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 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 ETHERNET_CONSTANTS_H +#define ETHERNET_CONSTANTS_H + +#include "netmanager_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +constexpr int ETHERNET_ERROR = -1; +constexpr int ETHERNET_SUCCESS = 0; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // ETHERNET_ERRORS_H \ No newline at end of file diff --git a/interfaces/innerkits/native/ethernetmanager/include/interface_configuration.h b/interfaces/innerkits/native/ethernetmanager/include/interface_configuration.h new file mode 100755 index 0000000..7445f41 --- /dev/null +++ b/interfaces/innerkits/native/ethernetmanager/include/interface_configuration.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 INTERFACE_CONFIGURATION_H +#define INTERFACE_CONFIGURATION_H + +#include "static_configuration.h" + +namespace OHOS { +namespace NetManagerStandard { +typedef enum { + STATIC, + DHCP, +} IPSetMode; +struct InterfaceConfiguration : public Parcelable { + IPSetMode mode_; + StaticConfiguration ipStatic_; + + virtual bool Marshalling(Parcel &parcel) const override; + static sptr Unmarshalling(Parcel &parcel); +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/innerkits/native/ethernetmanager/include/static_configuration.h b/interfaces/innerkits/native/ethernetmanager/include/static_configuration.h new file mode 100755 index 0000000..b269f65 --- /dev/null +++ b/interfaces/innerkits/native/ethernetmanager/include/static_configuration.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 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 STATIC_CONFIGURATION_H +#define STATIC_CONFIGURATION_H + +#include +#include + +#include "parcel.h" +#include "inet_addr.h" + +namespace OHOS { +namespace NetManagerStandard { +struct StaticConfiguration : public Parcelable { + INetAddr ipAddr_; + INetAddr route_; + INetAddr gate_; + INetAddr netMask_; + std::vector dnsServers_; + std::string domain_; + + virtual bool Marshalling(Parcel &parcel) const override; + static sptr Unmarshalling(Parcel &parcel); +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/innerkits/native/include/netmanager_constants.h b/interfaces/innerkits/native/include/netmanager_constants.h new file mode 100755 index 0000000..5dfc674 --- /dev/null +++ b/interfaces/innerkits/native/include/netmanager_constants.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 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 NETMANAGER_CONSTANTS_H +#define NETMANAGER_CONSTANTS_H + +#include + +namespace OHOS { +namespace NetManagerStandard { +constexpr int NETMANAGER_ERROR = -1; +constexpr int NETMANAGER_SUCCESS = 0; + +enum { + NETMANAGER_COMMON = 0x00, + NETMANAGER_DNS_RESOLVER_MANAGER = 0x01, + NETMANAGER_ETHERNET_MANAGER = 0x02, + NETMANAGER_NET_CONN_MANAGER = 0x03, + NETMANAGER_NET_POLICY_MANAGER = 0x04, +}; + +// Error code for common +constexpr ErrCode COMMON_ERR_OFFSET = ErrCodeOffset(SUBSYS_COMMUNICATION, NETMANAGER_COMMON); + +enum { + NETMANAGER_ERR_FAIL = COMMON_ERR_OFFSET, + NETMANAGER_ERR_MEMCPY_FAIL, + NETMANAGER_ERR_MEMSET_FAIL, + NETMANAGER_ERR_STRCPY_FAIL, + NETMANAGER_ERR_STRING_EMPTY, + NETMANAGER_ERR_LOCAL_PTR_NULL, + NETMANAGER_ERR_PERMISSION_ERR, + NETMANAGER_ERR_DESCRIPTOR_MISMATCH, + NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL, + NETMANAGER_ERR_WRITE_DATA_FAIL, + NETMANAGER_ERR_WRITE_REPLY_FAIL, + NETMANAGER_ERR_READ_DATA_FAIL, + NETMANAGER_ERR_READ_REPLY_FAIL, + NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL, + NETMANAGER_ERR_ADD_DEATH_RECIPIENT_FAIL, + NETMANAGER_ERR_REGISTER_CALLBACK_FAIL, + NETMANAGER_ERR_UNINIT, +}; + +// Error code for netmanager dns resolver +constexpr ErrCode DNS_ERR_OFFSET = ErrCodeOffset(SUBSYS_COMMUNICATION, NETMANAGER_DNS_RESOLVER_MANAGER); +// Error code for netmanager ethernet +constexpr ErrCode ETHERNET_ERR_OFFSET = ErrCodeOffset(SUBSYS_COMMUNICATION, NETMANAGER_ETHERNET_MANAGER); +// Error code for netmanager conn manager +constexpr ErrCode CONN_MANAGER_ERR_OFFSET = ErrCodeOffset(SUBSYS_COMMUNICATION, NETMANAGER_NET_CONN_MANAGER); +// Error code for netmanager policy manager +constexpr ErrCode POLICY_MANAGER_ERR_OFFSET = ErrCodeOffset(SUBSYS_COMMUNICATION, NETMANAGER_NET_POLICY_MANAGER); +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NETMANAGER_CONSTANTS_H \ No newline at end of file diff --git a/interfaces/innerkits/native/netconnmanager/BUILD.gn b/interfaces/innerkits/native/netconnmanager/BUILD.gn new file mode 100755 index 0000000..6ed54b2 --- /dev/null +++ b/interfaces/innerkits/native/netconnmanager/BUILD.gn @@ -0,0 +1,83 @@ +# Copyright (c) 2021 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") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +config("net_conn_manager_if_config") { + # header file path + include_dirs = [ + "$NETCONNMANAGER_SOURCE_DIR/include/ipc", + "$INNERKITS_ROOT/native/netconnmanager/include", + "$INNERKITS_ROOT/native/netconnmanager/include/ipc", + ] + + cflags = [] + if (is_double_framework) { + cflags = [ "-DCONFIG_DUAL_FRAMEWORK" ] + } + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + if (is_standard_system) { + cflags += [ "-DCONFIG_STANDARD_SYSTEM" ] + } + if (defined(build_public_version) && build_public_version) { + cflags += [ "-DBUILD_PUBLIC_VERSION" ] + } +} + +ohos_shared_library("net_conn_manager_if") { + sources = [ + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/inet_addr.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/ipc/net_conn_callback_stub.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/net_conn_callback_info.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/net_conn_client.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/net_link_info.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/net_specifier.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/net_supplier_info.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/route.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/ipc/net_conn_service_proxy.cpp", + ] + + include_dirs = [ "$NETCONNMANAGER_SOURCE_DIR/include/" ] + + public_configs = [ ":net_conn_manager_if_config" ] + + deps = [ "$NETMANAGER_BASE_ROOT/utils:net_manager_common" ] + + external_deps = [ + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_standard:samgr_proxy", + ] + + defines = [ + "NETMGR_LOG_TAG = \"NetConnManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (enable_netmgr_debug) { + defines += [ "NETMGR_DEBUG" ] + } + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/interfaces/innerkits/native/netconnmanager/include/inet_addr.h b/interfaces/innerkits/native/netconnmanager/include/inet_addr.h new file mode 100755 index 0000000..65615d5 --- /dev/null +++ b/interfaces/innerkits/native/netconnmanager/include/inet_addr.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 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 INET_ADDR_H +#define INET_ADDR_H + +#include + +#include "parcel.h" + +namespace OHOS { +namespace NetManagerStandard { +struct INetAddr : public Parcelable { + typedef enum { + UNKNOWN = 0x00, + IPV4 = 0x01, + IPV6 = 0x02, + } IpType; + + uint8_t type_ = UNKNOWN; + uint8_t family_ = 0x00; + uint8_t prefixlen_ = 0; + std::string address_; + std::string netMask_; + std::string hostName_; + + bool operator==(const INetAddr& obj) const; + + virtual bool Marshalling(Parcel &parcel) const override; + static sptr Unmarshalling(Parcel &parcel); + static bool Marshalling(Parcel &parcel, const sptr &object); + std::string ToString(const std::string tab = "") const; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/innerkits/native/netconnmanager/include/ipc/i_net_conn_callback.h b/interfaces/innerkits/native/netconnmanager/include/ipc/i_net_conn_callback.h new file mode 100755 index 0000000..c7fd30a --- /dev/null +++ b/interfaces/innerkits/native/netconnmanager/include/ipc/i_net_conn_callback.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 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 I_NET_CONN_CALLBACK_H +#define I_NET_CONN_CALLBACK_H + +#include + +#include "iremote_broker.h" + +#include "net_conn_callback_info.h" + +namespace OHOS { +namespace NetManagerStandard { +class INetConnCallback : public IRemoteBroker { +public: + virtual ~INetConnCallback() = default; +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.NetManagerStandard.INetConnCallback"); + enum { + NET_CONN_STATE_CHANGED = 0, + }; + +public: + virtual int32_t NetConnStateChanged(const sptr &info) = 0; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // I_NET_CONN_CALLBACK_H diff --git a/interfaces/innerkits/native/netconnmanager/include/ipc/net_conn_callback_stub.h b/interfaces/innerkits/native/netconnmanager/include/ipc/net_conn_callback_stub.h new file mode 100755 index 0000000..5eefd7e --- /dev/null +++ b/interfaces/innerkits/native/netconnmanager/include/ipc/net_conn_callback_stub.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 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 NET_CONN_CALLBACK_STUB_H +#define NET_CONN_CALLBACK_STUB_H + +#include + +#include "iremote_stub.h" + +#include "i_net_conn_callback.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetConnCallbackStub : public IRemoteStub { +public: + NetConnCallbackStub(); + virtual ~NetConnCallbackStub(); + + int32_t OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + using NetConnCallbackFunc = int32_t (NetConnCallbackStub::*)(MessageParcel &, MessageParcel &); + +private: + int32_t OnNetConnStateChanged(MessageParcel &data, MessageParcel &reply); + +private: + std::map memberFuncMap_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONN_CALLBACK_STUB_H diff --git a/interfaces/innerkits/native/netconnmanager/include/net_conn_callback_info.h b/interfaces/innerkits/native/netconnmanager/include/net_conn_callback_info.h new file mode 100755 index 0000000..9b11e49 --- /dev/null +++ b/interfaces/innerkits/native/netconnmanager/include/net_conn_callback_info.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 NET_CALLBACK_INFO_H +#define NET_CALLBACK_INFO_H + +#include + +#include "parcel.h" + +namespace OHOS { +namespace NetManagerStandard { +struct NetConnCallbackInfo : public Parcelable { + int32_t netState_ = 0; + uint32_t netType_ = 0; + + virtual bool Marshalling(Parcel &parcel) const override; + static sptr Unmarshalling(Parcel &parcel); + static bool Marshalling(Parcel &parcel, const sptr &object); + std::string ToString(const std::string &tab) const; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CALLBACK_INFO_H \ No newline at end of file diff --git a/interfaces/innerkits/native/netconnmanager/include/net_conn_client.h b/interfaces/innerkits/native/netconnmanager/include/net_conn_client.h new file mode 100755 index 0000000..218286e --- /dev/null +++ b/interfaces/innerkits/native/netconnmanager/include/net_conn_client.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021 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 NET_CONN_MANAGER_H +#define NET_CONN_MANAGER_H + +#include + +#include "parcel.h" +#include "singleton.h" + +#include "i_net_conn_service.h" +#include "net_link_info.h" +#include "net_specifier.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetConnClient { + DECLARE_DELAYED_SINGLETON(NetConnClient) + +public: + int32_t SystemReady(); + int32_t RegisterNetSupplier(uint32_t netType, const std::string &ident, uint64_t netCapabilities); + int32_t UnregisterNetSupplier(uint32_t supplierId); + int32_t RegisterNetConnCallback(const sptr &callback); + int32_t RegisterNetConnCallback(const sptr &netSpecifier, const sptr &callback); + int32_t UnregisterNetConnCallback(const sptr &callback); + int32_t UnregisterNetConnCallback(const sptr &netSpecifier, const sptr &callback); + int32_t UpdateNetSupplierInfo(uint32_t supplierId, const sptr &netSupplierInfo); + int32_t UpdateNetCapabilities(uint32_t supplierId, uint64_t netCapabilities); + int32_t UpdateNetLinkInfo(uint32_t supplierId, const sptr &netLinkInfo); + +private: + class NetConnDeathRecipient : public IRemoteObject::DeathRecipient { + public: + explicit NetConnDeathRecipient(NetConnClient &client) : client_(client) {} + ~NetConnDeathRecipient() override = default; + void OnRemoteDied(const wptr &remote) override + { + client_.OnRemoteDied(remote); + } + + private: + NetConnClient &client_; + }; + +private: + sptr GetProxy(); + void OnRemoteDied(const wptr &remote); + +private: + std::mutex mutex_; + sptr NetConnService_; + sptr deathRecipient_; +}; +} // namespace NetManagerStandard +} // namespace OHOS + +#endif // NET_CONN_MANAGER_H \ No newline at end of file diff --git a/interfaces/innerkits/native/netconnmanager/include/net_conn_constants.h b/interfaces/innerkits/native/netconnmanager/include/net_conn_constants.h new file mode 100755 index 0000000..8037422 --- /dev/null +++ b/interfaces/innerkits/native/netconnmanager/include/net_conn_constants.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 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 NET_CONN_CONSTANTS_H +#define NET_CONN_CONSTANTS_H + +namespace OHOS { +namespace NetManagerStandard { +enum NetConnResultCode { + NET_CONN_SUCCESS = 0, + NET_CONN_ERR_GET_REMOTE_OBJECT_FAILED = (-1), + NET_CONN_ERR_INPUT_NULL_PTR = (-2), + NET_CONN_ERR_INVALID_SUPPLIER_ID = (-3), + NET_CONN_ERR_INVALID_PARAMETER = (-4), + NET_CONN_ERR_NET_TYPE_NOT_FOUND = (-5), + NET_CONN_ERR_NO_ANY_NET_TYPE = (-6), + NET_CONN_ERR_NO_REGISTERED = (-7), + NET_CONN_ERR_INTERNAL_ERROR = (-1000) +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONN_CONSTANTS_H \ No newline at end of file diff --git a/interfaces/innerkits/native/netconnmanager/include/net_link_info.h b/interfaces/innerkits/native/netconnmanager/include/net_link_info.h new file mode 100755 index 0000000..7f907eb --- /dev/null +++ b/interfaces/innerkits/native/netconnmanager/include/net_link_info.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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 NET_LINK_INFO_H +#define NET_LINK_INFO_H + +#include + +#include "inet_addr.h" +#include "net_specifier.h" +#include "route.h" + +namespace OHOS { +namespace NetManagerStandard { +struct NetLinkInfo : public Parcelable { + std::string ifaceName_; + std::string domain_; + std::list netAddrList_; + std::list dnsList_; + std::list routeList_; + uint16_t mtu_ = 0; + + virtual bool Marshalling(Parcel &parcel) const override; + static sptr Unmarshalling(Parcel &parcel); + static bool Marshalling(Parcel &parcel, const sptr &object); + std::string ToString(const std::string &tab) const; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_LINK_INFO_H \ No newline at end of file diff --git a/interfaces/innerkits/native/netconnmanager/include/net_specifier.h b/interfaces/innerkits/native/netconnmanager/include/net_specifier.h new file mode 100755 index 0000000..d9ad85e --- /dev/null +++ b/interfaces/innerkits/native/netconnmanager/include/net_specifier.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 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 NET_SPECIFIER_H +#define NET_SPECIFIER_H + +#include + +#include "parcel.h" + +namespace OHOS { +namespace NetManagerStandard { +typedef enum { + NET_CAPABILITIES_NONE, + NET_CAPABILITIES_INTERNET = 1 << 0, + NET_CAPABILITIES_MMS = 1 << 1, + NET_CAPABILITIES_MAX +} NetCapabilities; + +typedef enum { + NET_TYPE_UNKNOWN, + NET_TYPE_CELLULAR, + NET_TYPE_ETHERNET, + NET_TYPE_MAX +} NetworkType; + +struct NetSpecifier : public Parcelable { + std::string ident_; + uint32_t netType_ = NET_TYPE_UNKNOWN; + uint64_t netCapabilities_ = NET_CAPABILITIES_NONE; + + virtual bool Marshalling(Parcel &parcel) const override; + static sptr Unmarshalling(Parcel &parcel); + static bool Marshalling(Parcel &parcel, const sptr &object); + std::string ToString(const std::string &tab) const; + + bool operator< (const NetSpecifier &spec) const + { + return (netType_ < spec.netType_) || (netType_ == spec.netType_ && netCapabilities_ < spec.netCapabilities_); + } +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/innerkits/native/netconnmanager/include/net_supplier_info.h b/interfaces/innerkits/native/netconnmanager/include/net_supplier_info.h new file mode 100755 index 0000000..f112575 --- /dev/null +++ b/interfaces/innerkits/native/netconnmanager/include/net_supplier_info.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 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 NET_SUPPLIER_INFO_H +#define NET_SUPPLIER_INFO_H + +#include + +#include "parcel.h" + +namespace OHOS { +namespace NetManagerStandard { +struct NetSupplierInfo : public Parcelable { + bool isAvailable_ = false; + bool isRoaming_ = false; + uint8_t strength_ = 0x00; + uint32_t frequency_ = 0x00; + + virtual bool Marshalling(Parcel &parcel) const override; + static sptr Unmarshalling(Parcel &parcel); + static bool Marshalling(Parcel &parcel, const sptr &object); + std::string ToString(const std::string &tab) const; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_SUPPLIER_INFO_H \ No newline at end of file diff --git a/interfaces/innerkits/native/netconnmanager/include/route.h b/interfaces/innerkits/native/netconnmanager/include/route.h new file mode 100755 index 0000000..c76de70 --- /dev/null +++ b/interfaces/innerkits/native/netconnmanager/include/route.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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 ROUTE_H +#define ROUTE_H + +#include + +#include "inet_addr.h" + +namespace OHOS { +namespace NetManagerStandard { +struct Route : public Parcelable { + std::string iface_; + INetAddr destination_; + INetAddr gateway_; + + bool operator==(const Route& obj) const; + + virtual bool Marshalling(Parcel &parcel) const override; + static sptr Unmarshalling(Parcel &parcel); + static bool Marshalling(Parcel &parcel, const sptr &object); + std::string ToString(const std::string &tab) const; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/innerkits/native/netpolicymanager/BUILD.gn b/interfaces/innerkits/native/netpolicymanager/BUILD.gn new file mode 100755 index 0000000..204acef --- /dev/null +++ b/interfaces/innerkits/native/netpolicymanager/BUILD.gn @@ -0,0 +1,75 @@ +# Copyright (c) 2021 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") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +config("net_policy_manager_if_config") { + # header file path + include_dirs = [ + "$NETPOLICYMANAGER_SOURCE_DIR/include/ipc", + "$INNERKITS_ROOT/native/netpolicymanager/include", + ] + + cflags = [] + if (is_double_framework) { + cflags = [ "-DCONFIG_DUAL_FRAMEWORK" ] + } + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + if (is_standard_system) { + cflags += [ "-DCONFIG_STANDARD_SYSTEM" ] + } + if (defined(build_public_version) && build_public_version) { + cflags += [ "-DBUILD_PUBLIC_VERSION" ] + } +} + +ohos_shared_library("net_policy_manager_if") { + sources = [ + "$NETPOLICYMANAGER_INNERKITS_SOURCE_DIR/src/net_policy_client.cpp", + "$NETPOLICYMANAGER_SOURCE_DIR/src/ipc/net_policy_service_proxy.cpp", + ] + + include_dirs = [ "$NETPOLICYMANAGER_SOURCE_DIR/include/" ] + + public_configs = [ ":net_policy_manager_if_config" ] + + deps = [ "$NETMANAGER_BASE_ROOT/utils:net_manager_common" ] + + external_deps = [ + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_standard:samgr_proxy", + ] + + defines = [ + "NETMGR_LOG_TAG = \"NetPolicyManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (enable_netmgr_debug) { + defines += [ "NETMGR_DEBUG" ] + } + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/interfaces/innerkits/native/netpolicymanager/include/net_policy_client.h b/interfaces/innerkits/native/netpolicymanager/include/net_policy_client.h new file mode 100755 index 0000000..13fbee5 --- /dev/null +++ b/interfaces/innerkits/native/netpolicymanager/include/net_policy_client.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 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 NET_POLICY_MANAGER_H +#define NET_POLICY_MANAGER_H + +#include "singleton.h" + +#include "i_net_policy_service.h" +#include "net_policy_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetPolicyClient { + DECLARE_DELAYED_SINGLETON(NetPolicyClient) + +public: + NetPolicyResultCode SetUidPolicy(uint32_t uid, NetUidPolicy policy); + NetUidPolicy GetUidPolicy(uint32_t uid); + std::vector GetUids(NetUidPolicy policy); + bool IsUidNetAccess(uint32_t uid, bool metered); + bool IsUidNetAccess(uint32_t uid, const std::string &ifaceName); + +private: + class NetPolicyDeathRecipient : public IRemoteObject::DeathRecipient { + public: + explicit NetPolicyDeathRecipient(NetPolicyClient &client) : client_(client) {} + ~NetPolicyDeathRecipient() override = default; + void OnRemoteDied(const wptr &remote) override + { + client_.OnRemoteDied(remote); + } + + private: + NetPolicyClient &client_; + }; + +private: + sptr GetProxy(); + void OnRemoteDied(const wptr &remote); + +private: + std::mutex mutex_; + sptr netPolicyService_; + sptr deathRecipient_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_POLICY_MANAGER_H diff --git a/interfaces/innerkits/native/netpolicymanager/include/net_policy_constants.h b/interfaces/innerkits/native/netpolicymanager/include/net_policy_constants.h new file mode 100755 index 0000000..18b00b1 --- /dev/null +++ b/interfaces/innerkits/native/netpolicymanager/include/net_policy_constants.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 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 NET_POLICY_CONSTANTS_H +#define NET_POLICY_CONSTANTS_H + +namespace OHOS { +namespace NetManagerStandard { +enum class NetPolicyResultCode { + ERR_NONE = 0, + ERR_INTERNAL_ERROR = (-1), + ERR_INVALID_UID = (-10001), + ERR_INVALID_POLICY = (-10002), +}; + +enum class NetUidPolicy { + NET_POLICY_NONE = 0, + NET_POLICY_ALLOW_METERED_BACKGROUND = 1 << 0, + NET_POLICY_TEMPORARY_ALLOW_METERED = 1 << 1, + NET_POLICY_REJECT_METERED_BACKGROUND = 1 << 2, + NET_POLICY_ALLOW_ALL = 1 << 5, + NET_POLICY_REJECT_ALL = 1 << 6, +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_POLICY_CONSTANTS_H diff --git a/netmanager_base_config.gni b/netmanager_base_config.gni new file mode 100755 index 0000000..9541928 --- /dev/null +++ b/netmanager_base_config.gni @@ -0,0 +1,32 @@ +# Copyright (c) 2021 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. + +SUBSYSTEM_DIR = "//foundation/communication" +NETMANAGER_BASE_ROOT = "$SUBSYSTEM_DIR/netmanager_standard" +NETMANAGERNATIVE_ROOT = "$NETMANAGER_BASE_ROOT/services/netmanagernative" +INNERKITS_ROOT = "$NETMANAGER_BASE_ROOT/interfaces/innerkits" +NETCONNMANAGER_INNERKITS_SOURCE_DIR = "$NETMANAGER_BASE_ROOT//frameworks/innerkitsimpl/netconnmanager" +NETPOLICYMANAGER_INNERKITS_SOURCE_DIR = "$NETMANAGER_BASE_ROOT//frameworks/innerkitsimpl/netpolicymanager" +DNSRESOLVERMANAGER_INNERKITS_SOURCE_DIR = "$NETMANAGER_BASE_ROOT//frameworks/innerkitsimpl/dnsresolvermanager" +ETHERNETMANAGER_INNERKITS_SOURCE_DIR = "$NETMANAGER_BASE_ROOT//frameworks/innerkitsimpl/ethernetmanager" +NETCONNMANAGER_SOURCE_DIR = "$NETMANAGER_BASE_ROOT/services/netconnmanager" +NETPOLICYMANAGER_SOURCE_DIR = "$NETMANAGER_BASE_ROOT/services/netpolicymanager" +NETCONNMANAGER_COMMON_DIR = "$NETMANAGER_BASE_ROOT/services/common" +DNSRESOLVERMANAGER_SOURCE_DIR = "$NETMANAGER_BASE_ROOT/services/dnsresolvermanager" +ETHERNETMANAGER_SOURCE_DIR = "$NETMANAGER_BASE_ROOT/services/ethernetmanager" +NETMANAGER_PREBUILTS_DIR = "$NETMANAGER_BASE_ROOT/prebuilts" + +use_js_debug = false +declare_args() { + enable_netmgr_debug = false +} diff --git a/ohos.build b/ohos.build new file mode 100755 index 0000000..79e447c --- /dev/null +++ b/ohos.build @@ -0,0 +1,62 @@ +{ + "subsystem": "communication", + "parts": { + "netmanager_standard": { + "variants": [ + "phone", + "wearable", + "ivi" + ], + "module_list": [ + "//foundation/communication/netmanager_standard/prebuilts/librarys/netd:libnet_manager_native", + "//foundation/communication/netmanager_standard/services/netconnmanager:net_conn_manager", + "//foundation/communication/netmanager_standard/services/dnsresolvermanager:dns_resolver_manager", + "//foundation/communication/netmanager_standard/services/netpolicymanager:net_policy_manager", + "//foundation/communication/netmanager_standard/services/ethernetmanager:ethernet_manager", + "//foundation/communication/netmanager_standard/interfaces/innerkits/native/netconnmanager:net_conn_manager_if", + "//foundation/communication/netmanager_standard/interfaces/innerkits/native/dnsresolvermanager:dns_resolver_manager_if", + "//foundation/communication/netmanager_standard/interfaces/innerkits/native/netpolicymanager:net_policy_manager_if", + "//foundation/communication/netmanager_standard/interfaces/innerkits/native/ethernetmanager:ethernet_manager_if", + "//foundation/communication/netmanager_standard/utils:net_manager_common", + "//foundation/communication/netmanager_standard/services/etc/init:netmanager_base.rc", + "//foundation/communication/netmanager_standard/services/etc/init:netd.rc", + "//foundation/communication/netmanager_standard/sa_profile:net_manager_profile", + "//foundation/communication/netmanager_standard/frameworks/js/netpolicy:netpolicy", + "//foundation/communication/netmanager_standard/frameworks/js/ethernet:ethernet", + "//foundation/communication/netmanager_standard/frameworks/js/dnsresolver:dnsresolver" + ], + "inner_kits": [ + { + "type": "so", + "name": "//foundation/communication/netmanager_standard/interfaces/innerkits/native/netconnmanager:net_conn_manager_if", + "header": { + "header_files": [ + "inet_addr.h", + "net_conn_client.h", + "net_link_info.h", + "net_supplier_info.h", + "net_conn_callback_info.h", + "net_specifier.h", + "route.h" + ], + "header_base": "//foundation/communication/netmanager_standard/interfaces/innerkits/native/netconnmanager/include" + } + }, + { + "type": "so", + "name": "//foundation/communication/netmanager_standard/interfaces/innerkits/native/netpolicymanager:net_policy_manager_if", + "header": { + "header_files": [ + "net_policy_client.h" + ], + "header_base": "//foundation/communication/netmanager_standard/interfaces/innerkits/native/netpolicymanager/include" + } + } + ], + "test_list": [ + "//foundation/communication/netmanager_standard/services/netconnmanager/test:unittest", + "//foundation/communication/netmanager_standard/services/netpolicymanager/test:unittest" + ] + } + } +} diff --git a/prebuilts/librarys/netd/BUILD.gn b/prebuilts/librarys/netd/BUILD.gn new file mode 100755 index 0000000..e994a13 --- /dev/null +++ b/prebuilts/librarys/netd/BUILD.gn @@ -0,0 +1,36 @@ +# +# Copyright (c) 2021 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") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +config("netd_public_config") { + include_dirs = [ + "$NETMANAGER_PREBUILTS_DIR/librarys/netd/include/common/include", + "$NETMANAGER_PREBUILTS_DIR/librarys/netd/include/net_mgr_native/include", + ] + + libs = [ "$NETMANAGER_PREBUILTS_DIR/librarys/netd/${target_cpu}/libnet_manager_native.z.so" ] +} + +ohos_prebuilt_shared_library("libnet_manager_native") { + source = "$NETMANAGER_PREBUILTS_DIR/librarys/netd/${target_cpu}/libnet_manager_native.z.so" + + public_configs = [ ":netd_public_config" ] + + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/prebuilts/librarys/netd/arm/libnet_manager_native.z.so b/prebuilts/librarys/netd/arm/libnet_manager_native.z.so new file mode 100755 index 0000000000000000000000000000000000000000..33a0bc71a02e4a86193e4aa7f4b770b8d474e9b3 GIT binary patch literal 194960 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

W?&Hg7{m>B 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 literal 0 HcmV?d00001 diff --git a/prebuilts/librarys/netd/arm64/libnet_manager_native.z.so b/prebuilts/librarys/netd/arm64/libnet_manager_native.z.so new file mode 100755 index 0000000000000000000000000000000000000000..c251c533eddd3b73cff500c5a167f76afa428a4f GIT binary patch literal 269728 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 +#include +#include +namespace OHOS { +namespace nmd { +template +class blocking_queue { +public: + explicit blocking_queue(unsigned int capacity) : start_(0), end_(0), capacity_(capacity), vt_(capacity + 1) {}; + ~blocking_queue() {}; + + bool isEmpty() + { + return this->end_ == this->start_; + } + + bool isFull() + { + return (this->start_ + this->capacity_ - this->end_) % (this->capacity_ + 1) == 0; + } + + void push(const T &e) + { + std::unique_lock lock(this->mutex_); + while (this->isFull()) { + this->notFull_.wait(lock); + } + + this->vt_[this->end_++] = e; + this->end_ %= (this->capacity_ + 1); + this->notEmpty_.notify_one(); + } + + T pop() + { + std::unique_lock lock(this->mutex_); + while (this->isEmpty()) { + this->notEmpty_.wait(lock); + } + + auto res = this->vt_[this->start_++]; + this->start_ %= (this->capacity_ + 1); + this->notFull_.notify_one(); + return res; + } + +private: + std::mutex mutex_; + std::condition_variable notFull_; + std::condition_variable notEmpty_; + unsigned int start_; + unsigned int end_; + unsigned int capacity_; + std::vector vt_; +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_BLOCKING_QUEUE_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/common/include/job.h b/prebuilts/librarys/netd/include/common/include/job.h new file mode 100755 index 0000000..e7123d5 --- /dev/null +++ b/prebuilts/librarys/netd/include/common/include/job.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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 INCLUDE_JOB_H__ +#define INCLUDE_JOB_H__ + +#include +#include "server_socket.h" +namespace OHOS { +namespace nmd { +class job { +public: + job(const int fd, const uint8_t *msg, const size_t msgLen, + const std::shared_ptr serverSocket) + : fd_(fd), msg_(msg, msg + msgLen), serverSocket_(serverSocket) + {} + virtual ~job() = default; + virtual void run() = 0; + +protected: + int fd_; + std::vector msg_; + std::shared_ptr serverSocket_; +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_JOB_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/common/include/net_utils.h b/prebuilts/librarys/netd/include/common/include/net_utils.h new file mode 100755 index 0000000..4de8fa8 --- /dev/null +++ b/prebuilts/librarys/netd/include/common/include/net_utils.h @@ -0,0 +1,539 @@ +/* + * Copyright (C) 2021 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 INCLUDE_NET_UTILS_H__ +#define INCLUDE_NET_UTILS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "warning_disable.h" +namespace OHOS { +namespace nmd { +namespace common { +namespace net_utils { +enum protocol : uint8_t { + PROTO_UNKNOWN = 0, + PROTO_TCP = 6, + PROTO_UDP = 17, +}; +// See also NetworkConstants.java in frameworks/base. +constexpr int IPV4_ADDR_LEN = 4; +constexpr int IPV4_ADDR_BITS = 32; +constexpr int IPV6_ADDR_LEN = 16; +constexpr int IPV6_ADDR_BITS = 128; + +// Referred from SHA256_DIGEST_LENGTH in boringssl +constexpr size_t SHA256_SIZE = 32; + +struct compact_ipdata { + uint8_t family {AF_UNSPEC}; + uint8_t cidrlen {0U}; // written and read in host-byte order + in_port_t port {0U}; // written and read in host-byte order + uint32_t scope_id {0U}; + + DISABLE_WARNING_PUSH + DISABLE_WARNING_C99_EXTENSIONS + union { + in_addr v4; + in6_addr v6; + } ip {.v6 = IN6ADDR_ANY_INIT}; // written and read in network-byte order + + DISABLE_WARNING_POP + // Classes that use compact_ipdata and this method should be sure to clear + // (i.e. zero or make uniform) any fields not relevant to the class. + friend bool operator==(const compact_ipdata &a, const compact_ipdata &b) + { + if ((a.family != b.family) || (a.cidrlen != b.cidrlen) || (a.port != b.port) || (a.scope_id != b.scope_id)) { + return false; + } + switch (a.family) { + case AF_UNSPEC: + // After the above checks, two AF_UNSPEC objects can be + // considered equal, for convenience. + return true; + case AF_INET: { + const in_addr v4a = a.ip.v4; + const in_addr v4b = b.ip.v4; + return (v4a.s_addr == v4b.s_addr); + } + case AF_INET6: { + const in6_addr v6a = a.ip.v6; + const in6_addr v6b = b.ip.v6; + return IN6_ARE_ADDR_EQUAL(&v6a, &v6b); + } + default: + break; + } + return false; + } + + // Classes that use compact_ipdata and this method should be sure to clear + // (i.e. zero or make uniform) any fields not relevant to the class. + friend bool operator!=(const compact_ipdata &a, const compact_ipdata &b) + { + return !(a == b); + } + + // Classes that use compact_ipdata and this method should be sure to clear + // (i.e. zero or make uniform) any fields not relevant to the class. + friend bool operator<(const compact_ipdata &a, const compact_ipdata &b) + { + if (a.family != b.family) + return (a.family < b.family); + switch (a.family) { + case AF_INET: { + const in_addr v4a = a.ip.v4; + const in_addr v4b = b.ip.v4; + if (v4a.s_addr != v4b.s_addr) + return (ntohl(v4a.s_addr) < ntohl(v4b.s_addr)); + break; + } + case AF_INET6: { + const in6_addr v6a = a.ip.v6; + const in6_addr v6b = b.ip.v6; + const int cmp = std::memcmp(v6a.s6_addr, v6b.s6_addr, IPV6_ADDR_LEN); + if (cmp != 0) + return cmp < 0; + break; + } + default: + break; + } + if (a.cidrlen != b.cidrlen) + return (a.cidrlen < b.cidrlen); + if (a.port != b.port) + return (a.port < b.port); + return (a.scope_id < b.scope_id); + } +}; + +static_assert(AF_UNSPEC <= std::numeric_limits::max(), "AF_UNSPEC value too large"); +static_assert(AF_INET <= std::numeric_limits::max(), "AF_INET value too large"); +static_assert(AF_INET6 <= std::numeric_limits::max(), "AF_INET6 value too large"); +static_assert(sizeof(compact_ipdata) == 24U, "compact_ipdata unexpectedly large"); + +struct addrinfo_deleter { + void operator()(struct addrinfo *p) const + { + if (p != nullptr) { + freeaddrinfo(p); + } + } +}; + +typedef std::unique_ptr ScopedAddrinfo; + +inline bool usesScopedIds(const in6_addr &ipv6) +{ + return (IN6_IS_ADDR_LINKLOCAL(&ipv6) || IN6_IS_ADDR_MC_LINKLOCAL(&ipv6)); +} + +class ip_prefix; +class ip_sock_addr; + +class ip_address { +public: + static bool forString(const std::string &repr, ip_address *ip); + static ip_address forString(const std::string &repr) + { + ip_address ip; + if (!forString(repr, &ip)) + return ip_address(); + return ip; + } + + ip_address() = default; + ip_address(const ip_address &) = default; + ip_address(ip_address &&) = default; + + DISABLE_WARNING_PUSH + DISABLE_WARNING_C99_EXTENSIONS + + explicit ip_address(const in_addr &ipv4); + explicit ip_address(const in6_addr &ipv6); + ip_address(const in6_addr &ipv6, uint32_t scope_id); + + DISABLE_WARNING_POP + + ip_address(const ip_address &ip, uint32_t scope_id) : ip_address(ip) + { + mData.scope_id = (family() == AF_INET6 && usesScopedIds(mData.ip.v6)) ? scope_id : 0U; + } + + ip_address &operator=(const ip_address &) = default; + ip_address &operator=(ip_address &&) = default; + + constexpr sa_family_t family() const noexcept + { + return mData.family; + } + constexpr uint32_t scope_id() const noexcept + { + return mData.scope_id; + } + + std::string toString() const noexcept; + + friend std::ostream &operator<<(std::ostream &os, const ip_address &ip) + { + os << ip.toString(); + return os; + } + friend bool operator==(const ip_address &a, const ip_address &b) + { + return (a.mData == b.mData); + } + friend bool operator!=(const ip_address &a, const ip_address &b) + { + return (a.mData != b.mData); + } + friend bool operator<(const ip_address &a, const ip_address &b) + { + return (a.mData < b.mData); + } + friend bool operator>(const ip_address &a, const ip_address &b) + { + return (b.mData < a.mData); + } + friend bool operator<=(const ip_address &a, const ip_address &b) + { + return (a < b) || (a == b); + } + friend bool operator>=(const ip_address &a, const ip_address &b) + { + return (b < a) || (a == b); + } + +private: + friend class ip_prefix; + friend class ip_sock_addr; + + explicit ip_address(const compact_ipdata &ipdata) : mData(ipdata) + { + mData.port = 0U; + switch (mData.family) { + case AF_INET: + mData.cidrlen = IPV4_ADDR_BITS; + mData.scope_id = 0U; + break; + case AF_INET6: + mData.cidrlen = IPV6_ADDR_BITS; + if (usesScopedIds(ipdata.ip.v6)) + mData.scope_id = ipdata.scope_id; + break; + default: + mData.cidrlen = 0U; + mData.scope_id = 0U; + break; + } + } + + compact_ipdata mData {}; +}; + +class ip_prefix { +public: + static bool forString(const std::string &repr, ip_prefix *prefix); + static ip_prefix forString(const std::string &repr) + { + ip_prefix prefix; + if (!forString(repr, &prefix)) + return ip_prefix(); + return prefix; + } + + ip_prefix() = default; + ip_prefix(const ip_prefix &) = default; + ip_prefix(ip_prefix &&) = default; + + explicit ip_prefix(const ip_address &ip) : mData(ip.mData) {} + + // Truncate the IP address |ip| at length |length|. Lengths greater than + // the address-family-relevant maximum, along with negative values, are + // interpreted as if the address-family-relevant maximum had been given. + ip_prefix(const ip_address &ip, size_t length); + + ip_prefix &operator=(const ip_prefix &) = default; + ip_prefix &operator=(ip_prefix &&) = default; + + constexpr sa_family_t family() const noexcept + { + return mData.family; + } + ip_address ip() const noexcept + { + return ip_address(mData); + } + in_addr addr4() const noexcept + { + return mData.ip.v4; + } + in6_addr addr6() const noexcept + { + return mData.ip.v6; + } + constexpr int length() const noexcept + { + return mData.cidrlen; + } + + bool isUninitialized() const noexcept; + std::string toString() const noexcept; + + friend std::ostream &operator<<(std::ostream &os, const ip_prefix &prefix) + { + os << prefix.toString(); + return os; + } + friend bool operator==(const ip_prefix &a, const ip_prefix &b) + { + return (a.mData == b.mData); + } + friend bool operator!=(const ip_prefix &a, const ip_prefix &b) + { + return (a.mData != b.mData); + } + friend bool operator<(const ip_prefix &a, const ip_prefix &b) + { + return (a.mData < b.mData); + } + friend bool operator>(const ip_prefix &a, const ip_prefix &b) + { + return (b.mData < a.mData); + } + friend bool operator<=(const ip_prefix &a, const ip_prefix &b) + { + return (a < b) || (a == b); + } + friend bool operator>=(const ip_prefix &a, const ip_prefix &b) + { + return (b < a) || (a == b); + } + +private: + compact_ipdata mData {}; +}; + +// An Internet socket address. +// +// Cannot represent other types of socket addresses (e.g. UNIX socket address, et cetera). +class ip_sock_addr { +public: + static ip_sock_addr toIPSockAddr(const std::string &repr, in_port_t port) + { + return ip_sock_addr(ip_address::forString(repr), port); + } + static ip_sock_addr toIPSockAddr(const sockaddr &sa) + { + switch (sa.sa_family) { + case AF_INET: + return ip_sock_addr(*reinterpret_cast(&sa)); + case AF_INET6: + return ip_sock_addr(*reinterpret_cast(&sa)); + default: + return ip_sock_addr(); + } + } + static ip_sock_addr toIPSockAddr(const sockaddr_storage &ss) + { + return toIPSockAddr(*reinterpret_cast(&ss)); + } + + ip_sock_addr() = default; + ip_sock_addr(const ip_sock_addr &) = default; + ip_sock_addr(ip_sock_addr &&) = default; + + explicit ip_sock_addr(const ip_address &ip) : mData(ip.mData) {} + ip_sock_addr(const ip_address &ip, in_port_t port) : mData(ip.mData) + { + mData.port = port; + } + explicit ip_sock_addr(const sockaddr_in &ipv4sa) + : ip_sock_addr(ip_address(ipv4sa.sin_addr), ntohs(ipv4sa.sin_port)) + {} + explicit ip_sock_addr(const sockaddr_in6 &ipv6sa) + : ip_sock_addr(ip_address(ipv6sa.sin6_addr, ipv6sa.sin6_scope_id), ntohs(ipv6sa.sin6_port)) + {} + + ip_sock_addr &operator=(const ip_sock_addr &) = default; + ip_sock_addr &operator=(ip_sock_addr &&) = default; + + constexpr sa_family_t family() const noexcept + { + return mData.family; + } + ip_address ip() const noexcept + { + return ip_address(mData); + } + constexpr in_port_t port() const noexcept + { + return mData.port; + } + + // Implicit conversion to sockaddr_storage. + operator sockaddr_storage() const noexcept + { + sockaddr_storage ss; + ss.ss_family = mData.family; + switch (mData.family) { + case AF_INET: + reinterpret_cast(&ss)->sin_addr = mData.ip.v4; + reinterpret_cast(&ss)->sin_port = htons(mData.port); + break; + case AF_INET6: + reinterpret_cast(&ss)->sin6_addr = mData.ip.v6; + reinterpret_cast(&ss)->sin6_port = htons(mData.port); + reinterpret_cast(&ss)->sin6_scope_id = mData.scope_id; + break; + default: + break; + } + return ss; + } + + std::string toString() const noexcept; + + friend std::ostream &operator<<(std::ostream &os, const ip_sock_addr &prefix) + { + os << prefix.toString(); + return os; + } + friend bool operator==(const ip_sock_addr &a, const ip_sock_addr &b) + { + return (a.mData == b.mData); + } + friend bool operator!=(const ip_sock_addr &a, const ip_sock_addr &b) + { + return (a.mData != b.mData); + } + friend bool operator<(const ip_sock_addr &a, const ip_sock_addr &b) + { + return (a.mData < b.mData); + } + friend bool operator>(const ip_sock_addr &a, const ip_sock_addr &b) + { + return (b.mData < a.mData); + } + friend bool operator<=(const ip_sock_addr &a, const ip_sock_addr &b) + { + return (a < b) || (a == b); + } + friend bool operator>=(const ip_sock_addr &a, const ip_sock_addr &b) + { + return (b < a) || (a == b); + } + +private: + compact_ipdata mData {}; +}; + +class sock_addr_utils final { +public: + static socklen_t sockaddrSize(const sockaddr *sa) + { + if (sa == nullptr) { + return 0; + } + + switch (sa->sa_family) { + case AF_INET: + return sizeof(sockaddr_in); + case AF_INET6: + return sizeof(sockaddr_in6); + default: + return 0; + } + } + +public: + sock_addr_utils() = default; /* args */ + ~sock_addr_utils() = default; +}; + +class fd_wrapper final { +public: + fd_wrapper() = default; + explicit fd_wrapper(const int fd) + { + reset(fd); + }; + fd_wrapper(const fd_wrapper &) = delete; + void operator=(const fd_wrapper &) = delete; + ~fd_wrapper() + { + reset(); + } + + int getFd() const + { + return fd_; + } + + operator int() const + { + return getFd(); + } + bool operator>=(int rhs) const + { + return getFd() >= rhs; + } + bool operator<(int rhs) const + { + return getFd() < rhs; + } + bool operator==(int rhs) const + { + return getFd() == rhs; + } + bool operator!=(int rhs) const + { + return getFd() != rhs; + } + bool operator==(const fd_wrapper &rhs) const + { + return getFd() == rhs.getFd(); + } + bool operator!=(const fd_wrapper &rhs) const + { + return getFd() != rhs.getFd(); + } + +public: + void reset(int newFd = -1) + { + if (fd_ != -1) { + close(fd_); + } + fd_ = newFd; + } + +private: + int fd_ = -1; +}; +using socket_fd = fd_wrapper; +} // namespace net_utils +} // namespace common +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_NET_UTILS_H__ diff --git a/prebuilts/librarys/netd/include/common/include/server_socket.h b/prebuilts/librarys/netd/include/common/include/server_socket.h new file mode 100755 index 0000000..2643a3b --- /dev/null +++ b/prebuilts/librarys/netd/include/common/include/server_socket.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 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 NETD_COMMON_SERVER_SOCKET_H__ +#define NETD_COMMON_SERVER_SOCKET_H__ + +#include "socket_base.h" +namespace OHOS { +namespace nmd { +namespace common { +class server_socket : public socket_base { +public: + server_socket(); + ~server_socket(); + + int bindPort(uint16_t port); + int bindFile(const char *filePath, const char *name); + +private: + struct sockaddr addr_ {}; +}; +} // namespace common +} // namespace nmd +} // namespace OHOS +#endif // !NETD_COMMON_SERVER_SOCKET_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/common/include/server_template.h b/prebuilts/librarys/netd/include/common/include/server_template.h new file mode 100755 index 0000000..c29ba9d --- /dev/null +++ b/prebuilts/librarys/netd/include/common/include/server_template.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 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 INCLUDE_SERVER_TEMPLATE_H__ +#define INCLUDE_SERVER_TEMPLATE_H__ +#include +#include +#include "server_socket.h" +#include "thread_pool.h" +namespace OHOS { +namespace nmd { +namespace common { +class server_template { + const char *const SOCKET_FILE_PATH = "/dev/socket"; + +public: + void start(); + void stop(); + void handler(int socketFd, const uint8_t *msg, const size_t msgLen); + +public: + explicit server_template(const char *socketName, const char *serverName) + : socketName_(socketName), serverName_(serverName), server_(std::make_shared()), + pool_(std::make_shared(16, 256)), job_(nullptr) + {} + virtual ~server_template() = default; + +protected: + virtual void initJob(const int socketFd, const uint8_t *msg, const size_t msgLen) = 0; + +protected: + std::string socketName_; + std::string serverName_; + std::shared_ptr server_; + std::shared_ptr pool_; + nmd::job *job_; + bool mRunning = false; +}; +} // namespace common +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_SERVER_TEMPLATE_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/common/include/socket_base.h b/prebuilts/librarys/netd/include/common/include/socket_base.h new file mode 100755 index 0000000..6ee2579 --- /dev/null +++ b/prebuilts/librarys/netd/include/common/include/socket_base.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2021 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 NETD_SOCKET_BASE_H__ +#define NETD_SOCKET_BASE_H__ + +#include +#include +#include +#include +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { +namespace common { +typedef struct end_point { + int port; +} end_point; +class socket_base { +public: + socket_base(); + virtual ~socket_base(); + + int createInet(); + int createUnix(); + int listenSocket(); + int acceptSocket(); + int connectSocket(struct sockaddr_in serverAddr); + ssize_t sendSocket(int socketFd, const char *buffer); + ssize_t sendSocket(const char *buffer); + virtual ssize_t sendMsg(const int socketFd, const msghdr &msg); + char *receiveSocket(char *buffer); + + template + void setRecevedHandler(R (*)(Params...)) + {} + + template + void setRecevedHandler(R (C::*func)(Params...), C *instance) + { + this->handler_ = + std::bind(func, instance, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + } + + int getSocketFileDescriptor() + { + return this->socketFd_; + } + +protected: + int socketFd_; + int epollFd_ = 0; + int eventCnt_ = 0; + struct epoll_event *epollEvents_; + struct epoll_event event_ {}; + std::function handler_; + +private: + int create(int domain, int protocol); +}; +} // namespace common +} // namespace nmd +} // namespace OHOS +#endif // !NETD_SOCKET_BASE_H__ diff --git a/prebuilts/librarys/netd/include/common/include/thread_pool.h b/prebuilts/librarys/netd/include/common/include/thread_pool.h new file mode 100755 index 0000000..aed9c9b --- /dev/null +++ b/prebuilts/librarys/netd/include/common/include/thread_pool.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 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 INCLUDE_THREAD_POOL_H__ +#define INCLUDE_THREAD_POOL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "blocking_queue.h" +#include "job.h" + +namespace OHOS { +namespace nmd { +class thread_pool { +public: + thread_pool(unsigned int threadNums, unsigned int queueSize); + + void execute(nmd::job *job); + + ~thread_pool(); + +private: + unsigned int threadNums_; + unsigned int queueSize_; + + bool running_ = false; + + std::vector workers_; + nmd::blocking_queue *workQueue_; + + std::mutex mutex_; + std::condition_variable cond_; + + void threadLoop(); + + nmd::job *takeJobFromQueue(); +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_THREAD_POOL_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/common/include/warning_disable.h b/prebuilts/librarys/netd/include/common/include/warning_disable.h new file mode 100755 index 0000000..1ae027e --- /dev/null +++ b/prebuilts/librarys/netd/include/common/include/warning_disable.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 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 INCLUDE_WARNING_DISABLE_H__ +#define INCLUDE_WARNING_DISABLE_H__ + +#if defined(__GNUC__) || defined(__clang__) +#define DO_PRAGMA(X) _Pragma(#X) +#define DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push) +#define DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop) +#define DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored warningName) + +#define DISABLE_WARNING_OLD_STYLE_CAST DISABLE_WARNING("-Wold-style-cast") +#define DISABLE_WARNING_MISSING_FIELD_INITIALIZERS DISABLE_WARNING("-Wmissing-field-initializers") +#define DISABLE_WARNING_SIGN_CONVERSION DISABLE_WARNING("-Wsign-conversion") +#define DISABLE_WARNING_IMPLICIT_INT_CONVERSION DISABLE_WARNING("-Wimplicit-int-conversion") +#define DISABLE_WARNING_SIGN_COMPARE DISABLE_WARNING("-Wsign-compare") +#define DISABLE_WARNING_SHORTEN_64_TO_32 DISABLE_WARNING("-Wshorten-64-to-32") +#define DISABLE_WARNING_CAST_ALIGN DISABLE_WARNING("-Wcast-align") +#define DISABLE_WARNING_UNUSED_PARAMETER DISABLE_WARNING("-Wunused-parameter") +#define DISABLE_WARNING_UNUSED_VARIABLE DISABLE_WARNING("-Wunused-variable") +#define DISABLE_WARNING_C99_EXTENSIONS DISABLE_WARNING("-Wc99-extensions") +// other warnings you want to deactivate... + +#else +#define DISABLE_WARNING_PUSH +#define DISABLE_WARNING_POP +#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER +#define DISABLE_WARNING_UNREFERENCED_FUNCTION +// other warnings you want to deactivate... + +#endif + +#endif // !INCLUDE_WARNING_DISABLE_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/dnsresolv.h b/prebuilts/librarys/netd/include/net_mgr_native/include/dnsresolv.h new file mode 100755 index 0000000..a3eb1c2 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/dnsresolv.h @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2021 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 INCLUDE_DNSRESOLV_H__ +#define INCLUDE_DNSRESOLV_H__ +#include +#include +#include +#include "net_utils.h" +#include "warning_disable.h" + +#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV | AI_ADDRCONFIG) + +namespace OHOS { +namespace nmd { +DISABLE_WARNING_PUSH +DISABLE_WARNING_OLD_STYLE_CAST +const uid_t NET_CONTEXT_INVALID_UID = ((uid_t)-1); +DISABLE_WARNING_POP + +const uint8_t RES_DEFAULT_TIMEOUT = 5; // default dns request timeout + +const int32_t ANY_SOCK_TYPE = 0; + +const pid_t NET_CONTEXT_INVALID_PID = -1; + +const uint8_t PTON_MAX = 16; +constexpr int MAX_PACKET = 8 * 1024; + +const uint8_t RCODE_TIMEOUT = 255; +const uint8_t RCODE_INTERNAL_ERROR = 254; + +const uint8_t MAXNS = 4; // max # name servers we'll track + +const long BILLION = 1000000000; + +const uint16_t DNS_REQ_PORT = 53; +const char *const DNS_REQ_PORT_STR = "53"; + +const uint8_t ANYSIZE_ARRAY = 1; + +// MARK_UNSET represents the default (i.e. unset) value for a socket mark. +const uint32_t NETID_UNSET = 0u; +const uint32_t MARK_UNSET = 0u; + +const uint32_t MAX_NAME_LEN = 64; +const uint32_t MAX_NAME_LIST_LEN = 1024; + +struct netd_net_context { + uint16_t appNetId; + uint32_t appMark; + uint16_t dnsNetId; + uint32_t dnsMark; + uid_t uid = NET_CONTEXT_INVALID_UID; + uint32_t flags; + pid_t pid = NET_CONTEXT_INVALID_PID; +}; + +union sockaddr_union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +}; + +struct res_target { + struct res_target *next; + const char *name; // domain name + int qclass; + int qtype; // class and type of query + std::vector answer = std::vector(MAX_PACKET, 0); // buffer to put answer + size_t n = 0; // result length +}; + +struct dns_res_state { + void init(const netd_net_context *netcontext) + { + if (netcontext == nullptr) { + return; + } + netid = netcontext->dnsNetId; + ndots = 1; + mark = netcontext->dnsMark; + + for (auto &sock : nssocks) { + sock.reset(); + } + } + + void closeSockets() + { + tcpNsSock.reset(); + isTcp = false; + + for (auto &sock : nssocks) { + sock.reset(); + } + } + + size_t nameserverCount() + { + return nsaddrs.size(); + } + + uint16_t netid; // NetId: cache key and socket mark + uid_t uid; // uid of the app that sent the DNS lookup + pid_t pid; // pid of the app that sent the DNS lookup + uint16_t id; // current message id + std::vector searchDomains {}; // domains to search + std::vector nsaddrs; + nmd::common::net_utils::socket_fd nssocks[MAXNS]; // UDP sockets to nameservers + unsigned ndots : 4; // threshold for initial abs. query + unsigned mark; // If non-0 SET_MARK to mark on all request sockets + nmd::common::net_utils::socket_fd tcpNsSock; // TCP socket + bool isTcp = false; +}; + +// Per-netid configuration parameters passed from netd to the resolver +struct dns_res_params { + uint16_t baseTimeoutMsec; // base query retry timeout (if 0, use RES_TIMEOUT) + uint8_t retryCount = 1; // number of retries + void operator=(const dns_res_params ¶m) + { + baseTimeoutMsec = param.baseTimeoutMsec; + retryCount = param.retryCount; + } +}; + +enum dns_request_send_flag : uint32_t { + // Send a single request to a single resolver and fail on timeout or network errors + NETD_DNS_RESOLV_NO_RETRY = 1 << 0, + + // Don't lookup this request in the cache, and don't cache the result of the lookup. + NETD_DNS_RESOLV_NO_CACHE_STORE = 1 << 1, + + // Don't lookup the request in cache. + NETD_DNS_RESOLV_NO_CACHE_LOOKUP = 1 << 2, +}; + +struct dnsresolver_params { + uint16_t netId = 0; + uint16_t baseTimeoutMsec = 0; + uint8_t retryCount = 0; + std::vector servers; + std::vector domains; +}; + +typedef struct alignas(8) dnsresolver_request_cmd { + enum cmd_id { + CREATE_NETWORK_CACHE, + SET_RESOLVER_CONFIG, + DESOTRY_NETWORK_CACHE, + GET_ADDR_INFO, + GET_ADDR_INFO_PROXY, + } cmdID; + uint16_t netid; + union { + struct dnsresolv_req_param { + addrinfo hints; + uid_t uid; + char hostName[MAX_NAME_LEN]; + char serverName[MAX_NAME_LEN]; + } reqParam; + + struct dnsresolv_cfg_param { + uint16_t baseTimeoutMsec; + uint8_t retryCount; + uint8_t serverCount; + uint8_t domainCount; + char servers[MAX_NAME_LIST_LEN]; + char domains[MAX_NAME_LIST_LEN]; + } cfgParam; + } u; +} dnsresolver_request_cmd_t; + +#define cmd_hints u.reqParam.hints +#define cmd_uid u.reqParam.uid +#define cmd_hostName u.reqParam.hostName +#define cmd_serverName u.reqParam.serverName + +#define cmd_baseTimeoutMsec u.cfgParam.baseTimeoutMsec +#define cmd_retryCount u.cfgParam.retryCount +#define cmd_serverCount u.cfgParam.serverCount +#define cmd_domainCount u.cfgParam.domainCount +#define cmd_servers u.cfgParam.servers +#define cmd_domains u.cfgParam.domains + +typedef struct alignas(8) dnsresolver_response_cmd { + enum cmd_id { + QUERY_STATE_OK, + QUERY_STATE_FAIL, + QUERY_SUCCESS_WITH_RESULT, + QUERY_STATE_BUTT + } cmdID = QUERY_STATE_BUTT; + int result = 0; + size_t resSize = 0; + uint8_t resData[ANYSIZE_ARRAY]; +} dnsresolver_response_cmd_t, *p_dnsresolver_response_cmd; + +typedef void (*get_network_context_callback)(uint16_t netid, uid_t uid, netd_net_context &netcontext); +struct dnsresolv_callbacks { + dnsresolv_callbacks() : getNetworkContext(nullptr) {} + get_network_context_callback getNetworkContext; +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_DNSRESOLV_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/dnsresolv_controller.h b/prebuilts/librarys/netd/include/net_mgr_native/include/dnsresolv_controller.h new file mode 100755 index 0000000..627fbe3 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/dnsresolv_controller.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 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 INCLUDE_DNSRESOLV_CONTROLLER_H__ +#define INCLUDE_DNSRESOLV_CONTROLLER_H__ + +#include +#include +#include +#include +namespace OHOS { +namespace nmd { +struct dnsresolver_params; +struct netd_net_context; +class dnsresolv_controller { +public: + int getResolverInfo(const uint16_t netid, std::vector &servers, std::vector &domains, + struct dns_res_params ¶m); + int setResolverConfig(const dnsresolver_params &resolvParams); + int createNetworkCache(const uint16_t netid); + int destoryNetworkCache(const uint16_t netid); + int flushNetworkCache(const uint16_t netid); + +public: + static int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, + struct addrinfo **res, const uint16_t netid); + static int getaddrinfoForNet(const char *hostname, const char *servname, const struct addrinfo *hints, + uint16_t netid, unsigned mark, struct addrinfo **res); + static int getaddrinfoFornetContext(const char *hostname, const char *servname, const addrinfo *hints, + const netd_net_context &netcontext, addrinfo **res); +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_DNSRESOLV_CONTROLLER_H__ diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/dnsresolv_service.h b/prebuilts/librarys/netd/include/net_mgr_native/include/dnsresolv_service.h new file mode 100755 index 0000000..defc48e --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/dnsresolv_service.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 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 INCLUDE_DNSRESOLV_SERVICE_H__ +#define INCLUDE_DNSRESOLV_SERVICE_H__ +#include +#include +#include +#include "dnsresolv.h" +#include "dnsresolv_controller.h" +#include "job.h" +#include "server_template.h" +namespace OHOS { +namespace nmd { +const char *const DNS_RESOLV_SERVICE_SOCK_NAME = "dnsresolvproxy.sock"; +const char *const DNS_RESOLV_SERVICE_NAME = "DNSResolverService"; +class dnsresolv_job : public job { +public: + dnsresolv_job(const int fd, const uint8_t *msg, const size_t msgLen, + const std::shared_ptr serverSocket) + : job(fd, msg, msgLen, serverSocket) + {} + ~dnsresolv_job() = default; + virtual void run() override; + void setupCallbacks(const dnsresolv_callbacks &callbacks) + { + dnsresolvCallbacks_ = callbacks; + } +private: + void doCreateNetworkCache(const dnsresolver_request_cmd *command); + void doSetResolverConfig(const dnsresolver_request_cmd *command); + void doDestroyNetworkCache(const dnsresolver_request_cmd *command); + void doGetAddrInfo(const dnsresolver_request_cmd *command); + void doGetAddrInfoProxy(const dnsresolver_request_cmd *command); + void responseOk(); + void responseOk(const struct addrinfo *res); + void responseFailed(const int ret); + size_t getNameList(const char *buffer, const size_t bufferSize, std::vector &namelist); + ssize_t sendResponseResult(dnsresolver_response_cmd &cmd); +private: + dnsresolv_callbacks dnsresolvCallbacks_; + dnsresolv_controller dnsresolvCtrl_; +}; + +class dnsresolv_service : public common::server_template { +public: + int getResolverInfo(const uint16_t netid, std::vector &servers, std::vector &domains, + dns_res_params ¶m); + int setResolverConfig(const dnsresolver_params &resolvParams); + int createNetworkCache(const uint16_t netid); + int flushNetworkCache(const uint16_t netid); + int destoryNetworkCache(const uint16_t netid); + int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, + struct addrinfo **res, const uint16_t netid); +public: + dnsresolv_service() : common::server_template(DNS_RESOLV_SERVICE_SOCK_NAME, DNS_RESOLV_SERVICE_NAME) {} + ~dnsresolv_service() = default; + bool init(const dnsresolv_callbacks &callbacks); +private: + virtual void initJob(const int socketFd, const uint8_t *msg, const size_t msgLen) override; +private: + dnsresolv_controller dnsresolvCtrl_; + dnsresolv_callbacks dnsresolvCallbacks_; +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_DNSRESOLV_SERVICE_H_ diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/event_reporter.h b/prebuilts/librarys/netd/include/net_mgr_native/include/event_reporter.h new file mode 100755 index 0000000..90dc732 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/event_reporter.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 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 INCLUDE_EVENT_REPORTER_H__ +#define INCLUDE_EVENT_REPORTER_H__ +#include + +namespace OHOS { +namespace nmd { +typedef struct inetd_unsolicited_event_listener { + void (*onInterfaceAddressUpdated)(const std::string &addr, const std::string &ifName, int flags, int scope); + void (*onInterfaceAddressRemoved)(const std::string &addr, const std::string &ifName, int flags, int scope); + void (*onInterfaceAdded)(const std::string &ifName); + void (*onInterfaceRemoved)(const std::string &ifName); + void (*onInterfaceChanged)(const std::string &ifName, bool up); + void (*onInterfaceLinkStateChanged)(const std::string &ifName, bool up); + void (*onRouteChanged)( + bool updated, const std::string &route, const std::string &gateway, const std::string &ifName); +} inetd_unsolicited_event_listener; + +class event_reporter { +public: + event_reporter() = default; + void registerEventListener(inetd_unsolicited_event_listener &listener); + inetd_unsolicited_event_listener getListener() + { + return this->listener_; + } + ~event_reporter(); + +private: + inetd_unsolicited_event_listener listener_; +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_EVENT_REPORTER_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/fwmark_server.h b/prebuilts/librarys/netd/include/net_mgr_native/include/fwmark_server.h new file mode 100755 index 0000000..7b09044 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/fwmark_server.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 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 __INCLUDE_FWMARK_SERVER_H__ +#define __INCLUDE_FWMARK_SERVER_H__ + +#include +#include "job.h" +#include "server_template.h" +namespace OHOS { +namespace nmd { +const char *const FWMARK_SERVER_SOCK_NAME = "fwmarkd.sock"; +const char *const FWMARK_SERVER_NAME = "FWMarkServer"; + +class fwmark_job : public job { +public: + fwmark_job(const int fd, const uint8_t *msg, const size_t msgLen, + const std::shared_ptr &serverSocket) + : job(fd, msg, msgLen, serverSocket) + {} + ~fwmark_job() = default; + + virtual void run() override; + +private: + void responseOk(); + void responseFailed(); +}; + +class fwmark_server : public common::server_template { +public: + fwmark_server() : common::server_template(FWMARK_SERVER_SOCK_NAME, FWMARK_SERVER_NAME) {} + + virtual ~fwmark_server() = default; + +private: + virtual void initJob(const int socketFd, const uint8_t *msg, const size_t msgLen) override; +}; +} // namespace nmd +} // namespace OHOS +#endif // !__INCLUDE_FWMARK_SERVER_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/interface_controller.h b/prebuilts/librarys/netd/include/net_mgr_native/include/interface_controller.h new file mode 100755 index 0000000..803f959 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/interface_controller.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 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 __INCLUDE_INTERFACE_CONTROLLER_H__ +#define __INCLUDE_INTERFACE_CONTROLLER_H__ +#include +#include +#include + +namespace OHOS { +namespace nmd { +typedef struct interface_configuration_parcel { + std::string ifName; + std::string hwAddr; + std::string ipv4Addr; + int prefixLength; + std::vector flags; + friend std::ostream &operator<<(std::ostream &os, const nmd::interface_configuration_parcel &parcel) + { + os << "ifName: " << parcel.ifName << "\n" + << "hwAddr: " << parcel.hwAddr << "\n" + << "ipv4Addr: " << parcel.ipv4Addr << "\n" + << "prefixLength: " << parcel.prefixLength << "\n" + << "flags: [" + << "\n"; + for (unsigned long i = 0; i < parcel.flags.size(); i++) { + os << " " << parcel.flags[i] << "\n"; + } + os << "] " + << "\n"; + return os; + } +} interface_configuration_parcel; + +class interface_controller { +public: + interface_controller(); + ~interface_controller(); + static int setMtu(const char *interfaceName, const char *mtuValue); + static int getMtu(const char *interfaceName); + static std::vector getInterfaceNames(); + static int clearAddrs(const std::string &ifName); + static int interfaceAddAddress(const std::string &ifName, const std::string &addr, const int prefixLen); + static int interfaceDelAddress(const std::string &ifName, const std::string &addr, const int prefixLen); + static int setParameter( + const char *family, const char *which, const char *ifName, const char *parameter, const char *value); + static int getParameter( + const char *family, const char *which, const char *ifName, const char *parameter, std::string *value); + static interface_configuration_parcel getConfig(const std::string &ifName); + static int setConfig(const nmd::interface_configuration_parcel &cfg); +}; +} // namespace nmd +} // namespace OHOS + +#endif // !__INCLUDE_INTERFACE_CONTROLLER_H__ diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/net_manager_native.h b/prebuilts/librarys/netd/include/net_mgr_native/include/net_manager_native.h new file mode 100755 index 0000000..cd8da04 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/net_manager_native.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2021 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 INCLUDE_NET_MANAGER_NATIVE_H__ +#define INCLUDE_NET_MANAGER_NATIVE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "event_reporter.h" + +namespace OHOS { +namespace nmd { +enum set_proc_sys_net { + IPV4 = 4, + IPV6 = 6, + CONF = 1, + NEIGH = 2, +}; +typedef struct route_info_parcel { + std::string destination; + std::string ifName; + std::string nextHop; + int mtu; +} route_info_parcel; + +typedef struct tether_offload_rule_parcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + std::vector destination; + int prefixLength; + std::vector srcL2Address; + std::vector dstL2Address; + int pmtu = 1500; +} tether_offload_rule_parcel; + +typedef struct tether_config_parcel { + bool usingLegacyDnsProxy; + std::vector dhcpRanges; +} tether_config_parcel; + +typedef struct mark_mask_parcel { + int mark; + int mask; +} mark_mask_parcel; +class NetManagerNative { +public: + NetManagerNative(); + ~NetManagerNative(); + + static void getOriginInterfaceIdex(); + static std::vector getCurrentInterfaceIdex(); + static void updateInterfaceIdex(unsigned int infIdex); + + void initChildChains(); + void initUnixSocket(); + void init(); + + int networkCreatePhysical(int netId, int permission); + int networkDestroy(int netId); + int networkAddInterface(int netId, std::string iface); + int networkRemoveInterface(int netId, std::string iface); + void socketDestroy(std::string iface); + void socketDestroy(int netId); + mark_mask_parcel getFwmarkForNetwork(int netId); + int networkAddRoute(int netId, std::string ifName, std::string destination, std::string nextHop); + int networkRemoveRoute(int netId, std::string ifName, std::string destination, std::string nextHop); + int networkGetDefault(); + int networkSetDefault(int netId); + int networkClearDefault(); + int networkSetPermissionForNetwork(int netId, NetworkPermission permission); + std::vector interfaceGetList(); + + int setProcSysNet(int32_t ipversion, int32_t which, const std::string ifname, const std::string parameter, + const std::string value); + int getProcSysNet(int32_t ipversion, int32_t which, const std::string ifname, const std::string parameter, + std::string *value); + + nmd::interface_configuration_parcel interfaceGetConfig(std::string ifName); + void interfaceSetConfig(interface_configuration_parcel cfg); + void interfaceClearAddrs(const std::string ifName); + int interfaceGetMtu(std::string ifName); + int interfaceSetMtu(std::string ifName, int mtuValue); + int interfaceAddAddress(std::string ifName, std::string addrString, int prefixLength); + int interfaceDelAddress(std::string ifName, std::string addrString, int prefixLength); + + void registerUnsolicitedEventListener(inetd_unsolicited_event_listener listener); + int networkAddRouteParcel(int netId, route_info_parcel routeInfo); + int networkRemoveRouteParcel(int netId, route_info_parcel routeInfo); + + long getCellularRxBytes(); + long getCellularTxBytes(); + long getAllRxBytes(); + long getAllTxBytes(); + long getUidTxBytes(int uid); + long getUidRxBytes(int uid); + traffic_stats_parcel interfaceGetStats(std::string interfaceName); + long getIfaceRxBytes(std::string interfaceName); + long getIfaceTxBytes(std::string interfaceName); + long getTetherRxBytes(); + long getTetherTxBytes(); + +private: + std::shared_ptr networkController_; + std::shared_ptr routeController_; + std::shared_ptr interfaceController_; + static std::vector interfaceIdex_; +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_NET_MANAGER_NATIVE_H__ diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_event.h b/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_event.h new file mode 100755 index 0000000..c6d2c88 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_event.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2021 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 INCLUDE_NETLINK_EVENT_H__ +#define INCLUDE_NETLINK_EVENT_H__ + +#include +#include +#include +#include +#include +#include +#include +namespace OHOS { +namespace nmd { +enum class Action { + Unknown = 0, + Add, + Remove, + Change, + LinkUp, + LinkDown, + AddressUpdated, + AddressRemoved, + RouteUpdated, + RouteRemoved, + NewRule, + DelRule, +}; +class netlink_event { +public: + netlink_event() = default; + bool parseInterfaceInfoInfoMessage(struct nlmsghdr *hdr); + bool parseInterafaceAddressMessage(struct nlmsghdr *hdr); + bool parseRouteMessage(struct nlmsghdr *hdr); + bool parseRuleMessage(struct nlmsghdr *hdr); + bool parseNetLinkMessage(char *buffer, ssize_t size); + + void setAction(Action action) + { + this->action_ = action; + } + Action getAction() + { + return this->action_; + } + + void addParam(std::string key, std::string value) + { + this->params_.insert(std::pair(key, value)); + } + const char *findParam(const char *key); + const char *rtMessageName(int type); + + ~netlink_event(); + +private: + Action action_; + std::map params_; +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_NETLINK_EVENT_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_handler.h b/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_handler.h new file mode 100755 index 0000000..200a90a --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_handler.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 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 INCLUDE_NETLINK_HANDLER_H__ +#define INCLUDE_NETLINK_HANDLER_H__ +#include +#include "event_reporter.h" +#include "netlink_listener.h" +#include "netlink_event.h" + +namespace OHOS { +namespace nmd { +class netlink_handler : public netlink_listener { +public: + void onEvent(std::shared_ptr evt); + + void notifyInterfaceAdded(const std::string &ifName); + void notifyInterfaceRemoved(const std::string &ifName); + void notifyInterfaceChanged(const std::string &ifName, bool isUp); + void notifyInterfaceLinkChanged(const std::string &ifName, bool isUp); + void notifyAddressUpdated(const std::string &addr, const std::string &ifName, int flags, int scope); + void notifyAddressRemoved(const std::string &addr, const std::string &ifName, int flags, int scope); + void notifyRouteChange( + bool updated, const std::string &route, const std::string &gateway, const std::string &ifName); + + int start(); + void stop(); + + int getSock() + { + return this->socketFd_; + } + + void setEventListener(const std::shared_ptr &reporter) + { + this->reporter_ = reporter; + } + + netlink_handler(int protocol, int pid); + ~netlink_handler(); + +private: + std::shared_ptr reporter_; +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_NETLINK_HANDLER_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_listener.h b/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_listener.h new file mode 100755 index 0000000..1b60816 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_listener.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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 INCLUDE_NETLINK_LISTENER_H__ +#define INCLUDE_NETLINK_LISTENER_H__ + +#include +#include "netlink_socket.h" +#include "netlink_event.h" + +namespace OHOS { +namespace nmd { +class netlink_listener : public netlink_socket { +public: + netlink_listener(int protocol, int pid); + ~netlink_listener(); + + void setOnEventHandler(const std::function)> &handler); + int listen(); + + void stopListen(); + bool getNetlinkListenerState(); + +private: + bool running_ = false; + std::function)> onEventHandler_; + + void onDataAvaliable(int fd, char *buf, ssize_t size); +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_NETLINK_LISTENER_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_manager.h b/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_manager.h new file mode 100755 index 0000000..97005a0 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_manager.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 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 INCLUDE_NETLINK_MANAGER_H__ +#define INCLUDE_NETLINK_MANAGER_H__ + +#include +#include "event_reporter.h" +#include "netlink_handler.h" +namespace OHOS { +namespace nmd { +namespace listeners { +void defaultOnInterfaceAddressUpdated(const std::string &, const std::string &, int, int); +void defaultOnInterfaceAddressRemoved(const std::string &, const std::string &, int, int); +void defaultOnInterfaceAdded(const std::string &); +void defaultOnInterfaceRemoved(const std::string &); +void defaultOnInterfaceChanged(const std::string &, bool); +void defaultOnInterfaceLinkStateChanged(const std::string &, bool); +void defaultOnRouteChanged(bool, const std::string &, const std::string &, const std::string &); +} // namespace listeners +class netlink_manager { +public: + void start(); + void stop(); + + int getRouteSock() + { + return this->routeHandler_->getSock(); + } + std::shared_ptr getRouteHandler() + { + return this->routeHandler_; + } + + static int getPid() + { + return pid_; + } + static void setPid(int pid) + { + pid_ = pid; + } + static std::shared_ptr getReporter() + { + return reporter_; + } + + explicit netlink_manager(int pid); + ~netlink_manager(); + +private: + static int pid_; + static std::shared_ptr reporter_; + + std::shared_ptr routeHandler_; + void startRouteHandler(); +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_NETLINK_MANAGER_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_socket.h b/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_socket.h new file mode 100755 index 0000000..0ea1934 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/netlink_socket.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 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 INCLUDE_NETLINK_SOCKET_H__ +#define INCLUDE_NETLINK_SOCKET_H__ + +#include +#include +#include +#include +#include +#include + +namespace OHOS { +namespace nmd { +class netlink_socket { +public: + int socketFd_; + int pid_ = 0; + + virtual ~netlink_socket(); + + void setSock(int sock) + { + this->socketFd_ = sock; + } + + int create(int protocol); + int create(int type, int protocol); + int binding(); + + int acceptAndListen(); + + int sendNetlinkMsgToKernel(struct nlmsghdr *msg); + + ssize_t receive(void *buf); + + int shutdown(); + + void setOnDataReceiveHandler(const std::function &handler); + + void setPid(int pid) + { + this->pid_ = pid; + } + +private: + std::function handler_; + struct sockaddr addr_ {}; + /** + * Link layer: RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK, RTM_SETLINK + * Address settings: RTM_NEWADDR, RTM_DELADDR, RTM_GETADDR + * Routing tables: RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE + * Neighbor cache: RTM_NEWNEIGH, RTM_DELNEIGH, RTM_GETNEIGH + * Routing rules: RTM_NEWRULE, RTM_DELRULE, RTM_GETRULE + * Queuing discipline settings: RTM_NEWQDISC, RTM_DELQDISC, RTM_GETQDISC + * Traffic classes used with queues: RTM_NEWTCLASS, RTM_DELTCLASS, RTM_GETTCLASS + * Traffic filters: RTM_NEWTFILTER, RTM_DELTFILTER, RTM_GETTFILTER + * Others: RTM_NEWACTION, RTM_DELACTION, RTM_GETACTION, RTM_NEWPREFIX, RTM_GETPREFIX, RTM_GETMULTICAST, + * RTM_GETANYCAST, RTM_NEWNEIGHTBL, RTM_GETNEIGHTBL, RTM_SETNEIGHTBL + */ + int send(unsigned short action, char *buffer, size_t size, unsigned short rtaType, char *attrBuf, + size_t attrBufLen); +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_NETLINK_SOCKET_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/netnative_log_wrapper.h b/prebuilts/librarys/netd/include/net_mgr_native/include/netnative_log_wrapper.h new file mode 100755 index 0000000..7e2464a --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/netnative_log_wrapper.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 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 NETNATIVE_LOG_WRAPPER_H +#define NETNATIVE_LOG_WRAPPER_H + +#include +#include "hilog/log.h" + +#ifndef NETMGRNATIVE_LOG_TAG +#define NETMGRNATIVE_LOG_TAG "NetdNativeService" +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel NET_MGR_LABEL = {LOG_CORE, LOG_DOMAIN, NETMGRNATIVE_LOG_TAG}; + +#define FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__) + +#define PRINT_NATIVE_LOG(op, fmt, ...) \ + (void)OHOS::HiviewDFX::HiLog::op(NET_MGR_LABEL, "[%{public}s-(%{public}s:%{public}d)]" fmt, __FUNCTION__, \ + FILENAME__, __LINE__, ##__VA_ARGS__) + +#define NETNATIVE_LOGD(fmt, ...) PRINT_NATIVE_LOG(Debug, fmt, ##__VA_ARGS__) +#define NETNATIVE_LOGE(fmt, ...) PRINT_NATIVE_LOG(Error, fmt, ##__VA_ARGS__) +#define NETNATIVE_LOGW(fmt, ...) PRINT_NATIVE_LOG(Warn, fmt, ##__VA_ARGS__) +#define NETNATIVE_LOGI(fmt, ...) PRINT_NATIVE_LOG(Info, fmt, ##__VA_ARGS__) +#define NETNATIVE_LOGF(fmt, ...) PRINT_NATIVE_LOG(Fatal, fmt, ##__VA_ARGS__) + +#endif // NETNATIVE_LOG_WRAPPER_H \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/network_controller.h b/prebuilts/librarys/netd/include/net_mgr_native/include/network_controller.h new file mode 100755 index 0000000..e9135a5 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/network_controller.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 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 INCLUDE_NETWORK_CONTROLLER_H__ +#define INCLUDE_NETWORK_CONTROLLER_H__ +#include +#include +#include +#include +#include "nmd_network.h" +namespace OHOS { +namespace nmd { +class network_controller { +public: + network_controller() = default; + ~network_controller(); + + int createPhysicalNetwork(uint16_t netId, Permission permission); + + int destroyNetwork(int netId); + + int setDefaultNetwork(int netId); + + int clearDefaultNetwork(); + + int getDefaultNetwork(); + + int addInterfaceToNetwork(int netId, std::string &interafceName); + + int removeInterfaceFromNetwork(int netId, std::string &interafceName); + + int addRoute(int netId, std::string interfaceName, std::string destination, std::string nextHop); + + int removeRoute(int netId, std::string interfaceName, std::string destination, std::string nextHop); + + int getFwmarkForNetwork(int netId); + + int setPermissionForNetwork(int netId, Permission permission); + + std::vector getNetworks(); + + nmd::NmdNetwork *getNetwork(int netId); + +private: + int defaultNetId_; + std::map networks_; + std::tuple findNetworkById(int netId); + int getNetworkForInterface(std::string &interfaceName); +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_NETWORK_CONTROLLER_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/nmd_network.h b/prebuilts/librarys/netd/include/net_mgr_native/include/nmd_network.h new file mode 100755 index 0000000..81acdb2 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/nmd_network.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 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 INCLUDE_NMD_NETWORK_H__ +#define INCLUDE_NMD_NETWORK_H__ + +#include +#include +namespace OHOS { +namespace nmd { +typedef enum Permission { + PERMISSION_NONE = 0x0, + PERMISSION_NETWORK = 0x1, + PERMISSION_SYSTEM = 0x3, +} NetworkPermission; + +class NmdNetwork { +public: + NmdNetwork(uint16_t netId, NetworkPermission permission); + + void asDefault(); + void removeAsDefault(); + + int addInterface(std::string &interfaceName); + int removeInterface(std::string &interfaceName); + int clearInterfaces(); + + bool hasInterface(std::string &interfaceName); + std::set getAllInterface() + { + return this->interfaces_; + } + + uint16_t getNetId() + { + return this->netId_; + } + NetworkPermission getPermission() + { + return this->permission_; + } + + bool isDefault() + { + return this->isDefault_; + } + + virtual ~NmdNetwork(); + +private: + uint16_t netId_; + + bool isDefault_ = false; + + NetworkPermission permission_; + + std::set interfaces_; +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_NMD_NETWORK_H__ diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/route_controller.h b/prebuilts/librarys/netd/include/net_mgr_native/include/route_controller.h new file mode 100755 index 0000000..654a075 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/route_controller.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 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 INCLUDE_ROUTE_CONTROLLER_H__ +#define INCLUDE_ROUTE_CONTROLLER_H__ + +#include +#include +#include "nmd_network.h" + +namespace OHOS { +namespace nmd { +typedef struct _inet_addr { + int family; + int bitlen; + int prefixlen; + uint8_t data[sizeof(struct in6_addr)]; +} _inet_addr; + +class route_controller { +public: + route_controller(); + ~route_controller(); + + static int createChildChains(const char *table, const char *parentChain, const char *childChain); + static int addInterfaceToDefaultNetwork(const char *interface, NetworkPermission permission); + static int removeInterfaceFromDefaultNetwork(const char *interface, NetworkPermission permission); + static int addInterfaceToPhysicalNetwork(uint16_t netId, const char *interface, NetworkPermission permission); + + static int removeInterfaceFromPhysicalNetwork( + uint16_t netId, const char *interfaceName, NetworkPermission permission); + + static int addRoute(int netId, std::string interfaceName, std::string destination, std::string nextHop); + + static int removeRoute(int netId, std::string interfaceName, std::string destination, std::string nextHop); + + static int read_addr(const char *addr, _inet_addr *res); + static int read_addr_gw(const char *addr, _inet_addr *res); + +private: + static int executeIptablesRestore(std::string command); + static void updateTableNamesFile(); + static std::map interfaceToTable_; + static uint32_t getRouteTableForInterface(const char *interfaceName); + + void modifyIpRule(std::string interface, NetworkPermission permission); +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_ROUTE_CONTROLLER_H__ \ No newline at end of file diff --git a/prebuilts/librarys/netd/include/net_mgr_native/include/traffic_controller.h b/prebuilts/librarys/netd/include/net_mgr_native/include/traffic_controller.h new file mode 100755 index 0000000..121e428 --- /dev/null +++ b/prebuilts/librarys/netd/include/net_mgr_native/include/traffic_controller.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2021 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 INCLUDE_TRAFFIC_CONTROLLER_H__ +#define INCLUDE_TRAFFIC_CONTROLLER_H__ +#include +#include +#include +namespace OHOS { +namespace nmd { +typedef struct arp_cache_information { + std::string ipAddr; + std::string macAddr; + std::string dev; + std::string state; + + friend std::ostream &operator<<(std::ostream &os, const arp_cache_information &information) + { + os << "ipAddr: " << information.ipAddr << " macAddr: " << information.macAddr + << " dev: " << information.dev << " state: " << information.state; + return os; + } +} arp_cache_information; + +typedef struct tether_traffic_account { + std::string bytes; + std::string sourceIp; + std::string destinationIp; + + friend std::ostream &operator<<(std::ostream &os, const tether_traffic_account &account) + { + os << "bytes: " << account.bytes << " sourceIp: " << account.sourceIp + << " destinationIp: " << account.destinationIp; + return os; + } +} tether_traffic_account; + +typedef struct tether_stats_parcel { + std::string iface; + unsigned int ifIndex = 0; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + + friend std::ostream &operator<<(std::ostream &os, const tether_stats_parcel &parcel) + { + os << "iface: " << parcel.iface << "ifIndex: " << parcel.ifIndex << "rxBytes: " << parcel.rxBytes + << "rxPackets: " << parcel.rxPackets << "txBytes: " << parcel.txBytes + << "txPackets: " << parcel.txPackets; + return os; + } +} tether_stats_parcel; + +typedef tether_stats_parcel traffic_stats_parcel; + +class traffic_controller { +public: + traffic_controller(); + ~traffic_controller(); + bool isTetherEnable(); + static nmd::traffic_stats_parcel getInterfaceTraffic(const std::string &ifName); + static long getAllRxTraffic(); + static long getAllTxTraffic(); + static std::vector getTetherClientInfo(); + static void startTrafficTether(); + static long getTxTetherTraffic(); + static long getRxTetherTraffic(); + static long getRxUidTraffic(int uid); + static long getTxUidTraffic(int uid); + static long getCellularRxTraffic(); + static long getCellularTxTraffic(); + static void traffic_controller_log(); + static void execIptablesRuleMethod(std::string &cmd); +}; +} // namespace nmd +} // namespace OHOS +#endif // !INCLUDE_TRAFFIC_CONTROLLER_H__ \ No newline at end of file diff --git a/sa_profile/1151.xml b/sa_profile/1151.xml new file mode 100755 index 0000000..92c4fc9 --- /dev/null +++ b/sa_profile/1151.xml @@ -0,0 +1,27 @@ + + + + netmanager + + 1151 + libnet_conn_manager.z.so + + + true + false + 1 + + diff --git a/sa_profile/1152.xml b/sa_profile/1152.xml new file mode 100755 index 0000000..e023646 --- /dev/null +++ b/sa_profile/1152.xml @@ -0,0 +1,27 @@ + + + + netmanager + + 1152 + libnet_policy_manager.z.so + + + true + false + 1 + + diff --git a/sa_profile/1156.xml b/sa_profile/1156.xml new file mode 100755 index 0000000..e7bfece --- /dev/null +++ b/sa_profile/1156.xml @@ -0,0 +1,27 @@ + + + + netmanager + + 1156 + libdns_resolver_manager.z.so + + + true + false + 1 + + diff --git a/sa_profile/1157.xml b/sa_profile/1157.xml new file mode 100755 index 0000000..67bec0b --- /dev/null +++ b/sa_profile/1157.xml @@ -0,0 +1,27 @@ + + + + netmanager + + 1157 + libethernet_manager.z.so + + + true + false + 1 + + diff --git a/sa_profile/BUILD.gn b/sa_profile/BUILD.gn new file mode 100755 index 0000000..ccd3584 --- /dev/null +++ b/sa_profile/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright (c) 2021 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/sa_profile/sa_profile.gni") + +ohos_sa_profile("net_manager_profile") { + sources = [ + "1151.xml", + "1152.xml", + "1156.xml", + "1157.xml", + ] + + part_name = "netmanager_standard" +} diff --git a/services/common/include/broadcast_manager.h b/services/common/include/broadcast_manager.h new file mode 100755 index 0000000..2a9ea06 --- /dev/null +++ b/services/common/include/broadcast_manager.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 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 BROADCAST_MANAGER_H +#define BROADCAST_MANAGER_H + +#include +#include + +#include "singleton.h" + +namespace OHOS { +namespace NetManagerStandard { +struct BroadcastInfo { + std::string action; + std::string data; + int32_t code; + bool ordered; + BroadcastInfo() : code(0), ordered(true) {} +}; + +class BroadcastManager { + DECLARE_DELAYED_SINGLETON(BroadcastManager) +public: + bool SendBroadcast(const BroadcastInfo &info, const std::map ¶m); + + bool SendBroadcast(const BroadcastInfo &info, const std::map ¶m); + + bool SendBroadcast(const BroadcastInfo &info, const std::map ¶m); + +private: + template + bool SendBroadcastEx(const BroadcastInfo &info, const std::map ¶m); +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // BROADCAST_MANAGER_H diff --git a/services/common/include/netd_controller.h b/services/common/include/netd_controller.h new file mode 100755 index 0000000..d6e4794 --- /dev/null +++ b/services/common/include/netd_controller.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2021 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 NETD_CONTROLLER_H +#define NETD_CONTROLLER_H + +#include +#include +#ifdef NATIVE_NETD_FEATURE +#include "dnsresolv_service.h" +#include "fwmark_server.h" +#include "net_manager_native.h" +#include "netlink_manager.h" +#else +#include +#include +#include +#include +#include +#include +#endif + +#include "net_mgr_log_wrapper.h" +#include "route.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetdController { +public: + NetdController(); + ~NetdController(); + void Init(); + + static NetdController *GetInstance(); + /** + * @brief Create a physical network + * + * @param netId + * @param permission Permission to create a physical network + * @return Return the return value of the netd interface call + */ + int32_t NetworkCreatePhysical(int32_t netId, int32_t permission); + + /** + * @brief Destroy the network + * + * @param netId + * @return Return the return value of the netd interface call + */ + int32_t NetworkDestroy(int32_t netId); + + /** + * @brief Add network port device + * + * @param netId + * @param iface Network port device name + * @return Return the return value of the netd interface call + */ + int32_t NetworkAddInterface(int32_t netId, const std::string &iface); + + /** + * @brief Delete network port device + * + * @param netId + * @param iface Network port device name + * @return Return the return value of the netd interface call + */ + int32_t NetworkRemoveInterface(int32_t netId, const std::string &iface); + + /** + * @brief Add route + * + * @param netId + * @param ifName Network port device name + * @param destination Target host ip + * @param nextHop Next hop address + * @return Return the return value of the netd interface call + */ + int32_t NetworkAddRoute(int32_t netId, const std::string &ifName, const std::string &destination, + const std::string &nextHop); + + /** + * @brief Remove route + * + * @param netId + * @param ifName Network port device name + * @param destination Target host ip + * @param nextHop Next hop address + * @return Return the return value of the netd interface call + */ + int32_t NetworkRemoveRoute(int32_t netId, const std::string &ifName, const std::string &destination, + const std::string &nextHop); + + /** + * @brief Turn off the device + * + * @param iface Network port device name + */ + void SetInterfaceDown(const std::string &iface); + + /** + * @brief Turn on the device + * + * @param iface Network port device name + */ + void SetInterfaceUp(const std::string &iface); + + /** + * @brief Clear the network interface ip address + * + * @param ifName Network port device name + */ + void InterfaceClearAddrs(const std::string &ifName); + + /** + * @brief Obtain mtu from the network interface device + * + * @param ifName Network port device name + * @return Return the return value of the netd interface call + */ + int32_t InterfaceGetMtu(const std::string &ifName); + + /** + * @brief Set mtu to network interface device + * + * @param ifName Network port device name + * @param mtu + * @return Return the return value of the netd interface call + */ + int32_t InterfaceSetMtu(const std::string &ifName, int32_t mtu); + + /** + * @brief Add ip address + * + * @param ifName Network port device name + * @param ipAddr ip address + * @param prefixLength subnet mask + * @return Return the return value of the netd interface call + */ + int32_t InterfaceAddAddress(const std::string &ifName, const std::string &ipAddr, int32_t prefixLength); + + /** + * @brief Delete ip address + * + * @param ifName Network port device name + * @param ipAddr ip address + * @param prefixLength subnet mask + * @return Return the return value of the netd interface call + */ + int32_t InterfaceDelAddress(const std::string &ifName, const std::string &ipAddr, int32_t prefixLength); + + /** + * @brief Set dns + * + * @param netId + * @param baseTimeoutMsec + * @param retryCount + * @param servers + * @param domains + * @return Return the return value of the netd interface call + */ + int32_t SetResolverConfig(uint16_t netId, uint16_t baseTimeoutMsec, uint8_t retryCount, + const std::vector &servers, const std::vector &domains); + /** + * @brief Get dns server param info + * + * @param netId + * @param servers + * @param domains + * @param baseTimeoutMsec + * @param retryCount + * @return Return the return value of the netd interface call + */ + int32_t GetResolverInfo(uint16_t netId, std::vector &servers, + std::vector &domains, uint16_t &baseTimeoutMsec, uint8_t &retryCount); + + /** + * @brief Create dns cache before set dns + * + * @param netId + * @return Return the return value for status of call + */ + int CreateNetworkCache(uint16_t netId); + + /** + * @brief Destory dns cache + * + * @param netId + * @return Return the return value of the netd interface call + */ + int DestoryNetworkCache(uint16_t netId); + + /** + * @brief Flush dns cache + * + * @param netId + * @return Return the return value of the netd interface call + */ + int FlushNetworkCache(uint16_t netId); + + /** + * @brief Domain name resolution Obtains the domain name address + * + * @param hostName + * @param serverName + * @param hints + * @param res + * @return Return the return value of the netd interface call + */ + int GetAddrInfo(const std::string &hostName, const std::string &serverName, + const struct addrinfo &hints, std::unique_ptr &res, uint16_t netId); + +#ifdef NATIVE_NETD_FEATURE +#else + int AddRoute(const std::string &ip, const std::string &mask, + const std::string &gateWay, const std::string &devName); +#endif +private: +#ifdef NATIVE_NETD_FEATURE + std::unique_ptr netdService_ = nullptr; + std::unique_ptr manager_ = nullptr; + std::unique_ptr fwmarkServer_ = nullptr; + std::unique_ptr dnsResolvService_ = nullptr; +#endif + static NetdController *singleInstance_; + static std::mutex mutex_; + bool initFlag_ = false; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NETD_CONTROLLER_H diff --git a/services/common/include/timer.h b/services/common/include/timer.h new file mode 100755 index 0000000..b10d4a8 --- /dev/null +++ b/services/common/include/timer.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 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 NET_MANAGER_TIMER_H +#define NET_MANAGER_TIMER_H + +#include +#include +#include +#include +#include +#include +#include + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +class Timer { +public: + Timer() : stopStatus_(true), tryStopFlag_(false) {} + + Timer(const Timer &timer) + { + stopStatus_ = timer.stopStatus_.load(); + tryStopFlag_ = timer.tryStopFlag_.load(); + } + + ~Timer() + { + Stop(); + } + + void Start(int interval, std::function taskFun) + { + if (stopStatus_ == false) { + return; + } + NETMGR_LOGI("start thread..."); + stopStatus_ = false; + std::thread([this, interval, taskFun]() { + while (!tryStopFlag_) { + std::this_thread::sleep_for(std::chrono::milliseconds(interval)); + taskFun(); + } + + std::lock_guard locker(mutex_); + stopStatus_ = true; + timerCond_.notify_one(); + }).detach(); + } + + void StartOnce(int interval, std::function taskFun) + { + std::thread([this, interval, taskFun]() { + if (!tryStopFlag_) { + std::this_thread::sleep_for(std::chrono::milliseconds(interval)); + taskFun(); + } + }).detach(); + } + + void Stop() + { + if (stopStatus_ || tryStopFlag_) { + return; + } + NETMGR_LOGI("stop thread..."); + tryStopFlag_ = true; + std::unique_lock locker(mutex_); + timerCond_.wait(locker, [this] { return stopStatus_ == true; }); + + if (stopStatus_ == true) + tryStopFlag_ = false; + } + +private: + std::atomic stopStatus_; + std::atomic tryStopFlag_; + std::mutex mutex_; + std::condition_variable timerCond_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_MANAGER_TIMER_H diff --git a/services/common/src/broadcast_manager.cpp b/services/common/src/broadcast_manager.cpp new file mode 100755 index 0000000..d95e9c3 --- /dev/null +++ b/services/common/src/broadcast_manager.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021 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 "broadcast_manager.h" + +#include "common_event_manager.h" +#include "common_event_support.h" +#include "want.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +BroadcastManager::BroadcastManager() {} + +BroadcastManager::~BroadcastManager() {} + +bool BroadcastManager::SendBroadcast(const BroadcastInfo &info, const std::map ¶m) +{ + return SendBroadcastEx(info, param); +} + +bool BroadcastManager::SendBroadcast(const BroadcastInfo &info, const std::map ¶m) +{ + return SendBroadcastEx(info, param); +} + +bool BroadcastManager::SendBroadcast(const BroadcastInfo &info, const std::map ¶m) +{ + return SendBroadcastEx(info, param); +} + +template +bool BroadcastManager::SendBroadcastEx(const BroadcastInfo &info, const std::map ¶m) +{ + if (info.action.empty()) { + NETMGR_LOGE("The parameter of action is empty"); + return false; + } + + AAFwk::Want want; + want.SetAction(info.action); + for (const auto &x : param) { + want.SetParam(x.first, x.second); + } + + EventFwk::CommonEventData eventData; + eventData.SetWant(want); + eventData.SetCode(info.code); + eventData.SetData(info.data); + EventFwk::CommonEventPublishInfo publishInfo; + publishInfo.SetOrdered(info.ordered); + + bool publishResult = EventFwk::CommonEventManager::PublishCommonEvent(eventData, publishInfo, nullptr); + if (publishResult) { + NETMGR_LOGI("Send broadcast is successfull"); + } else { + NETMGR_LOGE("Send broadcast is failed"); + } + + return publishResult; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/common/src/netd_controller.cpp b/services/common/src/netd_controller.cpp new file mode 100755 index 0000000..d16d0bb --- /dev/null +++ b/services/common/src/netd_controller.cpp @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2021 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 "netd_controller.h" + +#include "securec.h" +#ifdef NATIVE_NETD_FEATURE +#include +#include "net_conn_types.h" +#else +#include +#include +#endif + +namespace OHOS { +namespace NetManagerStandard { +NetdController *NetdController::singleInstance_ = nullptr; +std::mutex NetdController::mutex_; + +NetdController::NetdController() +{ + Init(); +} + +NetdController::~NetdController() {} + +void NetdController::Init() +{ + NETMGR_LOGI("netd Init"); + if (initFlag_) { + NETMGR_LOGI("netd initialization is complete"); + return; + } + initFlag_ = true; +#ifdef NATIVE_NETD_FEATURE + netdService_ = std::make_unique(); + netdService_->init(); + + int32_t pid = getpid(); + manager_ = std::make_unique(pid); + std::thread nlManager([&] { manager_->start(); }); + + fwmarkServer_ = std::make_unique(); + std::thread fwserve([&] { fwmarkServer_->start(); }); + + dnsResolvService_ = std::make_unique(); + std::thread dnsresolvServe([&] { dnsResolvService_->start(); }); + + nlManager.detach(); + fwserve.detach(); + dnsresolvServe.detach(); +#else + return; +#endif +} + +NetdController *NetdController::GetInstance() +{ + if (singleInstance_ == nullptr) { + std::unique_lock lock(mutex_); + if (singleInstance_ == nullptr) { + singleInstance_ = std::make_unique().release(); + } + } + + return singleInstance_; +} + +int32_t NetdController::NetworkCreatePhysical(int32_t netId, int32_t permission) +{ + NETMGR_LOGI("Create Physical network: netId[%{public}d], permission[%{public}d]", netId, permission); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return netdService_->networkCreatePhysical(netId, permission); +#else + return 0; +#endif +} + +int32_t NetdController::NetworkDestroy(int32_t netId) +{ + NETMGR_LOGI("Destroy network: netId[%{public}d]", netId); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return netdService_->networkDestroy(netId); +#else + return 0; +#endif +} + +int32_t NetdController::NetworkAddInterface(int32_t netId, const std::string &iface) +{ + NETMGR_LOGI("Add network interface: netId[%{public}d], iface[%{public}s]", netId, iface.c_str()); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return netdService_->networkAddInterface(netId, iface); +#else + return 0; +#endif +} + +int32_t NetdController::NetworkRemoveInterface(int32_t netId, const std::string &iface) +{ + NETMGR_LOGI("Remove network interface: netId[%{public}d], iface[%{public}s]", netId, iface.c_str()); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return netdService_->networkRemoveInterface(netId, iface); +#else + return 0; +#endif +} + +int32_t NetdController::NetworkAddRoute(int32_t netId, const std::string &ifName, + const std::string &destination, const std::string &nextHop) +{ + NETMGR_LOGI("Add Route: netId[%{public}d], ifName[%{public}s], destination[%{public}s], nextHop[%{public}s]", + netId, ifName.c_str(), destination.c_str(), nextHop.c_str()); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return netdService_->networkAddRoute(netId, ifName, destination, nextHop); +#else + std::string mask = "0.0.0.0"; + return AddRoute(destination, mask, nextHop, ifName); +#endif +} + +int32_t NetdController::NetworkRemoveRoute(int32_t netId, const std::string &ifName, + const std::string &destination, const std::string &nextHop) +{ + NETMGR_LOGI("Remove Route: netId[%{public}d], ifName[%{public}s], destination[%{public}s], nextHop[%{public}s]", + netId, ifName.c_str(), destination.c_str(), nextHop.c_str()); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return netdService_->networkRemoveRoute(netId, ifName, destination, nextHop); +#else + return 0; +#endif +} + +void NetdController::SetInterfaceDown(const std::string &iface) +{ + NETMGR_LOGI("Set interface down: iface[%{public}s]", iface.c_str()); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return; + } + auto interfaceConfig = netdService_->interfaceGetConfig(iface); + auto fit = std::find(interfaceConfig.flags.begin(), interfaceConfig.flags.end(), "up"); + if (fit != interfaceConfig.flags.end()) { + interfaceConfig.flags.erase(fit); + } + interfaceConfig.flags.push_back("down"); + netdService_->interfaceSetConfig(interfaceConfig); +#else + return; +#endif +} + +void NetdController::SetInterfaceUp(const std::string &iface) +{ + NETMGR_LOGI("Set interface up: iface[%{public}s]", iface.c_str()); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return; + } + auto interfaceConfig = netdService_->interfaceGetConfig(iface); + auto fit = std::find(interfaceConfig.flags.begin(), interfaceConfig.flags.end(), "down"); + if (fit != interfaceConfig.flags.end()) { + interfaceConfig.flags.erase(fit); + } + interfaceConfig.flags.push_back("up"); + netdService_->interfaceSetConfig(interfaceConfig); +#else + return; +#endif +} + +void NetdController::InterfaceClearAddrs(const std::string &ifName) +{ + NETMGR_LOGI("Clear addrs: ifName[%{public}s]", ifName.c_str()); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return; + } + return netdService_->interfaceClearAddrs(ifName); +#else + return; +#endif +} + +int32_t NetdController::InterfaceGetMtu(const std::string &ifName) +{ + NETMGR_LOGI("Get mtu: ifName[%{public}s]", ifName.c_str()); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return netdService_->interfaceGetMtu(ifName); +#else + return 0; +#endif +} + +int32_t NetdController::InterfaceSetMtu(const std::string &ifName, int32_t mtu) +{ + NETMGR_LOGI("Set mtu: ifName[%{public}s], mtu[%{public}d]", ifName.c_str(), mtu); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return netdService_->interfaceSetMtu(ifName, mtu); +#else + return 0; +#endif +} + +int32_t NetdController::InterfaceAddAddress(const std::string &ifName, + const std::string &ipAddr, int32_t prefixLength) +{ + NETMGR_LOGI("Add address: ifName[%{public}s], ipAddr[%{public}s], prefixLength[%{public}d]", + ifName.c_str(), ipAddr.c_str(), prefixLength); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return netdService_->interfaceAddAddress(ifName, ipAddr, prefixLength); +#else + return 0; +#endif +} + +int32_t NetdController::InterfaceDelAddress(const std::string &ifName, + const std::string &ipAddr, int32_t prefixLength) +{ + NETMGR_LOGI("Delete address: ifName[%{public}s], ipAddr[%{public}s], prefixLength[%{public}d]", + ifName.c_str(), ipAddr.c_str(), prefixLength); +#ifdef NATIVE_NETD_FEATURE + if (netdService_ == nullptr) { + NETMGR_LOGE("netdService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return netdService_->interfaceDelAddress(ifName, ipAddr, prefixLength); +#else + return 0; +#endif +} + +int32_t NetdController::SetResolverConfig(uint16_t netId, uint16_t baseTimeoutMsec, uint8_t retryCount, + const std::vector &servers, const std::vector &domains) +{ + std::unique_lock lock(mutex_); + NETMGR_LOGI("Set resolver config: netId[%{public}d]", netId); +#ifdef NATIVE_NETD_FEATURE + if (dnsResolvService_ == nullptr) { + NETMGR_LOGE("dnsResolvService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + const nmd::dnsresolver_params params = {netId, baseTimeoutMsec, retryCount, servers, domains}; + return dnsResolvService_->setResolverConfig(params); +#else + return 0; +#endif +} + +int32_t NetdController::GetResolverInfo(uint16_t netId, std::vector &servers, + std::vector &domains, + uint16_t &baseTimeoutMsec, uint8_t &retryCount) +{ + std::unique_lock lock(mutex_); + NETMGR_LOGI("Get resolver config: netId[%{public}d]", netId); +#ifdef NATIVE_NETD_FEATURE + if (dnsResolvService_ == nullptr) { + NETMGR_LOGE("dnsResolvService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + nmd::dns_res_params getParam; + int ret = dnsResolvService_->getResolverInfo(netId, servers, domains, getParam); + baseTimeoutMsec = getParam.baseTimeoutMsec; + retryCount = getParam.retryCount; + return ret; +#else + return 0; +#endif +} + +int32_t NetdController::CreateNetworkCache(uint16_t netId) +{ + std::unique_lock lock(mutex_); + NETMGR_LOGI("create Network cache: netId[%{public}d]", netId); +#ifdef NATIVE_NETD_FEATURE + if (dnsResolvService_ == nullptr) { + NETMGR_LOGE("dnsResolvService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return dnsResolvService_->createNetworkCache(netId); +#else + return 0; +#endif +} + +int NetdController::DestoryNetworkCache(uint16_t netId) +{ + std::unique_lock lock(mutex_); + NETMGR_LOGI("Destory dns cache: netId[%{public}d]", netId); +#ifdef NATIVE_NETD_FEATURE + if (dnsResolvService_ == nullptr) { + NETMGR_LOGE("dnsResolvService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return dnsResolvService_->destoryNetworkCache(netId); +#else + return 0; +#endif +} + +int NetdController::FlushNetworkCache(uint16_t netId) +{ + std::unique_lock lock(mutex_); + NETMGR_LOGI("Destory Flush dns cache: netId[%{public}d]", netId); +#ifdef NATIVE_NETD_FEATURE + if (dnsResolvService_ == nullptr) { + NETMGR_LOGE("dnsResolvService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + return dnsResolvService_->flushNetworkCache(netId); +#else + return 0; +#endif +} + +int NetdController::GetAddrInfo(const std::string &hostName, + const std::string &serverName, const struct addrinfo &hints, std::unique_ptr &res, uint16_t netId) +{ + std::unique_lock lock(mutex_); + NETMGR_LOGI("NetdController GetAddrInfo"); +#ifdef NATIVE_NETD_FEATURE + if (dnsResolvService_ == nullptr) { + NETMGR_LOGE("NetdController GetAddrInfo dnsResolvService_ is null"); + return ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL; + } + struct addrinfo *addrRes = nullptr; + int ret = dnsResolvService_->getaddrinfo(hostName.c_str(), nullptr, &hints, &addrRes, netId); + res.reset(addrRes); + return ret; +#else + return 0; +#endif +} + +#ifndef NATIVE_NETD_FEATURE +int NetdController::AddRoute(const std::string &ip, const std::string &mask, + const std::string &gateWay, const std::string &devName) +{ + int fd = 0; + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + NETMGR_LOGE("NetdController create socket fd[%{public}d]", fd); + return -1; + } + struct sockaddr_in _sin; + struct sockaddr_in *sin = &_sin; + struct rtentry rt; + bzero(&rt, sizeof(struct rtentry)); + bzero(sin, sizeof(struct sockaddr_in)); + sin->sin_family = AF_INET; + sin->sin_port = 0; + if (inet_aton(gateWay.c_str(), &sin->sin_addr) < 0) { + NETMGR_LOGE("NetdController inet_aton gateWay[%{public}s]", gateWay.c_str()); + return -1; + } + memcpy_s(&rt.rt_gateway, sizeof(rt.rt_gateway), sin, sizeof(struct sockaddr_in)); + (reinterpret_cast(&rt.rt_dst))->sin_family=AF_INET; + if (inet_aton(ip.c_str(), &((struct sockaddr_in*)&rt.rt_dst)->sin_addr) < 0) { + NETMGR_LOGE("NetdController inet_aton ip[%{public}s]", ip.c_str()); + return -1; + } + (reinterpret_cast(&rt.rt_genmask))->sin_family=AF_INET; + if (inet_aton(mask.c_str(), &(reinterpret_cast(&rt.rt_genmask))->sin_addr) < 0) { + NETMGR_LOGE("NetdController inet_aton mask[%{public}s]", mask.c_str()); + return -1; + } + if (!devName.empty()) { + rt.rt_dev = (char*)devName.c_str(); + } + rt.rt_flags = RTF_GATEWAY; + if (ioctl(fd, SIOCADDRT, &rt) < 0) { + NETMGR_LOGE("NetdController ioctl error"); + return -1; + } + close(fd); + return 0; +} +#endif +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/dnsresolvermanager/BUILD.gn b/services/dnsresolvermanager/BUILD.gn new file mode 100755 index 0000000..4926eb6 --- /dev/null +++ b/services/dnsresolvermanager/BUILD.gn @@ -0,0 +1,69 @@ +# Copyright (c) 2021 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") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +ohos_shared_library("dns_resolver_manager") { + sources = [ + "$DNSRESOLVERMANAGER_SOURCE_DIR/src/dns_resolver_service.cpp", + "$DNSRESOLVERMANAGER_SOURCE_DIR/src/ipc/dns_resolver_service_stub.cpp", + ] + + include_dirs = [ + "$DNSRESOLVERMANAGER_SOURCE_DIR/include", + "$DNSRESOLVERMANAGER_SOURCE_DIR/include/ipc", + "$INNERKITS_ROOT/native/dnsresolvermanager/include", + "$INNERKITS_ROOT/native/netconnmanager/include", + "$INNERKITS_ROOT/native/include", + "$NETCONNMANAGER_COMMON_DIR/include", + ] + + deps = [ + "$INNERKITS_ROOT/native/dnsresolvermanager:dns_resolver_manager_if", + "$INNERKITS_ROOT/native/netconnmanager:net_conn_manager_if", + "$NETMANAGER_BASE_ROOT/services/netconnmanager:net_conn_manager", + "$NETMANAGER_BASE_ROOT/utils:net_manager_common", + "$NETMANAGER_PREBUILTS_DIR/librarys/netd:libnet_manager_native", + "//utils/native/base:utils", + ] + + external_deps = [ + "aafwk_standard:want", + "appexecfwk_standard:libeventhandler", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_standard:samgr_proxy", + ] + + defines = [ + "NETMGR_LOG_TAG = \"DnsResolverManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + defines += [ "NATIVE_NETD_FEATURE" ] + + if (enable_netmgr_debug) { + defines += [ "NETMGR_DEBUG" ] + } + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/services/dnsresolvermanager/include/dns_resolver_service.h b/services/dnsresolvermanager/include/dns_resolver_service.h new file mode 100755 index 0000000..45f9efd --- /dev/null +++ b/services/dnsresolvermanager/include/dns_resolver_service.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 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 DNS_RESOLVER_SERVICE_H +#define DNS_RESOLVER_SERVICE_H + +#include "singleton.h" +#include "system_ability.h" + +#include "ipc/dns_resolver_service_stub.h" + +namespace OHOS { +namespace NetManagerStandard { +class DnsResolverService : public SystemAbility, + public DnsResolverServiceStub, + public std::enable_shared_from_this { + DECLARE_DELAYED_SINGLETON(DnsResolverService) + DECLARE_SYSTEM_ABILITY(DnsResolverService) + + enum ServiceRunningState { + STATE_STOPPED = 0, + STATE_RUNNING, + }; + +public: + void OnStart() override; + void OnStop() override; + + int32_t GetAddressesByName(const std::string &hostName, std::vector &addrInfo) override; + int32_t GetAddrInfo(const std::string &hostName, const std::string &server, + const sptr &hints, std::vector> &dnsAddrInfo) override; + int32_t CreateNetworkCache(uint16_t netId) override; + int32_t DestoryNetworkCache(uint16_t netId) override; + int32_t FlushNetworkCache(uint16_t netId) override; + int32_t SetResolverConfig(uint16_t netId, uint16_t baseTimeoutMsec, uint8_t retryCount, + const std::vector &servers, const std::vector &domains) override; + int32_t GetResolverInfo(uint16_t netId, std::vector &servers, + std::vector &domains, uint16_t &baseTimeoutMsec, uint8_t &retryCount) override; + +private: + bool Init(); + +private: + ServiceRunningState state_ = ServiceRunningState::STATE_STOPPED; + bool registerToService_ = false; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // DNS_RESOLVER_SERVICE_H \ No newline at end of file diff --git a/services/dnsresolvermanager/include/ipc/dns_resolver_service_proxy.h b/services/dnsresolvermanager/include/ipc/dns_resolver_service_proxy.h new file mode 100755 index 0000000..d0e8d1d --- /dev/null +++ b/services/dnsresolvermanager/include/ipc/dns_resolver_service_proxy.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 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 DNS_RESOLVER_SERVICE_PROXY_H +#define DNS_RESOLVER_SERVICE_PROXY_H + +#include + +#include "iremote_proxy.h" +#include "i_dns_resolver_service.h" + +namespace OHOS { +namespace NetManagerStandard { +class DnsResolverServiceProxy : public IRemoteProxy { +public: + explicit DnsResolverServiceProxy(const sptr &impl); + virtual ~DnsResolverServiceProxy(); + bool WriteInterfaceToken(MessageParcel &data); + int32_t GetAddressesByName(const std::string &hostName, std::vector &addrInfo) override; + int32_t GetAddrInfo(const std::string &hostName, const std::string &server, + const sptr &hints, std::vector> &dnsAddrInfo) override; + int32_t CreateNetworkCache(uint16_t netId) override; + int32_t DestoryNetworkCache(uint16_t netId) override; + int32_t FlushNetworkCache(uint16_t netId) override; + int32_t SetResolverConfig(uint16_t netId, uint16_t baseTimeoutMsec, uint8_t retryCount, + const std::vector &servers, const std::vector &domains) override; + int32_t GetResolverInfo(uint16_t netId, std::vector &servers, + std::vector &domains, uint16_t &baseTimeoutMsec, uint8_t &retryCount) override; + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // DNS_RESOLVER_SERVICE_PROXY_H \ No newline at end of file diff --git a/services/dnsresolvermanager/include/ipc/dns_resolver_service_stub.h b/services/dnsresolvermanager/include/ipc/dns_resolver_service_stub.h new file mode 100755 index 0000000..5ecf964 --- /dev/null +++ b/services/dnsresolvermanager/include/ipc/dns_resolver_service_stub.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 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 DNS_RESOLVER_SERVICE_STUB_H +#define DNS_RESOLVER_SERVICE_STUB_H + +#include +#include "iremote_stub.h" +#include "i_dns_resolver_service.h" + +namespace OHOS { +namespace NetManagerStandard { +class DnsResolverServiceStub : public IRemoteStub { + using DnsResolverServiceFunc = int32_t (DnsResolverServiceStub::*)(MessageParcel &, MessageParcel &); + +public: + DnsResolverServiceStub(); + ~DnsResolverServiceStub(); + int32_t OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + int32_t OnGetAddressesByName(MessageParcel &data, MessageParcel &reply); + int32_t OnGetAddrInfo(MessageParcel &data, MessageParcel &reply); + int32_t OnCreateNetworkCache(MessageParcel &data, MessageParcel &reply); + int32_t OnDestoryNetworkCache(MessageParcel &data, MessageParcel &reply); + int32_t OnFlushNetworkCache(MessageParcel &data, MessageParcel &reply); + int32_t OnSetResolverConfig(MessageParcel &data, MessageParcel &reply); + int32_t OnGetResolverInfo(MessageParcel &data, MessageParcel &reply); + std::map memberFuncMap_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // DNS_RESOLVER_SERVICE_STUB_H + diff --git a/services/dnsresolvermanager/include/ipc/i_dns_resolver_service.h b/services/dnsresolvermanager/include/ipc/i_dns_resolver_service.h new file mode 100755 index 0000000..2927f6c --- /dev/null +++ b/services/dnsresolvermanager/include/ipc/i_dns_resolver_service.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 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 I_DNS_RESOLVER_SERVICE_H +#define I_DNS_RESOLVER_SERVICE_H + +#include +#include + +#include "iremote_broker.h" +#include "iremote_object.h" +#include "inet_addr.h" + +#include "dns_addr_info.h" + +namespace OHOS { +namespace NetManagerStandard { +class IDnsResolverService : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.NetManagerStandard.IDnsResolverService"); + enum { + CMD_GET_ADDR_BY_NAME, + CMD_GET_ADDR_INFO, + CMD_CRT_NETWORK_CACHE, + CMD_DEL_NETWORK_CACHE, + CMD_FLS_NETWORK_CACHE, + CMD_SET_RESOLVER_CONFIG, + CMD_GET_RESOLVER_INFO, + }; + +public: + virtual int32_t GetAddressesByName(const std::string &hostName, std::vector &addrInfo) = 0; + virtual int32_t GetAddrInfo(const std::string &hostName, const std::string &server, + const sptr &hints, std::vector> &dnsAddrInfo) = 0; + virtual int32_t CreateNetworkCache(uint16_t netId) = 0; + virtual int32_t DestoryNetworkCache(uint16_t netId) = 0; + virtual int32_t FlushNetworkCache(uint16_t netId) = 0; + virtual int32_t SetResolverConfig(uint16_t netId, uint16_t baseTimeoutMsec, uint8_t retryCount, + const std::vector &servers, const std::vector &domains) = 0; + virtual int32_t GetResolverInfo(uint16_t netId, std::vector &servers, + std::vector &domains, uint16_t &baseTimeoutMsec, uint8_t &retryCount) = 0; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // I_DNS_RESOLVER_SERVICE_H \ No newline at end of file diff --git a/services/dnsresolvermanager/src/dns_resolver_service.cpp b/services/dnsresolvermanager/src/dns_resolver_service.cpp new file mode 100755 index 0000000..9370bbc --- /dev/null +++ b/services/dnsresolvermanager/src/dns_resolver_service.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2021 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 "dns_resolver_service.h" + +#include +#include +#include + +#include "system_ability_definition.h" + +#include "dns_resolver_constants.h" +#include "net_mgr_log_wrapper.h" +#include "netd_controller.h" + +namespace OHOS { +namespace NetManagerStandard { +const bool REGISTER_LOCAL_RESULT_DNS = SystemAbility::MakeAndRegisterAbility( + DelayedSingleton::GetInstance().get()); +constexpr int32_t IPV4_SIZE = 16; +constexpr int32_t IPV6_SIZE = 48; + +DnsResolverService::DnsResolverService() + : SystemAbility(COMM_DNS_MANAGER_SYS_ABILITY_ID, true) +{} + +DnsResolverService::~DnsResolverService() {} + +void DnsResolverService::OnStart() +{ + NETMGR_LOGI("DnsResolverService::OnStart"); + if (state_ == STATE_RUNNING) { + NETMGR_LOGI("DnsResolverService the state is already running"); + return; + } + if (!Init()) { + NETMGR_LOGE("DnsResolverService init failed"); + return; + } + state_ = STATE_RUNNING; +} + +void DnsResolverService::OnStop() +{ + state_ = STATE_STOPPED; + registerToService_ = false; +} + +bool DnsResolverService::Init() +{ + if (!REGISTER_LOCAL_RESULT_DNS) { + NETMGR_LOGE("DnsResolverService Register to local sa manager failed"); + return false; + } + if (!registerToService_) { + if (!Publish(DelayedSingleton::GetInstance().get())) { + NETMGR_LOGE("DnsResolverService Register to sa manager failed"); + return false; + } + registerToService_ = true; + } + NETMGR_LOGI("GetDnsServer suc"); + return true; +} + +static void FreeAddrInfo2(struct addrinfo *aiHead) +{ + struct addrinfo *ai = nullptr, *aiNext = nullptr; + for (ai = aiHead; ai != nullptr; ai = aiNext) { + if (ai->ai_addr != nullptr) { + free(ai->ai_addr); + ai->ai_addr = nullptr; + } + if (ai->ai_canonname != nullptr) { + free(ai->ai_canonname); + ai->ai_canonname = nullptr; + } + aiNext = ai->ai_next ; + free(ai); + if (aiNext == nullptr) { + return; + } + } +} + +static bool IsDomainValid(const std::string &hostName) +{ + if (hostName.empty()) { + return false; + } + static std::regex domainPattern("([0-9A-Za-z\\-_\\.]+)\\.([0-9a-z]+\\.[a-z]{2,3}(\\.[a-z]{2})?)"); + if (regex_match(hostName, domainPattern)) { + return true; + } + return false; +} + +static void ProcessIPV4(const struct addrinfo &addr, std::vector &addrInfo) +{ + char ip4Buf[IPV4_SIZE]; + bzero(ip4Buf, IPV4_SIZE); + struct sockaddr_in *sockAddr4 = reinterpret_cast(addr.ai_addr); + inet_ntop(AF_INET, &sockAddr4->sin_addr, ip4Buf, IPV4_SIZE); + INetAddr iNetAddr; + iNetAddr.family_ = addr.ai_family; + iNetAddr.address_ = std::string(ip4Buf); + addrInfo.push_back(iNetAddr); +} + +static void ProcessIPV6(const struct addrinfo &addr, std::vector &addrInfo) +{ + char ip6Buf[IPV6_SIZE]; + bzero(ip6Buf, IPV6_SIZE); + struct sockaddr_in6 *sockAddr6 = reinterpret_cast(addr.ai_addr); + inet_ntop(AF_INET6, &sockAddr6->sin6_addr, ip6Buf, IPV6_SIZE); + INetAddr iNetAddr; + iNetAddr.family_ = addr.ai_family; + iNetAddr.address_ = std::string(ip6Buf); + addrInfo.push_back(iNetAddr); +} + +inline void InitAddrInfo(struct addrinfo &hints, int32_t family, int32_t flags, int32_t protocol, int32_t sockType) +{ + bzero(&hints, sizeof(struct addrinfo)); + hints.ai_family = family; + hints.ai_flags = flags; + hints.ai_protocol = protocol; + hints.ai_socktype = sockType; +} + +int32_t DnsResolverService::GetAddressesByName(const std::string &hostName, std::vector &addrInfo) +{ + if (!IsDomainValid(hostName)) { + NETMGR_LOGE("Invalid domain name format"); + return DNS_ERROR; + } + struct addrinfo hints; + InitAddrInfo(hints, AF_INET, AI_PASSIVE, 0, SOCK_DGRAM); + std::unique_ptr res; + std::string server; + uint16_t netId = 0; + int32_t ret = NetdController::GetInstance()->GetAddrInfo(hostName, server, hints, res, netId); + if (ret != 0) { + NETMGR_LOGE("GetAddressesByName Call GetAddrInfo of NetdController ret[%{public}d]", ret); + return ret; + } + struct addrinfo *cur = nullptr; + struct addrinfo *resAddr = res.release(); + if (resAddr == nullptr) { + NETMGR_LOGE("GetAddrInfo of NetdController return resAddr error"); + return DNS_ERROR; + } + for (cur = resAddr; cur != nullptr; cur = cur->ai_next) { + if (cur->ai_family == AF_INET) { + ProcessIPV4(*cur, addrInfo); + } else if (cur->ai_family == AF_INET6) { + ProcessIPV6(*cur, addrInfo); + } + } + if (resAddr != nullptr) { + FreeAddrInfo2(resAddr); + } + NETMGR_LOGE("GetAddressesByName addrInfo size [%{public}d]", addrInfo.size()); + return DNS_SUCCESS; +} + +int32_t DnsResolverService::GetAddrInfo(const std::string &hostName, const std::string &server, + const sptr &hints, std::vector> &dnsAddrInfo) +{ + if (!IsDomainValid(hostName)) { + return DNS_ERROR; + } + struct addrinfo hints2; + InitAddrInfo(hints2, hints->family_, hints->flags_, hints->protocol_, hints->sockType_); + std::unique_ptr res; + uint16_t netId = 0; + int32_t ret = NetdController::GetInstance()->GetAddrInfo(hostName, server, hints2, res, netId); + if (ret < 0) { + return ret; + } + struct addrinfo *cur = nullptr; + struct addrinfo *resAddr = res.release(); + if (resAddr == nullptr) { + return DNS_ERROR; + } + char ipbuf[IPV4_SIZE]; + for (cur = resAddr; cur != nullptr; cur = cur->ai_next) { + sptr d = (std::make_unique()).release(); + if (d == nullptr) { + continue; + } + d->flags_ = cur->ai_flags; + d->family_ = cur->ai_family; + d->sockType_ = cur->ai_socktype; + d->protocol_ = cur->ai_protocol; + if (d->family_ == AF_INET) { + bzero(ipbuf, IPV4_SIZE); + auto addr = reinterpret_cast(cur->ai_addr); + inet_ntop(AF_INET, &addr->sin_addr, ipbuf, IPV4_SIZE); + d->addr_ = std::string(ipbuf); + } + dnsAddrInfo.push_back(d); + } + return DNS_SUCCESS; +} + +int32_t DnsResolverService::CreateNetworkCache(uint16_t netId) +{ + NETMGR_LOGI("DnsResolverService CreateNetworkCache netId[%{public}d]", netId); + return static_cast(NetdController::GetInstance()->CreateNetworkCache(netId)); +} + +int32_t DnsResolverService::DestoryNetworkCache(uint16_t netId) +{ + NETMGR_LOGI("DnsResolverService DestoryNetworkCache netId[%{public}d]", netId); + return static_cast(NetdController::GetInstance()->DestoryNetworkCache(netId)); +} + +int32_t DnsResolverService::FlushNetworkCache(uint16_t netId) +{ + NETMGR_LOGI("DnsResolverService FlushNetworkCache netId[%{public}d]", netId); + return static_cast(NetdController::GetInstance()->FlushNetworkCache(netId)); +} + +int32_t DnsResolverService::SetResolverConfig(uint16_t netId, uint16_t baseTimeoutMsec, uint8_t retryCount, + const std::vector &servers, const std::vector &domains) +{ + NETMGR_LOGI("DnsResolverService SetResolverConfig netId[%{public}d]", netId); + return static_cast(NetdController::GetInstance()->SetResolverConfig(netId, baseTimeoutMsec, + retryCount, servers, domains)); +} + +int32_t DnsResolverService::GetResolverInfo(uint16_t netId, std::vector &servers, + std::vector &domains, uint16_t &baseTimeoutMsec, uint8_t &retryCount) +{ + NETMGR_LOGI("DnsResolverService GetResolverInfo netId[%{public}d]", netId); + return static_cast(NetdController::GetInstance()->GetResolverInfo(netId, servers, domains, + baseTimeoutMsec, retryCount)); +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/dnsresolvermanager/src/ipc/dns_resolver_service_proxy.cpp b/services/dnsresolvermanager/src/ipc/dns_resolver_service_proxy.cpp new file mode 100755 index 0000000..4b77afe --- /dev/null +++ b/services/dnsresolvermanager/src/ipc/dns_resolver_service_proxy.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2021 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 "dns_resolver_service_proxy.h" +#include "ipc_types.h" +#include "net_mgr_log_wrapper.h" +#include "dns_resolver_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +DnsResolverServiceProxy::DnsResolverServiceProxy(const sptr &impl) + :IRemoteProxy(impl) +{ +} + +DnsResolverServiceProxy::~DnsResolverServiceProxy() {} + +bool DnsResolverServiceProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(DnsResolverServiceProxy::GetDescriptor())) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return false; + } + return true; +} + +int32_t DnsResolverServiceProxy::GetAddressesByName(const std::string &hostName, std::vector &addrInfo) +{ + MessageParcel data; + if (hostName.empty()) { + return NETMANAGER_ERR_STRING_EMPTY; + } + if (!WriteInterfaceToken(data)) { + return NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL; + } + if (!data.WriteString(hostName)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(CMD_GET_ADDR_BY_NAME, data, reply, option); + if (ret != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", ret); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + int32_t vsize = 0; + if (!reply.ReadInt32(vsize)) { + return NETMANAGER_ERR_READ_REPLY_FAIL; + } + for (int32_t i = 0; i < vsize; ++i) { + sptr addr = INetAddr::Unmarshalling(reply); + addrInfo.push_back(*addr); + } + return reply.ReadInt32(); +} + +int32_t DnsResolverServiceProxy::GetAddrInfo(const std::string &hostName, const std::string &server, + const sptr &hints, std::vector> &dnsAddrInfo) +{ + MessageParcel data; + if (hostName.empty()) { + return NETMANAGER_ERR_STRING_EMPTY; + } + if (!WriteInterfaceToken(data)) { + return NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL; + } + if (!data.WriteString(hostName)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + if (!data.WriteString(server)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + if (!hints->Marshalling(data)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(CMD_GET_ADDR_INFO, data, reply, option); + if (ret != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", ret); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + int32_t vsize; + if (!reply.ReadInt32(vsize)) { + return NETMANAGER_ERR_READ_REPLY_FAIL; + } + for (int32_t i = 0; i < vsize; ++i) { + auto d = DnsAddrInfo::Unmarshalling(reply); + if (d != nullptr) { + dnsAddrInfo.push_back(d); + } else { + return NETMANAGER_ERR_LOCAL_PTR_NULL; + } + } + return reply.ReadInt32(); +} + +int32_t DnsResolverServiceProxy::CreateNetworkCache(uint16_t netId) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + return NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL; + } + if (!data.WriteUint16(netId)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(CMD_CRT_NETWORK_CACHE, data, reply, option); + if (ret != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", ret); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + return reply.ReadInt32(); +} + +int32_t DnsResolverServiceProxy::DestoryNetworkCache(uint16_t netId) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + return NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL; + } + if (!data.WriteUint16(netId)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(CMD_DEL_NETWORK_CACHE, data, reply, option); + if (ret != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", ret); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + return reply.ReadInt32(); +} + +int32_t DnsResolverServiceProxy::FlushNetworkCache(uint16_t netId) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + return NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL; + } + if (!data.WriteUint16(netId)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(CMD_FLS_NETWORK_CACHE, data, reply, option); + if (ret != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", ret); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + return reply.ReadInt32(); +} + +int32_t DnsResolverServiceProxy::SetResolverConfig(uint16_t netId, uint16_t baseTimeoutMsec, uint8_t retryCount, + const std::vector &servers, const std::vector &domains) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + return NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL; + } + if (!data.WriteUint16(netId)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + if (!data.WriteUint16(baseTimeoutMsec)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + if (!data.WriteUint8(retryCount)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + int32_t vsize = servers.size(); + if (!data.WriteInt32(vsize)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + for (auto it = servers.begin(); it != servers.end(); ++it) { + if (!data.WriteString(*it)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + } + vsize = domains.size(); + if (!data.WriteInt32(vsize)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + for (auto it = domains.begin(); it != domains.end(); ++it) { + if (!data.WriteString(*it)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + } + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(CMD_SET_RESOLVER_CONFIG, data, reply, option); + if (ret != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", ret); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + return reply.ReadInt32(); +} + +int32_t DnsResolverServiceProxy::GetResolverInfo(uint16_t netId, std::vector &servers, + std::vector &domains, uint16_t &baseTimeoutMsec, uint8_t &retryCount) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + return NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL; + } + if (!data.WriteUint16(netId)) { + return NETMANAGER_ERR_WRITE_DATA_FAIL; + } + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(CMD_GET_RESOLVER_INFO, data, reply, option); + if (ret != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", ret); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + int32_t size = 0; + if (!reply.ReadInt32(size)) { + return NETMANAGER_ERR_READ_REPLY_FAIL; + } + std::string s; + for (int32_t i = 0; i < size; ++i) { + std::string().swap(s); + if (!reply.ReadString(s)) { + return NETMANAGER_ERR_READ_REPLY_FAIL; + } + servers.push_back(s); + } + if (!reply.ReadInt32(size)) { + return NETMANAGER_ERR_READ_REPLY_FAIL; + } + for (int32_t i = 0; i < size; ++i) { + std::string().swap(s); + if (!reply.ReadString(s)) { + return NETMANAGER_ERR_READ_REPLY_FAIL; + } + domains.push_back(s); + } + if (!reply.ReadUint16(baseTimeoutMsec)) { + return NETMANAGER_ERR_READ_REPLY_FAIL; + } + if (!reply.ReadUint8(retryCount)) { + return NETMANAGER_ERR_READ_REPLY_FAIL; + } + return reply.ReadInt32(); +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/dnsresolvermanager/src/ipc/dns_resolver_service_stub.cpp b/services/dnsresolvermanager/src/ipc/dns_resolver_service_stub.cpp new file mode 100755 index 0000000..50b68ba --- /dev/null +++ b/services/dnsresolvermanager/src/ipc/dns_resolver_service_stub.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2021 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 "dns_resolver_service_stub.h" + +#include "dns_resolver_constants.h" +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +DnsResolverServiceStub::DnsResolverServiceStub() +{ + memberFuncMap_[CMD_GET_ADDR_BY_NAME] = &DnsResolverServiceStub::OnGetAddressesByName; + memberFuncMap_[CMD_GET_ADDR_INFO] = &DnsResolverServiceStub::OnGetAddrInfo; + memberFuncMap_[CMD_CRT_NETWORK_CACHE] = &DnsResolverServiceStub::OnCreateNetworkCache; + memberFuncMap_[CMD_DEL_NETWORK_CACHE] = &DnsResolverServiceStub::OnDestoryNetworkCache; + memberFuncMap_[CMD_FLS_NETWORK_CACHE] = &DnsResolverServiceStub::OnFlushNetworkCache; + memberFuncMap_[CMD_SET_RESOLVER_CONFIG] = &DnsResolverServiceStub::OnSetResolverConfig; + memberFuncMap_[CMD_GET_RESOLVER_INFO] = &DnsResolverServiceStub::OnGetResolverInfo; +} + +DnsResolverServiceStub::~DnsResolverServiceStub() {} + +int32_t DnsResolverServiceStub::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + NETMGR_LOGI("stub call start, code = [%{public}d]", code); + + std::u16string myDescripter = DnsResolverServiceStub::GetDescriptor(); + std::u16string remoteDescripter = data.ReadInterfaceToken(); + if (myDescripter != remoteDescripter) { + NETMGR_LOGE("descriptor checked fail"); + return NETMANAGER_ERR_DESCRIPTOR_MISMATCH; + } + auto itFunc = memberFuncMap_.find(code); + if (itFunc != memberFuncMap_.end()) { + auto requestFunc = itFunc->second; + if (requestFunc != nullptr) { + return (this->*requestFunc)(data, reply); + } + } + + NETMGR_LOGI("stub default case, need check"); + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} + +int32_t DnsResolverServiceStub::OnGetAddressesByName(MessageParcel &data, MessageParcel &reply) +{ + std::string hostName; + if (!data.ReadString(hostName)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + std::vector addrInfo; + int32_t ret = GetAddressesByName(hostName, addrInfo); + if (!reply.WriteInt32(addrInfo.size())) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + for (auto s : addrInfo) { + if (!s.Marshalling(reply)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + } + if (!reply.WriteInt32(ret)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + return NETMANAGER_SUCCESS; +} + +int32_t DnsResolverServiceStub::OnGetAddrInfo(MessageParcel &data, MessageParcel &reply) +{ + std::string hostname; + std::string server; + if (!data.ReadString(hostname)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + if (!data.ReadString(server)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + sptr hints = DnsAddrInfo::Unmarshalling(data); + std::vector> dnsAddrInfo; + int32_t ret = GetAddrInfo(hostname, server, hints, dnsAddrInfo); + + int32_t vsize = dnsAddrInfo.size(); + if (!reply.WriteInt32(vsize)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + for (std::vector>::iterator it = dnsAddrInfo.begin(); it != dnsAddrInfo.end(); ++it) { + (*it)->Marshalling(reply); + } + if (!reply.WriteInt32(ret)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + return NETMANAGER_SUCCESS; +} + +int32_t DnsResolverServiceStub::OnCreateNetworkCache(MessageParcel &data, MessageParcel &reply) +{ + uint16_t netId = 0; + if (!data.ReadUint16(netId)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + int32_t ret = CreateNetworkCache(netId); + if (!reply.WriteInt32(ret)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + return NETMANAGER_SUCCESS; +} + +int32_t DnsResolverServiceStub::OnDestoryNetworkCache(MessageParcel &data, MessageParcel &reply) +{ + uint16_t netId = 0; + if (!data.ReadUint16(netId)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + int32_t ret = DestoryNetworkCache(netId); + if (!reply.WriteInt32(ret)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + return NETMANAGER_SUCCESS; +} + +int32_t DnsResolverServiceStub::OnFlushNetworkCache(MessageParcel &data, MessageParcel &reply) +{ + uint16_t netId = 0; + if (!data.ReadUint16(netId)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + int32_t ret = FlushNetworkCache(netId); + if (!reply.WriteInt32(ret)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + return NETMANAGER_SUCCESS; +} + +int32_t DnsResolverServiceStub::OnSetResolverConfig(MessageParcel &data, MessageParcel &reply) +{ + uint16_t netId = 0; + uint16_t baseTimeoutMsec = 0; + uint8_t retryCount = 0; + std::vector servers; + std::vector domains; + + if (!data.ReadUint16(netId)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + if (!data.ReadUint16(baseTimeoutMsec)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + if (!data.ReadUint8(retryCount)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + int32_t size; + if (!data.ReadInt32(size)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + + std::string s; + for (int32_t i = 0; i < size; ++i) { + std::string().swap(s); + if (!data.ReadString(s)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + servers.push_back(s); + } + + if (!data.ReadInt32(size)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + + for (int32_t i = 0; i < size; ++i) { + std::string().swap(s); + if (!data.ReadString(s)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + domains.push_back(s); + } + int32_t ret = SetResolverConfig(netId, baseTimeoutMsec, retryCount, servers, domains); + if (!reply.WriteInt32(ret)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + return NETMANAGER_SUCCESS; +} + +int32_t DnsResolverServiceStub::OnGetResolverInfo(MessageParcel &data, MessageParcel &reply) +{ + uint16_t netId = 0; + std::vector servers; + std::vector domains; + uint16_t baseTimeoutMsec = 0; + uint8_t retryCount = 0; + if (!data.ReadUint16(netId)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + int32_t ret = GetResolverInfo(netId, servers, domains, baseTimeoutMsec, retryCount); + + int32_t vsize = servers.size(); + if (!reply.WriteInt32(vsize)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + for (std::vector::iterator it = servers.begin(); it != servers.end(); ++it) { + if (!reply.WriteString(*it)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + } + + vsize = domains.size(); + if (!reply.WriteInt32(vsize)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + for (std::vector::iterator it = domains.begin(); it != domains.end(); ++it) { + if (!reply.WriteString(*it)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + } + + if (!reply.WriteUint16(baseTimeoutMsec)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + + if (!reply.WriteUint8(retryCount)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + + if (!reply.WriteInt32(ret)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + return NETMANAGER_SUCCESS; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/dnsresolvermanager/test/BUILD.gn b/services/dnsresolvermanager/test/BUILD.gn new file mode 100755 index 0000000..d55667c --- /dev/null +++ b/services/dnsresolvermanager/test/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright (c) 2021 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/test.gni") + +group("unittest") { + testonly = true + deps = [] + deps += [ "unittest/dns_resolver_manager_test:unittest" ] +} diff --git a/services/dnsresolvermanager/test/unittest/dns_resolver_manager_test/BUILD.gn b/services/dnsresolvermanager/test/unittest/dns_resolver_manager_test/BUILD.gn new file mode 100755 index 0000000..061f810 --- /dev/null +++ b/services/dnsresolvermanager/test/unittest/dns_resolver_manager_test/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright (c) 2021 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/test.gni") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +ohos_unittest("dns_resolver_manager_test") { + module_out_path = "netmanager_base/dns_resolver_manager_test" + + sources = [ + "$NETMANAGER_PREBUILTS_DIR/src/ipc/dns_resolver_service_proxy.cpp", + "dns_resolver_manager_test.cpp", + ] + + include_dirs = [ + "$INNERKITS_ROOT/native/dnsresolvermanager/include", + "$INNERKITS_ROOT/native/dnsresolvermanager/include/ipc", + "$NETMANAGER_PREBUILTS_DIR/include/ipc", + "$NETMANAGER_PREBUILTS_DIR/include", + ] + + deps = [ + "$INNERKITS_ROOT/native/dnsresolvermanager:dns_resolver_manager_if", + "$NETMANAGER_BASE_ROOT/utils:net_manager_common", + "$NETMANAGER_PREBUILTS_DIR:dnsresolvermanager", + ] + + external_deps = [ "ipc:ipc_core" ] + + defines = [ + "NETMGR_LOG_TAG = \"DnsResolverManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (enable_netmgr_debug) { + defines += [ "NETMGR_DEBUG" ] + } + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netmanager_standard" + subsystem_name = "communication" +} + +group("unittest") { + testonly = true + deps = [ ":ethernet_manager_test" ] +} diff --git a/services/dnsresolvermanager/test/unittest/dns_resolver_manager_test/dns_resolver_manager_test.cpp b/services/dnsresolvermanager/test/unittest/dns_resolver_manager_test/dns_resolver_manager_test.cpp new file mode 100755 index 0000000..094962b --- /dev/null +++ b/services/dnsresolvermanager/test/unittest/dns_resolver_manager_test/dns_resolver_manager_test.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2021 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 "dns_resolver_client.h" +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +using namespace testing::ext; +class DnsResolverManagerTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void DnsResolverManagerTest::SetUpTestCase() {} + +void DnsResolverManagerTest::TearDownTestCase() {} + +void DnsResolverManagerTest::SetUp() {} + +void DnsResolverManagerTest::TearDown() {} + +/** + * @tc.name: DnsResolverManagerTest001 + * @tc.desc: Test DnsResolverManager SetIfaceConfig. + * @tc.type: FUNC + */ +HWTEST_F(DnsResolverManagerTest, DnsResolverManagerTest001, TestSize.Level1) +{ + std::string server = "domain1"; + std::vector addrInfo; + uint16_t netId = 0; + uint16_t baseTimeoutMsec = 0x00; + uint8_t retryCount = 0x01; + std::vector servers = {"8.8.8.8", "114.114.114.114"}; + std::vector domains = {"domian1", "domian2"}; + int32_t ret = DelayedSingleton::GetInstance()->CreateNetworkCache(netId); + ret = DelayedSingleton::GetInstance()->SetResolverConfig(netId, + baseTimeoutMsec, retryCount, servers, domains); + ret = DelayedSingleton::GetInstance()->GetAddressesByName(server, addrInfo); + std::cout << "GetAddressesByName ret:" << ret << std::endl; + std::cout << "GetAddressesByName size:%d" << dnsAddrInfos.size() << std::endl; + for (auto s : addrInfo) { + std::cout << "dnsResolverService GetAddrInfo ip:"; + std::cout << static_cast(s.family_) << std::endl; + std::cout << s.address_ << std::endl; + } +} + +/** + * @tc.name: DnsResolverManagerTest001 + * @tc.desc: Test DnsResolverManager SetIfaceConfig. + * @tc.type: FUNC + */ +HWTEST_F(DnsResolverManagerTest, DnsResolverManagerTest002, TestSize.Level1) +{ + std::string server = "www.163.com"; + std::vector> dnsAddrInfos; + sptr hints = std::make_unique().release(); + hints->family_ = AF_INET; + hints->flags_ = AI_PASSIVE; + hints->protocol_ = 0; + hints->sockType_ = SOCK_DGRAM; + + DelayedSingleton::GetInstance()->GetAddrInfo(server, "", hints, dnsAddrInfos); + std::cout << "dnsAddrInfos size:%d" << dnsAddrInfos.size() << std::endl; + for (std::vector>::iterator it = dnsAddrInfos.begin(); it != dnsAddrInfos.end(); it++) { + std::cout << "dnsResolverService GetAddrInfo ip:" << std::endl; + std::cout << "ip type:" << static_cast(s.family_) << std::endl; + std::cout << "ip address:" << s.address_ << std::endl; + } +} + +/** + * @tc.name: DnsResolverManagerTest002 + * @tc.desc: Test DnsResolverManager SetIfaceConfig. + * @tc.type: FUNC + */ +HWTEST_F(DnsResolverManagerTest, DnsResolverManagerTest003, TestSize.Level1) +{ + int32_t netId = 0; + int32_t result = DelayedSingleton::GetInstance()->CreateNetworkCache(netId); + ASSERT_TRUE(result == 0); +} + +/** + * @tc.name: DnsResolverManagerTest003 + * @tc.desc: Test DnsResolverManager SetIfaceConfig. + * @tc.type: FUNC + */ +HWTEST_F(DnsResolverManagerTest, DnsResolverManagerTest004, TestSize.Level1) +{ + int32_t netId = 0; + int32_t result = DelayedSingleton::GetInstance()->DestoryNetworkCache(netId); + ASSERT_TRUE(result == 0); +} + +/** + * @tc.name: DnsResolverManagerTest004 + * @tc.desc: Test DnsResolverManager SetIfaceConfig. + * @tc.type: FUNC + */ +HWTEST_F(DnsResolverManagerTest, DnsResolverManagerTest005, TestSize.Level1) +{ + int32_t netId = 0; + int32_t result = DelayedSingleton::GetInstance()->FlushNetworkCache(netId); + ASSERT_TRUE(result == 0); +} + +/** + * @tc.name: DnsResolverManagerTest005 + * @tc.desc: Test DnsResolverManager SetIfaceConfig. + * @tc.type: FUNC + */ +HWTEST_F(DnsResolverManagerTest, DnsResolverManagerTest006, TestSize.Level1) +{ + int32_t netId = 0; + uint16_t baseTimeoutMsec = 0x00; + uint8_t retryCount = 0x01; + std::vector servers = {"8.8.8.8", "114.114.114.114"}; + std::vector domains = {"domian1", "domian2"}; + int32_t result = DelayedSingleton::GetInstance()->SetResolverConfig(netId, + baseTimeoutMsec, retryCount, servers, domains); + ASSERT_TRUE(result == 0); +} + +/** + * @tc.name: DnsResolverManagerTest005 + * @tc.desc: Test DnsResolverManager SetIfaceConfig. + * @tc.type: FUNC + */ +HWTEST_F(DnsResolverManagerTest, DnsResolverManagerTest006, TestSize.Level1) +{ + int32_t netId = 0; + std::vector servers; + std::vector domains; + uint16_t baseTimeoutMsec; + uint8_t retryCount; + int32_t result = DelayedSingleton::GetInstance()->GetResolverInfo(netId, + servers, domains, baseTimeoutMsec, retryCount); + ASSERT_TRUE(result == 0); + for (std::string& s : servers) { + std::cout << "GetResolverInfo server" << s << std::endl; + } + for (std::string& s : domains) { + std::cout << "GetResolverInfo domains" << s << std::endl; + } + std::cout << "GetResolverInfo baseTimeoutMsec" << baseTimeoutMsec << std::endl; + std::cout << "GetResolverInfo retryCount" << static_cast(retryCount) << std::endl; + std::cout << "TestGetResolverInfo ret:" << ret << std::endl; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/etc/init/BUILD.gn b/services/etc/init/BUILD.gn new file mode 100755 index 0000000..a0e0374 --- /dev/null +++ b/services/etc/init/BUILD.gn @@ -0,0 +1,39 @@ +# Copyright (c) 2021 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") + +## Install netmanager_base.rc/netmanager_base.rc to /system/etc/init +ohos_prebuilt_etc("netmanager_base.rc") { + if (use_musl) { + source = "netmanager_base.cfg" + } else { + source = "netmanager_base.rc" + } + + relative_install_dir = "init" + part_name = "netmanager_standard" + subsystem_name = "communication" +} + +## Install netd.rc/netd.cfg to /system/etc/init +ohos_prebuilt_etc("netd.rc") { + if (use_musl) { + source = "netd.cfg" + } else { + source = "netd.rc" + } + + relative_install_dir = "init" + part_name = "netmanager_standard" + subsystem_name = "communication" +} \ No newline at end of file diff --git a/services/etc/init/netd.cfg b/services/etc/init/netd.cfg new file mode 100755 index 0000000..4827be8 --- /dev/null +++ b/services/etc/init/netd.cfg @@ -0,0 +1,10 @@ +{ + "jobs" : [{ + "name" : "boot", + "cmds" : [ + "exec /system/bin/sleep 4", + "start netd" + ] + } + ] +} diff --git a/services/etc/init/netd.rc b/services/etc/init/netd.rc new file mode 100755 index 0000000..bf55a8d --- /dev/null +++ b/services/etc/init/netd.rc @@ -0,0 +1,19 @@ +# Copyright (c) 2021 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. +on boot + start netd + +#service netd /system/bin/sa_main /system/profile/netmanager.xml +# user root +# group root +# seclabel u:r:telephony:s0 diff --git a/services/etc/init/netmanager_base.cfg b/services/etc/init/netmanager_base.cfg new file mode 100755 index 0000000..908ede7 --- /dev/null +++ b/services/etc/init/netmanager_base.cfg @@ -0,0 +1,17 @@ +{ + "jobs" : [{ + "name" : "boot", + "cmds" : [ + "exec /system/bin/sleep 4", + "start netmanager" + ] + } + ], + "services" : [{ + "name" : "netmanager", + "path" : ["/system/bin/sa_main", "/system/profile/netmanager.xml"], + "uid" : "system", + "gid" : ["system", "shell"] + } + ] +} diff --git a/services/etc/init/netmanager_base.rc b/services/etc/init/netmanager_base.rc new file mode 100755 index 0000000..3d3c2a7 --- /dev/null +++ b/services/etc/init/netmanager_base.rc @@ -0,0 +1,19 @@ +# Copyright (c) 2021 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. +on boot + start netmanager + +service netmanager /system/bin/sa_main /system/profile/netmanager.xml + user system + group system shell + seclabel u:r:telephony:s0 \ No newline at end of file diff --git a/services/ethernetmanager/BUILD.gn b/services/ethernetmanager/BUILD.gn new file mode 100755 index 0000000..d37b4b5 --- /dev/null +++ b/services/ethernetmanager/BUILD.gn @@ -0,0 +1,76 @@ +# Copyright (c) 2021 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") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +ohos_shared_library("ethernet_manager") { + sources = [ + "$ETHERNETMANAGER_SOURCE_DIR/src/dev_interface_state.cpp", + "$ETHERNETMANAGER_SOURCE_DIR/src/ethernet_management.cpp", + "$ETHERNETMANAGER_SOURCE_DIR/src/ethernet_service.cpp", + "$ETHERNETMANAGER_SOURCE_DIR/src/ipc/ethernet_service_stub.cpp", + "$ETHERNETMANAGER_SOURCE_DIR/src/netLink_rtnl.cpp", + ] + + include_dirs = [ + "$ETHERNETMANAGER_SOURCE_DIR/include", + "$ETHERNETMANAGER_SOURCE_DIR/include/ipc", + "$ETHERNETMANAGER_SOURCE_DIR/include/dhcp", + "$INNERKITS_ROOT/native/include", + "$INNERKITS_ROOT/native/netconnmanager/include", + "$INNERKITS_ROOT/native/dnsresolvermanager/include", + "$INNERKITS_ROOT/native/ethernetmanager/include", + "//foundation/communication/wifi/services/wifi_standard/wifi_framework/dhcp_manage/mgr_service/include", + "//foundation/communication/wifi/services/wifi_standard/wifi_framework/dhcp_manage/mgr_service/interfaces", + ] + + deps = [ + "$INNERKITS_ROOT/native/ethernetmanager:ethernet_manager_if", + "$INNERKITS_ROOT/native/netconnmanager:net_conn_manager_if", + "$NETMANAGER_BASE_ROOT/services/netconnmanager:net_conn_manager", + "$NETMANAGER_BASE_ROOT/utils:net_manager_common", + "$NETMANAGER_PREBUILTS_DIR/librarys/netd:libnet_manager_native", + "//foundation/communication/wifi/services/wifi_standard/wifi_framework/dhcp_manage/mgr_service:dhcp_manager_service", + "//utils/native/base:utils", + ] + + external_deps = [ + "aafwk_standard:want", + "appexecfwk_standard:libeventhandler", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_standard:samgr_proxy", + ] + + defines = [ + "NETMGR_LOG_TAG = \"EthernetManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + defines += [ "NATIVE_NETD_FEATURE" ] + + if (enable_netmgr_debug) { + defines += [ "NETMGR_DEBUG" ] + } + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/services/ethernetmanager/include/dev_interface_state.h b/services/ethernetmanager/include/dev_interface_state.h new file mode 100755 index 0000000..b735237 --- /dev/null +++ b/services/ethernetmanager/include/dev_interface_state.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021 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 DEV_INTERFACE_CFG_H +#define DEV_INTERFACE_CFG_H + +#include +#include + +#include "i_net_conn_service.h" +#include "dhcp_define.h" + +#include "interface_configuration.h" + +namespace OHOS { +namespace NetManagerStandard { +constexpr int32_t MINIMUM_SUPPLIER_ID = 1000; +class DevInterfaceState : public virtual RefBase { + typedef enum { + REGISTERED, + UNREGISTERED, + LINK_AVAILABLE, + LINK_UNAVAILABLE + } ConnLinkState; + +public: + DevInterfaceState(); + ~DevInterfaceState(); + void SetDevName(const std::string &devName); + void SetDevHWaddr(const std::vector &hwAddr); + void SetNetCapabilities(uint64_t netCapabilities); + void SetLinkUp(bool up); + void SetLowerUp(bool lowerUp); + void SetlinkInfo(sptr &linkInfo); + void SetIfcfg(sptr &ifcfg); + void SetDhcpReqState(bool dhcpReqState); + void UpdateLinkInfo(const std::string &iface, const OHOS::Wifi::DhcpResult &result); + std::string GetDevName() const; + std::vector GetHWaddr() const; + uint64_t GetNetCapabilities() const; + bool GetLinkUp() const; + bool GetLowerUp() const; + sptr GetLinkInfo() const; + sptr GetIfcfg() const; + IPSetMode GetIPSetMode() const; + bool GetDhcpReqState() const; + + int32_t RemoteRegisterNetSupplier(); + int32_t RemoteUnregisterNetSupplier(); + int32_t RemoteUpdateNetLinkInfo(); + int32_t RemoteUpdateNetSupplierInfo(); + +private: + void UpdateLinkInfo(); + void UpdateSupplierAvailable(); + void SetIpAddr(); + +private: + ConnLinkState connLinkState_ = UNREGISTERED; + int32_t netSupplier_ = 0; + std::string devName_; + std::vector devHWaddr_; + bool linkUp_ = false; + bool lowerUp_ = false; + bool dhcpReqState_ = false; + sptr linkInfo_ = nullptr; + sptr netSupplierInfo_ = nullptr; + sptr ifcfg_ = nullptr; + const NetworkType networkType_ = NET_TYPE_ETHERNET; + uint64_t netCapabilities_ = NET_CAPABILITIES_INTERNET; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // DEV_INTERFACE_CFG_H \ No newline at end of file diff --git a/services/ethernetmanager/include/ethernet_management.h b/services/ethernetmanager/include/ethernet_management.h new file mode 100755 index 0000000..50f9858 --- /dev/null +++ b/services/ethernetmanager/include/ethernet_management.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 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 ETHERNET_MANAGEMENT_H +#define ETHERNET_MANAGEMENT_H + +#include +#include + +#include "iservice_registry.h" +#include "i_dhcp_result_notify.h" +#include "dhcp_service.h" +#include "system_ability_definition.h" + +#include "dev_interface_state.h" +#include "nlk_event_handle.h" +#include "netLink_rtnl.h" + +namespace OHOS { +namespace NetManagerStandard { +constexpr int32_t DHCP_TIMEOUT = 60; +class EthernetManagement : public NlkEventHandle { +public: + class EthDhcpResultNotify : public OHOS::Wifi::IDhcpResultNotify { + public: + explicit EthDhcpResultNotify(EthernetManagement ðernetManagement); + ~EthDhcpResultNotify() override; + void OnSuccess(int status, const std::string &ifname, OHOS::Wifi::DhcpResult &result) override; + void OnFailed(int status, const std::string &ifname, const std::string &reason) override; + void OnSerExitNotify(const std::string& ifname) override; + + private: + EthernetManagement ðernetManagement_; + }; + +public: + EthernetManagement(); + ~EthernetManagement(); + void Init(); + void UpdateInterfaceState(const std::string &dev, bool up, bool lowerUp); + int32_t UpdateDevInterfaceState(const std::string &iface, sptr cfg); + int32_t UpdateDevInterfaceLinkInfo(const std::string &iface, const OHOS::Wifi::DhcpResult &result); + sptr GetDevInterfaceCfg(const std::string &iface); + int32_t IsActivate(const std::string &iface); + std::vector GetActivateInterfaces(); + void RegisterNlk(NetLinkRtnl &nlk); + void Handle(const struct NlkEventInfo &info) override; + +private: + sptr netConnService_ = nullptr; + std::map> devs_; + std::unique_ptr dhcpService_ = nullptr; + std::unique_ptr dhcpResultNotify_ = nullptr; + std::mutex mutex_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // ETHERNET_MANAGEMENT_H \ No newline at end of file diff --git a/services/ethernetmanager/include/ethernet_service.h b/services/ethernetmanager/include/ethernet_service.h new file mode 100755 index 0000000..9abcbb0 --- /dev/null +++ b/services/ethernetmanager/include/ethernet_service.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 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 ETHERNET_SERVICE_H +#define ETHERNET_SERVICE_H + +#include "singleton.h" +#include "system_ability.h" + +#include "ipc/ethernet_service_stub.h" +#include "ethernet_management.h" + +namespace OHOS { +namespace NetManagerStandard { +class EthernetService : public SystemAbility, public EthernetServiceStub, + public std::enable_shared_from_this { + DECLARE_DELAYED_SINGLETON(EthernetService) + DECLARE_SYSTEM_ABILITY(EthernetService) + + enum ServiceRunningState { + STATE_STOPPED = 0, + STATE_RUNNING, + }; + +public: + void OnStart() override; + void OnStop() override; + + int32_t SetIfaceConfig(const std::string &iface, sptr &ic) override; + sptr GetIfaceConfig(const std::string &iface) override; + int32_t IsActivate(const std::string &iface) override; + std::vector GetActivateInterfaces() override; + +private: + bool Init(); + +private: + ServiceRunningState state_ = ServiceRunningState::STATE_STOPPED; + bool registerToService_ = false; + std::unique_ptr ethManagement_; + NetLinkRtnl nlkRtnl_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // ETHERNET_SERVICE_H \ No newline at end of file diff --git a/services/ethernetmanager/include/ipc/ethernet_service_proxy.h b/services/ethernetmanager/include/ipc/ethernet_service_proxy.h new file mode 100755 index 0000000..8732b7a --- /dev/null +++ b/services/ethernetmanager/include/ipc/ethernet_service_proxy.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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 ETHERNET_SERVICE_PROXY_H +#define ETHERNET_SERVICE_PROXY_H + +#include + +#include "iremote_proxy.h" +#include "i_ethernet_service.h" + +namespace OHOS { +namespace NetManagerStandard { +class EthernetServiceProxy : public IRemoteProxy { +public: + explicit EthernetServiceProxy(const sptr &impl); + virtual ~EthernetServiceProxy(); + bool WriteInterfaceToken(MessageParcel &data); + + int32_t SetIfaceConfig(const std::string &iface, sptr &ic) override; + sptr GetIfaceConfig(const std::string &iface) override; + int32_t IsActivate(const std::string &iface) override; + std::vector GetActivateInterfaces() override; + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // ETHERNET_SERVICE_PROXY_H \ No newline at end of file diff --git a/services/ethernetmanager/include/ipc/ethernet_service_stub.h b/services/ethernetmanager/include/ipc/ethernet_service_stub.h new file mode 100755 index 0000000..343c362 --- /dev/null +++ b/services/ethernetmanager/include/ipc/ethernet_service_stub.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 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 ETHERNET_SERVICE_STUB_H +#define ETHERNET_SERVICE_STUB_H + +#include +#include "iremote_stub.h" +#include "i_ethernet_service.h" + +namespace OHOS { +namespace NetManagerStandard { +class EthernetServiceStub : public IRemoteStub { + using EthernetServiceFunc = int32_t (EthernetServiceStub::*)(MessageParcel &, MessageParcel &); + +public: + EthernetServiceStub(); + ~EthernetServiceStub(); + int32_t OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + int32_t OnSetIfaceConfig(MessageParcel &data, MessageParcel &reply); + int32_t OnGetIfaceConfig(MessageParcel &data, MessageParcel &reply); + int32_t OnIsActivate(MessageParcel &data, MessageParcel &reply); + int32_t OnGetActivateInterfaces(MessageParcel &data, MessageParcel &reply); + +private: + std::map memberFuncMap_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // ETHERNET_SERVICE_STUB_H + diff --git a/services/ethernetmanager/include/ipc/i_ethernet_service.h b/services/ethernetmanager/include/ipc/i_ethernet_service.h new file mode 100755 index 0000000..21120b0 --- /dev/null +++ b/services/ethernetmanager/include/ipc/i_ethernet_service.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 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 I_ETHERNET_SERVICE_H +#define I_ETHERNET_SERVICE_H + +#include +#include + +#include "iremote_broker.h" +#include "iremote_object.h" + +#include "interface_configuration.h" + +namespace OHOS { +namespace NetManagerStandard { +constexpr int32_t GET_CFG_SUC = 1; +class IEthernetService : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.NetManagerStandard.IEthernetService"); + enum { + CMD_SET_IF_CFG, + CMD_GET_IF_CFG, + CMD_IS_ACTIVATE, + CMD_GET_ACTIVATE_INTERFACE, + }; + +public: + virtual int32_t SetIfaceConfig(const std::string &iface, sptr &ic) = 0; + virtual sptr GetIfaceConfig(const std::string &iface) = 0; + virtual int32_t IsActivate(const std::string &iface) = 0; + virtual std::vector GetActivateInterfaces() = 0; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // I_ETHERNET_SERVICE_H \ No newline at end of file diff --git a/services/ethernetmanager/include/netLink_rtnl.h b/services/ethernetmanager/include/netLink_rtnl.h new file mode 100755 index 0000000..f7847ed --- /dev/null +++ b/services/ethernetmanager/include/netLink_rtnl.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 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 NETLINK_RTNL_H +#define NETLINK_RTNL_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nlk_event_handle.h" + +namespace OHOS { +namespace NetManagerStandard { +constexpr int32_t NLK_SOCK_BUF_LEN = 20480; +constexpr int32_t NLK_BUFF_LEN = 2048; +constexpr int32_t NLK_HWADDR_BUF_LEN = 16; +constexpr int32_t NLK_HWADDR_LEN = 6; +constexpr int32_t NLK_TV_SEC = 5; +constexpr int32_t NLK_TV_USEC = 0; +class NetLinkRtnl { +public: + NetLinkRtnl(); + ~NetLinkRtnl(); + void NetLinkListenerThead(); + void Init(); + void RegisterHandle(sptr h); + static int32_t SetIpAddr(const std::string &ifName, const std::string &ip); + static std::vector GetHWaddr(const std::string &devName); + static void GetLinkInfo(std::vector &infos); + +private: + static int32_t CreateNetLinkSocket(); + static int32_t NetLinkSendMsg(int32_t fd, struct nlmsghdr &nlh); + static void ProcessReadMsg(std::unique_ptr &pBuff, int32_t len, std::vector &infos); + static NlkEventInfo ProcessLinkMsg(const struct nlmsghdr &nh); + int NetLinkHandle(int32_t netLinkSocket, fd_set& rdSet, struct timeval& timeout); + void ProcessIfInfoMsg(const struct nlmsghdr &nh); + void ProcessLinkEventMsg(std::unique_ptr &pBuff, int32_t len); + +private: + std::list> nlkHandles_; + static int32_t seq_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NETLINK_RTNL_H \ No newline at end of file diff --git a/services/ethernetmanager/include/nlk_event_handle.h b/services/ethernetmanager/include/nlk_event_handle.h new file mode 100755 index 0000000..6818c21 --- /dev/null +++ b/services/ethernetmanager/include/nlk_event_handle.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 NLK_EVENT_HANDLE_H +#define NLK_EVENT_HANDLE_H + +#include + +#include "refbase.h" + +namespace OHOS { +namespace NetManagerStandard { +struct NlkEventInfo { + std::string iface_; + uint64_t ifiFlags_ = 0; +}; + +class NlkEventHandle : public virtual RefBase { +public: + virtual void Handle(const struct NlkEventInfo &info) = 0; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NLK_EVENT_HANDLE_H \ No newline at end of file diff --git a/services/ethernetmanager/src/dev_interface_state.cpp b/services/ethernetmanager/src/dev_interface_state.cpp new file mode 100755 index 0000000..8d74934 --- /dev/null +++ b/services/ethernetmanager/src/dev_interface_state.cpp @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2021 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 "dev_interface_state.h" + +#include "net_conn_client.h" +#include "net_mgr_log_wrapper.h" + +#include "netLink_rtnl.h" +#include "ethernet_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +DevInterfaceState::DevInterfaceState() +{ + netSupplierInfo_ = std::make_unique().release(); +} + +DevInterfaceState::~DevInterfaceState() {} + +void DevInterfaceState::SetDevName(const std::string &devName) +{ + devName_ = devName; +} + +void DevInterfaceState::SetDevHWaddr(const std::vector &hwAddr) +{ + devHWaddr_ = hwAddr; +} + +void DevInterfaceState::SetNetCapabilities(uint64_t netCapabilities) +{ + netCapabilities_ = netCapabilities; +} + +void DevInterfaceState::SetLinkUp(bool up) +{ + linkUp_ = up; +} + +void DevInterfaceState::SetLowerUp(bool lowerUp) +{ + lowerUp_ = lowerUp; +} + +void DevInterfaceState::SetlinkInfo(sptr &linkInfo) +{ + linkInfo_ = linkInfo; +} + +void DevInterfaceState::SetIfcfg(sptr &ifcfg) +{ + ifcfg_ = ifcfg; + if (ifcfg_->mode_ == STATIC) { + UpdateLinkInfo(); + SetIpAddr(); + if (connLinkState_ == LINK_AVAILABLE) { + RemoteUpdateNetLinkInfo(); + } + } +} + +void DevInterfaceState::SetDhcpReqState(bool dhcpReqState) +{ + dhcpReqState_ = dhcpReqState; +} + +std::string DevInterfaceState::GetDevName() const +{ + return devName_; +} + +std::vector DevInterfaceState::GetHWaddr() const +{ + return devHWaddr_; +} + +uint64_t DevInterfaceState::GetNetCapabilities() const +{ + return netCapabilities_; +} + +bool DevInterfaceState::GetLinkUp() const +{ + return linkUp_; +} + +bool DevInterfaceState::GetLowerUp() const +{ + return lowerUp_; +} + +sptr DevInterfaceState::GetLinkInfo() const +{ + return linkInfo_; +} + +sptr DevInterfaceState::GetIfcfg() const +{ + return ifcfg_; +} + +IPSetMode DevInterfaceState::GetIPSetMode() const +{ + if (ifcfg_ == nullptr) { + return IPSetMode::STATIC; + } + return ifcfg_->mode_; +} + +bool DevInterfaceState::GetDhcpReqState() const +{ + return dhcpReqState_; +} + +int32_t DevInterfaceState::RemoteRegisterNetSupplier() +{ + if (connLinkState_ == UNREGISTERED) { + netSupplier_ = DelayedSingleton::GetInstance()->RegisterNetSupplier(networkType_, + devName_, netCapabilities_); + if (netSupplier_ > MINIMUM_SUPPLIER_ID) { + connLinkState_ = REGISTERED; + } + NETMGR_LOGI("DevInterfaceCfg RemoteRegisterNetSupplier netSupplier_[%{public}d]", netSupplier_); + } + return netSupplier_; +} + +int32_t DevInterfaceState::RemoteUnregisterNetSupplier() +{ + if (connLinkState_ == UNREGISTERED) { + return NETMANAGER_ERROR; + } + int ret = DelayedSingleton::GetInstance()->UnregisterNetSupplier(netSupplier_); + if (!ret) { + connLinkState_ = UNREGISTERED; + netSupplier_ = 0; + } + return ret; +} + +int32_t DevInterfaceState::RemoteUpdateNetLinkInfo() +{ + if (connLinkState_ == LINK_UNAVAILABLE) { + NETMGR_LOGE("DevInterfaceCfg RemoteUpdateNetLinkInfo regState_:LINK_UNAVAILABLE"); + return NETMANAGER_ERROR; + } + if (linkInfo_ == nullptr) { + NETMGR_LOGE("DevInterfaceCfg RemoteUpdateNetLinkInfo linkInfo_ is nullptr"); + return NETMANAGER_ERROR; + } + return DelayedSingleton::GetInstance()->UpdateNetLinkInfo(netSupplier_, linkInfo_); +} + +int32_t DevInterfaceState::RemoteUpdateNetSupplierInfo() +{ + if (connLinkState_ == UNREGISTERED) { + NETMGR_LOGE("DevInterfaceCfg RemoteUpdateNetSupplierInfo regState_:UNREGISTERED"); + return NETMANAGER_ERROR; + } + if (netSupplierInfo_ == nullptr) { + NETMGR_LOGE("DevInterfaceCfg RemoteUpdateNetSupplierInfo netSupplierInfo_ is nullptr"); + return NETMANAGER_ERROR; + } + UpdateSupplierAvailable(); + return DelayedSingleton::GetInstance()->UpdateNetSupplierInfo(netSupplier_, netSupplierInfo_); +} + +void DevInterfaceState::UpdateLinkInfo() +{ + if (!ifcfg_ && ifcfg_->mode_ != STATIC) { + return; + } + if (linkInfo_ == nullptr) { + linkInfo_ = std::make_unique().release(); + } + std::list().swap(linkInfo_->netAddrList_); + std::list().swap(linkInfo_->routeList_); + std::list().swap(linkInfo_->dnsList_); + linkInfo_->netAddrList_.push_back(ifcfg_->ipStatic_.ipAddr_); + struct Route route; + route.iface_ = devName_; + route.destination_ = ifcfg_->ipStatic_.route_; + route.gateway_ = ifcfg_->ipStatic_.gate_; + linkInfo_->routeList_.push_back(route); + for (auto it = ifcfg_->ipStatic_.dnsServers_.begin(); it != ifcfg_->ipStatic_.dnsServers_.end(); ++it) { + linkInfo_->dnsList_.push_back(*it); + } +} + +void DevInterfaceState::UpdateLinkInfo(const std::string &iface, const OHOS::Wifi::DhcpResult &result) +{ + NETMGR_LOGI("DevInterfaceCfg::UpdateLinkInfo"); + if (linkInfo_ == nullptr) { + linkInfo_ = std::make_unique().release(); + } + std::list().swap(linkInfo_->netAddrList_); + std::list().swap(linkInfo_->routeList_); + INetAddr ipAddr; + ipAddr.type_ = result.iptype; + ipAddr.address_ = result.strYourCli; + linkInfo_->netAddrList_.push_back(ipAddr); + struct Route route; + INetAddr gate; + INetAddr destination; + route.iface_ = iface; + if (result.strServer != result.strRouter1) { + gate.address_ = result.strServer; + if (result.strRouter1 == "*") { + destination.address_ = "0.0.0.0"; + } else { + destination.address_ = result.strRouter1; + } + route.destination_ = destination; + route.gateway_ = gate; + linkInfo_->routeList_.push_back(route); + } + if (result.strServer != result.strRouter2) { + gate.address_ = result.strServer; + if (result.strRouter2 == "*") { + destination.address_ = "0.0.0.0"; + } else { + destination.address_ = result.strRouter2; + } + route.destination_ = destination; + route.gateway_ = gate; + linkInfo_->routeList_.push_back(route); + } + ipAddr.address_ = result.strDns1; + linkInfo_->dnsList_.push_back(ipAddr); + ipAddr.address_ = result.strDns2; + linkInfo_->dnsList_.push_back(ipAddr); +} + +void DevInterfaceState::SetIpAddr() +{ + NetLinkRtnl::SetIpAddr(devName_, ifcfg_->ipStatic_.ipAddr_.address_); +} + +void DevInterfaceState::UpdateSupplierAvailable() +{ + bool isAvailable = linkUp_ & lowerUp_; + netSupplierInfo_->isAvailable_ = isAvailable; + if (isAvailable) { + connLinkState_ = LINK_AVAILABLE; + } else { + connLinkState_ = LINK_UNAVAILABLE; + } +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/ethernetmanager/src/ethernet_management.cpp b/services/ethernetmanager/src/ethernet_management.cpp new file mode 100755 index 0000000..c729a43 --- /dev/null +++ b/services/ethernetmanager/src/ethernet_management.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2021 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 "ethernet_management.h" + +#include "net_mgr_log_wrapper.h" +#include "ethernet_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +EthernetManagement::EthDhcpResultNotify::EthDhcpResultNotify(EthernetManagement ðernetManagement) + : ethernetManagement_(ethernetManagement) +{ +} + +EthernetManagement::EthDhcpResultNotify::~EthDhcpResultNotify() {} + +void EthernetManagement::EthDhcpResultNotify::OnSuccess(int status, const std::string &ifname, + OHOS::Wifi::DhcpResult &result) +{ + NETMGR_LOGI("Enter EthernetManagement::EthDhcpResultNotify::OnSuccess " + "ifname=[%{public}s], iptype=[%{public}d], strYourCli=[%{public}s], " + "strServer=[%{public}s], strSubnet=[%{public}s], strDns1=[%{public}s], " + "strDns2=[%{public}s] strRouter1=[%{public}s] strRouter2=[%{public}s]", + ifname.c_str(), result.iptype, result.strYourCli.c_str(), result.strServer.c_str(), result.strSubnet.c_str(), + result.strDns1.c_str(), result.strDns2.c_str(), result.strRouter1.c_str(), result.strRouter2.c_str()); + ethernetManagement_.UpdateDevInterfaceLinkInfo(ifname, result); + return; +} + +void EthernetManagement::EthDhcpResultNotify::OnFailed(int status, const std::string &ifname, const std::string &reason) +{ + NETMGR_LOGI("Enter EthernetManagement::EthDhcpResultNotify::OnFailed"); + return; +} + +void EthernetManagement::EthDhcpResultNotify::OnSerExitNotify(const std::string& ifname) +{ + NETMGR_LOGI("EthernetManagement::EthDhcpResultNotify::OnSerExitNotify"); + return; +} + +EthernetManagement::EthernetManagement() +{ + dhcpService_.reset(std::make_unique().release()); + dhcpResultNotify_.reset(std::make_unique(*this).release()); +} + +EthernetManagement::~EthernetManagement() {} + +void EthernetManagement::UpdateInterfaceState(const std::string &dev, bool up, bool lowerUp) +{ + NETMGR_LOGI("EthernetManagement UpdateInterfaceState dev[%{public}s] up[%{public}d] lowerUp[%{public}d]", + dev.c_str(), up, lowerUp); + std::unique_lock lock(mutex_); + auto fit = devs_.find(dev); + if (fit == devs_.end()) { + return; + } + sptr devState= fit->second; + devState->SetLinkUp(up); + devState->SetLowerUp(lowerUp); + IPSetMode mode = devState->GetIPSetMode(); + bool dhcpReqState = devState->GetDhcpReqState(); + NETMGR_LOGI("EthernetManagement UpdateInterfaceState mode[%{public}d] dhcpReqState[%{public}d]", + static_cast(mode), dhcpReqState); + if (lowerUp) { + devState->RemoteUpdateNetSupplierInfo(); + if (mode == DHCP && !dhcpReqState) { + NETMGR_LOGI("EthernetManagement StartDhcpClient[%{public}s]", dev.c_str()); + if (dhcpService_ == nullptr) { + NETMGR_LOGE("EthernetManagement::UpdateInterfaceState dhcpService_ is nullptr"); + return; + } + dhcpService_->StartDhcpClient(dev, false); + if (dhcpService_->GetDhcpResult(dev, dhcpResultNotify_.get(), DHCP_TIMEOUT) != 0) { + NETMGR_LOGE(" Dhcp connection failed.\n"); + } + devState->SetDhcpReqState(true); + } else { + devState->RemoteUpdateNetLinkInfo(); + } + } else { + if (mode == DHCP && dhcpReqState) { + NETMGR_LOGI("EthernetManagement StopDhcpClient[%{public}s]", dev.c_str()); + if (dhcpService_ == nullptr) { + NETMGR_LOGI("EthernetManagement::UpdateInterfaceState dhcpService_ is nullptr"); + return; + } + dhcpService_->StopDhcpClient(dev, false); + devState->SetDhcpReqState(false); + } + devState->RemoteUpdateNetSupplierInfo(); + } +} + +int32_t EthernetManagement::UpdateDevInterfaceState(const std::string &iface, sptr cfg) +{ + std::unique_lock lock(mutex_); + auto fit = devs_.find(iface); + if (fit == devs_.end() || fit->second == nullptr) { + NETMGR_LOGE("The iface[%{public}s] device or device information does not exist", iface.c_str()); + return ETHERNET_ERROR; + } + if (!fit->second->GetLinkUp()) { + return ETHERNET_ERROR; + } + fit->second->SetIfcfg(cfg); + return ETHERNET_SUCCESS; +} + +int32_t EthernetManagement::UpdateDevInterfaceLinkInfo(const std::string &iface, const OHOS::Wifi::DhcpResult &result) +{ + NETMGR_LOGI("EthernetManagement::UpdateDevInterfaceLinkInfo"); + std::unique_lock lock(mutex_); + auto fit = devs_.find(iface); + if (fit == devs_.end() || fit->second == nullptr) { + NETMGR_LOGE("The iface[%{public}s] device or device information does not exist", iface.c_str()); + return ETHERNET_ERROR; + } + if (!fit->second->GetLinkUp()) { + return ETHERNET_ERROR; + } + fit->second->UpdateLinkInfo(iface, result); + fit->second->RemoteUpdateNetLinkInfo(); + return ETHERNET_SUCCESS; +} + +sptr EthernetManagement::GetDevInterfaceCfg(const std::string &iface) +{ + std::unique_lock lock(mutex_); + auto fit = devs_.find(iface); + if (fit == devs_.end() || fit->second == nullptr) { + NETMGR_LOGE("The iface[%{public}s] device does not exist", iface.c_str()); + return nullptr; + } + return fit->second->GetIfcfg(); +} + +int32_t EthernetManagement::IsActivate(const std::string &iface) +{ + std::unique_lock lock(mutex_); + auto fit = devs_.find(iface); + if (fit == devs_.end() || fit->second == nullptr) { + NETMGR_LOGE("The iface[%{public}s] device does not exist", iface.c_str()); + return ETHERNET_ERROR; + } + return static_cast(fit->second->GetLinkUp()); +} + +std::vector EthernetManagement::GetActivateInterfaces() +{ + std::unique_lock lock(mutex_); + std::vector a; + for (auto it = devs_.begin(); it != devs_.end(); ++it) { + a.push_back(it->first); + } + return a; +} + +void EthernetManagement::RegisterNlk(NetLinkRtnl &nlk) +{ + nlk.RegisterHandle(this); +} + +void EthernetManagement::Handle(const struct NlkEventInfo &info) +{ + bool up = static_cast(info.ifiFlags_ & IFF_UP); + bool lowerUp = static_cast(info.ifiFlags_ & IFF_LOWER_UP); + NETMGR_LOGI("EthernetManagement Handle info dev[%{public}s] up[%{public}d] lowerUp[%{public}d]", + info.iface_.c_str(), up, lowerUp); + UpdateInterfaceState(info.iface_, up, lowerUp); +} + +void EthernetManagement::Init() +{ + std::vector linkInfos; + NetLinkRtnl::GetLinkInfo(linkInfos); + if (linkInfos.size() <= 0) { + NETMGR_LOGE("EthernetManagement link list is empty"); + return; + } + NETMGR_LOGI("EthernetManagement devs size[%{public}d]", linkInfos.size()); + for (auto it = linkInfos.begin(); it != linkInfos.end(); it++) { + std::string devName = it->iface_; + NETMGR_LOGI("EthernetManagement devName[%{public}s]", devName.c_str()); + if (devName.empty()) { + continue; + } + sptr devState = std::make_unique().release(); + devs_.insert(std::make_pair(devName, devState)); + sptr ifCfg = std::make_unique().release(); + ifCfg->mode_ = STATIC; + devState->SetIfcfg(ifCfg); + std::vector hwAddr = NetLinkRtnl::GetHWaddr(devName); + bool up = it->ifiFlags_ & IFF_UP; + bool lowerUp = it->ifiFlags_ & IFF_LOWER_UP; + devState->SetDevName(devName); + devState->SetDevHWaddr(hwAddr); + devState->SetLinkUp(up); + devState->SetLowerUp(lowerUp); + devState->RemoteRegisterNetSupplier(); + if (up && lowerUp) { + devState->RemoteUpdateNetSupplierInfo(); + } + } + NETMGR_LOGI("EthernetManagement devs_ size[%{public}d", devs_.size()); +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/ethernetmanager/src/ethernet_service.cpp b/services/ethernetmanager/src/ethernet_service.cpp new file mode 100755 index 0000000..21dae1e --- /dev/null +++ b/services/ethernetmanager/src/ethernet_service.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021 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 "ethernet_service.h" + +#include "net_mgr_log_wrapper.h" +#include "ethernet_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +const bool REGISTER_LOCAL_RESULT_ETH = SystemAbility::MakeAndRegisterAbility( + DelayedSingleton::GetInstance().get()); + +EthernetService::EthernetService() + : SystemAbility(COMM_ETHERNET_MANAGER_SYS_ABILITY_ID, true) +{ + ethManagement_ = std::make_unique(); +} + +EthernetService::~EthernetService() {} + +void EthernetService::OnStart() +{ + NETMGR_LOGI("EthernetService::OnStart"); + if (state_ == STATE_RUNNING) { + NETMGR_LOGI("EthernetService the state is already running"); + return; + } + if (!Init()) { + NETMGR_LOGE("EthernetService init failed"); + return; + } + nlkRtnl_.Init(); + if (ethManagement_ != nullptr) { + ethManagement_->Init(); + ethManagement_->RegisterNlk(nlkRtnl_); + } + state_ = STATE_RUNNING; +} + +void EthernetService::OnStop() +{ + state_ = STATE_STOPPED; + registerToService_ = false; +} + +bool EthernetService::Init() +{ + if (!REGISTER_LOCAL_RESULT_ETH) { + NETMGR_LOGE("EthernetService Register to local sa manager failed"); + return false; + } + if (!registerToService_) { + if (!Publish(DelayedSingleton::GetInstance().get())) { + NETMGR_LOGE("EthernetService Register to sa manager failed"); + return false; + } + registerToService_ = true; + } + NETMGR_LOGI("GetEthernetServer suc"); + return true; +} + +int32_t EthernetService::SetIfaceConfig(const std::string &iface, sptr &ic) +{ + NETMGR_LOGI("EthernetService SetIfaceConfig processing"); + if (ethManagement_ != nullptr) { + return ethManagement_->UpdateDevInterfaceState(iface, ic); + } else { + return ETHERNET_ERROR; + } +} + +sptr EthernetService::GetIfaceConfig(const std::string &iface) +{ + NETMGR_LOGI("EthernetService GetIfaceConfig processing"); + if (ethManagement_ != nullptr) { + return ethManagement_->GetDevInterfaceCfg(iface); + } else { + return nullptr; + } +} + +int32_t EthernetService::IsActivate(const std::string &iface) +{ + if (ethManagement_ != nullptr) { + return ethManagement_->IsActivate(iface); + } else { + return ETHERNET_ERROR; + } +} + +std::vector EthernetService::GetActivateInterfaces() +{ + if (ethManagement_ != nullptr) { + return ethManagement_->GetActivateInterfaces(); + } else { + return {}; + } +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/ethernetmanager/src/ipc/ethernet_service_proxy.cpp b/services/ethernetmanager/src/ipc/ethernet_service_proxy.cpp new file mode 100755 index 0000000..f42fc2f --- /dev/null +++ b/services/ethernetmanager/src/ipc/ethernet_service_proxy.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2021 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 "ethernet_service_proxy.h" +#include "ipc_types.h" +#include "net_mgr_log_wrapper.h" +#include "ethernet_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +EthernetServiceProxy::EthernetServiceProxy(const sptr &impl) + :IRemoteProxy(impl) +{ +} + +EthernetServiceProxy::~EthernetServiceProxy() {} + +bool EthernetServiceProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(EthernetServiceProxy::GetDescriptor())) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return false; + } + return true; +} + +int32_t EthernetServiceProxy::SetIfaceConfig(const std::string &iface, sptr &ic) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + return NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL; + } + if (!data.WriteString(iface)) { + return NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL; + } + if (!ic->Marshalling(data)) { + NETMGR_LOGE("proxy Marshalling failed"); + return NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL; + } + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(CMD_SET_IF_CFG, data, reply, option); + if (ret != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", ret); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + return reply.ReadInt32(); +} + +sptr EthernetServiceProxy::GetIfaceConfig(const std::string &iface) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + return nullptr; + } + if (!data.WriteString(iface)) { + return nullptr; + } + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return nullptr; + } + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(CMD_GET_IF_CFG, data, reply, option); + if (ret != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", ret); + return nullptr; + } + int32_t res = 0; + if (!reply.ReadInt32(res)) { + return nullptr; + } + if (res != GET_CFG_SUC) { + return nullptr; + } + return InterfaceConfiguration::Unmarshalling(reply); +} + +int32_t EthernetServiceProxy::IsActivate(const std::string &iface) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + return NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL; + } + if (!data.WriteString(iface)) { + return NETMANAGER_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL; + } + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(CMD_IS_ACTIVATE, data, reply, option); + if (ret != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", ret); + return NETMANAGER_ERR_IPC_CONNECT_STUB_FAIL; + } + + return reply.ReadInt32(); +} + +std::vector EthernetServiceProxy::GetActivateInterfaces() +{ + MessageParcel data; + std::vector ifaces; + if (!WriteInterfaceToken(data)) { + return ifaces; + } + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return ifaces; + } + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(CMD_GET_ACTIVATE_INTERFACE, data, reply, option); + if (ret != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", ret); + return ifaces; + } + + int32_t size = reply.ReadInt32(); + for (int i = 0; i < size; i++) { + ifaces.push_back(reply.ReadString()); + } + return ifaces; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/ethernetmanager/src/ipc/ethernet_service_stub.cpp b/services/ethernetmanager/src/ipc/ethernet_service_stub.cpp new file mode 100755 index 0000000..7568b5d --- /dev/null +++ b/services/ethernetmanager/src/ipc/ethernet_service_stub.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2021 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 "ethernet_service_stub.h" +#include "net_mgr_log_wrapper.h" +#include "ethernet_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +EthernetServiceStub::EthernetServiceStub() +{ + memberFuncMap_[CMD_SET_IF_CFG] = &EthernetServiceStub::OnSetIfaceConfig; + memberFuncMap_[CMD_GET_IF_CFG] = &EthernetServiceStub::OnGetIfaceConfig; + memberFuncMap_[CMD_IS_ACTIVATE] = &EthernetServiceStub::OnIsActivate; + memberFuncMap_[CMD_GET_ACTIVATE_INTERFACE] = &EthernetServiceStub::OnGetActivateInterfaces; +} + +EthernetServiceStub::~EthernetServiceStub() {} + +int32_t EthernetServiceStub::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + NETMGR_LOGI("stub call start, code = [%{public}d]", code); + + std::u16string myDescripter = EthernetServiceStub::GetDescriptor(); + std::u16string remoteDescripter = data.ReadInterfaceToken(); + if (myDescripter != remoteDescripter) { + NETMGR_LOGE("descriptor checked fail"); + return NETMANAGER_ERR_DESCRIPTOR_MISMATCH; + } + auto itFunc = memberFuncMap_.find(code); + if (itFunc != memberFuncMap_.end()) { + auto requestFunc = itFunc->second; + if (requestFunc != nullptr) { + return (this->*requestFunc)(data, reply); + } + } + + NETMGR_LOGI("stub default case, need check"); + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} + +int32_t EthernetServiceStub::OnSetIfaceConfig(MessageParcel &data, MessageParcel &reply) +{ + std::string iface; + if (!data.ReadString(iface)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + sptr ic = InterfaceConfiguration::Unmarshalling(data); + if (ic == nullptr) { + return NETMANAGER_ERR_LOCAL_PTR_NULL; + } + int32_t ret = SetIfaceConfig(iface, ic); + if (!reply.WriteInt32(ret)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + return NETMANAGER_SUCCESS; +} + +int32_t EthernetServiceStub::OnGetIfaceConfig(MessageParcel &data, MessageParcel &reply) +{ + std::string iface; + if (!data.ReadString(iface)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + sptr ic = GetIfaceConfig(iface); + if (ic != nullptr) { + if (!reply.WriteInt32(GET_CFG_SUC)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + if (!ic->Marshalling(reply)) { + NETMGR_LOGE("proxy Marshalling failed"); + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + } else { + if (!reply.WriteInt32(0)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + } + return NETMANAGER_SUCCESS; +} + +int32_t EthernetServiceStub::OnIsActivate(MessageParcel &data, MessageParcel &reply) +{ + std::string iface; + if (!data.ReadString(iface)) { + return NETMANAGER_ERR_READ_DATA_FAIL; + } + int32_t ret = IsActivate(iface); + if (!reply.WriteInt32(ret)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + return NETMANAGER_SUCCESS; +} + +int32_t EthernetServiceStub::OnGetActivateInterfaces(MessageParcel &data, MessageParcel &reply) +{ + std::vector ifaces = GetActivateInterfaces(); + if (!reply.WriteInt32(ifaces.size())) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + for (auto it = ifaces.begin(); it != ifaces.end(); ++it) { + if (!reply.WriteString(*it)) { + return NETMANAGER_ERR_WRITE_REPLY_FAIL; + } + } + return NETMANAGER_SUCCESS; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/ethernetmanager/src/netLink_rtnl.cpp b/services/ethernetmanager/src/netLink_rtnl.cpp new file mode 100755 index 0000000..8b60e2e --- /dev/null +++ b/services/ethernetmanager/src/netLink_rtnl.cpp @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2021 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 "netLink_rtnl.h" + +#include + +#include "securec.h" +#include "net_mgr_log_wrapper.h" +#include "ethernet_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +int32_t NetLinkRtnl::seq_ = 0; +NetLinkRtnl::NetLinkRtnl() +{ +} + +NetLinkRtnl::~NetLinkRtnl() {} + +void NetLinkRtnl::NetLinkListenerThead() +{ + int32_t netLinkSocket = 0; + netLinkSocket = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (netLinkSocket < 0) { + NETMGR_LOGE("NetLinkRtnl NetLinkListenerThead netLinkSocket create socket failed"); + return; + } + if (setsockopt(netLinkSocket, SOL_SOCKET, SO_RCVBUF, &NLK_SOCK_BUF_LEN, sizeof(NLK_SOCK_BUF_LEN)) != 0) { + NETMGR_LOGE("NetLinkRtnl NetLinkListenerThead setsockopt failed"); + return; + } + struct sockaddr_nl sa; + bzero(&sa, sizeof(sa)); + sa.nl_family = AF_NETLINK; + sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE; + if (bind(netLinkSocket, (struct sockaddr *) &sa, sizeof(sa)) != 0) { + NETMGR_LOGE("NetLinkRtnl NetLinkListenerThead bind failed"); + return; + } + fd_set rdSet; + struct timeval timeout; + timeout.tv_sec = NLK_TV_SEC; + timeout.tv_usec = NLK_TV_USEC; + NETMGR_LOGI("NetLinkRtnl NetLinkListenerThead init suc, create netLinkSocket[%{public}d]", netLinkSocket); + while (true) { + FD_ZERO(&rdSet); + FD_SET(netLinkSocket, &rdSet); + NetLinkHandle(netLinkSocket, rdSet, timeout); + } +} + +void NetLinkRtnl::Init() +{ + NETMGR_LOGI("NetLinkRtnl Init thread start"); + std::thread nlk(&NetLinkRtnl::NetLinkListenerThead, this); + nlk.detach(); + return; +} + +void NetLinkRtnl::RegisterHandle(sptr h) +{ + nlkHandles_.push_back(h); + NETMGR_LOGI("NetLinkRtnl RegisterHandle nlkHandles_ size[%{public}d]", nlkHandles_.size()); +} + +void NetLinkRtnl::ProcessIfInfoMsg(const struct nlmsghdr &nh) +{ + NETMGR_LOGI("NetLinkRtnl ProcessIfInfoMsg process"); + int32_t len = 0; + struct rtattr *tb[IFLA_MAX + 1]; + struct ifinfomsg *ifInfo = nullptr; + bzero(tb, sizeof(tb)); + ifInfo = reinterpret_cast(NLMSG_DATA(&nh)); + if (ifInfo->ifi_type != ARPHRD_ETHER) { + NETMGR_LOGE("NetLinkRtnl ProcessIfInfoMsg ifi_type is not ARPHRD_ETHER"); + return; + } + len = nh.nlmsg_len - NLMSG_SPACE(sizeof(*ifInfo)); + auto attr = IFLA_RTA(ifInfo); + for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) { + if (attr->rta_type <= IFLA_MAX) { + tb[attr->rta_type] = attr; + } + } + NlkEventInfo info; + if (tb[IFLA_IFNAME]) { + info.iface_ = std::string(reinterpret_cast(RTA_DATA(tb[IFLA_IFNAME]))); + } + info.ifiFlags_ = ifInfo->ifi_flags; + for (auto it = nlkHandles_.begin(); it != nlkHandles_.end(); ++it) { + (*it)->Handle(info); + } +} + +void NetLinkRtnl::ProcessLinkEventMsg(std::unique_ptr &pBuff, int32_t len) +{ + struct nlmsghdr *nh = nullptr; + if (!pBuff) { + return; + } + for (nh = reinterpret_cast(pBuff.release()); NLMSG_OK(nh, len); + nh = NLMSG_NEXT(nh, len)) { + if (!nh) { + break; + } + NETMGR_LOGI("NetLinkRtnl ProcessLinkEventMsg nh nlmsg_type[%{public}d]", nh->nlmsg_type); + switch (nh->nlmsg_type) { + case RTM_NEWLINK: + case RTM_DELLINK: + ProcessIfInfoMsg(*nh); + break; + default: + break; + } // switch + } // for +} + +int NetLinkRtnl::NetLinkHandle(int32_t netLinkSocket, fd_set& rdSet, struct timeval& timeout) +{ + int32_t selectFd = select(netLinkSocket + 1, &rdSet, nullptr, nullptr, &timeout); + if (selectFd < 0) { + NETMGR_LOGE("NetLinkRtnl NetLinkHandle select failed"); + return ETHERNET_ERROR; + } else if (selectFd > 0) { + if (FD_ISSET(netLinkSocket, &rdSet)) { + int8_t buff[NLK_BUFF_LEN]; + bzero(buff, sizeof(buff)); + int readRet = read(netLinkSocket, buff, sizeof(buff)); + std::unique_ptr pBuff(buff); + ProcessLinkEventMsg(pBuff, readRet); + } // if + } // else if + return ETHERNET_SUCCESS; +} + +int32_t NetLinkRtnl::SetIpAddr(const std::string &ifName, const std::string &ip) +{ + int32_t fd = 0; + struct ifreq ifr; + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (-1 == fd) { + return ETHERNET_ERROR; + } + strcpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), ifName.c_str()); + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + close(fd); + return ETHERNET_ERROR; + } + struct sockaddr_in *sin_net_ip = nullptr; + bzero(&ifr, sizeof(ifr)); + strncpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), ifName.c_str(), sizeof(ifr.ifr_name)-1); + sin_net_ip = reinterpret_cast(&ifr.ifr_addr); + sin_net_ip->sin_family = AF_INET; + inet_pton(AF_INET, ip.c_str(), &sin_net_ip->sin_addr); + if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) { + close(fd); + return ETHERNET_ERROR; + } + close(fd); + return ETHERNET_SUCCESS; +} + +std::vector NetLinkRtnl::GetHWaddr(const std::string &devName) +{ + int32_t sock = 0; + struct ifreq ifr; + uint8_t macaddr[NLK_HWADDR_BUF_LEN]; + bzero(macaddr, sizeof(macaddr)); + std::vector hwAddr; + sock=socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + NETMGR_LOGE("NetLinkRtnl GetHWaddr create socket error sock[%{public}d]", sock); + return hwAddr; + } + strcpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), devName.c_str()); + if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) { + NETMGR_LOGE("NetLinkRtnl GetHWaddr ioctl SIOCGIFHWADDR error"); + close(sock); + return hwAddr; + } + memcpy_s(macaddr, NLK_HWADDR_BUF_LEN, ifr.ifr_hwaddr.sa_data, NLK_HWADDR_LEN); + for (int32_t i = 0; i < NLK_HWADDR_LEN; i++) { + hwAddr.push_back(macaddr[i]); + } + close(sock); + return hwAddr; +} + +void NetLinkRtnl::GetLinkInfo(std::vector &infos) +{ + struct { + struct nlmsghdr nlh; + struct ifinfomsg ifm; + int8_t buf[NLK_BUFF_LEN]; + } req = { + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .nlh.nlmsg_type = RTM_GETLINK, + .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .nlh.nlmsg_seq = ++seq_, + .ifm.ifi_family = AF_UNSPEC, + }; + int32_t fd = CreateNetLinkSocket(); + if (fd < 0) { + NETMGR_LOGE("NetLinkRtnl GetLinkInfo CreateNetLinkSocket failed"); + return; + } + int32_t ret = NetLinkSendMsg(fd, req.nlh); + if (ret < 0) { + NETMGR_LOGE("NetLinkRtnl GetLinkInfo NetLinkSendMsg failed"); + return; + } + int8_t buff[NLK_SOCK_BUF_LEN]; + bzero(buff, sizeof(buff)); + ret = read(fd, buff, sizeof(buff)); + if (ret < 0) { + NETMGR_LOGE("read failed"); + } + std::unique_ptr pBuff(buff); + ProcessReadMsg(pBuff, ret, infos); +} + +void NetLinkRtnl::ProcessReadMsg(std::unique_ptr &pBuff, int32_t len, std::vector &infos) +{ + struct nlmsghdr *nh = nullptr; + if (pBuff == nullptr) { + return; + } + for (nh = reinterpret_cast(pBuff.release()); NLMSG_OK(nh, len); + nh = NLMSG_NEXT(nh, len)) { + if (!nh) { + break; + } + NETMGR_LOGI("NetLinkRtnl ProcessReadMsg nh nlmsg_type[%{public}d]", nh->nlmsg_type); + switch (nh->nlmsg_type) { + case RTM_NEWLINK: + case RTM_DELLINK: + infos.push_back(ProcessLinkMsg(*nh)); + break; + default: + break; + } // switch + } // for +} + +NlkEventInfo NetLinkRtnl::ProcessLinkMsg(const struct nlmsghdr &nh) +{ + NETMGR_LOGI("NetLinkRtnl ProcessIfInfoMsg process"); + int32_t len = 0; + struct rtattr *tb[IFLA_MAX + 1]; + struct ifinfomsg *ifInfo = nullptr; + bzero(tb, sizeof(tb)); + NlkEventInfo info; + ifInfo = reinterpret_cast(NLMSG_DATA(&nh)); + if (ifInfo->ifi_type != ARPHRD_ETHER) { + NETMGR_LOGE("NetLinkRtnl ProcessLinkMsg ifi_type is not ARPHRD_ETHER"); + return info; + } + len = nh.nlmsg_len - NLMSG_SPACE(sizeof(*ifInfo)); + auto attr = IFLA_RTA(ifInfo); + for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) { + if (attr->rta_type <= IFLA_MAX) { + tb[attr->rta_type] = attr; + } + } + if (tb[IFLA_IFNAME]) { + info.iface_ = std::string(reinterpret_cast(RTA_DATA(tb[IFLA_IFNAME]))); + } + info.ifiFlags_ = ifInfo->ifi_flags; + return info; +} + +int32_t NetLinkRtnl::CreateNetLinkSocket() +{ + socklen_t addr_len = 0; + struct sockaddr_nl snl; + int32_t fd = -1; + fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd < 0) { + NETMGR_LOGE("NetLinkRtnl CreateNetLinkSocket create socket error"); + return ETHERNET_ERROR; + } + int32_t ret = fcntl(fd, F_SETFL, O_NONBLOCK); + if (ret < 0) { + NETMGR_LOGE("NetLinkRtnl CreateNetLinkSocket fcntl error"); + close(fd); + return ETHERNET_ERROR; + } + bzero(&snl, sizeof(snl)); + snl.nl_family = AF_NETLINK; + snl.nl_groups = 0; + ret = bind(fd, reinterpret_cast(&snl), sizeof(snl)); + if (ret < 0) { + NETMGR_LOGE("NetLinkRtnl CreateNetLinkSocket bind error"); + close(fd); + return ETHERNET_ERROR; + } + addr_len = sizeof (snl); + ret = getsockname(fd, reinterpret_cast(&snl), &addr_len); + if (ret < 0 || addr_len != sizeof (snl)) { + NETMGR_LOGE("NetLinkRtnl CreateNetLinkSocket getsockname error"); + close(fd); + return ETHERNET_ERROR; + } + if (snl.nl_family != AF_NETLINK) { + NETMGR_LOGE("NetLinkRtnl CreateNetLinkSocket nl_family error"); + close(fd); + return ETHERNET_ERROR; + } + seq_ = time(NULL); + return fd; +} + +int32_t NetLinkRtnl::NetLinkSendMsg(int32_t fd, struct nlmsghdr &nlh) +{ + struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; + struct iovec iov = { + .iov_base = &nlh, + .iov_len = nlh.nlmsg_len + }; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + return sendmsg(fd, &msg, 0); +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/ethernetmanager/test/BUILD.gn b/services/ethernetmanager/test/BUILD.gn new file mode 100755 index 0000000..fb8d040 --- /dev/null +++ b/services/ethernetmanager/test/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright (c) 2021 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/test.gni") + +group("unittest") { + testonly = true + deps = [] + deps += [ "unittest/ethernet_manager_test:unittest" ] +} diff --git a/services/ethernetmanager/test/unittest/ethernet_manager_test/BUILD.gn b/services/ethernetmanager/test/unittest/ethernet_manager_test/BUILD.gn new file mode 100755 index 0000000..b1c2e44 --- /dev/null +++ b/services/ethernetmanager/test/unittest/ethernet_manager_test/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright (c) 2021 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/test.gni") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +ohos_unittest("ethernet_manager_test") { + module_out_path = "netmanager_base/ethernet_manager_test" + + sources = [ + "$NETMANAGER_PREBUILTS_DIR/src/ipc/ethernet_service_proxy.cpp", + "ethernet_manager_test.cpp", + ] + + include_dirs = [ + "$INNERKITS_ROOT/native/ethernetmanager/include", + "$INNERKITS_ROOT/native/ethernetmanager/include/ipc", + "$NETMANAGER_PREBUILTS_DIR/include/ipc", + "$NETMANAGER_PREBUILTS_DIR/include", + ] + + deps = [ + "$INNERKITS_ROOT/native/ethernetmanager:ethernet_manager_if", + "$NETMANAGER_BASE_ROOT/utils:net_manager_common", + "$NETMANAGER_PREBUILTS_DIR:ethernet_manager", + ] + + external_deps = [ "ipc:ipc_core" ] + + defines = [ + "NETMGR_LOG_TAG = \"EthernetManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (enable_netmgr_debug) { + defines += [ "NETMGR_DEBUG" ] + } + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netmanager_standard" + subsystem_name = "communication" +} + +group("unittest") { + testonly = true + deps = [ ":ethernet_manager_test" ] +} diff --git a/services/ethernetmanager/test/unittest/ethernet_manager_test/ethernet_manager_test.cpp b/services/ethernetmanager/test/unittest/ethernet_manager_test/ethernet_manager_test.cpp new file mode 100755 index 0000000..e87822d --- /dev/null +++ b/services/ethernetmanager/test/unittest/ethernet_manager_test/ethernet_manager_test.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2021 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 "ethernet_client.h" +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +using namespace testing::ext; +class EthernetManagerTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + sptr GetIfaceConfig(); +}; + +void EthernetManagerTest::SetUpTestCase() {} + +void EthernetManagerTest::TearDownTestCase() {} + +void EthernetManagerTest::SetUp() {} + +void EthernetManagerTest::TearDown() {} + +sptr EthernetManagerTest::GetIfaceConfig() +{ + sptr ic = (std::make_unique()).release(); + if (!ic) { + return ic; + } + ic->ipStatic_.ipAddr_.type_ = INetAddr::IPV4; + ic->ipStatic_.ipAddr_.family_ = 0x01; + ic->ipStatic_.ipAddr_.prefixlen_ = 0x01; + ic->ipStatic_.ipAddr_.address_ = "172.17.5.234"; + ic->ipStatic_.ipAddr_.netMask_ = "255.255.254.0"; + ic->ipStatic_.ipAddr_.hostName_ = "netAddr"; + ic->ipStatic_.route_.type_ = INetAddr::IPV4; + ic->ipStatic_.route_.family_ = 0x01; + ic->ipStatic_.route_.prefixlen_ = 0x01; + ic->ipStatic_.route_.address_ = "0.0.0.0"; + ic->ipStatic_.route_.netMask_ = "0.0.0.0"; + ic->ipStatic_.route_.hostName_ = "netAddr"; + ic->ipStatic_.gate_.type_ = INetAddr::IPV4; + ic->ipStatic_.gate_.family_ = 0x01; + ic->ipStatic_.gate_.prefixlen_ = 0x01; + ic->ipStatic_.gate_.address_ = "172.17.4.1"; + ic->ipStatic_.gate_.netMask_ = "0.0.0.0"; + ic->ipStatic_.gate_.hostName_ = "netAddr"; + ic->ipStatic_.netMask_.type_ = INetAddr::IPV4; + ic->ipStatic_.netMask_.family_ = 0x01; + ic->ipStatic_.netMask_.netMask_ = "255.255.255.0"; + ic->ipStatic_.netMask_.hostName_ = "netAddr"; + INetAddr dns1; + dns1.type_ = INetAddr::IPV4; + dns1.family_ = 0x01; + dns1.address_ = "8.8.8.8"; + dns1.hostName_ = "netAddr"; + INetAddr dns2; + dns2.type_ = INetAddr::IPV4; + dns2.family_ = 0x01; + dns2.address_ = "114.114.114.114"; + dns2.hostName_ = "netAddr"; + ic->ipStatic_.dnsServers_.push_back(dns1); + ic->ipStatic_.dnsServers_.push_back(dns2); + return ic; +} + +/** + * @tc.name: EthernetManager001 + * @tc.desc: Test EthernetManager SetIfaceConfig. + * @tc.type: FUNC + */ +HWTEST_F(EthernetManagerTest, EthernetManager001, TestSize.Level1) +{ + std::string iface = "eth0"; + sptr ic = GetIfaceConfig(); + int32_t result = DelayedSingleton::GetInstance()->SetIfaceConfig(iface, ic); + ASSERT_TRUE(result == 0); +} + +/** + * @tc.name: EthernetManager002 + * @tc.desc: Test EthernetManager SetIfaceConfig. + * @tc.type: FUNC + */ +HWTEST_F(EthernetManagerTest, EthernetManager002, TestSize.Level1) +{ + std::string iface = "eth0"; + sptr ic = + DelayedSingleton::GetInstance()->GetIfaceConfig(iface); + ASSERT_TRUE(result != nullptr); +} + +/** + * @tc.name: EthernetManager003 + * @tc.desc: Test EthernetManager Whether2Activate. + * @tc.type: FUNC + */ +HWTEST_F(EthernetManagerTest, EthernetManager003, TestSize.Level1) +{ + std::string iface = "eth0"; + int32_t result = DelayedSingleton::GetInstance()->IsActivate(iface); + ASSERT_TRUE(result == 0); +} + +/** + * @tc.name: EthernetManager004 + * @tc.desc: Test EthernetManager GetActivateInterfaces. + * @tc.type: FUNC + */ +HWTEST_F(EthernetManagerTest, EthernetManager004, TestSize.Level1) +{ + std::vector result = DelayedSingleton::GetInstance()->GetActivateInterfaces(); + for (std::string& s : result) { + std::cout << s << ","<< std::endl; + } +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/netconnmanager/BUILD.gn b/services/netconnmanager/BUILD.gn new file mode 100755 index 0000000..2b8b225 --- /dev/null +++ b/services/netconnmanager/BUILD.gn @@ -0,0 +1,77 @@ +# Copyright (c) 2021 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") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +ohos_shared_library("net_conn_manager") { + sources = [ + "$NETCONNMANAGER_COMMON_DIR/src/broadcast_manager.cpp", + "$NETCONNMANAGER_COMMON_DIR/src/netd_controller.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/ipc/net_conn_callback_proxy.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/ipc/net_conn_service_stub.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_conn_service.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_controller/net_controller_factory.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_controller/telephony_controller.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_id_manager.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_service.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_supplier.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/network.cpp", + ] + + include_dirs = [ + "$NETCONNMANAGER_SOURCE_DIR/include", + "$NETCONNMANAGER_SOURCE_DIR/include/ipc", + "$NETCONNMANAGER_SOURCE_DIR/include/net_controller", + "$INNERKITS_ROOT/native/netconnmanager/include", + "$NETCONNMANAGER_COMMON_DIR/include", + ] + + deps = [ + "$INNERKITS_ROOT/native/netconnmanager:net_conn_manager_if", + "$NETMANAGER_BASE_ROOT/utils:net_manager_common", + "$NETMANAGER_PREBUILTS_DIR/librarys/netd:libnet_manager_native", + "//utils/native/base:utils", + ] + + external_deps = [ + "aafwk_standard:want", + "appexecfwk_standard:libeventhandler", + "ces_standard:cesfwk_innerkits", + "core_service:tel_cellular_data_api", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_standard:samgr_proxy", + ] + + defines = [ + "NETMGR_LOG_TAG = \"NetConnManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + defines += [ "NATIVE_NETD_FEATURE" ] + + if (enable_netmgr_debug) { + defines += [ "NETMGR_DEBUG" ] + } + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/services/netconnmanager/include/ipc/i_net_conn_service.h b/services/netconnmanager/include/ipc/i_net_conn_service.h new file mode 100755 index 0000000..feec806 --- /dev/null +++ b/services/netconnmanager/include/ipc/i_net_conn_service.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021 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 I_NET_CONN_SERVICE_H +#define I_NET_CONN_SERVICE_H + +#include + +#include "iremote_broker.h" + +#include "net_link_info.h" +#include "net_specifier.h" +#include "net_supplier_info.h" +#include "i_net_conn_callback.h" + +namespace OHOS { +namespace NetManagerStandard { +class INetConnService : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.NetManagerStandard.INetConnService"); + enum { + CMD_NM_START, + CMD_NM_REGISTER_NET_SUPPLIER, + CMD_NM_SYSTEM_READY, + CMD_NM_REGISTER_NET_CONN_CALLBACK, + CMD_NM_REGISTER_NET_CONN_CALLBACK_BY_SPECIFIER, + CMD_NM_UNREGISTER_NET_CONN_CALLBACK, + CMD_NM_UNREGISTER_NET_CONN_CALLBACK_BY_SPECIFIER, + CMD_NM_REG_NET_SUPPLIER, + CMD_NM_UNREG_NETWORK, + CMD_NM_SET_NET_SUPPLIER_INFO, + CMD_NM_SET_NET_CAPABILTITES, + CMD_NM_SET_NET_LINK_INFO, + CMD_NM_END, + }; + +public: + virtual int32_t SystemReady() = 0; + virtual int32_t RegisterNetSupplier(uint32_t netType, const std::string &ident, uint64_t netCapabilities) = 0; + virtual int32_t UnregisterNetSupplier(uint32_t supplierId) = 0; + virtual int32_t RegisterNetConnCallback(const sptr &callback) = 0; + virtual int32_t RegisterNetConnCallback(const sptr &netSpecifier, + const sptr &callback) = 0; + virtual int32_t UnregisterNetConnCallback(const sptr &callback) = 0; + virtual int32_t UnregisterNetConnCallback(const sptr &netSpecifier, + const sptr &callback) = 0; + virtual int32_t UpdateNetSupplierInfo(uint32_t supplierId, const sptr &netSupplierInfo) = 0; + virtual int32_t UpdateNetCapabilities(uint32_t supplierId, uint64_t netCapabilities) = 0; + virtual int32_t UpdateNetLinkInfo(uint32_t supplierId, const sptr &netLinkInfo) = 0; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // I_NET_CONN_SERVICE_H diff --git a/services/netconnmanager/include/ipc/net_conn_callback_proxy.h b/services/netconnmanager/include/ipc/net_conn_callback_proxy.h new file mode 100755 index 0000000..27c2d02 --- /dev/null +++ b/services/netconnmanager/include/ipc/net_conn_callback_proxy.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 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 NET_CONN_CALLBACK_PROXY_H +#define NET_CONN_CALLBACK_PROXY_H + +#include "iremote_proxy.h" + +#include "i_net_conn_callback.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetConnCallbackProxy : public IRemoteProxy { +public: + explicit NetConnCallbackProxy(const sptr &impl); + virtual ~NetConnCallbackProxy(); + +public: + int32_t NetConnStateChanged(const sptr &info) override; + +private: + bool WriteInterfaceToken(MessageParcel &data); + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONN_CALLBACK_PROXY_H diff --git a/services/netconnmanager/include/ipc/net_conn_service_proxy.h b/services/netconnmanager/include/ipc/net_conn_service_proxy.h new file mode 100755 index 0000000..3c18c11 --- /dev/null +++ b/services/netconnmanager/include/ipc/net_conn_service_proxy.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 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 NET_CONN_SERVICE_PROXY_H +#define NET_CONN_SERVICE_PROXY_H + +#include "iremote_proxy.h" + +#include "i_net_conn_service.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetConnServiceProxy : public IRemoteProxy { +public: + explicit NetConnServiceProxy(const sptr &impl); + virtual ~NetConnServiceProxy(); + int32_t SystemReady() override; + int32_t RegisterNetSupplier(uint32_t netType, const std::string &ident, uint64_t netCapabilities) override; + int32_t UnregisterNetSupplier(uint32_t supplierId) override; + int32_t RegisterNetConnCallback(const sptr &callback) override; + int32_t RegisterNetConnCallback(const sptr &netSpecifier, + const sptr &callback) override; + int32_t UnregisterNetConnCallback(const sptr &callback) override; + int32_t UnregisterNetConnCallback(const sptr &netSpecifier, + const sptr &callback) override; + int32_t UpdateNetSupplierInfo(uint32_t supplierId, const sptr &netSupplierInfo) override; + int32_t UpdateNetCapabilities(uint32_t supplierId, uint64_t netCapabilities) override; + int32_t UpdateNetLinkInfo(uint32_t supplierId, const sptr &netLinkInfo) override; + +private: + bool WriteInterfaceToken(MessageParcel &data); + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONN_SERVICE_PROXY_H diff --git a/services/netconnmanager/include/ipc/net_conn_service_stub.h b/services/netconnmanager/include/ipc/net_conn_service_stub.h new file mode 100755 index 0000000..cf623fb --- /dev/null +++ b/services/netconnmanager/include/ipc/net_conn_service_stub.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 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 NET_CONN_SERVICE_STUB_H +#define NET_CONN_SERVICE_STUB_H + +#include + +#include "iremote_stub.h" + +#include "i_net_conn_service.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetConnServiceStub : public IRemoteStub { +public: + NetConnServiceStub(); + ~NetConnServiceStub(); + + int32_t OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + using NetConnServiceFunc = int32_t (NetConnServiceStub::*)(MessageParcel &, MessageParcel &); + +private: + int32_t OnSystemReady(MessageParcel &data, MessageParcel &reply); + int32_t OnRegisterNetSupplier(MessageParcel &data, MessageParcel &reply); + int32_t OnUnregisterNetSupplier(MessageParcel &data, MessageParcel &reply); + int32_t OnRegisterNetConnCallback(MessageParcel &data, MessageParcel &reply); + int32_t OnRegisterNetConnCallbackBySpecifier(MessageParcel &data, MessageParcel &reply); + int32_t OnUnregisterNetConnCallback(MessageParcel &data, MessageParcel &reply); + int32_t OnUnregisterNetConnCallbackBySpecifier(MessageParcel &data, MessageParcel &reply); + int32_t OnUpdateNetSupplierInfo(MessageParcel &data, MessageParcel &reply); + int32_t OnUpdateNetCapabilities(MessageParcel &data, MessageParcel &reply); + int32_t OnUpdateNetLinkInfo(MessageParcel &data, MessageParcel &reply); + +private: + int32_t ConvertCode(int32_t internalCode); + +private: + std::map memberFuncMap_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONN_SERVICE_STUB_H diff --git a/services/netconnmanager/include/net_conn_service.h b/services/netconnmanager/include/net_conn_service.h new file mode 100755 index 0000000..c33c467 --- /dev/null +++ b/services/netconnmanager/include/net_conn_service.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2021 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 NET_CONN_SERVICE_H +#define NET_CONN_SERVICE_H + +#include +#include +#include +#include + +#include "singleton.h" +#include "system_ability.h" + +#include "ipc/net_conn_service_stub.h" +#include "net_service.h" +#include "net_supplier.h" +#include "network.h" +#include "timer.h" + +namespace OHOS { +namespace NetManagerStandard { +constexpr uint32_t CONNECT_SERVICE_WAIT_TIME = 6000; +class NetConnService : public SystemAbility, + public NetConnServiceStub, + public std::enable_shared_from_this { + DECLARE_DELAYED_SINGLETON(NetConnService) + DECLARE_SYSTEM_ABILITY(NetConnService) + + using NET_SERVICE_LIST = std::list>; + using NET_NETWORK_LIST = std::list>; + using NET_SUPPLIER_LIST = std::list>; + +public: + void OnStart() override; + void OnStop() override; + /** + * @brief The interface in NetConnService can be called when the system is ready + * + * @return Returns 0, the system is ready, otherwise the system is not ready + */ + int32_t SystemReady() override; + + /** + * @brief The interface is register the network + * + * @param netType Network Type + * @param ident Unique identification of mobile phone card + * @param netCapabilities Network capabilities registered by the network supplier + * + * @return The id of the network supplier + */ + int32_t RegisterNetSupplier(uint32_t netType, const std::string &ident, uint64_t netCapabilities) override; + + /** + * @brief The interface is unregister the network + * + * @param supplierId The id of the network supplier + * + * @return Returns 0, unregister the network successfully, otherwise it will fail + */ + int32_t UnregisterNetSupplier(uint32_t supplierId) override; + + /** + * @brief Register net connection callback + * + * @param netSpecifier specifier information + * @param callback The callback of INetConnCallback interface + * + * @return Returns 0, successfully register net connection callback, otherwise it will failed + */ + int32_t RegisterNetConnCallback(const sptr &callback) override; + + /** + * @brief Register net connection callback by NetSpecifier + * + * @param netSpecifier specifier information + * @param callback The callback of INetConnCallback interface + * + * @return Returns 0, successfully register net connection callback, otherwise it will failed + */ + int32_t RegisterNetConnCallback(const sptr &netSpecifier, + const sptr &callback) override; + + /** + * @brief Unregister net connection callback + * + * @return Returns 0, successfully unregister net connection callback, otherwise it will fail + */ + int32_t UnregisterNetConnCallback(const sptr &callback) override; + + /** + * @brief Unregister net connection callback by NetSpecifier + * + * @return Returns 0, successfully unregister net connection callback, otherwise it will fail + */ + int32_t UnregisterNetConnCallback(const sptr &netSpecifier, + const sptr &callback) override; + + /** + * @brief The interface is update network connection status information + * + * @param supplierId The id of the network supplier + * @param netSupplierInfo network connection status information + * + * @return Returns 0, successfully update the network connection status information, otherwise it will fail + */ + int32_t UpdateNetSupplierInfo(uint32_t supplierId, const sptr &netSupplierInfo) override; + + /** + * @brief The interface is Create or delete network services based on the supplierId and the netCapabilities + * + * @param supplierId The id of the network supplier + * @param netCapabilities Network capabilities registered by the network supplier + * + * @return Returns 0, successfully create network service or delete network service, otherwise fail + */ + int32_t UpdateNetCapabilities(uint32_t supplierId, uint64_t netCapabilities) override; + + /** + * @brief The interface is update network link attribute information + * + * @param supplierId The id of the network supplier + * @param netLinkInfo network link attribute information + * + * @return Returns 0, successfully update the network link attribute information, otherwise it will fail + */ + int32_t UpdateNetLinkInfo(uint32_t supplierId, const sptr &netLinkInfo) override; + static void ReConnectServiceTask(); + +private: + bool Init(); + sptr GetNetSupplierFromList( + uint32_t netType, const std::string &ident); + sptr GetNetSupplierFromListById(uint32_t supplierId); + sptr GetNetworkFromListBySupplierId(uint32_t supplierId); + void DeleteSupplierFromListById(uint32_t supplierId); + void DeleteNetworkFromListBySupplierId(uint32_t supplierId); + bool DeleteServiceFromListByCap(int32_t netId, const NetCapabilities &netCapability); + void DeleteServiceFromListByNet(const Network &network); + bool IsServiceInList(int32_t netId, const NetCapabilities &netCapability) const; + int32_t ReConnectService(); + void ThreadExitTask(); + int32_t NotifyNetConnStateChanged(const sptr &info); + +private: + enum ServiceRunningState { + STATE_STOPPED = 0, + STATE_RUNNING, + }; + + bool registerToService_; + ServiceRunningState state_; + sptr defaultNetService_ = nullptr; + + NET_SERVICE_LIST netServices_; + NET_NETWORK_LIST networks_; + NET_SUPPLIER_LIST netSupplier_; + + Timer reConnectTimer_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONN_SERVICE_H diff --git a/services/netconnmanager/include/net_conn_types.h b/services/netconnmanager/include/net_conn_types.h new file mode 100755 index 0000000..5578a72 --- /dev/null +++ b/services/netconnmanager/include/net_conn_types.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 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 NET_CONN_TYPES_H +#define NET_CONN_TYPES_H + +namespace OHOS { +namespace NetManagerStandard { +enum ResultCode { + ERR_NONE = 0, + ERR_SERVICE_REQUEST_SUCCESS = (-1), + ERR_SERVICE_REQUEST_CONNECT_FAIL = (-2), + ERR_SERVICE_UPDATE_NET_LINK_INFO_FAIL = (-3), + ERR_SERVICE_CONNECTING = (-4), + ERR_SERVICE_CONNECTED = (-5), + ERR_SERVICE_DISCONNECTED_FAIL = (-6), + ERR_SERVICE_DISCONNECTING = (-7), + ERR_SERVICE_DISCONNECTED_SUCCESS = (-8), + ERR_SERVICE_NULL_PTR = (-9), + ERR_NO_SUPPLIER = (-10), + ERR_NO_NETWORK = (-11), + ERR_INVALID_PARAMS = (-12), + ERR_INVALID_NETORK_TYPE = (-13), + ERR_SERVICE_UPDATE_NET_LINK_INFO_SUCCES = (-14), + ERR_NET_MONITOR_OPT_SUCCESS = (-15), + ERR_NET_MONITOR_OPT_FAILED = (-16), + ERR_NET_SUPPLIER_NO_API = (-17), + ERR_NET_TYPE_NOT_FOUND = (-18), + ERR_NO_ANY_NET_TYPE = (-19), + ERR_NO_REGISTERED = (-20), +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONN_TYPES_H diff --git a/services/netconnmanager/include/net_controller/i_net_controller.h b/services/netconnmanager/include/net_controller/i_net_controller.h new file mode 100755 index 0000000..a079463 --- /dev/null +++ b/services/netconnmanager/include/net_controller/i_net_controller.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021 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 I_NET_CONTROLLER_H +#define I_NET_CONTROLLER_H + +#include "net_specifier.h" +#include "net_supplier_info.h" + +namespace OHOS { +namespace NetManagerStandard { +class INetController : public virtual RefBase { +public: + virtual ~INetController() = default; + virtual int32_t RequestNetwork(const std::string &ident, NetCapabilities netCapabilitiy) = 0; + virtual int32_t ReleaseNetwork(const std::string &ident, NetCapabilities netCapabilitiy) = 0; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // I_NET_CONTROLLER_H \ No newline at end of file diff --git a/services/netconnmanager/include/net_controller/net_controller_factory.h b/services/netconnmanager/include/net_controller/net_controller_factory.h new file mode 100755 index 0000000..20bab0e --- /dev/null +++ b/services/netconnmanager/include/net_controller/net_controller_factory.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 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 NET_CONTROLLER_FACTORY_H +#define NET_CONTROLLER_FACTORY_H + +#include +#include +#include "i_net_controller.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetControllerFactory { + DECLARE_DELAYED_SINGLETON(NetControllerFactory) +public: + sptr MakeNetController(uint32_t netType); + +private: + sptr GetNetControllerFromMap(uint32_t netType); + std::map> netControllers; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONTROLLER_FACTORY_H \ No newline at end of file diff --git a/services/netconnmanager/include/net_controller/telephony_controller.h b/services/netconnmanager/include/net_controller/telephony_controller.h new file mode 100755 index 0000000..ac9b77c --- /dev/null +++ b/services/netconnmanager/include/net_controller/telephony_controller.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021 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 TELEPHONY_CONTROLLER_H +#define TELEPHONY_CONTROLLER_H + +#include + +#include "i_net_controller.h" + +namespace OHOS { +namespace NetManagerStandard { +class TelephonyController : public INetController { +public: + TelephonyController(); + ~TelephonyController() = default; + + /** + * @brief When a network request is initiated, the cellular data activation data interface will be called + * + * @param ident_ Unique identification of mobile phone card + * @param netCapabilitiy Network capabilities registered by Cellular Data + * + * @return Return the return value of the cellular data interface call + */ + int32_t RequestNetwork(const std::string &ident, NetCapabilities netCapabilitiy) override; + + /** + * @brief When the network is disconnected, the cellular data deactivation interface will be called + * + * @param ident_ Unique identification of mobile phone card + * @param netCapabilitiy Network capabilities registered by Cellular Data + * + * @return Return the return value of the cellular data interface call + */ + int32_t ReleaseNetwork(const std::string &ident, NetCapabilities netCapabilitiy) override; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // TELEPHONY_CONTROLLER_H diff --git a/services/netconnmanager/include/net_id_manager.h b/services/netconnmanager/include/net_id_manager.h new file mode 100755 index 0000000..d6bd027 --- /dev/null +++ b/services/netconnmanager/include/net_id_manager.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 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 NET_ID_MANAGER_H +#define NET_ID_MANAGER_H + +#include +#include +#include + +#include + +namespace OHOS { +namespace NetManagerStandard { +// Class used to reserve and release net IDs. +class NetIdManager { + DECLARE_DELAYED_SINGLETON(NetIdManager) +public: + int32_t ReserveNetId(); + void ReleaseNetId(int32_t netId); + +public: + static constexpr int32_t TUN_IF_RANGE = 0x0400; + static constexpr int32_t MAX_NET_ID = 65535 - TUN_IF_RANGE; + static constexpr int32_t MIN_NET_ID = 100; +private: + std::atomic lastNetId_ = -1; + std::atomic maxNetId_ = MAX_NET_ID; + std::map netIdInUse_; + std::mutex mtx_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_ID_MANAGER_H \ No newline at end of file diff --git a/services/netconnmanager/include/net_service.h b/services/netconnmanager/include/net_service.h new file mode 100755 index 0000000..5b757eb --- /dev/null +++ b/services/netconnmanager/include/net_service.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2021 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 NET_SERVICE_H +#define NET_SERVICE_H + +#include +#include +#include + +#include "network.h" +#include "i_net_conn_callback.h" + +namespace OHOS { +namespace NetManagerStandard { +enum ServiceState { + SERVICE_STATE_UNKNOWN = 0, + SERVICE_STATE_IDLE = 1, + SERVICE_STATE_CONNECTING = 2, + SERVICE_STATE_READY = 3, + SERVICE_STATE_CONNECTED = 4, + SERVICE_STATE_DISCONNECTING = 5, + SERVICE_STATE_DISCONNECTED = 6, + SERVICE_STATE_FAILURE = 7, +}; + +class NetService : public virtual RefBase { +public: + NetService(const std::string &ident, NetworkType networkType, + NetCapabilities netCapability, sptr &network); + ~NetService() = default; + void SetIdent(const std::string &ident); + void SetNetworkType(const NetworkType &networkType); + void SetNetCapability(const NetCapabilities &netCapability); + void SetServiceState(const ServiceState &serviceState); + std::string GetIdent() const; + NetworkType GetNetworkType() const; + NetCapabilities GetNetCapability() const; + ServiceState GetServiceState() const; + sptr GetNetwork() const; + + /** + * @brief Initiate a network connection request to the network service of the network supplier + * + * @return Return ERR_SERVICE_REQUEST_SUCCESS, Succeed + */ + int32_t ServiceConnect(); + + /** + * @brief Initiate a disconnect request to the network service of the network supplier + * + * @return Return ERR_SERVICE_DISCONNECTED_SUCCESS, Succeed + */ + int32_t ServiceDisConnect(); + + /** + * @brief Automatically initiate a network connection request to the network service of the network supplier + * + * @return Return ERR_SERVICE_REQUEST_SUCCESS, Succeed + */ + int32_t ServiceAutoConnect(); + + /** + * @brief Register net connection callback + * + * @return Return ERR_NONE, Succeed + */ + void RegisterNetConnCallback(const sptr &callback); + + /** + * @brief Unregister net connection callback + * + * @return Return ERR_NONE, Succeed + */ + int32_t UnregisterNetConnCallback(const sptr &callback); + + bool IsConnecting() const; + bool IsConnected() const; + +private: + int32_t NetworkConnect(); + int32_t NetworkDisConnect(); + void UpdateServiceState(ServiceState serviceState); + int32_t NotifyNetConnStateChanged(const sptr &info); + +private: + std::string ident_; + NetworkType networkType_ = NET_TYPE_UNKNOWN; + ServiceState state_ = SERVICE_STATE_IDLE; + + NetCapabilities netCapability_ = NET_CAPABILITIES_NONE; + sptr network_; + + std::vector> netConnCallback_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_SERVICE_H \ No newline at end of file diff --git a/services/netconnmanager/include/net_supplier.h b/services/netconnmanager/include/net_supplier.h new file mode 100755 index 0000000..d3115d1 --- /dev/null +++ b/services/netconnmanager/include/net_supplier.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021 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 NET_SUPPLIER_H +#define NET_SUPPLIER_H + +#include + +#include "i_net_controller.h" + +namespace OHOS { +namespace NetManagerStandard { +class Network; +class NetService; +class NetSupplier : public virtual RefBase { +public: + NetSupplier(); + NetSupplier(NetworkType netSupplierType, const std::string &netSupplierIdent); + ~NetSupplier() = default; + bool operator==(const NetSupplier &netSupplier) const; + NetworkType GetNetSupplierType() const; + std::string GetNetSupplierIdent() const; + bool SupplierConnection(NetCapabilities netCapabilities); + bool SupplierDisconnection(NetCapabilities netCapabilities); + void UpdateNetSupplierInfo(const NetSupplierInfo &netSupplierInfo); + uint32_t GetSupplierId() const; + bool GetConnected() const; + bool GetAvailable() const; + bool GetRoaming() const; + bool GetStrength() const; + bool GetFrequency() const; + +private: + sptr netController_; + NetworkType netSupplierType_; + std::string netSupplierIdent_; + uint32_t supplierId_ = 0; + uint16_t frequency_ = 0x00; + uint8_t strength_ = 0x00; + bool connected_ = false; + bool isAvailable_ = false; // whether the network is available + bool isRoaming_ = false; + const int32_t REG_OK = 1; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_SUPPLIER_H diff --git a/services/netconnmanager/include/network.h b/services/netconnmanager/include/network.h new file mode 100755 index 0000000..03a5f8e --- /dev/null +++ b/services/netconnmanager/include/network.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021 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 NETWORK_H +#define NETWORK_H + +#include "inet_addr.h" +#include "net_link_info.h" +#include "net_supplier.h" +#include "route.h" + +namespace OHOS { +namespace NetManagerStandard { +class Network : public virtual RefBase { +public: + Network(sptr &supplier); + ~Network(); + bool operator==(const Network &network) const; + + bool NetworkConnect(const NetCapabilities &netCapability); + bool NetworkDisconnect(const NetCapabilities &netCapability); + bool UpdateNetLinkInfo(const NetLinkInfo &netLinkInfo); + void SetIpAdress(const INetAddr &ipAdress); + void SetDns(const INetAddr &dns); + void SetRoute(const Route &route); + INetAddr GetIpAdress() const; + INetAddr GetDns() const; + Route GetRoute() const; + NetLinkInfo GetNetLinkInfo() const; + int32_t GetNetId() const; + sptr GetNetSupplier() const; + bool UpdateNetSupplierInfo(const NetSupplierInfo &netSupplierInfo); + bool IsNetworkConnecting() const; + void SetConnected(bool connected); + void SetConnecting(bool connecting); + void UpdateInterfaces(const NetLinkInfo &netLinkInfo); + void UpdateRoutes(const NetLinkInfo &netLinkInfo); + void UpdateDnses(const NetLinkInfo &netLinkInfo); + void updateMtu(const NetLinkInfo &netLinkInfo); + +private: + NetLinkInfo netLinkInfo_; + INetAddr ipAddr_; + INetAddr dns_; + Route route_; + + // netd network param + bool isPhyNetCreated_ = false; + bool isConnecting_ = false; + bool isConnected_ = false; + + sptr supplier_; + int32_t netId_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NETWORK_H diff --git a/services/netconnmanager/src/ipc/net_conn_callback_proxy.cpp b/services/netconnmanager/src/ipc/net_conn_callback_proxy.cpp new file mode 100755 index 0000000..e7615e1 --- /dev/null +++ b/services/netconnmanager/src/ipc/net_conn_callback_proxy.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 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 "net_conn_callback_proxy.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +NetConnCallbackProxy::NetConnCallbackProxy(const sptr &impl) + : IRemoteProxy(impl) +{} + +NetConnCallbackProxy::~NetConnCallbackProxy() {} + +int32_t NetConnCallbackProxy::NetConnStateChanged(const sptr &info) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return ERR_FLATTEN_OBJECT; + } + + if (!info->Marshalling(data)) { + NETMGR_LOGE("Proxy Marshalling failed"); + return ERR_FLATTEN_OBJECT; + } + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return ERR_NULL_OBJECT; + } + + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(NET_CONN_STATE_CHANGED, data, reply, option); + if (ret != ERR_NONE) { + NETMGR_LOGE("Proxy SendRequest failed, ret code:[%{public}d]", ret); + } + return ret; +} + +bool NetConnCallbackProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(NetConnCallbackProxy::GetDescriptor())) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return false; + } + return true; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/services/netconnmanager/src/ipc/net_conn_service_proxy.cpp b/services/netconnmanager/src/ipc/net_conn_service_proxy.cpp new file mode 100755 index 0000000..c3f927f --- /dev/null +++ b/services/netconnmanager/src/ipc/net_conn_service_proxy.cpp @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2021 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 "net_conn_service_proxy.h" + +#include "net_conn_constants.h" +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +NetConnServiceProxy::NetConnServiceProxy(const sptr &impl) + : IRemoteProxy(impl) +{} + +NetConnServiceProxy::~NetConnServiceProxy() {} + +int32_t NetConnServiceProxy::SystemReady() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return ERR_FLATTEN_OBJECT; + } + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return ERR_NULL_OBJECT; + } + int32_t error = remote->SendRequest(CMD_NM_SYSTEM_READY, data, reply, option); + if (error != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", error); + } + return error; +} + +int32_t NetConnServiceProxy::RegisterNetSupplier( + uint32_t netType, const std::string &ident, uint64_t netCapabilities) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return NET_CONN_ERR_INVALID_SUPPLIER_ID; + } + + NETMGR_LOGI("proxy netType[%{public}d], ident[%{public}s], netCapabilities[%{public}lld]", + netType, ident.c_str(), netCapabilities); + if (!data.WriteUint32(netType)) { + return NET_CONN_ERR_INVALID_SUPPLIER_ID; + } + if (!data.WriteString(ident)) { + return NET_CONN_ERR_INVALID_SUPPLIER_ID; + } + if (!data.WriteUint64(netCapabilities)) { + return NET_CONN_ERR_INVALID_SUPPLIER_ID; + } + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NET_CONN_ERR_INVALID_SUPPLIER_ID; + } + int32_t error = remote->SendRequest(CMD_NM_REG_NET_SUPPLIER, data, reply, option); + if (error != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", error); + return NET_CONN_ERR_INVALID_SUPPLIER_ID; + } + + return reply.ReadInt32(); +} + +int32_t NetConnServiceProxy::UnregisterNetSupplier(uint32_t supplierId) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return ERR_FLATTEN_OBJECT; + } + + NETMGR_LOGI("proxy supplierId[%{public}d]", supplierId); + if (!data.WriteUint32(supplierId)) { + return ERR_FLATTEN_OBJECT; + } + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return ERR_NULL_OBJECT; + } + int32_t error = remote->SendRequest(CMD_NM_UNREG_NETWORK, data, reply, option); + if (error != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", error); + return error; + } + + return reply.ReadInt32(); +} + +int32_t NetConnServiceProxy::RegisterNetConnCallback(const sptr &callback) +{ + if (callback == nullptr) { + NETMGR_LOGE("The parameter of callback is nullptr"); + return NET_CONN_ERR_INPUT_NULL_PTR; + } + + MessageParcel dataParcel; + if (!WriteInterfaceToken(dataParcel)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return NET_CONN_ERR_INVALID_PARAMETER; + } + dataParcel.WriteRemoteObject(callback->AsObject().GetRefPtr()); + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NET_CONN_ERR_GET_REMOTE_OBJECT_FAILED; + } + + MessageOption option; + MessageParcel replyParcel; + int32_t retCode = remote->SendRequest(CMD_NM_REGISTER_NET_CONN_CALLBACK, dataParcel, replyParcel, option); + NETMGR_LOGI("SendRequest retCode:[%{public}d]", retCode); + if (retCode != NET_CONN_SUCCESS) { + return retCode; + } + return replyParcel.ReadInt32(); +} + +int32_t NetConnServiceProxy::RegisterNetConnCallback(const sptr &netSpecifier, + const sptr &callback) +{ + if (netSpecifier == nullptr || callback == nullptr) { + NETMGR_LOGE("The parameter of netSpecifier or callback is nullptr"); + return NET_CONN_ERR_INPUT_NULL_PTR; + } + + MessageParcel dataParcel; + if (!WriteInterfaceToken(dataParcel)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return NET_CONN_ERR_INVALID_PARAMETER; + } + netSpecifier->Marshalling(dataParcel); + dataParcel.WriteRemoteObject(callback->AsObject().GetRefPtr()); + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NET_CONN_ERR_GET_REMOTE_OBJECT_FAILED; + } + + MessageOption option; + MessageParcel replyParcel; + int32_t retCode = remote->SendRequest( + CMD_NM_REGISTER_NET_CONN_CALLBACK_BY_SPECIFIER, dataParcel, replyParcel, option); + NETMGR_LOGI("SendRequest retCode:[%{public}d]", retCode); + if (retCode != NET_CONN_SUCCESS) { + return retCode; + } + return replyParcel.ReadInt32(); +} + +int32_t NetConnServiceProxy::UnregisterNetConnCallback(const sptr &callback) +{ + if (callback == nullptr) { + NETMGR_LOGE("The parameter of callback is nullptr"); + return NET_CONN_ERR_INPUT_NULL_PTR; + } + + MessageParcel dataParcel; + if (!WriteInterfaceToken(dataParcel)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return NET_CONN_ERR_INVALID_PARAMETER; + } + dataParcel.WriteRemoteObject(callback->AsObject().GetRefPtr()); + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NET_CONN_ERR_GET_REMOTE_OBJECT_FAILED; + } + + MessageOption option; + MessageParcel replyParcel; + int32_t retCode = remote->SendRequest(CMD_NM_UNREGISTER_NET_CONN_CALLBACK, dataParcel, replyParcel, option); + NETMGR_LOGI("SendRequest retCode:[%{public}d]", retCode); + if (retCode != NET_CONN_SUCCESS) { + return retCode; + } + return replyParcel.ReadInt32(); +} + +int32_t NetConnServiceProxy::UnregisterNetConnCallback(const sptr &netSpecifier, + const sptr &callback) +{ + if (netSpecifier == nullptr || callback == nullptr) { + NETMGR_LOGE("The parameter of netSpecifier or callback is nullptr"); + return NET_CONN_ERR_INPUT_NULL_PTR; + } + + MessageParcel dataParcel; + if (!WriteInterfaceToken(dataParcel)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return NET_CONN_ERR_INVALID_PARAMETER; + } + netSpecifier->Marshalling(dataParcel); + dataParcel.WriteRemoteObject(callback->AsObject().GetRefPtr()); + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NET_CONN_ERR_GET_REMOTE_OBJECT_FAILED; + } + + MessageOption option; + MessageParcel replyParcel; + int32_t retCode = remote->SendRequest( + CMD_NM_UNREGISTER_NET_CONN_CALLBACK_BY_SPECIFIER, dataParcel, replyParcel, option); + NETMGR_LOGI("SendRequest retCode:[%{public}d]", retCode); + if (retCode != NET_CONN_SUCCESS) { + return retCode; + } + return replyParcel.ReadInt32(); +} + +int32_t NetConnServiceProxy::UpdateNetSupplierInfo(uint32_t supplierId, + const sptr &netSupplierInfo) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return ERR_FLATTEN_OBJECT; + } + + NETMGR_LOGI("proxy supplierId[%{public}d]", supplierId); + if (!data.WriteUint32(supplierId)) { + return ERR_FLATTEN_OBJECT; + } + NETMGR_LOGI("proxy supplierId[%{public}d] Marshalling success", supplierId); + if (!netSupplierInfo->Marshalling(data)) { + NETMGR_LOGE("proxy Marshalling failed"); + return ERR_FLATTEN_OBJECT; + } + NETMGR_LOGI("proxy Marshalling success"); + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return ERR_NULL_OBJECT; + } + int32_t error = remote->SendRequest(CMD_NM_SET_NET_SUPPLIER_INFO, data, reply, option); + if (error != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", error); + return error; + } + + return reply.ReadInt32(); +} + +int32_t NetConnServiceProxy::UpdateNetCapabilities(uint32_t supplierId, uint64_t netCapabilities) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return IPC_PROXY_ERR; + } + + NETMGR_LOGI("proxy supplierId[%{public}d], netCapabilities[%{public}lld]", supplierId, netCapabilities); + if (!data.WriteUint32(supplierId)) { + return ERR_FLATTEN_OBJECT; + } + if (!data.WriteUint64(netCapabilities)) { + return ERR_FLATTEN_OBJECT; + } + NETMGR_LOGI("proxy Marshalling success"); + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return ERR_NULL_OBJECT; + } + int32_t error = remote->SendRequest(CMD_NM_SET_NET_CAPABILTITES, data, reply, option); + if (error != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", error); + return error; + } + + return reply.ReadInt32(); +} + +int32_t NetConnServiceProxy::UpdateNetLinkInfo(uint32_t supplierId, const sptr &netLinkInfo) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return IPC_PROXY_ERR; + } + + if (!data.WriteUint32(supplierId)) { + return IPC_PROXY_ERR; + } + + if (!netLinkInfo->Marshalling(data)) { + NETMGR_LOGE("proxy Marshalling failed"); + return IPC_PROXY_ERR; + } + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return ERR_NULL_OBJECT; + } + int32_t error = remote->SendRequest(CMD_NM_SET_NET_LINK_INFO, data, reply, option); + if (error != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", error); + return error; + } + + return reply.ReadInt32(); +} + +bool NetConnServiceProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(NetConnServiceProxy::GetDescriptor())) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return false; + } + return true; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/services/netconnmanager/src/ipc/net_conn_service_stub.cpp b/services/netconnmanager/src/ipc/net_conn_service_stub.cpp new file mode 100755 index 0000000..d07f326 --- /dev/null +++ b/services/netconnmanager/src/ipc/net_conn_service_stub.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2021 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 "net_conn_service_stub.h" + +#include "net_conn_types.h" +#include "net_conn_constants.h" +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +NetConnServiceStub::NetConnServiceStub() +{ + memberFuncMap_[CMD_NM_SYSTEM_READY] = &NetConnServiceStub::OnSystemReady; + memberFuncMap_[CMD_NM_REGISTER_NET_CONN_CALLBACK] = &NetConnServiceStub::OnRegisterNetConnCallback; + memberFuncMap_[CMD_NM_REGISTER_NET_CONN_CALLBACK_BY_SPECIFIER] = + &NetConnServiceStub::OnRegisterNetConnCallbackBySpecifier; + memberFuncMap_[CMD_NM_UNREGISTER_NET_CONN_CALLBACK] = &NetConnServiceStub::OnUnregisterNetConnCallback; + memberFuncMap_[CMD_NM_UNREGISTER_NET_CONN_CALLBACK_BY_SPECIFIER] = + &NetConnServiceStub::OnUnregisterNetConnCallbackBySpecifier; + memberFuncMap_[CMD_NM_REG_NET_SUPPLIER] = &NetConnServiceStub::OnRegisterNetSupplier; + memberFuncMap_[CMD_NM_UNREG_NETWORK] = &NetConnServiceStub::OnUnregisterNetSupplier; + memberFuncMap_[CMD_NM_SET_NET_SUPPLIER_INFO] = &NetConnServiceStub::OnUpdateNetSupplierInfo; + memberFuncMap_[CMD_NM_SET_NET_CAPABILTITES] = &NetConnServiceStub::OnUpdateNetCapabilities; + memberFuncMap_[CMD_NM_SET_NET_LINK_INFO] = &NetConnServiceStub::OnUpdateNetLinkInfo; +} + +NetConnServiceStub::~NetConnServiceStub() {} + +int32_t NetConnServiceStub::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + NETMGR_LOGI("stub call start, code = [%{public}d]", code); + + std::u16string myDescripter = NetConnServiceStub::GetDescriptor(); + std::u16string remoteDescripter = data.ReadInterfaceToken(); + if (myDescripter != remoteDescripter) { + NETMGR_LOGE("descriptor checked fail"); + return ERR_FLATTEN_OBJECT; + } + + auto itFunc = memberFuncMap_.find(code); + if (itFunc != memberFuncMap_.end()) { + auto requestFunc = itFunc->second; + if (requestFunc != nullptr) { + return (this->*requestFunc)(data, reply); + } + } + + NETMGR_LOGI("stub default case, need check"); + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} + +int32_t NetConnServiceStub::OnSystemReady(MessageParcel &data, MessageParcel &reply) +{ + SystemReady(); + return ERR_NONE; +} + +int32_t NetConnServiceStub::OnRegisterNetSupplier(MessageParcel &data, MessageParcel &reply) +{ + NETMGR_LOGI("stub processing"); + uint32_t netType; + std::string ident; + uint64_t netCapabilities; + if (!data.ReadUint32(netType)) { + return ERR_FLATTEN_OBJECT; + } + + if (!data.ReadString(ident)) { + return ERR_FLATTEN_OBJECT; + } + + if (!data.ReadUint64(netCapabilities)) { + return ERR_FLATTEN_OBJECT; + } + + int32_t ret = RegisterNetSupplier(netType, ident, netCapabilities); + if (ret == ERR_NO_NETWORK || ret == ERR_NO_SUPPLIER) { + NETMGR_LOGE("Register network supplier failed, error code:[%{public}d].", ret); + ret = NET_CONN_ERR_INVALID_SUPPLIER_ID; + } + if (!reply.WriteInt32(ret)) { + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetConnServiceStub::OnUnregisterNetSupplier(MessageParcel &data, MessageParcel &reply) +{ + uint32_t supplierId; + if (!data.ReadUint32(supplierId)) { + return ERR_FLATTEN_OBJECT; + } + + int32_t ret = UnregisterNetSupplier(supplierId); + if (!reply.WriteInt32(ret)) { + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetConnServiceStub::OnRegisterNetConnCallback(MessageParcel &data, MessageParcel &reply) +{ + int32_t result = NET_CONN_SUCCESS; + sptr remote = data.ReadRemoteObject(); + if (remote == nullptr) { + NETMGR_LOGE("Callback ptr is nullptr."); + result = NET_CONN_ERR_GET_REMOTE_OBJECT_FAILED; + reply.WriteInt32(result); + return result; + } + + sptr callback = iface_cast(remote); + if (callback == nullptr) { + result = NET_CONN_ERR_INPUT_NULL_PTR; + reply.WriteInt32(result); + return result; + } + + result = ConvertCode(RegisterNetConnCallback(callback)); + reply.WriteInt32(result); + return result; +} + +int32_t NetConnServiceStub::OnRegisterNetConnCallbackBySpecifier(MessageParcel &data, MessageParcel &reply) +{ + sptr netSpecifier = NetSpecifier::Unmarshalling(data); + + int32_t result = ERR_FLATTEN_OBJECT; + sptr remote = data.ReadRemoteObject(); + if (remote == nullptr) { + NETMGR_LOGE("callback ptr is nullptr."); + reply.WriteInt32(result); + return result; + } + + sptr callback = iface_cast(remote); + if (callback == nullptr) { + result = NET_CONN_ERR_INPUT_NULL_PTR; + reply.WriteInt32(result); + return result; + } + + result = ConvertCode(RegisterNetConnCallback(netSpecifier, callback)); + reply.WriteInt32(result); + return result; +} + +int32_t NetConnServiceStub::OnUnregisterNetConnCallback(MessageParcel &data, MessageParcel &reply) +{ + int32_t result = ERR_FLATTEN_OBJECT; + sptr remote = data.ReadRemoteObject(); + if (remote == nullptr) { + NETMGR_LOGE("callback ptr is nullptr."); + reply.WriteInt32(result); + return result; + } + + sptr callback = iface_cast(remote); + if (callback == nullptr) { + result = NET_CONN_ERR_INPUT_NULL_PTR; + reply.WriteInt32(result); + return result; + } + + result = ConvertCode(UnregisterNetConnCallback(callback)); + reply.WriteInt32(result); + return result; +} + +int32_t NetConnServiceStub::OnUnregisterNetConnCallbackBySpecifier(MessageParcel &data, MessageParcel &reply) +{ + sptr netSpecifier = NetSpecifier::Unmarshalling(data); + + int32_t result = ERR_FLATTEN_OBJECT; + sptr remote = data.ReadRemoteObject(); + if (remote == nullptr) { + NETMGR_LOGE("callback ptr is nullptr."); + reply.WriteInt32(result); + return result; + } + + sptr callback = iface_cast(remote); + if (callback == nullptr) { + result = NET_CONN_ERR_INPUT_NULL_PTR; + reply.WriteInt32(result); + return result; + } + + result = ConvertCode(UnregisterNetConnCallback(netSpecifier, callback)); + reply.WriteInt32(result); + return result; +} + +int32_t NetConnServiceStub::OnUpdateNetSupplierInfo(MessageParcel &data, MessageParcel &reply) +{ + uint32_t supplierId; + if (!data.ReadUint32(supplierId)) { + return ERR_FLATTEN_OBJECT; + } + + sptr netSupplierInfo = NetSupplierInfo::Unmarshalling(data); + int32_t ret = UpdateNetSupplierInfo(supplierId, netSupplierInfo); + if (!reply.WriteInt32(ret)) { + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetConnServiceStub::OnUpdateNetCapabilities(MessageParcel &data, MessageParcel &reply) +{ + uint32_t supplierId; + uint64_t netCapabilities; + + if (!data.ReadUint32(supplierId)) { + return ERR_FLATTEN_OBJECT; + } + + if (!data.ReadUint64(netCapabilities)) { + return ERR_FLATTEN_OBJECT; + } + + NETMGR_LOGI("stub execute UpdateNetCapabilities"); + int32_t ret = UpdateNetCapabilities(supplierId, netCapabilities); + if (!reply.WriteInt32(ret)) { + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetConnServiceStub::OnUpdateNetLinkInfo(MessageParcel &data, MessageParcel &reply) +{ + uint32_t supplierId; + + if (!data.ReadUint32(supplierId)) { + return ERR_FLATTEN_OBJECT; + } + + sptr netLinkInfo = NetLinkInfo::Unmarshalling(data); + + int32_t ret = UpdateNetLinkInfo(supplierId, netLinkInfo); + if (!reply.WriteInt32(ret)) { + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetConnServiceStub::ConvertCode(int32_t internalCode) +{ + switch (internalCode) { + case static_cast(ERR_NONE): + return static_cast(NET_CONN_SUCCESS); + case static_cast(ERR_SERVICE_NULL_PTR): + return static_cast(NET_CONN_ERR_INPUT_NULL_PTR); + case static_cast(ERR_NET_TYPE_NOT_FOUND): + return static_cast(NET_CONN_ERR_NET_TYPE_NOT_FOUND); + case static_cast(ERR_NO_ANY_NET_TYPE): + return static_cast(NET_CONN_ERR_NO_ANY_NET_TYPE); + case static_cast(ERR_NO_REGISTERED): + return static_cast(NET_CONN_ERR_NO_REGISTERED); + default: + break; + } + + return static_cast(NET_CONN_ERR_INTERNAL_ERROR); +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/services/netconnmanager/src/net_conn_service.cpp b/services/netconnmanager/src/net_conn_service.cpp new file mode 100755 index 0000000..78cb2a8 --- /dev/null +++ b/services/netconnmanager/src/net_conn_service.cpp @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2021 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 "net_conn_service.h" + +#include "system_ability_definition.h" + +#include "net_conn_types.h" +#include "net_service.h" +#include "net_supplier.h" +#include "netd_controller.h" +#include "net_mgr_log_wrapper.h" +#include "broadcast_manager.h" + +namespace OHOS { +namespace NetManagerStandard { +const bool REGISTER_LOCAL_RESULT = + SystemAbility::MakeAndRegisterAbility(DelayedSingleton::GetInstance().get()); + +NetConnService::NetConnService() + : SystemAbility(COMM_NET_CONN_MANAGER_SYS_ABILITY_ID, true), registerToService_(false), + state_(STATE_STOPPED) +{ +} + +NetConnService::~NetConnService() {} + +void NetConnService::OnStart() +{ + if (state_ == STATE_RUNNING) { + NETMGR_LOGI("the state is already running"); + return; + } + if (!Init()) { + NETMGR_LOGE("init failed"); + return; + } + state_ = STATE_RUNNING; +} + +void NetConnService::OnStop() +{ + state_ = STATE_STOPPED; + registerToService_ = false; +} + +bool NetConnService::Init() +{ + if (!REGISTER_LOCAL_RESULT) { + NETMGR_LOGE("Register to local sa manager failed"); + registerToService_ = false; + return false; + } + if (!registerToService_) { + if (!Publish(DelayedSingleton::GetInstance().get())) { + NETMGR_LOGE("Register to sa manager failed"); + return false; + } + registerToService_ = true; + } + return true; +} + +int32_t NetConnService::SystemReady() +{ + NETMGR_LOGI("System ready."); + return 0; +} + +int32_t NetConnService::RegisterNetSupplier(uint32_t netType, const std::string &ident, uint64_t netCapabilities) +{ + NETMGR_LOGI("register supplier, netType[%{public}d] ident[%{public}s] netCapabilities[%{public}lld]", + netType, ident.c_str(), netCapabilities); + + // According to netType, ident, get the supplier from the list and save the supplierId in the list + if (netType >= NET_TYPE_MAX || netType <= NET_TYPE_UNKNOWN) { + NETMGR_LOGE("netType parameter invalid"); + return ERR_INVALID_NETORK_TYPE; + } + + sptr supplier = GetNetSupplierFromList(netType, ident); + if (supplier != nullptr) { + NETMGR_LOGI("supplier already exists."); + return supplier->GetSupplierId(); + } + + // If there is no supplier in the list, create a supplier + supplier = (std::make_unique(static_cast(netType), ident)).release(); + if (supplier == nullptr) { + NETMGR_LOGE("supplier is nullptr"); + return ERR_NO_SUPPLIER; + } + + // create network + sptr network = (std::make_unique(supplier)).release(); + if (network == nullptr) { + NETMGR_LOGE("network is nullptr"); + return ERR_NO_NETWORK; + } + + // create service by netCapabilities + NetworkType type = static_cast(netType); + if (netCapabilities & NET_CAPABILITIES_INTERNET) { + auto service = std::make_unique(ident, type, NET_CAPABILITIES_INTERNET, network).release(); + if (service != nullptr) { + netServices_.push_back(service); + defaultNetService_ = service; + } + } + + if (netCapabilities & NET_CAPABILITIES_MMS) { + auto service = std::make_unique(ident, type, NET_CAPABILITIES_MMS, network).release(); + if (service != nullptr) { + netServices_.push_back(service); + } + } + + // save supplier, network to list + netSupplier_.push_back(supplier); + networks_.push_back(network); + NETMGR_LOGI("netSupplier_ size[%{public}d] networks_ size[%{public}d] netServices_ size[%{public}d]", + netSupplier_.size(), networks_.size(), netServices_.size()); + + // connect service + if (defaultNetService_ != nullptr) { + NETMGR_LOGI("service is connecting..."); + int32_t result = defaultNetService_->ServiceConnect(); + if (result != ERR_SERVICE_REQUEST_SUCCESS) { + NETMGR_LOGE("connect service failed, errCode: %{public}X", result); + reConnectTimer_.StartOnce(CONNECT_SERVICE_WAIT_TIME, NetConnService::ReConnectServiceTask); + } + } + + return supplier->GetSupplierId(); +} + +void NetConnService::ReConnectServiceTask() +{ + NETMGR_LOGI("defaultNetService reConnectService start"); + int32_t result = DelayedSingleton::GetInstance()->ReConnectService(); + if (result != ERR_SERVICE_REQUEST_SUCCESS) { + NETMGR_LOGE("service reconnection failed! errCode:%{public}d", result); + return; + } + + NETMGR_LOGI("defaultNetService reConnectService successfully!"); +} + +int32_t NetConnService::ReConnectService() +{ + if (defaultNetService_ == nullptr) { + NETMGR_LOGE("default service is nullptr"); + return ERR_SERVICE_NULL_PTR; + } + if (defaultNetService_->IsConnected() || defaultNetService_->IsConnecting()) { + defaultNetService_->ServiceDisConnect(); + } + NETMGR_LOGI("service is connecting..."); + return defaultNetService_->ServiceConnect(); +} + +int32_t NetConnService::UnregisterNetSupplier(uint32_t supplierId) +{ + NETMGR_LOGI("UnregisterNetSupplier supplierId[%{public}d]", supplierId); + // Remove supplier from the list based on supplierId + sptr supplier = GetNetSupplierFromListById(supplierId); + if (supplier == nullptr) { + NETMGR_LOGE("supplier doesn't exist."); + return ERR_NO_SUPPLIER; + } + + sptr network = GetNetworkFromListBySupplierId(supplierId); + if (network == nullptr) { + NETMGR_LOGE("GetNetworkFromListBySupplierId get error, network is nullptr"); + DeleteSupplierFromListById(supplierId); + return ERR_NO_NETWORK; + } + + DeleteServiceFromListByNet(*network); + DeleteNetworkFromListBySupplierId(supplierId); + DeleteSupplierFromListById(supplierId); + NETMGR_LOGI("netSupplier_ size[%{public}d], networks_ size[%{public}d], netServices_ size[%{public}d]", + netSupplier_.size(), networks_.size(), netServices_.size()); + + return ERR_NONE; +} + +int32_t NetConnService::RegisterNetConnCallback(const sptr &callback) +{ + if (callback == nullptr) { + NETMGR_LOGE("The parameter callback is null"); + return ERR_SERVICE_NULL_PTR; + } + + if (netServices_.empty()) { + NETMGR_LOGE("netServices_ is empty"); + return ERR_NO_ANY_NET_TYPE; + } + + for (auto &netService : netServices_) { + netService->RegisterNetConnCallback(callback); + } + + return ERR_NONE; +} + +int32_t NetConnService::RegisterNetConnCallback(const sptr &netSpecifier, + const sptr &callback) +{ + if (netSpecifier == nullptr || callback == nullptr) { + NETMGR_LOGE("The parameter of netSpecifier or callback is null"); + return ERR_SERVICE_NULL_PTR; + } + + if (netServices_.empty()) { + NETMGR_LOGE("netServices_ is empty"); + return ERR_NO_ANY_NET_TYPE; + } + + for (auto it = netServices_.begin(); it != netServices_.end(); ++it) { + NetCapabilities netCapabilit = (*it)->GetNetCapability(); + if ((*it)->GetNetworkType() == netSpecifier->netType_ + && (netCapabilit & netSpecifier->netCapabilities_) == netCapabilit) { + (*it)->RegisterNetConnCallback(callback); + return ERR_NONE; + } + } + + return ERR_NET_TYPE_NOT_FOUND; +} + +int32_t NetConnService::UnregisterNetConnCallback(const sptr &callback) +{ + if (callback == nullptr) { + NETMGR_LOGE("callback is null"); + return ERR_SERVICE_NULL_PTR; + } + + if (netServices_.empty()) { + NETMGR_LOGE("netServices_ is empty"); + return ERR_NO_ANY_NET_TYPE; + } + + for (auto &netService : netServices_) { + netService->UnregisterNetConnCallback(callback); + } + + return ERR_NONE; +} + +int32_t NetConnService::UnregisterNetConnCallback(const sptr &netSpecifier, + const sptr &callback) +{ + if (netSpecifier == nullptr || callback == nullptr) { + NETMGR_LOGE("The parameter of netSpecifier or callback is null"); + return ERR_SERVICE_NULL_PTR; + } + + if (netServices_.empty()) { + NETMGR_LOGE("netServices_ is empty"); + return ERR_NO_ANY_NET_TYPE; + } + + for (auto it = netServices_.begin(); it != netServices_.end(); ++it) { + NetCapabilities netCapabilit = (*it)->GetNetCapability(); + if ((*it)->GetNetworkType() == netSpecifier->netType_ + && (netCapabilit & netSpecifier->netCapabilities_) == netCapabilit) { + return (*it)->UnregisterNetConnCallback(callback); + } + } + + return ERR_NET_TYPE_NOT_FOUND; +} + +int32_t NetConnService::UpdateNetSupplierInfo(uint32_t supplierId, const sptr &netSupplierInfo) +{ + NETMGR_LOGI("Update supplier info: supplierId[%{public}d]", supplierId); + if (netSupplierInfo == nullptr) { + NETMGR_LOGE("netSupplierInfo is nullptr"); + return ERR_INVALID_PARAMS; + } + + NETMGR_LOGI("Update supplier info: netSupplierInfo[%{public}s]", netSupplierInfo->ToString("").c_str()); + + // According to supplierId, get the supplier from the list + sptr supplier = GetNetSupplierFromListById(supplierId); + if (supplier == nullptr) { + NETMGR_LOGE("supplier is nullptr"); + return ERR_NO_SUPPLIER; + } + + // Call NetSupplier class to update network connection status information + sptr network = GetNetworkFromListBySupplierId(supplier->GetSupplierId()); + if (network == nullptr) { + NETMGR_LOGE("network is nullptr"); + return ERR_NO_NETWORK; + } + network->UpdateNetSupplierInfo(*netSupplierInfo); + + return ERR_NONE; +} + +int32_t NetConnService::UpdateNetCapabilities(uint32_t supplierId, uint64_t netCapabilities) +{ + NETMGR_LOGI("supplierId[%{public}d] netCapabilities[%{public}lld]", supplierId, netCapabilities); + // According to supplierId, get the supplier from the list + sptr supplier = GetNetSupplierFromListById(supplierId); + if (supplier == nullptr) { + NETMGR_LOGE("supplier is nullptr"); + return ERR_NO_SUPPLIER; + } + + // According to netId, get network from the list + sptr network = GetNetworkFromListBySupplierId(supplier->GetSupplierId()); + if (network == nullptr) { + NETMGR_LOGE("network is nullptr"); + return ERR_NO_NETWORK; + } + auto type = supplier->GetNetSupplierType(); + auto ident = supplier->GetNetSupplierIdent(); + // Create or delete network services based on the netCapabilities + if (netCapabilities & NET_CAPABILITIES_INTERNET) { + if (!IsServiceInList(network->GetNetId(), NET_CAPABILITIES_INTERNET)) { + auto service = std::make_unique(ident, type, NET_CAPABILITIES_INTERNET, network).release(); + netServices_.push_back(service); + } + } else { + if (IsServiceInList(network->GetNetId(), NET_CAPABILITIES_INTERNET)) { + DeleteServiceFromListByCap(network->GetNetId(), NET_CAPABILITIES_INTERNET); + } + } + + if (netCapabilities & NET_CAPABILITIES_MMS) { + if (!IsServiceInList(network->GetNetId(), NET_CAPABILITIES_MMS)) { + auto service = std::make_unique(ident, type, NET_CAPABILITIES_MMS, network).release(); + netServices_.push_back(service); + } + } else { + if (IsServiceInList(network->GetNetId(), NET_CAPABILITIES_MMS)) { + DeleteServiceFromListByCap(network->GetNetId(), NET_CAPABILITIES_MMS); + } + } + NETMGR_LOGI("netSupplier_ size[%{public}d], networks_ size[%{public}d], netServices_ size[%{public}d]", + netSupplier_.size(), networks_.size(), netServices_.size()); + return ERR_NONE; +} + +int32_t NetConnService::UpdateNetLinkInfo(uint32_t supplierId, const sptr &netLinkInfo) +{ + NETMGR_LOGI("supplierId[%{public}d]", supplierId); + if (netLinkInfo == nullptr) { + NETMGR_LOGE("netLinkInfo is nullptr"); + return ERR_INVALID_PARAMS; + } + + NETMGR_LOGI("Update netlink info: netLinkInfo[%{public}s]", netLinkInfo->ToString("").c_str()); + // According to supplierId, get the supplier from the list + sptr supplier = GetNetSupplierFromListById(supplierId); + if (supplier == nullptr) { + NETMGR_LOGE("supplier is nullptr"); + return ERR_NO_SUPPLIER; + } + // According to supplier id, get network from the list + sptr network = GetNetworkFromListBySupplierId(supplier->GetSupplierId()); + if (network == nullptr) { + NETMGR_LOGE("network is nullptr"); + return ERR_NO_NETWORK; + } + // Call Network class to update network link attribute information + network->UpdateNetLinkInfo(*netLinkInfo); + return ERR_NONE; +} + +sptr NetConnService::GetNetSupplierFromList( + uint32_t netType, const std::string &ident) +{ + for (auto it = netSupplier_.begin(); it != netSupplier_.end(); ++it) { + auto supplierType = (*it)->GetNetSupplierType(); + auto supplierIdent = (*it)->GetNetSupplierIdent(); + if ((netType == supplierType) && (ident.compare(supplierIdent) == 0)) { + return *it; + } + } + + NETMGR_LOGE("net supplier is nullptr"); + return nullptr; +} + +sptr NetConnService::GetNetSupplierFromListById(uint32_t supplierId) +{ + for (auto it = netSupplier_.begin(); it != netSupplier_.end(); ++it) { + auto id = (*it)->GetSupplierId(); + if (supplierId == id) { + return *it; + } + } + + NETMGR_LOGE("net supplier is nullptr"); + return nullptr; +} + +void NetConnService::DeleteSupplierFromListById(uint32_t supplierId) +{ + for (auto it = netSupplier_.begin(); it != netSupplier_.end(); ++it) { + auto id = (*it)->GetSupplierId(); + if (supplierId == id) { + netSupplier_.erase(it); + return; + } + } +} + +void NetConnService::DeleteNetworkFromListBySupplierId(uint32_t supplierId) +{ + for (auto it = networks_.begin(); it != networks_.end(); ++it) { + sptr netSupplier = (*it)->GetNetSupplier(); + if ((netSupplier != nullptr) && (netSupplier->GetSupplierId() == supplierId)) { + networks_.erase(it); + return; + } + } +} + +sptr NetConnService::GetNetworkFromListBySupplierId(uint32_t supplierId) +{ + for (auto it = networks_.begin(); it != networks_.end(); ++it) { + sptr netSupplier = (*it)->GetNetSupplier(); + if ((netSupplier != nullptr) && (netSupplier->GetSupplierId() == supplierId)) { + return *it; + } + } + + NETMGR_LOGE("network is nullptr"); + return nullptr; +} + +void NetConnService::DeleteServiceFromListByNet(const Network &network) +{ + sptr currNetwork = nullptr; + for (auto it = netServices_.begin(); it != netServices_.end();) { + currNetwork = (*it)->GetNetwork(); + if (currNetwork != nullptr && *currNetwork == network) { + netServices_.erase(it++); + } else { + ++it; + } + } +} + +bool NetConnService::DeleteServiceFromListByCap(int32_t netId, const NetCapabilities &netCapability) +{ + sptr network = nullptr; + for (auto it = netServices_.begin(); it != netServices_.end(); ++it) { + network = (*it)->GetNetwork(); + if (network == nullptr) { + continue; + } + if ((network->GetNetId() == netId) && (netCapability == (*it)->GetNetCapability())) { + netServices_.erase(it); + return true; + } + } + + return false; +} + +bool NetConnService::IsServiceInList(int32_t netId, const NetCapabilities &netCapability) const +{ + sptr network = nullptr; + for (auto it = netServices_.begin(); it != netServices_.end(); ++it) { + network = (*it)->GetNetwork(); + if (network == nullptr) { + continue; + } + if ((network->GetNetId() == netId) && (netCapability == (*it)->GetNetCapability())) { + return true; + } + } + + return false; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/services/netconnmanager/src/net_controller/net_controller_factory.cpp b/services/netconnmanager/src/net_controller/net_controller_factory.cpp new file mode 100755 index 0000000..28bc387 --- /dev/null +++ b/services/netconnmanager/src/net_controller/net_controller_factory.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 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 "net_controller_factory.h" + +#include "net_mgr_log_wrapper.h" +#include "telephony_controller.h" + +namespace OHOS { +namespace NetManagerStandard { +NetControllerFactory::NetControllerFactory() {} +NetControllerFactory::~NetControllerFactory() {} + +sptr NetControllerFactory::MakeNetController(uint32_t netType) +{ + NETMGR_LOGI("make controller netType[%{public}d]", netType); + sptr netController = GetNetControllerFromMap(netType); + if (netController != nullptr) { + return netController; + } + NETMGR_LOGI("factory need create netController"); + + switch (netType) { + case NET_TYPE_CELLULAR: + NETMGR_LOGI("factory create TelephonyController"); + netController = (std::make_unique()).release(); + netControllers.insert(std::make_pair(NET_TYPE_CELLULAR, netController)); + break; + default: + break; + } + + return netController; +} + +sptr NetControllerFactory::GetNetControllerFromMap(uint32_t netType) +{ + auto it = netControllers.find(netType); + if (it != netControllers.end()) { + return it->second; + } + NETMGR_LOGI("INetController* is not found, return null"); + return nullptr; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/netconnmanager/src/net_controller/telephony_controller.cpp b/services/netconnmanager/src/net_controller/telephony_controller.cpp new file mode 100755 index 0000000..74e10b5 --- /dev/null +++ b/services/netconnmanager/src/net_controller/telephony_controller.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "telephony_controller.h" + +#include "cellular_data_client.h" +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +TelephonyController::TelephonyController() {}; + +int32_t TelephonyController::RequestNetwork(const std::string &ident, NetCapabilities netCapabilitiy) +{ + NETMGR_LOGI("Request telephony network."); + return Telephony::CellularDataClient::GetInstance().RequestNet(ident, static_cast(netCapabilitiy)); +} + +int32_t TelephonyController::ReleaseNetwork(const std::string &ident, NetCapabilities netCapabilitiy) +{ + NETMGR_LOGI("Release telephony network."); + return Telephony::CellularDataClient::GetInstance().ReleaseNet(ident, static_cast(netCapabilitiy)); +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/services/netconnmanager/src/net_id_manager.cpp b/services/netconnmanager/src/net_id_manager.cpp new file mode 100755 index 0000000..2fbd55b --- /dev/null +++ b/services/netconnmanager/src/net_id_manager.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 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 "net_id_manager.h" + +namespace OHOS { +namespace NetManagerStandard { +NetIdManager::NetIdManager() {} + +NetIdManager::~NetIdManager() {} + +int32_t NetIdManager::ReserveNetId() +{ + std::lock_guard lck(mtx_); + for (int32_t i = MIN_NET_ID; i <= maxNetId_; ++i) { + if (lastNetId_ < maxNetId_) { + ++lastNetId_; + } else { + lastNetId_ = MIN_NET_ID; + } + if (netIdInUse_.find(lastNetId_) == netIdInUse_.end()) { + netIdInUse_.insert(std::pair(lastNetId_, true)); + break; + } + } + + return lastNetId_; +} + +void NetIdManager::ReleaseNetId(int32_t netId) +{ + std::lock_guard lck(mtx_); + auto it = netIdInUse_.find(netId); + if (it != netIdInUse_.end()) { + netIdInUse_.erase(it); + } +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/netconnmanager/src/net_service.cpp b/services/netconnmanager/src/net_service.cpp new file mode 100755 index 0000000..f88836d --- /dev/null +++ b/services/netconnmanager/src/net_service.cpp @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2021 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 "net_service.h" + +#include "net_conn_types.h" +#include "broadcast_manager.h" +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +NetService::NetService( + const std::string &ident, NetworkType networkType, NetCapabilities netCapability, sptr &network) + : ident_(ident), networkType_(networkType), netCapability_(netCapability), network_(network) +{} + +void NetService::SetIdent(const std::string &ident) +{ + ident_ = ident; +} + +void NetService::SetNetworkType(const NetworkType &networkType) +{ + networkType_ = networkType; +} + +void NetService::SetNetCapability(const NetCapabilities &netCapability) +{ + netCapability_ = netCapability; +} + +void NetService::SetServiceState(const ServiceState &serviceState) +{ + state_ = serviceState; +} + +std::string NetService::GetIdent() const +{ + return ident_; +} + +NetworkType NetService::GetNetworkType() const +{ + return networkType_; +} + +NetCapabilities NetService::GetNetCapability() const +{ + return netCapability_; +} + +ServiceState NetService::GetServiceState() const +{ + return state_; +} + +sptr NetService::GetNetwork() const +{ + return network_; +} + +int32_t NetService::ServiceConnect() +{ + NETMGR_LOGI("service connect"); + if (IsConnecting()) { + NETMGR_LOGI("this service is connecting"); + return ERR_SERVICE_CONNECTING; + } + if (IsConnected()) { + NETMGR_LOGI("this service is already connected"); + return ERR_SERVICE_CONNECTED; + } + + // Filtering is not a custom network service type + switch (networkType_) { + case NET_TYPE_CELLULAR: + break; + case NET_TYPE_UNKNOWN: + default: + NETMGR_LOGE("thWe parameter networkType_[%{public}d] passed in is invalid", networkType_); + return ERR_INVALID_NETORK_TYPE; + } + UpdateServiceState(SERVICE_STATE_IDLE); + + // Call network class to activate the network + if (NetworkConnect() < 0) { + NETMGR_LOGE("this service request network failed"); + + UpdateServiceState(SERVICE_STATE_FAILURE); + NetworkDisConnect(); + UpdateServiceState(SERVICE_STATE_DISCONNECTED); + UpdateServiceState(SERVICE_STATE_IDLE); + return ERR_SERVICE_REQUEST_CONNECT_FAIL; + } + // Update the network status after activating the network successfully + UpdateServiceState(SERVICE_STATE_READY); + NETMGR_LOGI("this service request network is successful"); + + return ERR_SERVICE_REQUEST_SUCCESS; +} + +int32_t NetService::ServiceDisConnect() +{ + NETMGR_LOGI("service disconnect"); + if (state_ == SERVICE_STATE_DISCONNECTING) { + NETMGR_LOGI("this service is disconnecting"); + return ERR_SERVICE_DISCONNECTING; + } + if (state_ == SERVICE_STATE_DISCONNECTED) { + NETMGR_LOGI("this service has been disconnected"); + return ERR_SERVICE_DISCONNECTED_SUCCESS; + } + + UpdateServiceState(SERVICE_STATE_DISCONNECTING); + NETMGR_LOGI("NetworkDisConnect start"); + // Call network class to deactivate the network + if (NetworkDisConnect() < 0) { + NETMGR_LOGE("this service failed to disconnect"); + UpdateServiceState(SERVICE_STATE_FAILURE); + return ERR_SERVICE_DISCONNECTED_FAIL; + } + // Update the network status after deactivating the network successfully + UpdateServiceState(SERVICE_STATE_DISCONNECTED); + UpdateServiceState(SERVICE_STATE_IDLE); + NETMGR_LOGI("this service successfully disconnected"); + + return ERR_SERVICE_DISCONNECTED_SUCCESS; +} + +int32_t NetService::ServiceAutoConnect() +{ + NETMGR_LOGI("service auto connect"); + return ServiceConnect(); +} + +int32_t NetService::NetworkConnect() +{ + int32_t retCode = -1; + + UpdateServiceState(SERVICE_STATE_CONNECTING); + NETMGR_LOGI("execute NetworkConnect()"); + // Call Network class activate the network + if (network_->NetworkConnect(netCapability_)) { + retCode = 0; + } + NETMGR_LOGI("connect is [%{public}s]", (retCode > -1) ? "successfull" : "failed"); + return retCode; +} + +int32_t NetService::NetworkDisConnect() +{ + int32_t retCode = -1; + // Call Network class deactivate the network + if (network_->NetworkDisconnect(netCapability_)) { + retCode = 0; + } + NETMGR_LOGI("disconnect is [%{public}s]", (retCode > -1) ? "successfull" : "failed"); + return retCode; +} + +void NetService::UpdateServiceState(ServiceState serviceState) +{ + switch (serviceState) { + case SERVICE_STATE_IDLE: + case SERVICE_STATE_CONNECTING: + case SERVICE_STATE_READY: + case SERVICE_STATE_CONNECTED: + case SERVICE_STATE_DISCONNECTING: + case SERVICE_STATE_DISCONNECTED: + case SERVICE_STATE_FAILURE: + state_ = serviceState; + break; + case SERVICE_STATE_UNKNOWN: + default: + state_ = SERVICE_STATE_FAILURE; + break; + } + + BroadcastInfo info; + // EventFwk::CommonEventSupport::COMMON_EVENT_NETMANAGER_CONNECTION_STATE_CHANGED + info.action = "usual.event.netmanager.NETMANAGER_CONNECTION_STATE_CHANGED"; + info.data = "Net Manager Connection State Changed"; + info.code = static_cast(serviceState); + info.ordered = true; + std::string netTypeName = std::to_string(static_cast(networkType_)); + std::map param = {{"NetType", netTypeName}}; + DelayedSingleton::GetInstance()->SendBroadcast(info, param); + + sptr netConnCallback = (std::make_unique()).release(); + if (netConnCallback == nullptr) { + NETMGR_LOGE("make_unique() failed"); + return; + } + netConnCallback->netState_ = static_cast(serviceState); + netConnCallback->netType_ = static_cast(networkType_); + NotifyNetConnStateChanged(netConnCallback); + + NETMGR_LOGI("serviceState is [%{public}d]", state_); +} + +bool NetService::IsConnecting() const +{ + bool isConnecting = false; + + switch (state_) { + case SERVICE_STATE_UNKNOWN: + case SERVICE_STATE_FAILURE: + case SERVICE_STATE_IDLE: + isConnecting = network_->IsNetworkConnecting(); + break; + case SERVICE_STATE_CONNECTING: + isConnecting = true; + break; + case SERVICE_STATE_READY: + case SERVICE_STATE_CONNECTED: + case SERVICE_STATE_DISCONNECTING: + case SERVICE_STATE_DISCONNECTED: + default: + break; + } + + NETMGR_LOGI("isConnecting is [%{public}d]", isConnecting); + return isConnecting; +} + +bool NetService::IsConnected() const +{ + bool isConnected = false; + switch (state_) { + case SERVICE_STATE_UNKNOWN: + case SERVICE_STATE_FAILURE: + case SERVICE_STATE_IDLE: + case SERVICE_STATE_CONNECTING: + case SERVICE_STATE_DISCONNECTING: + case SERVICE_STATE_DISCONNECTED: + break; + case SERVICE_STATE_READY: + case SERVICE_STATE_CONNECTED: + isConnected = true; + break; + default: + break; + } + NETMGR_LOGI("isConnected is [%{public}d]", isConnected); + return isConnected; +} + +void NetService::RegisterNetConnCallback(const sptr &callback) +{ + if (callback == nullptr) { + NETMGR_LOGE("The parameter callback is null"); + return; + } + + for (auto iter = netConnCallback_.begin(); iter != netConnCallback_.end(); ++iter) { + if (callback->AsObject().GetRefPtr() == (*iter)->AsObject().GetRefPtr()) { + NETMGR_LOGI("netConnCallback_ had this callback"); + return; + } + } + netConnCallback_.emplace_back(callback); +} + +int32_t NetService::UnregisterNetConnCallback(const sptr &callback) +{ + if (callback == nullptr) { + NETMGR_LOGE("The parameter of callback is null"); + return ERR_SERVICE_NULL_PTR; + } + + for (auto iter = netConnCallback_.begin(); iter != netConnCallback_.end(); ++iter) { + if (callback->AsObject().GetRefPtr() == (*iter)->AsObject().GetRefPtr()) { + netConnCallback_.erase(iter); + return ERR_NONE; + } + } + + return ERR_NO_REGISTERED; +} + +int32_t NetService::NotifyNetConnStateChanged(const sptr &info) +{ + for (const auto &callback : netConnCallback_) { + callback->NetConnStateChanged(info); + } + + return ERR_NONE; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/services/netconnmanager/src/net_supplier.cpp b/services/netconnmanager/src/net_supplier.cpp new file mode 100755 index 0000000..1c7d9bb --- /dev/null +++ b/services/netconnmanager/src/net_supplier.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2021 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 "net_supplier.h" + +#include + +#include "net_controller_factory.h" +#include "net_service.h" +#include "net_mgr_log_wrapper.h" +#include "telephony_controller.h" + +namespace OHOS { +namespace NetManagerStandard { +static std::atomic g_nextNetSupplierId = 0x03EB; + +NetSupplier::NetSupplier(NetworkType netSupplierType, const std::string &netSupplierIdent) +{ + sptr netController = + DelayedSingleton::GetInstance().get()->MakeNetController(netSupplierType); + if (netController != nullptr) { + netController_ = netController; + } + netSupplierType_ = netSupplierType; + netSupplierIdent_ = netSupplierIdent; + supplierId_ = g_nextNetSupplierId++; +} + +bool NetSupplier::operator==(const NetSupplier &netSupplier) const +{ + return supplierId_ == netSupplier.supplierId_ && + netSupplierType_ == netSupplier.netSupplierType_ && + netSupplierIdent_ == netSupplier.netSupplierIdent_; +} + +NetworkType NetSupplier::GetNetSupplierType() const +{ + return netSupplierType_; +} + +std::string NetSupplier::GetNetSupplierIdent() const +{ + return netSupplierIdent_; +} + +bool NetSupplier::SupplierConnection(NetCapabilities netCapabilities) +{ + NETMGR_LOGI("param ident[%{public}s] netCapabilities[%{public}lld]", netSupplierIdent_.c_str(), + static_cast(netCapabilities)); + if (netController_ == nullptr) { + NETMGR_LOGE("netController_ is nullptr"); + return false; + } + NETMGR_LOGI("execute RequestNetwork"); + int32_t errCode = netController_->RequestNetwork(netSupplierIdent_, netCapabilities); + NETMGR_LOGI("RequestNetwork errCode[%{public}d]", errCode); + if (errCode == REG_OK) { + connected_ = true; + return true; + } + + return false; +} + +bool NetSupplier::SupplierDisconnection(NetCapabilities netCapabilities) +{ + NETMGR_LOGI("param ident_[%{public}s] netCapabilities[%{public}lld]", netSupplierIdent_.c_str(), + static_cast(netCapabilities)); + if (netController_ == nullptr) { + NETMGR_LOGE("netController_ is nullptr"); + return false; + } + NETMGR_LOGI("execute ReleaseNetwork"); + int32_t errCode = netController_->ReleaseNetwork(netSupplierIdent_, netCapabilities); + NETMGR_LOGI("ReleaseNetwork errCode[%{public}d]", errCode); + if (errCode == REG_OK) { + connected_ = false; + return true; + } + return false; +} + +void NetSupplier::UpdateNetSupplierInfo(const NetSupplierInfo &netSupplierInfo) +{ + isAvailable_ = netSupplierInfo.isAvailable_; + isRoaming_ = netSupplierInfo.isRoaming_; + strength_ = netSupplierInfo.strength_; + frequency_ = netSupplierInfo.frequency_; + NETMGR_LOGI( + "isAvailable_[%{public}d] isRoaming_[%{public}d] strength_[%{public}d] " + "frequency_[%{public}d]", + isAvailable_, isRoaming_, strength_, frequency_); +} + +uint32_t NetSupplier::GetSupplierId() const +{ + return supplierId_; +} + +bool NetSupplier::GetConnected() const +{ + return connected_; +} + +bool NetSupplier::GetAvailable() const +{ + return isAvailable_; +} + +bool NetSupplier::GetRoaming() const +{ + return isRoaming_; +} + +bool NetSupplier::GetStrength() const +{ + return strength_; +} + +bool NetSupplier::GetFrequency() const +{ + return frequency_; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/netconnmanager/src/network.cpp b/services/netconnmanager/src/network.cpp new file mode 100755 index 0000000..a908604 --- /dev/null +++ b/services/netconnmanager/src/network.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2021 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 "network.h" + +#include "net_id_manager.h" +#include "netd_controller.h" +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +Network::Network(sptr &supplier) : supplier_(supplier) +{ + netId_ = DelayedSingleton::GetInstance()->ReserveNetId(); + NetdController::GetInstance()->CreateNetworkCache(netId_); +} + +Network::~Network() +{ + NetdController::GetInstance()->DestoryNetworkCache(netId_); +} + +bool Network::operator==(const Network &network) const +{ + return (supplier_ != nullptr && network.supplier_ != nullptr) && + *supplier_ == *(network.supplier_) && + netId_ == network.netId_; +} + +bool Network::NetworkConnect(const NetCapabilities &netCapability) +{ + NETMGR_LOGI("supplier is connecting"); + if (isConnected_) { + NETMGR_LOGI("supplier is connected"); + return true; + } + + // Call NetSupplier class to activate the network + NETMGR_LOGI("SupplierDisconnection processing"); + bool ret = supplier_->SupplierDisconnection(netCapability); + if (!ret) { + NETMGR_LOGE("connect failed"); + return ret; + } + + isConnecting_ = true; + isConnected_ = true; + return ret; +} + +bool Network::NetworkDisconnect(const NetCapabilities &netCapability) +{ + NETMGR_LOGI("supplier is disConnecting"); + if (!isConnecting_ && !isConnected_) { + NETMGR_LOGI("no connecting or connected"); + return false; + } + + // Call NetSupplier class to deactivate the network + NETMGR_LOGI("SupplierDisconnection processing"); + bool ret = supplier_->SupplierDisconnection(netCapability); + if (!ret) { + NETMGR_LOGE("disconnect failed"); + } + + return ret; +} + +bool Network::UpdateNetLinkInfo(const NetLinkInfo &netLinkInfo) +{ + NETMGR_LOGI("update net link information process"); + UpdateInterfaces(netLinkInfo); + UpdateRoutes(netLinkInfo); + UpdateDnses(netLinkInfo); + updateMtu(netLinkInfo); + netLinkInfo_ = netLinkInfo; + return true; +} + +int32_t Network::GetNetId() const +{ + return netId_; +} + +void Network::SetIpAdress(const INetAddr &ipAdress) +{ + ipAddr_ = ipAdress; +} + +void Network::SetDns(const INetAddr &dns) +{ + dns_ = dns; +} + +void Network::SetRoute(const Route &route) +{ + route_ = route; +} + +NetLinkInfo Network::GetNetLinkInfo() const +{ + return netLinkInfo_; +} + +INetAddr Network::GetIpAdress() const +{ + return ipAddr_; +} + +INetAddr Network::GetDns() const +{ + return dns_; +} + +Route Network::GetRoute() const +{ + return route_; +} + +sptr Network::GetNetSupplier() const +{ + return supplier_; +} + +bool Network::UpdateNetSupplierInfo(const NetSupplierInfo &netSupplierInfo) +{ + NETMGR_LOGI("process strart"); + supplier_->UpdateNetSupplierInfo(netSupplierInfo); + + if (!isPhyNetCreated_) { + std::string permission; + // Create a physical network + NetdController::GetInstance()->NetworkCreatePhysical(netId_, 0); + isPhyNetCreated_ = true; + } + return true; +} + +bool Network::IsNetworkConnecting() const +{ + return isConnecting_; +} + +void Network::SetConnected(bool connected) +{ + isConnected_ = connected; +} + +void Network::SetConnecting(bool connecting) +{ + isConnecting_ = connecting; +} + +void Network::UpdateInterfaces(const NetLinkInfo &netLinkInfo) +{ + if (netLinkInfo.ifaceName_ == netLinkInfo_.ifaceName_) { + return; + } + + // Call netd to add and remove interface + if (!netLinkInfo.ifaceName_.empty()) { + NetdController::GetInstance()->NetworkAddInterface(netId_, netLinkInfo.ifaceName_); + } + if (!netLinkInfo_.ifaceName_.empty()) { + NetdController::GetInstance()->NetworkRemoveInterface(netId_, netLinkInfo_.ifaceName_); + } +} + +void Network::UpdateRoutes(const NetLinkInfo &netLinkInfo) +{ + for (auto it = netLinkInfo.routeList_.begin(); it != netLinkInfo.routeList_.end(); ++it) { + const struct Route &route = *it; + if (std::find(netLinkInfo_.routeList_.begin(), netLinkInfo_.routeList_.end(), *it) == + netLinkInfo_.routeList_.end()) { + NetdController::GetInstance()->NetworkAddRoute( + netId_, route.iface_, route.destination_.address_, route.gateway_.address_); + } + } + + for (auto it = netLinkInfo_.routeList_.begin(); it != netLinkInfo_.routeList_.end(); ++it) { + const struct Route &route = *it; + if (std::find(netLinkInfo.routeList_.begin(), netLinkInfo.routeList_.end(), *it) == + netLinkInfo.routeList_.end()) { + NetdController::GetInstance()->NetworkRemoveRoute( + netId_, route.iface_, route.destination_.address_, route.gateway_.address_); + } + } +} + +void Network::UpdateDnses(const NetLinkInfo &netLinkInfo) +{ + std::vector servers; + std::vector doamains; + for (auto it = netLinkInfo.dnsList_.begin(); it != netLinkInfo.dnsList_.end(); ++it) { + auto dns = *it; + servers.push_back(dns.address_); + doamains.push_back(dns.hostName_); + } + // Call netd to set dns + NetdController::GetInstance()->SetResolverConfig(netId_, 0, 1, servers, doamains); +} + +void Network::updateMtu(const NetLinkInfo &netLinkInfo) +{ + if (netLinkInfo.mtu_ == netLinkInfo_.mtu_) { + return; + } + + NetdController::GetInstance()->InterfaceSetMtu(netLinkInfo.ifaceName_, netLinkInfo.mtu_); +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/services/netconnmanager/test/BUILD.gn b/services/netconnmanager/test/BUILD.gn new file mode 100755 index 0000000..3ec7832 --- /dev/null +++ b/services/netconnmanager/test/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright (c) 2021 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/test.gni") + +group("unittest") { + testonly = true + deps = [] + deps += [ "unittest/net_conn_manager_test:unittest" ] +} diff --git a/services/netconnmanager/test/mock/BUILD.gn b/services/netconnmanager/test/mock/BUILD.gn new file mode 100755 index 0000000..801a9b0 --- /dev/null +++ b/services/netconnmanager/test/mock/BUILD.gn @@ -0,0 +1,13 @@ +# Copyright (c) 2021 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. + diff --git a/services/netconnmanager/test/unittest/net_conn_manager_test/BUILD.gn b/services/netconnmanager/test/unittest/net_conn_manager_test/BUILD.gn new file mode 100755 index 0000000..4e39299 --- /dev/null +++ b/services/netconnmanager/test/unittest/net_conn_manager_test/BUILD.gn @@ -0,0 +1,70 @@ +# Copyright (c) 2021 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/test.gni") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +SUBSYSTEM_DIR = "//foundation/communication" +NETMANAGER_BASE_ROOT = "$SUBSYSTEM_DIR/netmanager_standard" +INNERKITS_ROOT = "$NETMANAGER_BASE_ROOT/interfaces/innerkits" +NETCONNMANAGER_SOURCE_DIR = "$NETMANAGER_BASE_ROOT/services/netconnmanager" + +ohos_unittest("net_conn_manager_test") { + module_out_path = "netmanager_base/net_conn_manager_test" + + sources = [ + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/ipc/net_conn_callback_stub.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/ipc/net_conn_service_proxy.cpp", + "net_conn_callback_test.cpp", + "net_conn_manager_test.cpp", + ] + + include_dirs = [ + "$INNERKITS_ROOT/native/netconnmanager/include", + "$INNERKITS_ROOT/native/netconnmanager/include/ipc", + "$NETCONNMANAGER_SOURCE_DIR/include/ipc", + "$NETCONNMANAGER_SOURCE_DIR/include", + ] + + deps = [ + "$INNERKITS_ROOT/native/netconnmanager:net_conn_manager_if", + "$NETCONNMANAGER_SOURCE_DIR:net_conn_manager", + "$NETMANAGER_BASE_ROOT/utils:net_manager_common", + ] + + external_deps = [ "ipc:ipc_core" ] + + defines = [ + "NETMGR_LOG_TAG = \"NetConnManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (enable_netmgr_debug) { + defines += [ "NETMGR_DEBUG" ] + } + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netmanager_standard" + subsystem_name = "communication" +} + +group("unittest") { + testonly = true + deps = [ ":net_conn_manager_test" ] +} diff --git a/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_callback_test.cpp b/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_callback_test.cpp new file mode 100755 index 0000000..10f6d66 --- /dev/null +++ b/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_callback_test.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 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 "net_conn_callback_test.h" + +#include + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +NetConnCallbackTest::NetConnCallbackTest() {} + +NetConnCallbackTest::~NetConnCallbackTest() {} + +void NetConnCallbackTest::NotifyAll() +{ + std::unique_lock callbackLock(callbackMutex_); + cv_.notify_all(); +} + +void NetConnCallbackTest::WaitFor(int timeoutSecond) +{ + std::unique_lock callbackLock(callbackMutex_); + cv_.wait_for(callbackLock, std::chrono::seconds(timeoutSecond)); +} + +int32_t NetConnCallbackTest::NetConnStateChanged(const sptr &info) +{ + if (info == nullptr) { + NETMGR_LOGI("NetConnCallbackTest::NetConnStateChanged(), info is nullptr"); + return -1; + } + + NETMGR_LOGI("NetConnCallbackTest::NetConnStateChanged(), netState_:[%{public}d], netType_:[%{public}d]", + info->netState_, info->netType_); + + netState_ = info->netState_; + NotifyAll(); + + return 0; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_callback_test.h b/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_callback_test.h new file mode 100755 index 0000000..98da266 --- /dev/null +++ b/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_callback_test.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 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 NET_CONN_CALLBACK_TEST_H +#define NET_CONN_CALLBACK_TEST_H + +#include +#include + +#include "net_conn_callback_stub.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetConnCallbackTest : public NetConnCallbackStub { +public: + NetConnCallbackTest(); + virtual ~NetConnCallbackTest() override; + int32_t NetConnStateChanged(const sptr &info) override; + + void WaitFor(int timeoutSecond); + + int GetNetState() const + { + return netState_; + } + +private: + void NotifyAll(); + int32_t netState_ = 0; + std::mutex callbackMutex_; + std::condition_variable cv_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONN_CALLBACK_TEST_H diff --git a/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_manager_test.cpp b/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_manager_test.cpp new file mode 100755 index 0000000..0aa631e --- /dev/null +++ b/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_manager_test.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2021 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 "net_conn_client.h" +#include "net_conn_types.h" +#include "net_conn_callback_test.h" +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +constexpr int WAIT_TIME_SECOND_LONG = 60; +using namespace testing::ext; +class NetConnManagerTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + sptr GetUpdateLinkInfoSample() const; + + sptr GetINetConnCallbackSample() const; +}; + +void NetConnManagerTest::SetUpTestCase() {} + +void NetConnManagerTest::TearDownTestCase() {} + +void NetConnManagerTest::SetUp() {} + +void NetConnManagerTest::TearDown() {} + +sptr NetConnManagerTest::GetUpdateLinkInfoSample() const +{ + sptr netLinkInfo = (std::make_unique()).release(); + netLinkInfo->ifaceName_ = "test"; + netLinkInfo->domain_ = "test"; + + sptr netAddr = (std::make_unique()).release(); + netAddr->type_ = INetAddr::IPV4; + netAddr->family_ = 0x10; + netAddr->prefixlen_ = 0x17; + netAddr->address_ = "192.168.2.0"; + netAddr->netMask_ = "192.255.255.255"; + netAddr->hostName_ = "netAddr"; + netLinkInfo->netAddrList_.push_back(*netAddr); + + sptr dns = (std::make_unique()).release(); + dns->type_ = INetAddr::IPV4; + dns->family_ = 0x10; + dns->prefixlen_ = 0x17; + dns->address_ = "192.168.2.0"; + dns->netMask_ = "192.255.255.255"; + dns->hostName_ = "netAddr"; + netLinkInfo->dnsList_.push_back(*dns); + + sptr route = (std::make_unique()).release(); + route->iface_ = "iface0"; + route->destination_.type_ = INetAddr::IPV4; + route->destination_.family_ = 0x10; + route->destination_.prefixlen_ = 0x17; + route->destination_.address_ = "192.168.2.0"; + route->destination_.netMask_ = "192.255.255.255"; + route->destination_.hostName_ = "netAddr"; + route->gateway_.type_ = INetAddr::IPV4; + route->gateway_.family_ = 0x10; + route->gateway_.prefixlen_ = 0x17; + route->gateway_.address_ = "192.168.2.0"; + route->gateway_.netMask_ = "192.255.255.255"; + route->gateway_.hostName_ = "netAddr"; + netLinkInfo->routeList_.push_back(*route); + + netLinkInfo->mtu_ = 0x5DC; + + return netLinkInfo; +} + +sptr NetConnManagerTest::GetINetConnCallbackSample() const +{ + sptr callback = (std::make_unique()).release(); + return callback; +} + +/** + * @tc.name: NetConnManager001 + * @tc.desc: Test NetConnManager SystemReady. + * @tc.type: FUNC + */ +HWTEST_F(NetConnManagerTest, NetConnManager001, TestSize.Level1) +{ + int32_t result = DelayedSingleton::GetInstance()->SystemReady(); + ASSERT_TRUE(result == 0); +} + +/** + * @tc.name: NetConnManager002 + * @tc.desc: Test NetConnManager RegisterNetSupplier. + * @tc.type: FUNC + */ +HWTEST_F(NetConnManagerTest, NetConnManager002, TestSize.Level1) +{ + uint64_t netCapabilities = 0x00; + netCapabilities |= NET_CAPABILITIES_INTERNET; + netCapabilities |= NET_CAPABILITIES_MMS; + + std::string ident = "ident01"; + int32_t result = DelayedSingleton::GetInstance()->RegisterNetSupplier(NET_TYPE_CELLULAR, ident, + netCapabilities); + ASSERT_TRUE(result >= ERR_NONE); +} + +/** + * @tc.name: NetConnManager003 + * @tc.desc: Test NetConnManager UnregisterNetSupplier. + * @tc.type: FUNC + */ +HWTEST_F(NetConnManagerTest, NetConnManager003, TestSize.Level1) +{ + uint64_t netCapabilities = 0x01; + netCapabilities |= NET_CAPABILITIES_INTERNET; + netCapabilities |= NET_CAPABILITIES_MMS; + + std::string ident = "ident02"; + int32_t resSupplierId = DelayedSingleton::GetInstance()->RegisterNetSupplier(NET_TYPE_CELLULAR, + ident, netCapabilities); + ASSERT_TRUE(resSupplierId >= ERR_NONE); + + int32_t result = DelayedSingleton::GetInstance()->UnregisterNetSupplier(resSupplierId); + ASSERT_TRUE(result == ERR_NONE); +} + +/** + * @tc.name: NetConnManager004 + * @tc.desc: Test NetConnManager UpdateNetSupplierInfo. + * @tc.type: FUNC + */ + +HWTEST_F(NetConnManagerTest, NetConnManager004, TestSize.Level1) +{ + uint64_t netCapabilities = 0x02; + netCapabilities |= NET_CAPABILITIES_INTERNET; + netCapabilities |= NET_CAPABILITIES_MMS; + + std::string ident = "ident03"; + int32_t resSupplierId = DelayedSingleton::GetInstance()->RegisterNetSupplier(NET_TYPE_CELLULAR, + ident, netCapabilities); + ASSERT_TRUE(resSupplierId >= ERR_NONE); + + sptr netSupplierInfo = new NetSupplierInfo; + netSupplierInfo->isAvailable_ = true; + netSupplierInfo->isRoaming_ = true; + netSupplierInfo->strength_ = 0x64; + netSupplierInfo->frequency_ = 0x10; + int32_t result = DelayedSingleton::GetInstance()->UpdateNetSupplierInfo(resSupplierId, + netSupplierInfo); + ASSERT_TRUE(result == ERR_NONE); +} + +/** + * @tc.name: NetConnManager005 + * @tc.desc: Test NetConnManager UpdateNetLinkInfo. + * @tc.type: FUNC + */ +HWTEST_F(NetConnManagerTest, NetConnManager005, TestSize.Level1) +{ + uint64_t netCapabilities = 0x03; + netCapabilities |= NET_CAPABILITIES_INTERNET; + netCapabilities |= NET_CAPABILITIES_MMS; + + std::string ident = "ident04"; + int32_t resSupplierId = DelayedSingleton::GetInstance()->RegisterNetSupplier(NET_TYPE_CELLULAR, + ident, netCapabilities); + ASSERT_TRUE(resSupplierId >= ERR_NONE); + + sptr netLinkInfo = GetUpdateLinkInfoSample(); + int32_t result = DelayedSingleton::GetInstance()->UpdateNetLinkInfo(resSupplierId, netLinkInfo); + ASSERT_TRUE(result == ERR_NONE); +} + +/** + * @tc.name: NetConnManager006 + * @tc.desc: Test NetConnManager RegisterNetConnCallback. + * @tc.type: FUNC + */ +HWTEST_F(NetConnManagerTest, NetConnManager006, TestSize.Level1) +{ + uint64_t netCapabilities = 0x02; + netCapabilities |= NET_CAPABILITIES_INTERNET; + + std::string ident = "ident"; + int32_t resSupplierId = DelayedSingleton::GetInstance()->RegisterNetSupplier(NET_TYPE_CELLULAR, + ident, netCapabilities); + ASSERT_TRUE(resSupplierId >= ERR_NONE); + + sptr callback = GetINetConnCallbackSample(); + int32_t result = DelayedSingleton::GetInstance()->RegisterNetConnCallback(callback); + if (result == ERR_NONE) { + callback->WaitFor(WAIT_TIME_SECOND_LONG); + int32_t netState = callback->GetNetState(); + std::cout << "NetConnManager006 RegisterNetConnCallback netState:" << netState << std::endl; + ASSERT_GT(netState, 0); // > + } else { + std::cout << "NetConnManager006 RegisterNetConnCallback return fail" << std::endl; + } + + result = DelayedSingleton::GetInstance()->UnregisterNetConnCallback(callback); + ASSERT_TRUE(result == ERR_NONE); +} + +/** + * @tc.name: NetConnManager007 + * @tc.desc: Test NetConnManager RegisterNetConnCallback. + * @tc.type: FUNC + */ +HWTEST_F(NetConnManagerTest, NetConnManager007, TestSize.Level1) +{ + uint64_t netCapabilities = 0x02; + netCapabilities |= NET_CAPABILITIES_INTERNET; + + std::string ident = "ident"; + int32_t resSupplierId = DelayedSingleton::GetInstance()->RegisterNetSupplier(NET_TYPE_CELLULAR, + ident, netCapabilities); + ASSERT_TRUE(resSupplierId >= ERR_NONE); + + sptr netSpecifier = (std::make_unique()).release(); + netSpecifier->ident_ = "ident"; + netSpecifier->netType_ = NET_TYPE_CELLULAR; + netSpecifier->netCapabilities_ = NET_CAPABILITIES_INTERNET; + + sptr callback = GetINetConnCallbackSample(); + int32_t result = DelayedSingleton::GetInstance()->RegisterNetConnCallback(netSpecifier, callback); + if (result == ERR_NONE) { + callback->WaitFor(WAIT_TIME_SECOND_LONG); + int32_t netState = callback->GetNetState(); + std::cout << "NetConnManager007 RegisterNetConnCallback netState:" << netState << std::endl; + ASSERT_GT(netState, 0); // > + } else { + std::cout << "NetConnManager007 RegisterNetConnCallback return fail" << std::endl; + } + + result = DelayedSingleton::GetInstance()->UnregisterNetConnCallback(netSpecifier, callback); + ASSERT_TRUE(result == ERR_NONE); +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/services/netpolicymanager/BUILD.gn b/services/netpolicymanager/BUILD.gn new file mode 100755 index 0000000..5654d2a --- /dev/null +++ b/services/netpolicymanager/BUILD.gn @@ -0,0 +1,69 @@ +# Copyright (c) 2021 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") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +ohos_shared_library("net_policy_manager") { + sources = [ + "$NETCONNMANAGER_COMMON_DIR/src/netd_controller.cpp", + "$NETPOLICYMANAGER_SOURCE_DIR/src/ipc/net_policy_service_stub.cpp", + "$NETPOLICYMANAGER_SOURCE_DIR/src/net_policy_file.cpp", + "$NETPOLICYMANAGER_SOURCE_DIR/src/net_policy_service.cpp", + "$NETPOLICYMANAGER_SOURCE_DIR/src/net_policy_traffic.cpp", + ] + + include_dirs = [ + "$NETPOLICYMANAGER_SOURCE_DIR/include", + "$NETPOLICYMANAGER_SOURCE_DIR/include/ipc", + "$NETCONNMANAGER_SOURCE_DIR/include/net_controller", + "$INNERKITS_ROOT/native/netpolicymanager/include", + "$INNERKITS_ROOT/native/netconnmanager/include", + "$NETCONNMANAGER_COMMON_DIR/include", + "$NETCONNMANAGER_SOURCE_DIR/include", + ] + + deps = [ + "$NETCONNMANAGER_SOURCE_DIR:net_conn_manager", + "$NETMANAGER_BASE_ROOT/utils:net_manager_common", + "$NETMANAGER_PREBUILTS_DIR/librarys/netd:libnet_manager_native", + "//third_party/jsoncpp:jsoncpp", + "//utils/native/base:utils", + ] + + external_deps = [ + "ipc:ipc_core", + "safwk:system_ability_fwk", + ] + + defines = [ + "NETMGR_LOG_TAG = \"NetPolicyManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + defines += [ "NATIVE_NETD_FEATURE" ] + + if (enable_netmgr_debug) { + defines += [ "NETMGR_DEBUG" ] + } + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/services/netpolicymanager/include/ipc/i_net_policy_service.h b/services/netpolicymanager/include/ipc/i_net_policy_service.h new file mode 100755 index 0000000..43213b7 --- /dev/null +++ b/services/netpolicymanager/include/ipc/i_net_policy_service.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 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 I_NET_POLICY_SERVICE_H +#define I_NET_POLICY_SERVICE_H + +#include "iremote_broker.h" +#include "net_policy_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +class INetPolicyService : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.NetManagerStandard.INetPolicyService"); + enum { + CMD_NSM_START = 0, + CMD_NSM_SET_UID_POLICY = 1, + CMD_NSM_GET_UID_POLICY = 2, + CMD_NSM_GET_UIDS = 3, + CMD_NSM_IS_NET_ACCESS_METERED = 4, + CMD_NSM_IS_NET_ACCESS_IFACENAME = 5, + CMD_NSM_END = 100, + }; + +public: + virtual NetPolicyResultCode SetUidPolicy(uint32_t uid, NetUidPolicy policy) = 0; + virtual NetUidPolicy GetUidPolicy(uint32_t uid) = 0; + virtual std::vector GetUids(NetUidPolicy policy) = 0; + virtual bool IsUidNetAccess(uint32_t uid, bool metered) = 0; + virtual bool IsUidNetAccess(uint32_t uid, const std::string &ifaceName) = 0; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // I_NET_POLICY_SERVICE_H diff --git a/services/netpolicymanager/include/ipc/net_policy_service_proxy.h b/services/netpolicymanager/include/ipc/net_policy_service_proxy.h new file mode 100755 index 0000000..55b5785 --- /dev/null +++ b/services/netpolicymanager/include/ipc/net_policy_service_proxy.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 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 NET_POLICY_SERVICE_PROXY_H +#define NET_POLICY_SERVICE_PROXY_H + +#include "iremote_proxy.h" + +#include "i_net_policy_service.h" +#include "net_policy_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetPolicyServiceProxy : public IRemoteProxy { +public: + explicit NetPolicyServiceProxy(const sptr &impl); + virtual ~NetPolicyServiceProxy(); + NetPolicyResultCode SetUidPolicy(uint32_t uid, NetUidPolicy policy) override; + NetUidPolicy GetUidPolicy(uint32_t uid) override; + std::vector GetUids(NetUidPolicy policy) override; + bool IsUidNetAccess(uint32_t uid, bool metered) override; + bool IsUidNetAccess(uint32_t uid, const std::string &ifaceName) override; + +private: + bool WriteInterfaceToken(MessageParcel &data); + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_POLICY_SERVICE_PROXY_H diff --git a/services/netpolicymanager/include/ipc/net_policy_service_stub.h b/services/netpolicymanager/include/ipc/net_policy_service_stub.h new file mode 100755 index 0000000..7e3f246 --- /dev/null +++ b/services/netpolicymanager/include/ipc/net_policy_service_stub.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 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 NET_POLICY_SERVICE_STUB_H +#define NET_POLICY_SERVICE_STUB_H + +#include + +#include "iremote_stub.h" + +#include "i_net_policy_service.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetPolicyServiceStub : public IRemoteStub { +public: + NetPolicyServiceStub(); + ~NetPolicyServiceStub(); + + int32_t OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + using NetPolicyServiceFunc = int32_t (NetPolicyServiceStub::*)(MessageParcel &, MessageParcel &); + +private: + int32_t OnSetUidPolicy(MessageParcel &data, MessageParcel &reply); + int32_t OnGetUidPolicy(MessageParcel &data, MessageParcel &reply); + int32_t OnGetUids(MessageParcel &data, MessageParcel &reply); + int32_t OnIsUidNetAccessMetered(MessageParcel &data, MessageParcel &reply); + int32_t OnIsUidNetAccessIfaceName(MessageParcel &data, MessageParcel &reply); + +private: + std::map memberFuncMap_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_POLICY_SERVICE_STUB_H diff --git a/services/netpolicymanager/include/net_policy_define.h b/services/netpolicymanager/include/net_policy_define.h new file mode 100755 index 0000000..1882f29 --- /dev/null +++ b/services/netpolicymanager/include/net_policy_define.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 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 NET_POLICY_DEFINE_H +#define NET_POLICY_DEFINE_H + +namespace OHOS { +namespace NetManagerStandard { +const mode_t CHOWN_RWX_USR_GRP = 0770; +const char POLICY_FILE_NAME[] = "/data/system/net_policy.json"; +const char CONFIG_HOS_VERSION[] = "hosVersion"; +const char CONFIG_UID_POLICY[] = "uidPolicy"; +const char CONFIG_UID[] = "uid"; +const char CONFIG_POLICY[] = "policy"; +const char HOS_VERSION[] = "1.0"; +const int32_t CONVERT_LENGTH_TEN = 10; + +/* network allow policy mask */ +const uint32_t NET_POLICY_ALLOW_MASK = 0b00100011; + +struct UidPolicy { + std::string uid; + std::string policy; +}; + +struct NetPolicy { + std::vector uidPolicys; + std::string hosVersion; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_POLICY_DEFINE_H \ No newline at end of file diff --git a/services/netpolicymanager/include/net_policy_file.h b/services/netpolicymanager/include/net_policy_file.h new file mode 100755 index 0000000..03e222a --- /dev/null +++ b/services/netpolicymanager/include/net_policy_file.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021 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 NET_POLICY_FILE_H +#define NET_POLICY_FILE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "refbase.h" + +#include "net_policy_constants.h" +#include "net_policy_define.h" + +namespace OHOS { +namespace NetManagerStandard { +enum class NetUidPolicyOpType { + NET_POLICY_UID_OP_TYPE_ADD = 1, + NET_POLICY_UID_OP_TYPE_DELETE = 2, + NET_POLICY_UID_OP_TYPE_UPDATE = 3, +}; + +class NetPolicyFile : public virtual RefBase { +public: + bool InitPolicy(); + bool IsUidPolicyExist(uint32_t uid); + bool ReadFile(const std::string& fileName, std::string& content); + bool Json2Obj(const std::string& content, NetPolicy& netPolicy); + bool WriteFile(const std::string& fileName); + bool WriteFile(const NetUidPolicyOpType netUidPolicyOpType, uint32_t uid, NetUidPolicy policy); + NetUidPolicy GetUidPolicy(uint32_t uid); + bool GetUids(NetUidPolicy policy, std::vector &uids); + +private: + bool FileExists(const std::string& fileName); + bool CreateFile(const std::string& fileName); + +private: + NetPolicy netPolicy_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_POLICY_FILE_H + diff --git a/services/netpolicymanager/include/net_policy_service.h b/services/netpolicymanager/include/net_policy_service.h new file mode 100755 index 0000000..45a6505 --- /dev/null +++ b/services/netpolicymanager/include/net_policy_service.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021 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 NET_POLICY_SERVICE_H +#define NET_POLICY_SERVICE_H + +#include +#include "singleton.h" +#include "system_ability.h" + +#include "net_policy_traffic.h" + +#include "ipc/net_policy_service_stub.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetPolicyService : public SystemAbility, + public NetPolicyServiceStub, + public std::enable_shared_from_this { + DECLARE_DELAYED_SINGLETON(NetPolicyService) + DECLARE_SYSTEM_ABILITY(NetPolicyService) + +public: + void OnStart() override; + void OnStop() override; + /** + * @brief The interface is set uid policy + * + * @param uid uid + * @param policy policy + * + * @return Returns 0 success, otherwise fail + */ + NetPolicyResultCode SetUidPolicy(uint32_t uid, NetUidPolicy policy) override; + NetUidPolicy GetUidPolicy(uint32_t uid) override; + std::vector GetUids(NetUidPolicy policy) override; + bool IsUidNetAccess(uint32_t uid, bool metered) override; + bool IsUidNetAccess(uint32_t uid, const std::string &ifaceName) override; + +private: + bool Init(); + +private: + enum ServiceRunningState { + STATE_STOPPED = 0, + STATE_RUNNING, + }; + + sptr netPolicyTraffic_; + sptr netPolicyFile_; + bool registerToService_; + ServiceRunningState state_; + std::mutex mutex_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_POLICY_SERVICE_H diff --git a/services/netpolicymanager/include/net_policy_traffic.h b/services/netpolicymanager/include/net_policy_traffic.h new file mode 100755 index 0000000..5cf28c1 --- /dev/null +++ b/services/netpolicymanager/include/net_policy_traffic.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 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 NET_POLICY_TRAFFIC_H +#define NET_POLICY_TRAFFIC_H + +#include "singleton.h" +#include "system_ability.h" + +#include "ipc/net_policy_service_stub.h" +#include "net_policy_file.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetPolicyTraffic : public virtual RefBase { +public: + NetPolicyTraffic(sptr netPolicyFile); + bool IsUidPolicyExist(uint32_t uid); + NetPolicyResultCode AddUidPolicy(uint32_t uid, NetUidPolicy policy); + NetPolicyResultCode SetUidPolicy(uint32_t uid, NetUidPolicy policy); + NetPolicyResultCode DeleteUidPolicy(uint32_t uid, NetUidPolicy policy); + bool IsPolicyValid(NetUidPolicy &policy); + +private: + sptr netPolicyFile_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_POLICY_TRAFFIC_H diff --git a/services/netpolicymanager/src/ipc/net_policy_service_proxy.cpp b/services/netpolicymanager/src/ipc/net_policy_service_proxy.cpp new file mode 100755 index 0000000..de12d42 --- /dev/null +++ b/services/netpolicymanager/src/ipc/net_policy_service_proxy.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2021 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 "net_policy_service_proxy.h" + +#include "net_policy_constants.h" +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +NetPolicyServiceProxy::NetPolicyServiceProxy(const sptr &impl) + : IRemoteProxy(impl) +{} + +NetPolicyServiceProxy::~NetPolicyServiceProxy() {} + +NetPolicyResultCode NetPolicyServiceProxy::SetUidPolicy(uint32_t uid, NetUidPolicy policy) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return NetPolicyResultCode::ERR_INTERNAL_ERROR; + } + + if (!data.WriteUint32(uid)) { + return NetPolicyResultCode::ERR_INTERNAL_ERROR; + } + + if (!data.WriteUint32(static_cast(policy))) { + return NetPolicyResultCode::ERR_INTERNAL_ERROR; + } + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NetPolicyResultCode::ERR_INTERNAL_ERROR; + } + + int32_t error = remote->SendRequest(CMD_NSM_SET_UID_POLICY, data, reply, option); + if (error != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", error); + return NetPolicyResultCode::ERR_INTERNAL_ERROR; + } + + return static_cast(reply.ReadInt32()); +} + +NetUidPolicy NetPolicyServiceProxy::GetUidPolicy(uint32_t uid) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return NetUidPolicy::NET_POLICY_NONE; + } + + if (!data.WriteUint32(uid)) { + return NetUidPolicy::NET_POLICY_NONE; + } + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NetUidPolicy::NET_POLICY_NONE; + } + + int32_t error = remote->SendRequest(CMD_NSM_GET_UID_POLICY, data, reply, option); + if (error != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", error); + return NetUidPolicy::NET_POLICY_NONE; + } + + return static_cast(reply.ReadInt32()); +} + +std::vector NetPolicyServiceProxy::GetUids(NetUidPolicy policy) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + std::vector uids; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return uids; + } + + if (!data.WriteUint32(static_cast(policy))) { + return uids; + } + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return uids; + } + + int32_t error = remote->SendRequest(CMD_NSM_GET_UIDS, data, reply, option); + if (error != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", error); + return uids; + } + + bool errorRet = reply.ReadUInt32Vector(&uids); + if (errorRet == false) { + NETMGR_LOGE("proxy SendRequest Readuint32Vector failed"); + } + + return uids; +} + +bool NetPolicyServiceProxy::IsUidNetAccess(uint32_t uid, bool metered) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + std::vector uids; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return false; + } + + if (!data.WriteUint32(uid)) { + return false; + } + + if (!data.WriteBool(metered)) { + return false; + } + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return false; + } + + int32_t error = remote->SendRequest(CMD_NSM_IS_NET_ACCESS_METERED, data, reply, option); + if (error != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", error); + return false; + } + + return reply.ReadBool(); +} + +bool NetPolicyServiceProxy::IsUidNetAccess(uint32_t uid, const std::string &ifaceName) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + std::vector uids; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return false; + } + + if (!data.WriteUint32(uid)) { + return false; + } + + if (!data.WriteString(ifaceName)) { + return false; + } + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return false; + } + + int32_t error = remote->SendRequest(CMD_NSM_IS_NET_ACCESS_IFACENAME, data, reply, option); + if (error != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", error); + return false; + } + + return reply.ReadBool(); +} + +bool NetPolicyServiceProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(NetPolicyServiceProxy::GetDescriptor())) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return false; + } + return true; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/services/netpolicymanager/src/ipc/net_policy_service_stub.cpp b/services/netpolicymanager/src/ipc/net_policy_service_stub.cpp new file mode 100755 index 0000000..21d330c --- /dev/null +++ b/services/netpolicymanager/src/ipc/net_policy_service_stub.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2021 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 "net_policy_service_stub.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +NetPolicyServiceStub::NetPolicyServiceStub() +{ + memberFuncMap_[CMD_NSM_SET_UID_POLICY] = &NetPolicyServiceStub::OnSetUidPolicy; + memberFuncMap_[CMD_NSM_GET_UID_POLICY] = &NetPolicyServiceStub::OnGetUidPolicy; + memberFuncMap_[CMD_NSM_GET_UIDS] = &NetPolicyServiceStub::OnGetUids; + memberFuncMap_[CMD_NSM_IS_NET_ACCESS_METERED] = &NetPolicyServiceStub::OnIsUidNetAccessMetered; + memberFuncMap_[CMD_NSM_IS_NET_ACCESS_IFACENAME] = &NetPolicyServiceStub::OnIsUidNetAccessIfaceName; +} + +NetPolicyServiceStub::~NetPolicyServiceStub() {} + +int32_t NetPolicyServiceStub::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + std::u16string myDescripter = NetPolicyServiceStub::GetDescriptor(); + std::u16string remoteDescripter = data.ReadInterfaceToken(); + if (myDescripter != remoteDescripter) { + NETMGR_LOGE("descriptor checked fail"); + return ERR_FLATTEN_OBJECT; + } + + auto itFunc = memberFuncMap_.find(code); + if (itFunc != memberFuncMap_.end()) { + auto requestFunc = itFunc->second; + if (requestFunc != nullptr) { + return (this->*requestFunc)(data, reply); + } + } + + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} + +int32_t NetPolicyServiceStub::OnSetUidPolicy(MessageParcel &data, MessageParcel &reply) +{ + uint32_t uid; + if (!data.ReadUint32(uid)) { + return ERR_FLATTEN_OBJECT; + } + + uint32_t netPolicy; + if (!data.ReadUint32(netPolicy)) { + return ERR_FLATTEN_OBJECT; + } + + if (!reply.WriteInt32(static_cast(SetUidPolicy(uid, static_cast(netPolicy))))) { + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetPolicyServiceStub::OnGetUidPolicy(MessageParcel &data, MessageParcel &reply) +{ + uint32_t uid; + if (!data.ReadUint32(uid)) { + return ERR_FLATTEN_OBJECT; + } + + if (!reply.WriteInt32(static_cast(GetUidPolicy(uid)))) { + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetPolicyServiceStub::OnGetUids(MessageParcel &data, MessageParcel &reply) +{ + uint32_t policy; + if (!data.ReadUint32(policy)) { + return ERR_FLATTEN_OBJECT; + } + + if (!reply.WriteUInt32Vector(GetUids(static_cast(policy)))) { + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetPolicyServiceStub::OnIsUidNetAccessMetered(MessageParcel &data, MessageParcel &reply) +{ + uint32_t uid = 0; + bool metered = false; + if (!data.ReadUint32(uid)) { + return ERR_FLATTEN_OBJECT; + } + + if (!data.ReadBool(metered)) { + return ERR_FLATTEN_OBJECT; + } + + bool ret = IsUidNetAccess(uid, metered); + if (!reply.WriteBool(ret)) { + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetPolicyServiceStub::OnIsUidNetAccessIfaceName(MessageParcel &data, MessageParcel &reply) +{ + uint32_t uid = 0; + std::string ifaceName; + if (!data.ReadUint32(uid)) { + return ERR_FLATTEN_OBJECT; + } + + if (!data.ReadString(ifaceName)) { + return ERR_FLATTEN_OBJECT; + } + + bool ret = IsUidNetAccess(uid, ifaceName); + if (!reply.WriteBool(ret)) { + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/services/netpolicymanager/src/net_policy_file.cpp b/services/netpolicymanager/src/net_policy_file.cpp new file mode 100755 index 0000000..6036f34 --- /dev/null +++ b/services/netpolicymanager/src/net_policy_file.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2021 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 "net_policy_file.h" + +#include +#include + +#include "net_policy_define.h" +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +bool NetPolicyFile::FileExists(const std::string &fileName) +{ + struct stat buffer; + return (stat(fileName.c_str(), &buffer) == static_cast(NetPolicyResultCode::ERR_NONE)); +} + +bool NetPolicyFile::CreateFile(const std::string& fileName) +{ + if (fileName.empty() || FileExists(fileName)) { + NETMGR_LOGE("fileName empty or file not exists."); + return false; + } + + int32_t fd = open(fileName.c_str(), O_CREAT | O_WRONLY, CHOWN_RWX_USR_GRP); + if (fd < 0) { + NETMGR_LOGE("open file error."); + return false; + } + close(fd); + + return true; +} + +bool NetPolicyFile::Json2Obj(const std::string &content, NetPolicy &netPolicy) +{ + if (content.empty()) { + return false; + } + + Json::Value root; + Json::CharReaderBuilder buidler; + std::unique_ptr reader(buidler.newCharReader()); + JSONCPP_STRING errs; + + bool isSuccess = reader->parse(content.c_str(), content.c_str() + content.length(), &root, &errs); + if (isSuccess && errs.size() == 0) { + netPolicy.hosVersion = root[CONFIG_HOS_VERSION].asString(); + if (netPolicy.hosVersion.empty()) { + netPolicy.hosVersion = HOS_VERSION; + } + const Json::Value arrayUidPolicy = root[CONFIG_UID_POLICY]; + uint32_t size = arrayUidPolicy.size(); + UidPolicy uidPolicy; + for (uint32_t i = 0; i < size; i++) { + uidPolicy.uid= arrayUidPolicy[i][CONFIG_UID].asString(); + uidPolicy.policy = arrayUidPolicy[i][CONFIG_POLICY].asString(); + netPolicy.uidPolicys.push_back(uidPolicy); + } + } + + return true; +} + +bool NetPolicyFile::ReadFile(const std::string &fileName, std::string &fileContent) +{ + if (fileName.empty()) { + NETMGR_LOGE("fileName empty."); + return false; + } + + if (!FileExists(fileName)) { + NETMGR_LOGE("[%{public}s] not exist.", fileName.c_str()); + return false; + } + + std::fstream file(fileName.c_str(), std::fstream::in); + if (file.is_open() == false) { + NETMGR_LOGE("fstream failed."); + return false; + } + + std::stringstream buffer; + buffer << file.rdbuf(); + fileContent = buffer.str(); + file.close(); + + return true; +} + +bool NetPolicyFile::WriteFile(const std::string &fileName) +{ + if (fileName.empty()) { + NETMGR_LOGE("fileName is empty."); + return false; + } + + Json::Value root; + Json::StreamWriterBuilder builder; + std::unique_ptr streamWriter(builder.newStreamWriter()); + std::fstream file(fileName.c_str(), std::fstream::out); + if (file.is_open() == false) { + NETMGR_LOGE("fstream failed."); + return false; + } + + root[CONFIG_HOS_VERSION] = Json::Value(netPolicy_.hosVersion); + uint32_t size = netPolicy_.uidPolicys.size(); + for (uint32_t i = 0; i < size; i++) { + Json::Value uidPolicy; + uidPolicy[CONFIG_UID] = netPolicy_.uidPolicys[i].uid; + uidPolicy[CONFIG_POLICY] = netPolicy_.uidPolicys[i].policy; + std::string policy = std::to_string(static_cast(NetUidPolicy::NET_POLICY_TEMPORARY_ALLOW_METERED)); + /* Temporary permission, no need to write files */ + if (netPolicy_.uidPolicys[i].policy == policy) { + continue; + } + root[CONFIG_UID_POLICY].append(uidPolicy); + } + std::ostringstream out; + streamWriter->write(root, &out); + file << out.str().c_str(); + file.close(); + + return true; +} + +bool NetPolicyFile::WriteFile(const NetUidPolicyOpType netUidPolicyOpType, uint32_t uid, NetUidPolicy policy) +{ + if (netUidPolicyOpType == NetUidPolicyOpType::NET_POLICY_UID_OP_TYPE_UPDATE) { + for (auto &uidPolicy : netPolicy_.uidPolicys) { + if (uidPolicy.uid == std::to_string(uid)) { + uidPolicy.policy = std::to_string(static_cast(policy)); + break; + } + } + } else if (netUidPolicyOpType == NetUidPolicyOpType::NET_POLICY_UID_OP_TYPE_DELETE) { + for (auto iter = netPolicy_.uidPolicys.begin(); iter != netPolicy_.uidPolicys.end(); ++iter) { + if (iter->uid == std::to_string(uid)) { + netPolicy_.uidPolicys.erase(iter); + break; + } + } + } else { + UidPolicy uidPolicy; + uidPolicy.uid = std::to_string(uid); + uidPolicy.policy = std::to_string(static_cast(policy)); + netPolicy_.uidPolicys.push_back(uidPolicy); + } + + if (!WriteFile(POLICY_FILE_NAME)) { + NETMGR_LOGE("WriteFile failed"); + return false; + } + + return true; +} + +bool NetPolicyFile::IsUidPolicyExist(uint32_t uid) +{ + uint32_t size = netPolicy_.uidPolicys.size(); + for (uint32_t i = 0; i < size; i++) { + if (static_cast(std::stol(netPolicy_.uidPolicys[i].uid)) == uid) { + return true; + } + } + + return false; +} + +NetUidPolicy NetPolicyFile::GetUidPolicy(uint32_t uid) +{ + for (auto &uidPolicy : netPolicy_.uidPolicys) { + if (uidPolicy.uid == std::to_string(uid)) { + return static_cast(std::stol(uidPolicy.policy)); + } + } + + return NetUidPolicy::NET_POLICY_NONE; +} + +bool NetPolicyFile::GetUids(NetUidPolicy policy, std::vector &uids) +{ + for (auto &uidPolicy : netPolicy_.uidPolicys) { + if (uidPolicy.policy == std::to_string(static_cast(policy))) { + uint32_t uid = static_cast(std::stol(uidPolicy.uid)); + uids.push_back(uid); + } + } + + return true; +} + +bool NetPolicyFile::InitPolicy() +{ + std::string content; + if (!ReadFile(POLICY_FILE_NAME, content)) { + if (!CreateFile(POLICY_FILE_NAME)) { + NETMGR_LOGE("CreateFile [%{public}s] failed", POLICY_FILE_NAME); + return false; + } + } + if (!content.empty() && !Json2Obj(content, netPolicy_)) { + NETMGR_LOGE("Analysis fileconfig failed"); + return false; + } + return true; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/netpolicymanager/src/net_policy_service.cpp b/services/netpolicymanager/src/net_policy_service.cpp new file mode 100755 index 0000000..cb5e641 --- /dev/null +++ b/services/netpolicymanager/src/net_policy_service.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2021 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 "net_policy_service.h" + +#include "system_ability_definition.h" + +#include "net_policy_constants.h" +#include "net_policy_define.h" +#include "net_policy_file.h" +#include "net_policy_traffic.h" + +#include "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +const bool REGISTER_LOCAL_RESULT = + SystemAbility::MakeAndRegisterAbility(DelayedSingleton::GetInstance().get()); + +NetPolicyService::NetPolicyService() + : SystemAbility(COMM_NET_POLICY_MANAGER_SYS_ABILITY_ID, true), registerToService_(false), state_(STATE_STOPPED) +{ + netPolicyFile_ = (std::make_unique()).release(); + netPolicyTraffic_ = (std::make_unique(netPolicyFile_)).release(); +} + +NetPolicyService::~NetPolicyService() {} + +void NetPolicyService::OnStart() +{ + if (state_ == STATE_RUNNING) { + return; + } + if (!Init()) { + NETMGR_LOGE("init failed"); + return; + } + state_ = STATE_RUNNING; +} + +void NetPolicyService::OnStop() +{ + state_ = STATE_STOPPED; + registerToService_ = false; +} + +bool NetPolicyService::Init() +{ + if (!REGISTER_LOCAL_RESULT) { + NETMGR_LOGE("Register to local sa manager failed"); + registerToService_ = false; + return false; + } + if (!registerToService_) { + if (!Publish(DelayedSingleton::GetInstance().get())) { + NETMGR_LOGE("Register to sa manager failed"); + return false; + } + registerToService_ = true; + } + + bool error = netPolicyFile_->InitPolicy(); + if (!error) { + NETMGR_LOGE("InitPolicyTraffic failed"); + return false; + } + + return true; +} + +NetPolicyResultCode NetPolicyService::SetUidPolicy(uint32_t uid, NetUidPolicy policy) +{ + std::unique_lock lock(mutex_); + NETMGR_LOGI("SetUidPolicy info: uid[%{public}d] policy[%{public}d]", uid, static_cast(policy)); + /* delete uid policy */ + if (policy == NetUidPolicy::NET_POLICY_NONE) { + return netPolicyTraffic_->DeleteUidPolicy(uid, policy); + } + + /* update policy */ + if (!netPolicyFile_->IsUidPolicyExist(uid)) { + return netPolicyTraffic_->AddUidPolicy(uid, policy); + } else { + return netPolicyTraffic_->SetUidPolicy(uid, policy); + } +} + +NetUidPolicy NetPolicyService::GetUidPolicy(uint32_t uid) +{ + NETMGR_LOGI("GetUidPolicy info: uid[%{public}d]", uid); + return netPolicyFile_->GetUidPolicy(uid); +} + +std::vector NetPolicyService::GetUids(NetUidPolicy policy) +{ + NETMGR_LOGI("GetUids info: policy[%{public}d]", static_cast(policy)); + std::vector uids; + if (!netPolicyFile_->GetUids(policy, uids)) { + NETMGR_LOGE("GetUids failed"); + }; + return uids; +} + +bool NetPolicyService::IsUidNetAccess(uint32_t uid, bool metered) +{ + NETMGR_LOGI("IsUidNetAccess info: uid[%{public}d]", uid); + NetUidPolicy uidPolicy = netPolicyFile_->GetUidPolicy(uid); + if (uidPolicy == NetUidPolicy::NET_POLICY_NONE) { + return true; + } + + NETMGR_LOGI("IsUidNetAccess info: policy[%{public}d]", static_cast(uidPolicy)); + if (static_cast(uidPolicy) & NET_POLICY_ALLOW_MASK) { + return true; + } + + return false; +} + +bool NetPolicyService::IsUidNetAccess(uint32_t uid, const std::string &ifaceName) +{ + NETMGR_LOGI("IsUidNetAccess info: uid[%{public}d] ifaceName[%{public}s]", uid, ifaceName.c_str()); + NetUidPolicy uidPolicy = netPolicyFile_->GetUidPolicy(uid); + if (uidPolicy == NetUidPolicy::NET_POLICY_NONE) { + return true; + } + + if (static_cast(uidPolicy) & NET_POLICY_ALLOW_MASK) { + return true; + } + + return false; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/services/netpolicymanager/src/net_policy_traffic.cpp b/services/netpolicymanager/src/net_policy_traffic.cpp new file mode 100755 index 0000000..86e24a6 --- /dev/null +++ b/services/netpolicymanager/src/net_policy_traffic.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2021 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 "net_policy_traffic.h" + +#include +#include + +#include "net_mgr_log_wrapper.h" +#include "net_policy_constants.h" +#include "net_policy_define.h" +#include "net_policy_file.h" + +namespace OHOS { +namespace NetManagerStandard { +NetPolicyTraffic::NetPolicyTraffic(sptr netPolicyFile) : netPolicyFile_(netPolicyFile) +{ +} + +bool NetPolicyTraffic::IsPolicyValid(NetUidPolicy &policy) +{ + switch (policy) { + case NetUidPolicy::NET_POLICY_NONE: + case NetUidPolicy::NET_POLICY_ALLOW_METERED_BACKGROUND: + case NetUidPolicy::NET_POLICY_TEMPORARY_ALLOW_METERED: + case NetUidPolicy::NET_POLICY_REJECT_METERED_BACKGROUND: + case NetUidPolicy::NET_POLICY_ALLOW_ALL: + case NetUidPolicy::NET_POLICY_REJECT_ALL: { + return true; + } + default: { + NETMGR_LOGE("Invalid policy [%{public}d]", static_cast(policy)); + return false; + } + } +} + +NetPolicyResultCode NetPolicyTraffic::AddUidPolicy(uint32_t uid, NetUidPolicy policy) +{ + NETMGR_LOGI("AddUidPolicy info:uid[%{public}d] policy[%{public}d]", uid, static_cast(policy)); + if (netPolicyFile_ == nullptr) { + NETMGR_LOGE("AddUidPolicy netPolicyFile is null"); + return NetPolicyResultCode::ERR_INTERNAL_ERROR; + } + + if (!IsPolicyValid(policy)) { + return NetPolicyResultCode::ERR_INVALID_POLICY; + } + + if (!netPolicyFile_->WriteFile(NetUidPolicyOpType::NET_POLICY_UID_OP_TYPE_ADD, uid, policy)) { + NETMGR_LOGE("AddUidPolicy WriteFile failed"); + return NetPolicyResultCode::ERR_INTERNAL_ERROR; + } + + return NetPolicyResultCode::ERR_NONE; +} + +NetPolicyResultCode NetPolicyTraffic::SetUidPolicy(uint32_t uid, NetUidPolicy policy) +{ + NETMGR_LOGI("SetUidPolicy info:uid[%{public}d] policy[%{public}d]", uid, static_cast(policy)); + if (netPolicyFile_ == nullptr) { + NETMGR_LOGE("SetUidPolicy netPolicyFile is null"); + return NetPolicyResultCode::ERR_INTERNAL_ERROR; + } + + if (!IsPolicyValid(policy)) { + return NetPolicyResultCode::ERR_INVALID_POLICY; + } + + if (!netPolicyFile_->WriteFile(NetUidPolicyOpType::NET_POLICY_UID_OP_TYPE_UPDATE, uid, policy)) { + NETMGR_LOGE("SetUidPolicy WriteFile failed"); + return NetPolicyResultCode::ERR_INTERNAL_ERROR; + } + + return NetPolicyResultCode::ERR_NONE; +} + +NetPolicyResultCode NetPolicyTraffic::DeleteUidPolicy(uint32_t uid, NetUidPolicy policy) +{ + NETMGR_LOGI("DeleteUidPolicy info:uid[%{public}d] policy[%{public}d]", uid, static_cast(policy)); + if (netPolicyFile_ == nullptr) { + NETMGR_LOGE("DeleteUidPolicy netPolicyFile is null"); + return NetPolicyResultCode::ERR_INTERNAL_ERROR; + } + + if (!IsPolicyValid(policy)) { + return NetPolicyResultCode::ERR_INVALID_POLICY; + } + + if (!netPolicyFile_->WriteFile(NetUidPolicyOpType::NET_POLICY_UID_OP_TYPE_DELETE, uid, policy)) { + NETMGR_LOGE("DeleteUidPolicy WriteFile failed"); + return NetPolicyResultCode::ERR_INTERNAL_ERROR; + } + + return NetPolicyResultCode::ERR_NONE; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/services/netpolicymanager/test/BUILD.gn b/services/netpolicymanager/test/BUILD.gn new file mode 100755 index 0000000..dd18445 --- /dev/null +++ b/services/netpolicymanager/test/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright (c) 2021 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/test.gni") + +group("unittest") { + testonly = true + deps = [] + deps += [ "unittest/net_policy_manager_test:unittest" ] +} diff --git a/services/netpolicymanager/test/unittest/net_policy_manager_test/BUILD.gn b/services/netpolicymanager/test/unittest/net_policy_manager_test/BUILD.gn new file mode 100755 index 0000000..a287112 --- /dev/null +++ b/services/netpolicymanager/test/unittest/net_policy_manager_test/BUILD.gn @@ -0,0 +1,64 @@ +# Copyright (c) 2021 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/test.gni") +import( + "//foundation/communication/netmanager_standard/netmanager_base_config.gni") + +ohos_unittest("net_policy_manager_test") { + module_out_path = "netmanager_base/net_policy_manager_test" + + sources = [ + "//foundation/communication/netmanager_standard/services/netpolicymanager/src/ipc/net_policy_service_proxy.cpp", + "net_policy_manager_test.cpp", + ] + + include_dirs = [ + "$INNERKITS_ROOT/native/netpolicymanager/include", + "$NETPOLICYMANAGER_SOURCE_DIR/include/ipc", + "$NETPOLICYMANAGER_SOURCE_DIR/include", + ] + + deps = [ + "$INNERKITS_ROOT/native/netpolicymanager:net_policy_manager_if", + "$NETMANAGER_BASE_ROOT/utils:net_manager_common", + ] + + external_deps = [ + "ipc:ipc_core", + "safwk:system_ability_fwk", + ] + + defines = [ + "NETMGR_LOG_TAG = \"NetPolicyManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (enable_netmgr_debug) { + defines += [ "NETMGR_DEBUG" ] + } + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netmanager_standard" + subsystem_name = "communication" +} + +group("unittest") { + testonly = true + deps = [ ":net_policy_manager_test" ] +} diff --git a/services/netpolicymanager/test/unittest/net_policy_manager_test/net_policy_manager_test.cpp b/services/netpolicymanager/test/unittest/net_policy_manager_test/net_policy_manager_test.cpp new file mode 100755 index 0000000..5f61727 --- /dev/null +++ b/services/netpolicymanager/test/unittest/net_policy_manager_test/net_policy_manager_test.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2021 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 "net_mgr_log_wrapper.h" +#include "net_policy_define.h" +#include "net_policy_file.h" +#include "net_policy_traffic.h" +#include "net_policy_constants.h" +#include "net_policy_client.h" +#include "net_policy_service.h" + +namespace OHOS { +namespace NetManagerStandard { +using namespace testing::ext; +class NetPolicyManagerTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void NetPolicyManagerTest::SetUpTestCase() {} + +void NetPolicyManagerTest::TearDownTestCase() {} + +void NetPolicyManagerTest::SetUp() {} + +void NetPolicyManagerTest::TearDown() {} + +/** + * @tc.name: NetPolicyManager001 + * @tc.desc: Test NetPolicyManager SetUidPolicy. + * @tc.type: FUNC + */ +HWTEST_F(NetPolicyManagerTest, NetPolicyManager001, TestSize.Level1) +{ + NetPolicyResultCode result = DelayedSingleton::GetInstance()->SetUidPolicy(1, + NetUidPolicy::NET_POLICY_ALLOW_METERED_BACKGROUND); + ASSERT_TRUE(result != NetPolicyResultCode::ERR_INVALID_UID); +} + +/** + * @tc.name: NetPolicyManager002 + * @tc.desc: Test NetPolicyManager GetUidPolicy. + * @tc.type: FUNC + */ +HWTEST_F(NetPolicyManagerTest, NetPolicyManager002, TestSize.Level1) +{ + NetUidPolicy result = DelayedSingleton::GetInstance()->GetUidPolicy(1); + ASSERT_TRUE(result == NetUidPolicy::NET_POLICY_ALLOW_METERED_BACKGROUND); +} + +/** + * @tc.name: NetPolicyManager003 + * @tc.desc: Test NetPolicyManager GetUids. + * @tc.type: FUNC + */ +HWTEST_F(NetPolicyManagerTest, NetPolicyManager003, TestSize.Level1) +{ + std::vector result; + NetUidPolicy policy = NetUidPolicy::NET_POLICY_ALLOW_METERED_BACKGROUND; + result = DelayedSingleton::GetInstance()->GetUids(policy); + ASSERT_TRUE(result.size() != 0); +} + +/** + * @tc.name: NetPolicyManager004 + * @tc.desc: Test NetPolicyManager IsUidNetAccess. + * @tc.type: FUNC + */ +HWTEST_F(NetPolicyManagerTest, NetPolicyManager004, TestSize.Level1) +{ + bool result = DelayedSingleton::GetInstance()->IsUidNetAccess(1, false); + ASSERT_TRUE(result == true); +} + +/** + * @tc.name: NetPolicyManager005 + * @tc.desc: Test NetPolicyManager IsUidNetAccess. + * @tc.type: FUNC + */ +HWTEST_F(NetPolicyManagerTest, NetPolicyManager005, TestSize.Level1) +{ + bool result = DelayedSingleton::GetInstance()->IsUidNetAccess(1, std::string("test")); + ASSERT_TRUE(result == true); +} +} +} diff --git a/utils/BUILD.gn b/utils/BUILD.gn new file mode 100755 index 0000000..4ccccfc --- /dev/null +++ b/utils/BUILD.gn @@ -0,0 +1,60 @@ +# Copyright (c) 2021 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") + +group("common_target") { + deps = [ ":net_manager_common" ] +} + +config("netmgr_common_config") { + include_dirs = [ "log/include" ] +} + +ohos_shared_library("net_manager_common") { + sources = [ "log/src/net_mgr_log_wrapper.cpp" ] + + defines = [ + "NETMGR_LOG_TAG = \"NetMgrCommon\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (is_standard_system) { + defines += [ "STANDARD_SYSTEM_ENABLE" ] + } + + public_configs = [ + ":netmgr_common_config", + "//utils/native/base:utils_config", + ] + + public_deps = [ "//utils/native/base:utils" ] + + if (is_double_framework) { + cflags_cc = [ "-DCONFIG_DUAL_FRAMEWORK" ] + } + + if (is_standard_system) { + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps = [ "hilog:libhilog" ] + } + + external_deps += [ + "appexecfwk_standard:libeventhandler", + "native_appdatamgr:native_preferences", + ] + + part_name = "netmanager_standard" + subsystem_name = "communication" +} diff --git a/utils/log/include/net_mgr_log_wrapper.h b/utils/log/include/net_mgr_log_wrapper.h new file mode 100755 index 0000000..194a178 --- /dev/null +++ b/utils/log/include/net_mgr_log_wrapper.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021 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 NET_MGR_LOG_WRAPPER_H +#define NET_MGR_LOG_WRAPPER_H + +#include +#include "hilog/log.h" + +namespace OHOS { +namespace NetManagerStandard { +enum class NetMgrLogLevel { + DEBUG = 0, + INFO, + WARN, + ERROR, + FATAL, +}; + +class NetMgrLogWrapper { +public: + static bool JudgeLevel(const NetMgrLogLevel &level); + + static void SetLogLevel(const NetMgrLogLevel &level) + { + level_ = level; + } + + static const NetMgrLogLevel &GetLogLevel() + { + return level_; + } + + static std::string GetBriefFileName(const std::string &file); + +private: + static NetMgrLogLevel level_; +}; + +#ifndef NETMGR_LOG_TAG +#define NETMGR_LOG_TAG "NetMgrSubsystem" +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel NET_MGR_LABEL = {LOG_CORE, LOG_DOMAIN, NETMGR_LOG_TAG}; + +#ifdef NETMGR_DEBUG +#define PRINT_LOG(op, fmt, ...) \ + (void)OHOS::HiviewDFX::HiLog::op(NET_MGR_LABEL, "[%{public}s-(%{public}s:%{public}d)]" fmt, __FUNCTION__, \ + __FILE_NAME__, __LINE__, ##__VA_ARGS__) +#else +#define PRINT_LOG(op, fmt, ...) +#endif + +#define NETMGR_LOGD(fmt, ...) PRINT_LOG(Debug, fmt, ##__VA_ARGS__) +#define NETMGR_LOGE(fmt, ...) PRINT_LOG(Error, fmt, ##__VA_ARGS__) +#define NETMGR_LOGW(fmt, ...) PRINT_LOG(Warn, fmt, ##__VA_ARGS__) +#define NETMGR_LOGI(fmt, ...) PRINT_LOG(Info, fmt, ##__VA_ARGS__) +#define NETMGR_LOGF(fmt, ...) PRINT_LOG(Fatal, fmt, ##__VA_ARGS__) +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_MGR_LOG_WRAPPER_H \ No newline at end of file diff --git a/utils/log/src/net_mgr_log_wrapper.cpp b/utils/log/src/net_mgr_log_wrapper.cpp new file mode 100755 index 0000000..ffba66e --- /dev/null +++ b/utils/log/src/net_mgr_log_wrapper.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 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 "net_mgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +// initial static member object +NetMgrLogLevel NetMgrLogWrapper::level_ = NetMgrLogLevel::DEBUG; + +bool NetMgrLogWrapper::JudgeLevel(const NetMgrLogLevel &level) +{ + const NetMgrLogLevel &curLevel = NetMgrLogWrapper::GetLogLevel(); + if (level < curLevel) { + return false; + } + return true; +} + +std::string NetMgrLogWrapper::GetBriefFileName(const std::string &file) +{ + auto pos = file.find_last_of("/"); + if (pos != std::string::npos) { + return file.substr(pos + 1); + } + + pos = file.find_last_of("\\"); + if (pos != std::string::npos) { + return file.substr(pos + 1); + } + + return file; +} +} // namespace Telephony +} // namespace OHOS \ No newline at end of file