From cc47dec095142d9529f3d5a3eb32d2184da3644d Mon Sep 17 00:00:00 2001 From: hhchinasoft Date: Thu, 4 Nov 2021 10:28:38 +0800 Subject: [PATCH] L2 http code commit --- http/LICENSE | 177 ++ http/README.en.md | 36 + http/README.md | 81 + .../net_connection_manager_arch_zh.png | Bin 0 -> 18703 bytes http/figures/net_manager_arch_zh.png | Bin 0 -> 41997 bytes .../netconnmanager/src/inet_addr.cpp | 170 + .../netconnmanager/src/net_conn_manager.cpp | 156 + .../netconnmanager/src/net_link_info.cpp | 218 ++ .../netconnmanager/src/net_provider_info.cpp | 125 + .../netconnmanager/src/net_specifier.cpp | 107 + .../netconnmanager/src/route.cpp | 126 + http/frameworks/js/napi/BUILD.gn | 108 + .../js/napi/http/include/http_base_context.h | 41 + .../js/napi/http/include/http_enum_define.h | 63 + .../js/napi/http/include/http_event_list.h | 34 + .../js/napi/http/include/http_napi.h | 63 + .../js/napi/http/include/http_request.h | 82 + .../include/http_request_options_context.h | 148 + .../js/napi/http/include/http_response.h | 72 + .../js/napi/http/include/napi_util.h | 93 + .../frameworks/js/napi/http/src/http_napi.cpp | 619 ++++ .../js/napi/http/src/http_request.cpp | 334 ++ .../frameworks/js/napi/http/src/napi_util.cpp | 262 ++ .../napi/socket/include/extra_options_base.h | 77 + .../js/napi/socket/include/netaddress.h | 34 + .../napi/socket/include/socket_base_context.h | 40 + .../js/napi/socket/include/socket_napi.h | 73 + .../napi/socket/include/socket_remote_info.h | 77 + .../napi/socket/include/socket_state_base.h | 66 + .../napi/socket/include/tcp_connect_options.h | 55 + .../js/napi/socket/include/tcp_event_list.h | 34 + .../napi/socket/include/tcp_extra_options.h | 92 + .../js/napi/socket/include/tcp_send_options.h | 56 + .../js/napi/socket/include/tcp_socket.h | 71 + .../js/napi/socket/include/udp_event_list.h | 34 + .../napi/socket/include/udp_extra_options.h | 42 + .../js/napi/socket/include/udp_send_options.h | 44 + .../js/napi/socket/include/udp_socket.h | 75 + .../js/napi/socket/src/socket_napi.cpp | 2215 +++++++++++++ .../js/napi/socket/src/tcp_socket.cpp | 150 + .../js/napi/socket/src/udp_socket.cpp | 103 + .../napi/websocket/include/websocket_napi.h | 27 + .../js/napi/websocket/src/websocket_napi.cpp | 24 + .../innerkits/native/netconnmanager/BUILD.gn | 82 + .../native/netconnmanager/include/inet_addr.h | 48 + .../include/net_conn_constants.h | 27 + .../netconnmanager/include/net_conn_manager.h | 67 + .../netconnmanager/include/net_link_info.h | 42 + .../include/net_provider_info.h | 38 + .../netconnmanager/include/net_specifier.h | 49 + .../native/netconnmanager/include/route.h | 39 + http/interfaces/kits/js/@ohos.net.http.d.ts | 191 ++ http/interfaces/kits/js/@ohos.net.socket.d.ts | 137 + .../kits/js/@ohos.net.webSocket.d.ts | 73 + http/interfaces/kits/js/basic.d.ts | 16 + http/netmanager_config.gni | 26 + http/ohos.build | 19 + http/sa_profile/1151.xml | 27 + http/sa_profile/BUILD.gn | 22 + http/services/etc/init/BUILD.gn | 26 + .../services/etc/init/netmanager_standard.cfg | 17 + http/services/etc/init/netmanager_standard.rc | 19 + http/services/netconnmanager/BUILD.gn | 73 + .../include/ipc/i_net_conn_service.h | 56 + .../include/ipc/net_conn_service_proxy.h | 43 + .../include/ipc/net_conn_service_stub.h | 49 + .../netconnmanager/include/net_conn_service.h | 131 + .../netconnmanager/include/net_conn_types.h | 39 + .../include/net_controller/i_net_controller.h | 30 + .../net_controller/net_controller_factory.h | 35 + .../net_controller/telephony_controller.h | 51 + .../netconnmanager/include/net_id_manager.h | 46 + .../netconnmanager/include/net_provider.h | 59 + .../netconnmanager/include/net_service.h | 91 + .../netconnmanager/include/netd_controller.h | 182 ++ .../services/netconnmanager/include/network.h | 74 + .../src/ipc/net_conn_service_proxy.cpp | 237 ++ .../src/ipc/net_conn_service_stub.cpp | 189 ++ .../netconnmanager/src/net_conn_service.cpp | 398 +++ .../net_controller/net_controller_factory.cpp | 57 + .../net_controller/telephony_controller.cpp | 35 + .../netconnmanager/src/net_id_manager.cpp | 52 + .../netconnmanager/src/net_provider.cpp | 135 + .../netconnmanager/src/net_service.cpp | 238 ++ .../netconnmanager/src/netd_controller.cpp | 337 ++ http/services/netconnmanager/src/network.cpp | 236 ++ http/services/netconnmanager/test/BUILD.gn | 23 + .../netconnmanager/test/local_test/BUILD.gn | 78 + .../netconnmanager/test/local_test/test.cpp | 352 +++ .../netconnmanager/test/mock/BUILD.gn | 14 + .../unittest/net_conn_manager_test/BUILD.gn | 60 + .../net_conn_manager_test.cpp | 220 ++ http/services/netmanagernative/BUILD.gn | 90 + .../common/huawei_secure_c/include/securec.h | 635 ++++ .../huawei_secure_c/include/securectype.h | 566 ++++ .../common/huawei_secure_c/src/fscanf_s.c | 53 + .../common/huawei_secure_c/src/fwscanf_s.c | 52 + .../common/huawei_secure_c/src/gets_s.c | 72 + .../common/huawei_secure_c/src/input.inl | 2188 +++++++++++++ .../common/huawei_secure_c/src/memcpy_s.c | 565 ++++ .../common/huawei_secure_c/src/memmove_s.c | 121 + .../common/huawei_secure_c/src/memset_s.c | 572 ++++ .../common/huawei_secure_c/src/output.inl | 1636 ++++++++++ .../common/huawei_secure_c/src/scanf_s.c | 49 + .../common/huawei_secure_c/src/secinput.h | 184 ++ .../common/huawei_secure_c/src/securecutil.c | 73 + .../common/huawei_secure_c/src/securecutil.h | 537 ++++ .../huawei_secure_c/src/secureinput_a.c | 36 + .../huawei_secure_c/src/secureinput_w.c | 55 + .../huawei_secure_c/src/secureprintoutput.h | 123 + .../huawei_secure_c/src/secureprintoutput_a.c | 171 + .../huawei_secure_c/src/secureprintoutput_w.c | 148 + .../common/huawei_secure_c/src/snprintf_s.c | 110 + .../common/huawei_secure_c/src/sprintf_s.c | 58 + .../common/huawei_secure_c/src/sscanf_s.c | 58 + .../common/huawei_secure_c/src/strcat_s.c | 101 + .../common/huawei_secure_c/src/strcpy_s.c | 353 +++ .../common/huawei_secure_c/src/strncat_s.c | 119 + .../common/huawei_secure_c/src/strncpy_s.c | 143 + .../common/huawei_secure_c/src/strtok_s.c | 118 + .../common/huawei_secure_c/src/swprintf_s.c | 48 + .../common/huawei_secure_c/src/swscanf_s.c | 54 + .../common/huawei_secure_c/src/vfscanf_s.c | 65 + .../common/huawei_secure_c/src/vfwscanf_s.c | 64 + .../common/huawei_secure_c/src/vscanf_s.c | 66 + .../common/huawei_secure_c/src/vsnprintf_s.c | 141 + .../common/huawei_secure_c/src/vsprintf_s.c | 68 + .../common/huawei_secure_c/src/vsscanf_s.c | 88 + .../common/huawei_secure_c/src/vswprintf_s.c | 59 + .../common/huawei_secure_c/src/vswscanf_s.c | 76 + .../common/huawei_secure_c/src/vwscanf_s.c | 65 + .../common/huawei_secure_c/src/wcscat_s.c | 107 + .../common/huawei_secure_c/src/wcscpy_s.c | 86 + .../common/huawei_secure_c/src/wcsncat_s.c | 112 + .../common/huawei_secure_c/src/wcsncpy_s.c | 107 + .../common/huawei_secure_c/src/wcstok_s.c | 114 + .../common/huawei_secure_c/src/wmemcpy_s.c | 71 + .../common/huawei_secure_c/src/wmemmove_s.c | 70 + .../common/huawei_secure_c/src/wscanf_s.c | 52 + .../netmanagernative/common/include/bitcast.h | 36 + .../common/include/blocking_queue.h | 62 + .../common/include/error_code.h | 30 + .../common/include/interface_utils.h | 22 + .../netmanagernative/common/include/job.h | 24 + .../netmanagernative/common/include/logger.h | 112 + .../common/include/net_utils.h | 528 ++++ .../netmanagernative/common/include/raii.h | 125 + .../netmanagernative/common/include/rwlock.h | 52 + .../common/include/server_socket.h | 24 + .../common/include/server_template.h | 41 + .../common/include/socket_base.h | 66 + .../common/include/thread_pool.h | 40 + .../netmanagernative/common/include/utils.h | 35 + .../common/include/warning_disable.h | 31 + .../common/src/error_code.cpp | 39 + .../common/src/interface_utils.cpp | 294 ++ .../netmanagernative/common/src/job.cpp | 1 + .../netmanagernative/common/src/logger.cpp | 47 + .../netmanagernative/common/src/net_utils.cpp | 178 ++ .../netmanagernative/common/src/rwlock.cpp | 58 + .../common/src/server_socket.cpp | 69 + .../common/src/server_template.cpp | 38 + .../common/src/socket_base.cpp | 154 + .../common/src/thread_pool.cpp | 66 + .../netmanagernative/common/src/utils.cpp | 71 + .../client/include/dnsresolv_client.h | 50 + .../client/include/fwmark_client.h | 19 + .../client/src/dnsresolv_client.cpp | 432 +++ .../client/src/fwmark_client.cpp | 55 + .../net_mgr_native/include/dnsresolv.h | 226 ++ .../net_mgr_native/include/dnsresolv_cache.h | 128 + .../include/dnsresolv_controller.h | 31 + .../include/dnsresolv_service.h | 75 + .../net_mgr_native/include/event_reporter.h | 34 + .../net_mgr_native/include/fwmark.h | 18 + .../net_mgr_native/include/fwmark_command.h | 15 + .../net_mgr_native/include/fwmark_server.h | 38 + .../net_mgr_native/include/get_addr_info.h | 169 + .../include/interface_controller.h | 55 + .../net_mgr_native/include/iptables_process.h | 37 + .../include/native_netd_service.h | 116 + .../net_mgr_native/include/netlink_event.h | 61 + .../net_mgr_native/include/netlink_handler.h | 47 + .../net_mgr_native/include/netlink_listener.h | 31 + .../net_mgr_native/include/netlink_manager.h | 58 + .../net_mgr_native/include/netlink_msg.h | 55 + .../net_mgr_native/include/netlink_socket.h | 67 + .../include/netnative_log_wrapper.h | 40 + .../net_mgr_native/include/network.h | 60 + .../include/network_controller.h | 53 + .../net_mgr_native/include/route_controller.h | 50 + .../net_mgr_native/include/sock_diag.h | 34 + .../include/traffic_controller.h | 79 + .../net_mgr_native/src/dnsresolv_cache.cpp | 587 ++++ .../src/dnsresolv_controller.cpp | 60 + .../net_mgr_native/src/dnsresolv_service.cpp | 312 ++ .../net_mgr_native/src/event_reporter.cpp | 9 + .../net_mgr_native/src/fwmark_server.cpp | 52 + .../net_mgr_native/src/get_addr_info.cpp | 2792 +++++++++++++++++ .../src/interface_controller.cpp | 359 +++ .../net_mgr_native/src/iptables_process.cpp | 179 ++ .../src/native_netd_service.cpp | 332 ++ .../net_mgr_native/src/netlink_event.cpp | 344 ++ .../net_mgr_native/src/netlink_handler.cpp | 160 + .../net_mgr_native/src/netlink_listener.cpp | 61 + .../net_mgr_native/src/netlink_manager.cpp | 68 + .../net_mgr_native/src/netlink_msg.cpp | 160 + .../net_mgr_native/src/netlink_socket.cpp | 217 ++ .../net_mgr_native/src/network.cpp | 80 + .../net_mgr_native/src/network_controller.cpp | 189 ++ .../net_mgr_native/src/route_controller.cpp | 487 +++ .../net_mgr_native/src/sock_diag.cpp | 182 ++ .../net_mgr_native/src/traffic_controller.cpp | 376 +++ .../net_mgr_native/tests/BUILD.gn | 71 + .../net_mgr_native/tests/api_time_elapsed.cpp | 124 + .../net_mgr_native/tests/bit_cast_test.cpp | 11 + .../net_mgr_native/tests/dns_query.cpp | 186 ++ .../tests/dnsresolv_client_test.cpp | 53 + .../tests/dnsresolv_client_test.h | 25 + .../net_mgr_native/tests/error_code_test.cpp | 12 + .../tests/fwmark_client_test.cpp | 13 + .../net_mgr_native/tests/interface_test.cpp | 338 ++ .../tests/iptables_restore_test.cpp | 13 + .../net_mgr_native/tests/main.cpp | 113 + .../net_mgr_native/tests/main.h | 57 + .../tests/native_netd_service_test.cpp | 156 + .../tests/native_netd_service_test1.cpp | 156 + .../tests/netd_control_test.cpp | 25 + .../tests/netlink_event_test.cpp | 275 ++ .../net_mgr_native/tests/netlink_test.cpp | 186 ++ .../tests/network_controller_test.cpp | 246 ++ .../net_mgr_native/tests/resolv_dns_test.cpp | 309 ++ .../net_mgr_native/tests/set_param.cpp | 126 + .../net_mgr_native/tests/sock_diag_test.cpp | 42 + .../tests/stable/stability_test.cpp | 224 ++ .../net_mgr_native/tests/tests.cpp | 77 + .../net_mgr_native/tests/time_elapsed.h | 55 + .../net_mgr_native/tests/traffic_test.cpp | 146 + .../tests/unit/block_queue_unit_test.cpp | 23 + .../unit/dnsresolv_service_unit_test.cpp | 271 ++ .../tests/unit/event_reporter_unit_test.cpp | 73 + .../tests/unit/get_addr_info_unit_test.cpp | 343 ++ .../tests/unit/net_utils_unit_test.cpp | 12 + .../tests/unit/netlink_handler_unit_test.cpp | 443 +++ .../tests/unit/netlink_manager_unit_test.cpp | 34 + .../tests/unit/route_controller_unit_test.cpp | 46 + .../unit/traffic_controller_unit_test.cpp | 11 + .../tests/unit/traffic_init_unit_test.cpp | 65 + .../tests/unit/utils_unit_test.cpp | 27 + http/utils/BUILD.gn | 66 + http/utils/log/include/netmgr_log_wrapper.h | 69 + http/utils/log/src/netmgr_log_wrapper.cpp | 47 + 252 files changed, 37539 insertions(+) create mode 100644 http/LICENSE create mode 100644 http/README.en.md create mode 100644 http/README.md create mode 100644 http/figures/net_connection_manager_arch_zh.png create mode 100644 http/figures/net_manager_arch_zh.png create mode 100644 http/frameworks/innerkitsimpl/netconnmanager/src/inet_addr.cpp create mode 100644 http/frameworks/innerkitsimpl/netconnmanager/src/net_conn_manager.cpp create mode 100644 http/frameworks/innerkitsimpl/netconnmanager/src/net_link_info.cpp create mode 100644 http/frameworks/innerkitsimpl/netconnmanager/src/net_provider_info.cpp create mode 100644 http/frameworks/innerkitsimpl/netconnmanager/src/net_specifier.cpp create mode 100644 http/frameworks/innerkitsimpl/netconnmanager/src/route.cpp create mode 100644 http/frameworks/js/napi/BUILD.gn create mode 100644 http/frameworks/js/napi/http/include/http_base_context.h create mode 100644 http/frameworks/js/napi/http/include/http_enum_define.h create mode 100644 http/frameworks/js/napi/http/include/http_event_list.h create mode 100644 http/frameworks/js/napi/http/include/http_napi.h create mode 100644 http/frameworks/js/napi/http/include/http_request.h create mode 100644 http/frameworks/js/napi/http/include/http_request_options_context.h create mode 100644 http/frameworks/js/napi/http/include/http_response.h create mode 100644 http/frameworks/js/napi/http/include/napi_util.h create mode 100644 http/frameworks/js/napi/http/src/http_napi.cpp create mode 100644 http/frameworks/js/napi/http/src/http_request.cpp create mode 100644 http/frameworks/js/napi/http/src/napi_util.cpp create mode 100644 http/frameworks/js/napi/socket/include/extra_options_base.h create mode 100644 http/frameworks/js/napi/socket/include/netaddress.h create mode 100644 http/frameworks/js/napi/socket/include/socket_base_context.h create mode 100644 http/frameworks/js/napi/socket/include/socket_napi.h create mode 100644 http/frameworks/js/napi/socket/include/socket_remote_info.h create mode 100644 http/frameworks/js/napi/socket/include/socket_state_base.h create mode 100644 http/frameworks/js/napi/socket/include/tcp_connect_options.h create mode 100644 http/frameworks/js/napi/socket/include/tcp_event_list.h create mode 100644 http/frameworks/js/napi/socket/include/tcp_extra_options.h create mode 100644 http/frameworks/js/napi/socket/include/tcp_send_options.h create mode 100644 http/frameworks/js/napi/socket/include/tcp_socket.h create mode 100644 http/frameworks/js/napi/socket/include/udp_event_list.h create mode 100644 http/frameworks/js/napi/socket/include/udp_extra_options.h create mode 100644 http/frameworks/js/napi/socket/include/udp_send_options.h create mode 100644 http/frameworks/js/napi/socket/include/udp_socket.h create mode 100644 http/frameworks/js/napi/socket/src/socket_napi.cpp create mode 100644 http/frameworks/js/napi/socket/src/tcp_socket.cpp create mode 100644 http/frameworks/js/napi/socket/src/udp_socket.cpp create mode 100644 http/frameworks/js/napi/websocket/include/websocket_napi.h create mode 100644 http/frameworks/js/napi/websocket/src/websocket_napi.cpp create mode 100644 http/interfaces/innerkits/native/netconnmanager/BUILD.gn create mode 100644 http/interfaces/innerkits/native/netconnmanager/include/inet_addr.h create mode 100644 http/interfaces/innerkits/native/netconnmanager/include/net_conn_constants.h create mode 100644 http/interfaces/innerkits/native/netconnmanager/include/net_conn_manager.h create mode 100644 http/interfaces/innerkits/native/netconnmanager/include/net_link_info.h create mode 100644 http/interfaces/innerkits/native/netconnmanager/include/net_provider_info.h create mode 100644 http/interfaces/innerkits/native/netconnmanager/include/net_specifier.h create mode 100644 http/interfaces/innerkits/native/netconnmanager/include/route.h create mode 100644 http/interfaces/kits/js/@ohos.net.http.d.ts create mode 100644 http/interfaces/kits/js/@ohos.net.socket.d.ts create mode 100644 http/interfaces/kits/js/@ohos.net.webSocket.d.ts create mode 100644 http/interfaces/kits/js/basic.d.ts create mode 100644 http/netmanager_config.gni create mode 100644 http/ohos.build create mode 100644 http/sa_profile/1151.xml create mode 100644 http/sa_profile/BUILD.gn create mode 100644 http/services/etc/init/BUILD.gn create mode 100644 http/services/etc/init/netmanager_standard.cfg create mode 100644 http/services/etc/init/netmanager_standard.rc create mode 100644 http/services/netconnmanager/BUILD.gn create mode 100644 http/services/netconnmanager/include/ipc/i_net_conn_service.h create mode 100644 http/services/netconnmanager/include/ipc/net_conn_service_proxy.h create mode 100644 http/services/netconnmanager/include/ipc/net_conn_service_stub.h create mode 100644 http/services/netconnmanager/include/net_conn_service.h create mode 100644 http/services/netconnmanager/include/net_conn_types.h create mode 100644 http/services/netconnmanager/include/net_controller/i_net_controller.h create mode 100644 http/services/netconnmanager/include/net_controller/net_controller_factory.h create mode 100644 http/services/netconnmanager/include/net_controller/telephony_controller.h create mode 100644 http/services/netconnmanager/include/net_id_manager.h create mode 100644 http/services/netconnmanager/include/net_provider.h create mode 100644 http/services/netconnmanager/include/net_service.h create mode 100644 http/services/netconnmanager/include/netd_controller.h create mode 100644 http/services/netconnmanager/include/network.h create mode 100644 http/services/netconnmanager/src/ipc/net_conn_service_proxy.cpp create mode 100644 http/services/netconnmanager/src/ipc/net_conn_service_stub.cpp create mode 100644 http/services/netconnmanager/src/net_conn_service.cpp create mode 100644 http/services/netconnmanager/src/net_controller/net_controller_factory.cpp create mode 100644 http/services/netconnmanager/src/net_controller/telephony_controller.cpp create mode 100644 http/services/netconnmanager/src/net_id_manager.cpp create mode 100644 http/services/netconnmanager/src/net_provider.cpp create mode 100644 http/services/netconnmanager/src/net_service.cpp create mode 100644 http/services/netconnmanager/src/netd_controller.cpp create mode 100644 http/services/netconnmanager/src/network.cpp create mode 100644 http/services/netconnmanager/test/BUILD.gn create mode 100644 http/services/netconnmanager/test/local_test/BUILD.gn create mode 100644 http/services/netconnmanager/test/local_test/test.cpp create mode 100644 http/services/netconnmanager/test/mock/BUILD.gn create mode 100644 http/services/netconnmanager/test/unittest/net_conn_manager_test/BUILD.gn create mode 100644 http/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_manager_test.cpp create mode 100644 http/services/netmanagernative/BUILD.gn create mode 100644 http/services/netmanagernative/common/huawei_secure_c/include/securec.h create mode 100644 http/services/netmanagernative/common/huawei_secure_c/include/securectype.h create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/fscanf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/fwscanf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/gets_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/input.inl create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/memcpy_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/memmove_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/memset_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/output.inl create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/scanf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/secinput.h create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/securecutil.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/securecutil.h create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/secureinput_a.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/secureinput_w.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/secureprintoutput.h create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/secureprintoutput_a.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/secureprintoutput_w.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/snprintf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/sprintf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/sscanf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/strcat_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/strcpy_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/strncat_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/strncpy_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/strtok_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/swprintf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/swscanf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/vfscanf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/vfwscanf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/vscanf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/vsnprintf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/vsprintf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/vsscanf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/vswprintf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/vswscanf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/vwscanf_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/wcscat_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/wcscpy_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/wcsncat_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/wcsncpy_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/wcstok_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/wmemcpy_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/wmemmove_s.c create mode 100644 http/services/netmanagernative/common/huawei_secure_c/src/wscanf_s.c create mode 100644 http/services/netmanagernative/common/include/bitcast.h create mode 100644 http/services/netmanagernative/common/include/blocking_queue.h create mode 100644 http/services/netmanagernative/common/include/error_code.h create mode 100644 http/services/netmanagernative/common/include/interface_utils.h create mode 100644 http/services/netmanagernative/common/include/job.h create mode 100644 http/services/netmanagernative/common/include/logger.h create mode 100644 http/services/netmanagernative/common/include/net_utils.h create mode 100644 http/services/netmanagernative/common/include/raii.h create mode 100644 http/services/netmanagernative/common/include/rwlock.h create mode 100644 http/services/netmanagernative/common/include/server_socket.h create mode 100644 http/services/netmanagernative/common/include/server_template.h create mode 100644 http/services/netmanagernative/common/include/socket_base.h create mode 100644 http/services/netmanagernative/common/include/thread_pool.h create mode 100644 http/services/netmanagernative/common/include/utils.h create mode 100644 http/services/netmanagernative/common/include/warning_disable.h create mode 100644 http/services/netmanagernative/common/src/error_code.cpp create mode 100644 http/services/netmanagernative/common/src/interface_utils.cpp create mode 100644 http/services/netmanagernative/common/src/job.cpp create mode 100644 http/services/netmanagernative/common/src/logger.cpp create mode 100644 http/services/netmanagernative/common/src/net_utils.cpp create mode 100644 http/services/netmanagernative/common/src/rwlock.cpp create mode 100644 http/services/netmanagernative/common/src/server_socket.cpp create mode 100644 http/services/netmanagernative/common/src/server_template.cpp create mode 100644 http/services/netmanagernative/common/src/socket_base.cpp create mode 100644 http/services/netmanagernative/common/src/thread_pool.cpp create mode 100644 http/services/netmanagernative/common/src/utils.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/client/include/dnsresolv_client.h create mode 100644 http/services/netmanagernative/net_mgr_native/client/include/fwmark_client.h create mode 100644 http/services/netmanagernative/net_mgr_native/client/src/dnsresolv_client.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/client/src/fwmark_client.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/include/dnsresolv.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/dnsresolv_cache.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/dnsresolv_controller.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/dnsresolv_service.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/event_reporter.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/fwmark.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/fwmark_command.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/fwmark_server.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/get_addr_info.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/interface_controller.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/iptables_process.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/native_netd_service.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/netlink_event.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/netlink_handler.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/netlink_listener.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/netlink_manager.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/netlink_msg.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/netlink_socket.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/netnative_log_wrapper.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/network.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/network_controller.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/route_controller.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/sock_diag.h create mode 100644 http/services/netmanagernative/net_mgr_native/include/traffic_controller.h create mode 100644 http/services/netmanagernative/net_mgr_native/src/dnsresolv_cache.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/dnsresolv_controller.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/dnsresolv_service.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/event_reporter.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/fwmark_server.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/get_addr_info.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/interface_controller.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/iptables_process.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/native_netd_service.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/netlink_event.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/netlink_handler.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/netlink_listener.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/netlink_manager.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/netlink_msg.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/netlink_socket.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/network.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/network_controller.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/route_controller.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/sock_diag.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/src/traffic_controller.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/BUILD.gn create mode 100644 http/services/netmanagernative/net_mgr_native/tests/api_time_elapsed.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/bit_cast_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/dns_query.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/dnsresolv_client_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/dnsresolv_client_test.h create mode 100644 http/services/netmanagernative/net_mgr_native/tests/error_code_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/fwmark_client_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/interface_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/iptables_restore_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/main.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/main.h create mode 100644 http/services/netmanagernative/net_mgr_native/tests/native_netd_service_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/native_netd_service_test1.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/netd_control_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/netlink_event_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/netlink_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/network_controller_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/resolv_dns_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/set_param.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/sock_diag_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/stable/stability_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/tests.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/time_elapsed.h create mode 100644 http/services/netmanagernative/net_mgr_native/tests/traffic_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/unit/block_queue_unit_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/unit/dnsresolv_service_unit_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/unit/event_reporter_unit_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/unit/get_addr_info_unit_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/unit/net_utils_unit_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/unit/netlink_handler_unit_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/unit/netlink_manager_unit_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/unit/route_controller_unit_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/unit/traffic_controller_unit_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/unit/traffic_init_unit_test.cpp create mode 100644 http/services/netmanagernative/net_mgr_native/tests/unit/utils_unit_test.cpp create mode 100644 http/utils/BUILD.gn create mode 100644 http/utils/log/include/netmgr_log_wrapper.h create mode 100644 http/utils/log/src/netmgr_log_wrapper.cpp diff --git a/http/LICENSE b/http/LICENSE new file mode 100644 index 000000000..4947287f7 --- /dev/null +++ b/http/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/http/README.en.md b/http/README.en.md new file mode 100644 index 000000000..0471c0c3b --- /dev/null +++ b/http/README.en.md @@ -0,0 +1,36 @@ +# communication_netmanager_standard + +#### 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**} + +#### Software Architecture +Software architecture description + +#### Installation + +1. xxxx +2. xxxx +3. xxxx + +#### Instructions + +1. xxxx +2. xxxx +3. xxxx + +#### Contribution + +1. Fork the repository +2. Create Feat_xxx branch +3. Commit your code +4. Create Pull Request + + +#### Gitee Feature + +1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md +2. Gitee blog [blog.gitee.com](https://blog.gitee.com) +3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) +4. The most valuable open source project [GVP](https://gitee.com/gvp) +5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) +6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/http/README.md b/http/README.md new file mode 100644 index 000000000..08f63d1cb --- /dev/null +++ b/http/README.md @@ -0,0 +1,81 @@ +# Net Manager + +- [简介](#section112mcpsimp) +- [目录](#section125mcpsimp) +- [约束](#section133mcpsimp) +- [相关仓](#section155mcpsimp) + + + +## 简介 + +网络管理介绍: + +​ 网络管理模块作为电话子系统可裁剪部件,依赖于蜂窝数据管理,主要分为连接管理、策略管理、流量管理、网络共享、VPN管理五大模块;如图1:网络管理架构图; + +**图 1** 网络管理架构图 + +![](figures/net_manager_arch_zh.png) + +连接管理介绍: + +​ 负责与蜂窝数据交互,请求到IP后,再与Netd交互并将路由参数设置到内核,使得蜂窝数据连接且可用,最终实现上网,如图2:网络连接架构图; + +**图 2** 网络连接架构图 + +![](figures/net_conn_manager_arch_zh.png) + +## 目录 + +``` +/foundation/communication/netstack/http/netstack/http/ +├── frameworks # 框架代码 +│   ├── innerkitsimpl # 内部接口实现 +│   │   └── netconnmanager +│   │   └── src +│   └── js # JS接口实现 +│   └── napi +│   ├── http +│   ├── socket +│   └── websocket +├── interfaces # 接口代码 +│   ├── innerkits # 内部接口 +│   │   └── native +│   │   └── netconnmanager +│   │   └── include +│   └── kits # 外部接口 +│   └── js +├── sa_profile # 服务配置文件 +├── services # 核心服务代码目录 +│   ├── common # 网络管理公共组件 +│   ├── etc # 网络管理进程配置脚本 +│   │   └── init +│   ├── netconnmanager # 连接管理代码 +│   │   ├── include # 头文件 +│   │   │   ├── ipc # IPC通信头文件 +│   │   │   ├── net_controller # 网络控制 +│   │   ├── src # 源文件目录 +│   │   │   ├── ipc # IPC通信源文件 +│   │   │   ├── net_controller # 网络控制实现 +│   │   └── 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) + diff --git a/http/figures/net_connection_manager_arch_zh.png b/http/figures/net_connection_manager_arch_zh.png new file mode 100644 index 0000000000000000000000000000000000000000..bef52c52dda63cd5746a3e0b737bfdef5f9010e2 GIT binary patch literal 18703 zcmc({c_7r?+b}+qh>(gxwv;WRgb+hQi!2F6w(QFwyBH&~BulokMp+V}#f*JO+4ns& z7(xp=X>WuUp^biPy@#>Y! zHzANcx)2DpI2|WCPlLu@8|53y5Xk#z2BJ9)XzzEqa>oq< zVfsw|p=xl>wS+*fWL>?ie9PMeKgmUmsL+Zg34EF@zNnX6i9@u*NGFxEdWtMXvSS}yryK>^ID$Cn@L1J~(Cujos zgUmiBDN0Qy|C}rD8}2jiGu}y$Ps#gP?opwYuBa<7FOMEK!fp1a9h>>_be? z>=on-)Kyj07D!?<+^4=!8_bZ?r!`eXz8+ideaFWDdzu?X4Lv7HfZYW(>k0rnDrG) zrT5~u@o1=%oKY8xGP|L$8&y|SR8*^cW|EhjrOVoJ(W&d9uO&~Yh_QSMPRqF#ef{|v z{QP{1PXS$Xntl$CI@{RkrjwUl@>Kb~U0fD04n;}r`cH$%czut|*e>rUNEIr4kRVfW zdoP6$`)N7>VTHm81}0S|GP=ne%3hgMNTd$k`cQY?DO%V@Y(vazZ$Ncl6y1x|)WrV1 z14X7X1^%wwIY{Zxt`bXf1DsJT5BR_O;m@^d8`#e3cv(-KZ#e){b>1sabK-}+7FGfp z*v))FP7WihE-*{<{hIb9tmosMJ+ggNvSHFEF6eo%q-H9nsx6>zP78~aZBXMk@IFuQ zxx+m5w~y}s7V!GEb&9_BL^13ui?VY?$wN8;T=#rfhRq%pjVL-zDbYY%`N#|+b7o9H z+(GnJI^4-8AzI^n+G8JU&T3rjarO8v=ZOaR(LChi}!-p4p#X)VZ+T$-Mp44%X;8=C<>| zU6QykZMvr@N_LBnEZ&kd8Q-;p<%X>*L7LuW3t|V=;{>-`E6=z-cn}iQ?pB5=x%$XC zcCvPT&Z`<*Ed6LU1x#|zd1FZ2#z{p=w?C5dVs}>2qv)v@zU{@`J|x1_jni?5K8h1V zdtL$N2n0LlR2juChz||Gf>FMTDA{OdQm46^T)&1)|w-v9A!rH9axa(2{hAil-Kj}@E z4x>L4zhiVJ95o#Fnb5>{h-f>nHJ$DG`P^P}YQ8&xE?NJRfI_8YSJ+{6%y$M;V!y(n zK?;|@EC|=qKDv@L-42z7WLdek@CEfkE#m}sZL9y&_~Hw=L2Le!+K`I*9Osrv%XweY zq~7dfVhtx*%cq;6j*U=DH4-1^PafA3J2^jx^!X1FLQ@-|6PHP87CRiDNn*jMU=+V; z0#+X`nXgLX6Qs=0_!t06X{)ZPQYe$|QGSz)0B`cUy1HV9Htr;8VN|UP6?ZT=%{Wv` z#8PC5%RI^ujl8XbOh#IQBw>;D!i%M>M5ep?jymV zo!^9)LdDa=yA*usFr|78C@CH!`c5VoOsq~mH|=+NX!2nCluzICTYYCz6P33m*7DV1 zOY6+Ky^VZ9e%q0K?8+K3k~_)Oqtb|y0{6Q~e4(-~FJz@Va8bUE)f2ghJx3A|b3p@6 z*ci{xu`z3-_Zq9IauH2d?a(>f$@&RgB&Q4$M-H@qY-}w1`tw?-FuRJ@_wQ{fInZW2 zwxoJlzS_;%xnt#hSj_7D#>Us;oIxB;roirI8Z(=;z|Iif9@j5LVsL2vUh-7DCpfkK zSwshP9SQqZu=EUX)Rw}gm^}^fsGl&6C@#r+%Be*UgOQW;=~S+k3kx` z;5OTYsYhN*HGzbYA8XFu9wz$bHA1V>@B{aU*4GMV+aFJ$v#T0^SOvokrcR9L~U zo`6zE3UU%&tt~lRCf&G1y3w14*tFcUKWRuVdh?goR~2p_EyA;8sggWwZOo?}1Z5|< z`wAuCsp=$;PWSg$$33f5V6Ke{dB*0O7oq{r0g-?vT`yA7{4wh3#6LmxrXWh3hR=za zN$>VJyhS#uU-mN&eDEsVh!t?`YGd_dioN}AS`+CncP?kn^Vpx?c{IMdAEVc{sGEb3 zz9+{d?_{b>@^Jfj*`%tlvK*t1b-T4;8~mRDC|HphfJ#DmjrdHBjJ%l6FiUBJ_FNj= z*nC1Z@gvPpbT}+_sJ|>pEBxIyaXj?KHPjr@Vdp{|*Zpa}F_cc=jXr3K35FM|_B10n z(?;;*ClYf|3?ebu2#dMe&z*E89#J#2JNIkG@9B<4gJp$v(#!J){f~;K zQA@RfDSY*1D7V~&3li{nSkP)TRJ!1b&`xPgA}3&mei9-LcNA#2`$OmKdyhN@pyK(C zC226Z6GeEHM%%j8j<&3|un*(SQ5gq+DbOWC=#AJ9=VX?zvit{^Ia{lrn>@H`V(K%= zihp)hYo6j_kf=L5bCt{OQ|X8i_wbb=w+_Zl#X5bDDbwW}$5SmX9k$GQ_2hAv&#wve zpCO0`TIwxZpfYhoe)Q25v#D!*Z&g`Vi^Lz^JM?72NNNqi`M!JVDba{M#Rl`kuP+3~ z04p&~D0br`YqpKwatiLem}nSL61|cwp2Ws>nZ&LI-7dB>R}Na9&$z$*{YDSZ^?|c# z@12H9V=U9Q=Bsy>CR=dZ!#LRH?dDNph5z;g9PSkJ2b@IO{t3%iV)@|7qk8ev(Ua8m ze%lI)iqZwtS#n7g^Jr`_>Kh0|cn1v|l5#Feo>t7oWbOy)%)R^!KY+*jesH?`^C4r#gp_ul`m_} zZ67Ib{IcWsuF`nm?Dl(i7V}MuB)$Ie0mSye4S-;OwZ|Qckl=07{0m`V-k{rEv@+aq%*j^J}+kN$%=@;wC3ktE2L@y;2 zef7P2ZmHwzZPH`CyIoxCtECTC^X&SR=bqWAN_=vV6}u27z`{wKV&3){kK86M@4Ekq z7)iLOl?!Qcx#Nm$>$<5lVY%Zf_r3#C0y`&eycIf<#X(-YQV0zl=?}sguQ-yLXbx2E zlX*B)g7uurm%c2&Gs~CnoTXq=P`jsg!1NFQ(Uyp)`Q>*G6KFH!HXE)t^920VCP8k6 zFVSY)jE6!JUJOLK)RUCF9+``fy}+xb-`7!}Ws~+7Uk{-)=9- z>yR$yiy~r^n^B*~89Jj6I}M)?B47hc(@8`bp*_JAx#anerbjJu=Cxlr4my8zdCj;vb#d z8F_{%esW5O^e)I~G~P2|Ku_)m_Y&qBRxWp_5az{%YT{G)*|u07pi21MuRVY8@$cgK z1q&jgO4y_QW^r=9zrZMm29i&13X}0!tb#)N#)=flVhwe4!lA_oHc2{W!pR=-P)ilO z%9)^+bb-^5_|_wDdDH6Wn3X&LaTI8j;X0&+@(t6&=@UnrnGGMAnnzCn#23RgZ5Ul? zk;B|NBUpK6n(qu;cG0KjZ7cXTN1o8@kj$wfbZ{ zd93qP(_$ScuWpN}Wdcn=w>Bw2WFZ%&Ls|;kiR33b9Xk0b6Qf2rt!k6Bybmc~$a_=m zw9KYXLhEAU9>$`X523{@iAfBT;(MC*$gpCJv9={hKKG%?NGwVwO74cwEvaBpNz5s~ z;`8y)40_1~sPh+j49cxGRtTZQ8hbJCMgc>gxK|*S4Wnl*RPtt$nZXyhQAfj?gR{3V zLWtALr1ffCaR8qX0v2E0x3M`;eWoaVZS}_ohIzTT@M;Z_NTkKZ_w38VD*uD)L(nza zU|2=atEAwc6j7Z!b}I-I=P^+nyIRzvcqB1`L&NXZFfpn746vMB>S%j_2>B1Tcc~fspyHD$TT;lFva>Vz`a$?zdb zK1Rt$V|4tFP6kxoB=t{>giM=>*3vceSigKs6Cbe@dPke2tq7XR1Qmh^U_7U{9D+HT zD}pGdP)9nKUMYkSGOe1_vNNIub~-oONsynOP<9sPnRE^>ZW=8_y+5B4Hk>|Aa|zD{m>52)8V)JX5?CXH)U0!HA28r=_kXe|k#)mW%(2I^tH~^6bZsWW{iIJVvUg zR_MvI>gg4Cv7(B1uQYScU$&rfe$bPm!H{YD>?WyR=%?j1mGf*aJKO6iY-(Mi#>K=N z1j5oQ5zWH5J9W%IrmCb8Hez@PEC5h)_H;}7#aGRqNWM+X*?oGc=sF9{oMBJ(TN6#i zxZF)eO`51RvD@(r1F&j&Rzuz$8;&V0%Z-eGe6RH6TL2@rX#4!@#=j*wBH1O zPO#4T>%s_&BOd3n`8XIh`b@X=D9GgtBkUH#_8m-J+6K%*fw9dzn_YUdte!$Og>kle!DN z*JLwmnR*~@>m17@vtpnw`pHpolXCYacL_G!R*-Yf=#Uo9ooVY{nbevK|6mLYLwiOjv%Yq|&&6Dw zhh|~*IX7o?%WTk7r4%;i(b5Y*nTo{jBd<=51Dv7iAKm3EsuSxxhTwX57Ay5i6?rW+ zB=piMQg77OcZm)@!wg%WezI>;oVAK!F5jvmP2Jq?*-};Y+5ZO5^5msZWG3*$rR*p6PkkQtO*HlVsiwWTvS~K}vIK=+)?;~ujkXmdVLL~9Jf?4RIMY}~< z3WU%Hbx3hy`sqlSZ{7DsJ}jSSBQfWxnS9r< zk#4dlvN_U`xu&{bz>CAy+22&E zaxgY-hMZ2}*Rh_%i^urSw85XOccJhf#^>_wOR8j14(j!Gra2WkST_89*loFP4cT>* z5`6Np3F&R#F(fjdaSRnK|GKDvG23_@DfYcv?XF_|V`eEbk!=3gaVp=UwCtjLyxQTX zOQ2N>9~EAAyj5OPl=Bnl53@^ieq2_}@;v%Jz~ci(uxTI(p&L@W-|sAgfFCT)p5cmb6dVVjWuAk#TEjLN9OE5gFF&G1O4FM8L^8E z#-7(WPbl_mNX{o-=j38+>V4UiEK;^S@@YaDq*X*NkAJyqI5KK*O0l>1e=EN7FpS_6 zo8o%Yv-kc@I}{;USv<8l)7-T8|IPM#6(Lfu)~Iq>kjzSvWMhj*uPyqfP{oUH z&%^e`@~=MyU&vJbD_e%mNj$fYBPsl0{2%@-N}g#98B$T}RkT!@;{zVx1K+;@-{%QpIA z2wz^r&0ef7KmF3W(7d8;F-q$Fsb0kc8LG;*zaop${Zwi5t886!oe6!VUgl!C@MAS% zr%ddAygf2E+P+_9RcyqhM;`McfL>=yB0!(fNIvk{7RuoK%; zdZhD>-H#q$vDi5I>@1iXRfH@arNnyzMVFS?JS$K)pph%f!<%*@OlFWQr!9|v9i~agsIzM4AGD-FwTW5g;F|+_#GP;m-QDwIx|oNbLHgIg~9Y- zdY<}?>rv@f@ka4%Z`yBK(F$9hqC4rgX7jQ(^eicM+~(#M+bNG5Wya2TO~srmm-RTC z@#U}shpueQc3cW(wjiEr=*U_VyY?ie6UCI*UMOShqmE_lS~vMZfnuI?_$hJm>wTEF z`$a$Z;y_2UQ`SnWB%&LpTw4syzy-!r-U6U(<^5=znJl^b-yjr)fCH!MOuF0 za@0B|xJy$2)5Av{BvDZ}>ah=f@ueXDSI^mtl0T=pOAi$n_5SqjJGZ~@-K2kJ)Gjww z8q|$4E>XDk&(D=|eS`RXt2rGX52*&)C)E=hNxf(f@6|qo8w_Pu2)4ht&PAFuCDj!_ zHTs>k{bS^8o*iGw@60Ut{INsP!LU(m>!bGA=VOSbMaehtnS~}T|L%VbzqX#fLrC9Q zhVFp;?Y&L%h+XL~R$O;j`DziJHbShQYZkS{VeHdE@)To5|kl$*nWJe<3 z1iwse@wp~{>QhgcnUKyjBWtLVt3+mI<{LbB0Q$c)%ZT>zjzRUNUXQZ=U^)$VeZa%8YAo@j3Pf)NM2coQMG`(SNAbFFE{0$UoIlTyncWF%wY|Ed{43rEtB` zmsvZ!0gE-&&iq znQLVw(jt{IazZ5m<>8|5gvPg?N$QkQXTD?Yp7CoojgOz;Nb1MkioIpjY78eUk2klc zHmAzDUENo;h_*wGbuGT!h0Xlq;FS&0jzGWMZWL2{^RvA6K-LRKB;3)gy8@-~fr6!m z!<)l&@fXR?Z#F|3Q^fzp)Rm}V&(q2GcMJU=S?SF6!u#9)o=Z-DvuoOKrctx&uWBvB zerYE!X|mB@Ttp+}mo@Ho2(+XNBdY*c7((^~jv}5mj#J#~ zUmDDC-{F}-iepKU^=jmk_Vs<=`EOF7Fr+J)+B3qmSat=>&~@_N8(v0`1X)w7EVPrw zTQ>`1Jxr_i?c4u%|N6@p{fX-Tt>C|JU9TW7W=_J@wZpef$ezj)M|&V{ z`_8ck)aMX*YSZwG=LU;CU#?MowxpPLF1+S$F8oyH8kHMGh_tQ27=sTh$oU^Xu2@rt z?Vz_b$PQp$(~+{?T|KBqXOByE`54O^agefZol-u=mkW2OZMzmIafz}DChRqTl(AN@ zU*`1wS~_L0<~4BpYM88AE08wE+m7wyk9e00T-leyT8(KpwG;_i>~%_ySlE!xQiUc} zA~M%aZt!FtR1>nt*;g*qGPr&;@mo~wX%KqEA_4-v4%>rGmaUdq$JMUvIAcH@^5&^4 z*b~5V;X+4*Ls@d+w-s(O@oR6rdjPs*teLM~k&RHopRNs7tB5>Cd9@lYu5|TULIoYt z`Jg=y=%X5Q&vGUPhGl8tDpAiiR~PlY!g->zzi^BGD3Td~+PCmi(}vxZ7JHbQKh4>( zL)|DCDGs~WXz!_9QU&WpKXp0uHFK^QjiQfmN55C#fu&rPtr|{~QSg5!W}PfA=sJkZ zT=R&-&RYfTX8kCea;@o%cQCG_AbmT$@1jv2ycxf*USVW!mlM{YgpV2qVj!#%{_{`R zhqY<2F&rtKj9RZ6U`@2Zra2ECu;jFK0UOXRBJce3&eYbHC3i+ z`bJIyr)&`5sl&}%E+dOkUWxin69)jt3a;vW^1*G5*cg_@NFIBLDG>nalP+~0se++K zcEE0RJCgwF@}a_AVkOju4tSLFoV+-^V+L+#Ap29pXiQw{mEI^%U6F6(?El%;Q# zy?*ha*-nCnNpY-r7;Rg`lQ{blU`Ciqml2CdK(93garo=UedL*f zJ56nLq87^KSF7Ni>c#4t+FK$kf`}zSK-~8N_*wi(%xMRez4iEfEZCH840&JNGRcN* zVFnM5WMK82upGCxHuX6%Y9<{Qmm>htV#Fk`r!SdZ2+YI`Oekz42)eNckkr?Q#*-0< zODAU8nTy)ve(G$Ae5o#b5rrvv(2J&5AWX!88SgpZz-fop*2dHZcFE+&vX3RL&mS(6 z`hJlkdsw)2%)o!rK!d@et{?r_`y@3TQ^@Am21RSbV^1*8c|Lv8u3liMHv6;1v)LI6 zI_qpL@n1Oh)5ib1&0nqUc|m-IhbKgn3}v;z`41?(BS1+{n)i~cUnx2V)X9)}M@|=2 zcK254TGM4}Q*g3GAWU7qkB-)?oTW#KLj!}9O?>fEuGZx})l*f@{;v5N3}Oj;8!Ydh z_ot>>j@esbartIc26?vEhs{5|wJw5(hKAD8(mp?996JE=(aBvJpcKjX+I+aur{{R% zqtU(ETN3$$4!G5sfm4tBnwlQ7x2acaiDsFHEb(2Sa^=XOX*GKcUH*AkuXg;TW0~;F ze!9ROb0T*d+54Iq$^6mq$Glwg8>vh5H)N4&2U9hB z61SJm!)3guB25J(XJ5Cj-0wwWz6f@oV@Kai$%Bui%^jb2 zIL)=cW3b8h34Y(RKBp}`pE!kH#TBb77u-ZjkeJtw1Jd#GLiaFv3Ws>(67UZgyN*Mx zDlqTdvyxn|(aHmbv(&xRqhdSIBf}JfUZa`&qA}axla7@g8PJ#e7FqH-c(rPn3rApq z$6+OD`_PG278r(%H5%{rS5J*lXMn9To;$%wua%*UbXEmP1U(O=voD!AirG_vRpWQc zFFE4(u&Locza_6yfOD_bUTOnwg=0c5f&J-edmeh#zdn|KCPE>-6UA$bG;9!v+2>j7 z=rkS(q^AD;@*W5zmqs26fdm-7qcnmY*PNuj5~v^$$Ds(^vIWn62t>lTR)Lk$>D9lC z_}g$A`D%7Ow7K#3rTri5+TMP@5ZB}oFY+P*ceL9z?$C&S#SwXE=8}zdQj1_?j?~BG zaSeeYojh-Sf72^1H?Dab;cw0oBbw8btj?tKru4VkM@c4Cs=fJkhXCgjlMx<+A+Nt* zmJ~r)KP&SKbTpLAmuZrSnOqMp9?E)D(s!n=z2o*qvG{q7sf+S+nzlJ!9a{I2 zTC_HVdos^DT$C4kX3+$-CESkGHxzhHZ;X>W_u?nNTw4|Tn#TZ}@0aFVgh^+;TCDx^ zds8;?ZWxB%L6p@Q=z_3H(Srx^&!U&_$x1Hl=Qs^a2Ksz* z-QKh-=eu!r$&Qrd3`i9i-yBBPalb#O=T9(7SU_R2zY^HpQc-M*>wSF&Y=6vu&BpKI zccsrW^l9TC#xdGW4SKlq1NWlq+nHnIR>)Pl)0+aR=;e!CN1d=s`(W!UX;agsOXcQ+ zl7rn0?^|sp=rG!2h52xyi+7??Q^o4N?MW!C3|cp@0`-+&Kc`t7k^f7~7CAlrn1MS~ zTg~4(7f(Jbb9kur-eABf*TrDv#?uhrMy`PnjI5x9Y10+oPUP3j_sc<*%d;~mPW!3S z1*SJFGht}Ev=25PCSMc`%w6o2DXc8aU)G+w30NYwo-2LJH|Iy{@#T6=!1W&<6Sw3$ zqz5)Gw48*pJ^Mv_0#vf)uKzP$LD9G7@=)9NEk&|PEgci+i+4nI7~+2x_N5YDEw$kC zekn~ZG3n0#pIXZdfn;2sC4wW&_Mh6x4Yu9J`zTNn}(s%;OkMr=%eAfaiu^N?G4{!##&z(qLL5i^%1wtIZ zJCDCyK|r>#ZK5XCHF+M$viTG(ub@{4OEtl^V@2)T^JF7g8)`@(m?+iVVgj81M7DMk zl+9_8T@7h(!C|$_-glE;hOo<7sHNTSfm*2f>Z2-EQ2C56$IY$nhvag2O3no!EyzHJ zT}q3Zv0(>(mQzb^G2J-6zQP5IRxiYrn5DG33;H@A@S<`gJ1*Hl#?bRaZJ}7Fq4oO{-BN?8mHYL$%7MvIq|0UYs>GZRi5b1CrF~{`5{`c?q zQ#W~y;lY61E}t- zLv96whrIuIC?6`lKTZz7TfuorjhWHWpMCi<&LiiSA!bj=(Az;wu)e;Y{jJP$Vq)S; zDCd&WsgsAn{3sv&%X?#v^G@q{~2` zjO4pZqhj3hg^`+Yb?o@a72Kx$(fAPchG4AcwD(lknwc3(v@FC7Mj1NH@->JkpA$p^B$0=1O8uo!E~`KLQe>QyeIO9gCuuwqPi6*+=0S~Iaxyk1F7B}89!Nl4(@}o1 z0vuYFMmTOkAcIWwNjbp+OA8VD^vm}gH9Z;zslS>i z>nRL0A;4$R;~||{>Z2qJuwv6f694-A<^YANq&<+^Y4>-wy?rw6`oe#8ZGN{rP6Y`_ z;4r8W-ntAKKiPVm9GO6r-rlE4{Qz~?OXtk@y_9ADKrx6n_CUT+`h8RjSYW#s#Tnyr zgWTD%KUmVl_xLgi>>|>Vp3!vwYp0}&v~ZjO(&hpG;&m!c$-)5LHJeDtnAn%&GAG88 z$uxXDH~gxsNTf1ux%}EbpdA0ERITQBsb0@^a6GL2EMII=b~uEsq_WQCFI18WsJmTG z2YMQlmv+?P{x+kIuKQysW4RHZVufS3zgRFqBss~nepE9XTbL8QF!yL}q9@R!{y^GP z)H*VO%TDG);<(z$yFDO&VmA8zY){FFQdrjjOs2Q}{ur0*D%a2B^LKkv21|IK4wX`C z4yH>{GlUv2L>Wa5p+MHls$qCQTK-I==7ZizCQr@Vt$$Jn3AjB@f58gTPbYeO1fBK_ z7Fu#o?vN~Z;@ct56it(V?`Tqy*{z1lmlpLJ`Vjh-oc(7^t_+ZMx?C$o4iLe0pL$l8 zX3|@h+ZQVFjQUedZ*@nF^V}}s0@DtAq8$|7hQb~>kOLqp$i2wZqw(8!_}{sBd(Gtz zRXvxvqb@4>^IgzfS51a|?C>t4zv&8>@MumvGoSPM0>d^As#>G4U(>RC`qzYPZ&mMX zagHqP>!Io#ovD4x!dn^q7vHW-gT49E_Bzg44#MGQoG3;8sN~>ZxCq1N+|qr2ybRT# zRSGI%_=h_2W@{lfdw7VWv^W0!Gj1aiw*ivBPoYJedZulM4W`%EZ}0m8}u5oXc)de97_NPRmvJ#AwLD8gZ?rS zU{5Dq#_J6DxS%_G6uDL2hM91O8e_s7p^svz^#Ez zQi=k_q8_L=;q9?edpT-h4AX|5mpN-;zAM_enb_YzZi)mONYxsT6^?Q$j3SQ}Rs6onxj z3@XA_s|=dLm@q0Ruxz;su2-G0`_qryx^XQC97z#U$ZCBGLLOshZ7DZXo`FIu5Q!Br z9=UgyswiuA0JYqsh9e)cKbOfQf6O*l$pAa@h^F;E|Di%ViW3f#Dhx2Vxi(ylS0E?Z zcFD0)pLEK@aEdx-B{_i`F;3W@DWf;$X7-JI_=jPWdE1sEb0go1;xlTZt}zMsINxXX z(CqotbLzp5^Z5!V+;b$hv;Q&Ue>m2^T+hLgOTRh;#}Cf8$I3zi`eLY^t`QC{srBUb z{cgtzAars(Mqn;pyxaP_{R4xEZ$xB7PTlLL`wJehk*v$4J+O;MfjOtY6!}t`9!wW! zb;IEtd5PdXwZvmPUiOE|1AinOv!le>LGzdWBu-?5;PzG9 z*^CEE+KKuF){&5%+RTGQ2Ih=2;vflLwLWs1AYLSn-gw1MQ!@~p#INMdaJC`xN@Cz0~jPq19JH8w&@dhWdYPxGApW@T|GA$DHXT>&GPx9>$1& zT^~8T_LRNDwbKJr)M@`VwNa+gDR2PB2<$H#!&)MwhgjCNy|qhWNVhMZTlK-@ zY$t8(uQl**PQo#=g4VS}nH;Nu-7kh;f9hpTASTM^`41y?4sNgy=1lDSwdDQo&dnWW zrE>?lR-K|jpr&Sods*Y_g|2f|&mt#IT`ETS%oKn5n+e8wyO^IM%4PME$$ze~|5q;V zf87}@UXXyi1rPIo=sCi%*U)BrR;uKe%YO&SIpEmc$}QwCInm}=eb)bt=3(62Pa}~rb>1TC>-2g| zHRlfLa{^~m9ofV9bStkivMZyof!pKtRqRZ%{^yyz?_9&zeHaavLGsVZzTnTo7o87IR?&2C2>1cll|mN~a0=G`-vd-R?;zwAyIU zGJc@>Q*Xi#ra}UHrj8;Ok0NGD{9D{Rd5s{V{JV0^r=wtGi4{zN+7T%g3iM*+&Sue0 z_hNF47~~m+efrhQ74WS!aJ=sBrId)2tH=`o8NpEto~^GW5_*5=I51f#I8Wj%pcjEN zrU7^%3KHJtM2h)!6fIxBU|Pvao`s5x8xuGqqTPORrBmg*M8LxdEnRT5cLyd{^DQgH z!9pH^#rl~)NMl$1ymvC<*YCO#^lF{Bf7dXv3J-IZq=g(1)asEzFEaK}u?bq; zt^VH9Bis}E`BBKI``MR#7sQGxmzv2%lykdB?A6Aezv36)k~*{9UbK`Ruzx4Puk91x zIY0yN@#AJOcCU^RV^Ql)dTo!oBbIrPaLsbf=&w&{PO%Qw+zCN8a0euRga^5SActnkBGW84_oGmco!m2wjm zA7cl1%Uc_|7#@+`1of+7B>!It>Kg~zQ6TmFHDbMTN`b6P<`itKrk>y4SlXj5FWzRs zbiT5%Q}zrGSVygSSp0D(tfy6O0hP+g|>Nd;WIO0?PEGw z!l-9XYg0s5Al_%AS)0_yQOmmY5gM{|no5(;quVwH!3{L%W+wC;rR#^~>!N-HDcaD+ zy$4eRD9rtl8Lhaz((_+QS#h%~n$$i|jG{0tcWr*SLc#5<^=f>x%!0g5r8vhXSx{GV1!Sp8gb{ z1pq>NwpUGeR>}Lv{~ScVA6YfdH81g>c=LerDYy416=e`%y4{(Ie0#SbY4MZ@8B5^S z_Gk#2(pFFTq8r=;{Js+OK-H4+I${}E>eRYap>c&L_*VlaXg>n*2TKp8yR&5~#~8_B zaT2X)*l%Rn&co+@*Voo2_*}`i;K}vqBr1^I`it-*fE^3QUc;w4V!%z-jo#OaR#8+> zET(q-HmD~{bcI5RW8mIFbEf-ba{{^iA3-hq?srLK@@)SAd-$SlOi_~J)28Y6dGyv? zPy4=wUlav+(AYc-R0E3wmk|hdcIg2xLD~{hJXnj|Ov8a2>)0K~YfYs|w@#B63~GI@ z;~@I$v}PD!Lr)D5^uonQ!pUq1Sl#!>u(WDC3@uUB9`VXN(6#<=zn?|^0{td^*#Rw` zb`E|)!z-UfXJ!m&eUDmzZ}~^CQVKd7}|ae zK27$m$;Z&d#2S&3y7krP5mp)pw&W zll@TWi-i@2yB98J@*mEGinCedYd4OSM_nnsmHznCAd14t>@NFJbe>DsLixR^y}UJSg&ss$(RVMKXY1Ld zU%nHg_rKitD&6%u&#UI>SEE_<(m6|J6)fjg*@7?k2Q zbx&lj98O?&Egi?OjTLr+%fB|QKXS9*q8CxqpQd}fn9Azak5T410%v=Kw^y0wvkEzm zzt6>jDj2WPM7hA$OuZ)#p^1}0nc2#Tqyr}g#Kq33g3#wr^{8tXf4?v}aQyfQvhGu) zO4dGLsK5Ey166*zCUNv{%QR(bNJbl5A#khYgm{&qD?#9(vHdR{92+eLJDUJ$qtfnq zB7~Qp3Ht~B?UEY) oTcn}_s<$z3BEkO%+S&7wU6@_??)@H+goj*J)x2DI$t>{y1K6t^%m4rY literal 0 HcmV?d00001 diff --git a/http/figures/net_manager_arch_zh.png b/http/figures/net_manager_arch_zh.png new file mode 100644 index 0000000000000000000000000000000000000000..5c247ab20cd8ca8afc0605e104cc8f33720563b4 GIT binary patch literal 41997 zcmaI8bwE{3+c!$5q;!W!cS$PU5=wV>$EI6CVACN;mxy$;Noncs+|ngT=UM3eKJWc} z=bY~kcFdZYHFI6R`CYX(kt%OxFwjWQU|?V{oqYkGw*LjMx&mSr@p;;SjP&uf-rBz2Heqx?kLmy1-PESiFi00BTSCUH}?oQ zr4N{>u0@|}NNQ_9Vp30E94o)vFT)>8s%)Fx+&@js zFvBL5X`YV1IQOVo7L8=wufv=mV-OOW{~D38x3AuLivo%YpI#o`u&DC(_4d}28yr?z zHr#FZvD~&f(p|vWTjYb}-579V=e?e4c>bSPk+XBp)sZMdcImwX5yUB7v02ef)e>CR zQ0#kwt-F_>KDDi|wSE;C6TxMvDw)y#^INq6Q?Phxzupdq}XfLYA#C-0& zJEJ=^_>~oGCzv(=lZ@G%dHP={2ZDN#xY}#Lw{TXDN0@ZcwKH( z8f$Uo?d|O**JKl-+aVS-BwZDrnLfuh;LCBjEBektw*L(uyhF@4Gl&GI*nPnaalGn@ z`UHM!F_n4b{fd=cqA7Wftx0cN!wb0P`rz_=fs99sGy5JNv@Z?8ob>I6o&AB3z~*&8gPUe`VcUGMSZ+%8E27Ib$4d5Exij46*&mim z_H{GTQX!7{sbZ~yKFYA?8e?_JmhZnlt8h$dj7dN9xGxl+r20+rEv=kQ#7F!1f8fx{ z;`scC0P8!{hI-n7z{2>hY}BF3y9J^vENat~`a%0<-}ZQE>UqQdp~qqB0}XLV!Kn1@ zEz?cA@u`L&J6+a72B+Kuo!*arl4^;7V@6MPtqPGe2ayNwu(cdp3Br2>ul$f=GatcE zyJtV`9+=Pm4aAAsUx~`1C*L#u87c_LZH^;j+aH{U-$Wqs^OF=gK4Xm7VY&|C6Z~&P zCmXrNUmYw2Vc+lOvNI8ekCv0W9gbd~*O8Ti3ti>Ec^g0T^*98yveP~VGW+|{dq+0` zT%2hF98<;jt2K7Dh_mY`UmWT6!fDg;+IFQ4+b&Nt*xP@d665#?YZENB6c_hpK$2To z>lN(%ImHpm{H2WY9)x(QBm=y6qJH$O*VrQK-_}g>4{zIkZj3Q##JFW4hR@a)+F78y zVLvA){`)a&RS=f?hFjH-4ny3U1h~1%>f5I!sII!@PkIG7lSQ{@2LAUx-ma!}KXlu> z$<${B&%~e1*M*cTD?7HFgtf4J?>ohc%E%D9PYJ9KjosA5f|O#Pt*SjNeve#CdnF3- z7^{0Na@J}AEK+b+0UUM%Mn5OV`6xugKOiIL)A<~(0{_bxWf4Yr5Ze9j&!*}iwq*Jej`W8qk##DD5d(~7s6XhF-e~@y!ao(!sB_gA4fLR{f!X?HcE5Y2X z^32tQJR)WH$4`aU`8w4DzR4<1*Ji=>ZZ$YQ-!EO1boHCHSPHr_9NTseM@;HYi-r65 zm-kM3e@S7AfauFL-zhG(Dqww2LwBx8tEZ2MYA?IuD~ePkEgZ*2>^)x^;Iei;X~4HL zOVA76Zu2}5_onDB6Whd|+>KU)r-#cKWiT{7vuidf zUR>@mO|dYurb+iVW26DW#4#CqI%!xj9~!_~&Yx*}4y)7ca-cio>1>L{HH2rM!ZTt- zovUxuof)I|n-ZmpVkS_HvM@F#oJAVsD#FRZv)A)AmJIGjtNm$~D0-*$qovNfjaiG% zXI4stMU%vZNY0=ACIhs-1U{5smfx&s?vT5l6BC>^*UKO|oLh&_L_b%qeQ6HC!0M`g z7nz(?Thp*u`s}MnAxX9#L-$Dals}i)$?Ds=P)gUh^A>C&^h+0{3!-N2C}Lc-x>(6s zC!MnqR$0pI2TOmw+I?5K1m zKghW|h~1DemVeu_oO@ZN&u6r-hcq)-_$n&PgBfcSc|1Mh=Hq8rZa?l!=nGGftH9U>k&aza=^J}B-Bl{1l6?M>7aO?&*rmD1=OM{^qf~h2t(1%$&(E|p?MgqW-F=86a>&(wn_OW*&m z_s~n)_P?07{Gtd`we2DdvWb9$dLKFGkHP_4+I3CXmhW9js2xO-|EPO#7y?DB5A(Cm$%n)Ik}auS{Gn+ED)CP^UeoH7OaiL(6L>Ow4~97s#@B ze&5@s&-`xk^$igjD=539N}ui6JSwBmUvp+A*_e;ir{1M6*Cu5rBtBu zpUka)@YQ9M<0WE+-dcP$>W0xNtoasR?7OJ5Zk&~|sYVcqS2vy>VhUWK^^doM#E*OI zJDlZZJk))>E5))g>JCBE9I$y6!R{XFtSR=i4j7$q7+Rz;K?EXB;>qkoi2mv={JYJo zQ*ZBa{?he8pGPX+3J-sqw@%WP>==I1b-mW^3r^+p1?`Jd`z z51yg!h=8rdgq41ln0E6MicH=_j znk7>@1+?Q)BKGm2(wB06wc0M_-0;AS!vv;G{V3G~I$ZX!6%)H#ame>1M$)T={g~*c zrJZ3>pUoJf?#W-dY;&O7@j;Le=Sn{jXW)NUAdEq|hwBT9pM>MZ}Fb+ z_;vw~VU6mX#81pC{lf@|!g||tzr%pM%yJ=jHe}6)}`XxF= zL|^(h$Cve}y`4U6Z=@B!Fq4Y?a}9RiJ@I?093)`V)0NRMTd0?p>9i4Gjw!ZnDqvI2Dq?FvKA z3JkZ=hzeqvMBv{uG3Pq;EiB~V63nrx{(s1=N^lFBZ|FWfd(hBZO@djyD#Vp{{1Ozp zBQQ7;(x@P<^Rq{}Ph-+1;d9V8L3cL>k;gqhdaj7_HVC1mr36)axEO{Zo(lJYSvhUw zCWK|_E5m-1tYdyjX4I3$VH;$sF^L13x-X~6RN*Ch$}~FxJZYTx@)K1cuBNEea7#@& zsT?ECl$r(>ab2Y6zBe6WxsL!V91$QElam}uhcW`(KuTV; z*X0S>H~7^gz4rz%ThBhSlOX)VGk?za1sQkgI@N6}ZP)ElV7n`$gs}>InFPmwj-k}e>y<_g$V1yv;$W1gtV1i(b4eNS15=V1>`ZC_D$=a)56?ymCg_6 zUNxQj2r1-BO=btOyO+O1%8b2IIy- zv)mY5yyg&hGtp*w(M3q9xzTx)IrFU6=Cv?2`O-M^LncSdF(wxYBkG?e(_Q-0uO7N| z;&L~#tez*qB!{vE51|}10dz5P0J-(h5=!gr=~-s@Fi2AnlM4H1jOE2LwBuPC_Yhz< zfqq+uke`Ci{5i*OF%=WScl`AzZ;tTd1wN{Li9>qYD?jy(~N^#Ou~UZhwHvXf!hnOKLR}Hq|YX(B}wX9Jk|u+r?FBxjPmrb3dZ?JP_-g z%=fGQS<=>MA(AswW2u`3HGPqZF3{p7frXP;TgC`~3j2UL?VM|IP}N0^Q@gL;Cqq$D zmZM*dVKVp2sH~wr&J(0W6vMIS0vJ)@5cSPYD-quY@}WS1u4kQqLZj8=)}OTVDqIcWqI7wOU@MLSF36HY4G zz%?x!wTzQ=UviF68uWp@iHk1-Lq6aV}~ zGD&(5>(2GO8?|!V`$*`UX-)|WKR>^l9+yJjv}VO;Op7;tnWS!dfj6Jy{UX)G>#IIQ zV&TRY&bcCzUs{~3DLZwWlHCj8LJS{$&Thv_8xr7mS@;ND^zO~qZtL#VeqHRMwwt%E zX!sL1B5JG7B&^&dw(8!K8;J!_YAx1trQdryUh(c}9G$p!-~4WWVB*vElF5MBf!eWJ zTJ-nu>P_Mu7g#t8Cio&$>m-ZUrf)YLo|lEZ$UtwmKa`MzJcd@=CXm0NQK;HZ@T2GE z;^r&j2usdPTL^Q1#xrll_+$kM-d7!O?{LejUanS5vER&1l21Fw2>E8y7j882-TxTb zN4IeLwKhrKKL2GaE+73u0$QKXf0MD(TrDtW5owsN0h*cV>L=1&CUzneirbqc)K`&z zlWz}V#Vl=SYgcuAN6AS#1iHgc7GI>29>xvO|1q`>+W(LuHZeRu>V5nI-)s7%2vw|` zUNY39B$2ldU%~wBR`-6`u9Qiu@69_)mJX&^X5T^?lTyzDJiGDy07vA^uQ?f-Z;`oo zUWcPjY_KhVx}w6-{wOl*x@t@guOyWNJu(*teH!`G$WPgapRwCGi%CwH^VZ_~0og3^ ziZdkcqtwfh8p~0Y1+33GRBn1MfowwPZ&g03s(oM^bGAev2O*P#q!q`U5e3-C*WamM$$v9hWKhDj_LS(GRog{gp#L$??%X^wH4xpsOwPP`!J`||i*7&W!zrZKJB|JgDrVLu zdrGol13npZl_6ks6|5_Lg^yppfapGc^fpZ9-KVH+{lbpFjsbAFZOG=t@!oIFj|%Q=12G8N!~m7+%M9AaOVxOhhvZB+pFIR@!F%r*`WgPB1}t-pVOx!MO=gs#N; zlH-@(LrxrM_tQ}-4G3-weabjw0HJ?kVtDdOpGMMzlV568gG=L$T35au_dw5OYb1tg zM%gS(0euzbK;fPoEuO9Y#^6`wpQ(o5ft*QTmjJP)qj9xBJ#yDQusygU_1)k79?cfZMIWW8r3?^Gs~KhXXs)OGuS8j2VWg|k!cdKZ?rw!>@#2t z%hI;{UZ3X2ii(@7fH{b6t4W_QiPPffP7%QU6H>DPoz+{`NV6*{-+s?5IRk2%uM`$}?M2LtVpL4Ib{A*dpJwvu0DYCnTwu@|{5WrNR;( z&Ckky`dnZmIpaTiG}^s4m?$%n>>}rHy(=koIMWAfBI>`S-RHls4cXtOS`jnQC7Ugx ze9c+ne`aJ@6f3vqP>Na?pFwty5uyD09 zrFTz0$^W?4dFx;y6jlHu$mEws$grmPols}7zG>uAS>dKjY?=yOm|8kiP2N9V^oz;Dx80r);J^uH206<@2FIrE!3dwlaH?EwX*Y2d=6RHZU{N z@(TMQH7(P(nD+6j%m%zMXV^XUqx1Lm)6es~VTGqh^q9ViDl#HJIYnX1*Hn*#R$TR2 zsfV@14GD-q6tnQAwA$cdd8XD2OCTy;a=4g1+{r=L^*9UKk*Et$Ea{x zsr*wwusp5%z1UL}B$?mid^<7V94jvEus!;4Fj_f%Z}d$qLfuX8kB^EmPFO}y``2qy zA-#UZp#c~mw5Q04#BJ#$2g)?Tm6T{K+0{p8_LGy0AMiPqJCIqz=7jU0KXkXwG^|=O ztC*w6pXBLLc-YD#{Y+M2&)`HUp~e0*xQeuLQy)*7C(p8WX^sv3f=%H|6QK@i!K$+? z`^)$AaCu%tX9&I>CK1C>X}$SQRe6YLO=|-Iq_(m)>csn#SjxwKwPfkzgC}|;-4WWo z^&z*i)?C7Cl_`Mw1c>SQvI}1Eyzqb5Rl!jba@c0J?qF=l|0NJ7W`~%M{jhYhrFD7j zQ{w_nP0Hnin)~hX;rF!Ncg}U`KDl*bcUd0{NB{;sTrHC{xD4TxGy%sOwB(xA&4f5OPOjVd!2R=^03TyiKXK02ct@=O{U5H z_BId(%JUqI^mNCNG{xJP8j=?m$1{Krf4Cd)#4U{7Tba<_*@)q0QF}-0dQ+s35!ipi zXew6TOF@!@r9<6ghATfKa}hwdIQo_H3m%1g2@ z`MpYl*!$YO)aK@*T)3yh5xkNcOjCaQ3c3DCzFZMLs6^utS?f`6somLO%ZhP^yK)99 zqr!_JJze6*AN+i^SP4K;#eFx*V7W)b`#sG%{6Q+dSW@Rrzw%byvHcv+St>`50z8Tt zn!^;wgYwv-KcQb^_+Cz4f2u(~^j8QPB=k5ly|>x0d|PVa0V|Ql;~aXG&D7-U-w&=4M=X zn-Clb_)Pc(q0sU}r-nhl;<96@LzHo9wtUeCYD4ltQQw4x|^U#0S-?%sBh32y8pryeR*WBcnsB`3H3m z;ZO1i;!ik^OZn)N3G>7=S9$MbmlggI;;3=e)57o`N3;W;*!zD%a;s+>)gwgU{pjt+ z^X#{?`?xpB%O46TXDS=xA1O3I{3oR?C)#K_ShJi7l-ioTE_yg74F5G=?>hgirv3WZ zf&S{acvV~d$5GQm>0a!{*RXn&Y0Ae`r1_g);KdIMwa7mM?kgTY;4-3oUc;sk8pfeq zW~ZC+78AKJUSDA$7l-D*cI+%2F&8|t%=Qa=>Xw6Y)SbH3_;~&L(K1O^Yz;xGQL#^- zEtMfYxC7NCA{%3HJ}Z_PSb4z1b^!R#2t2}_M%ozR6?TO-2Ot=QMlK<|Rfz)}!!sK0 zJdfPNS3ooYxSXo=++w~!=!C$b!PspfcvL6RhxlbQ&NCzmkF278&9C|FGmER6-uePL z|IOzcYc()pU#XI>>Vc8prAOAwrx1fomV5*~_&O`tdjo8M-LiBlNSnq4Gc}+H_)oyA z(N`E1dhQ^wLOCJeno7&zvn61OUaf6xd!ik|_vAo5Hh?U9+6zArmP#>|+tORTE;8lL zbH*;E7Rp&iSG>23QRfW$CfXKEWDVu6^X9X~&#DEA(Da+a1hRtn-ysP)XiC1!&c|ze zyg$xYzupMBbZEaCc64xb9Cs>f6xHv)`%)Vq!R33*@6W8iz+1roy{Tc$S!mt$?g|>K zx_a{5?|P#!xq@(3CeBo-@EYU1+j+ghY3ZlsV{4`N8=Af82%tOUbaC~8fNlcj?bwID z>EYoc((Q3}N=*oIVx(;p_v+G8q;l%*e1OY`4%CkvDbT#P7QwH8kQdeH8%=aF6X4&& z0bag8&JxKNJ%$=rJ>yiSt0U_+4`l8}$v%9QWA?$bPpwc3klf{cD6w7;v}hXL2n=TC zP;d0uX@mjdysb>8|HO1ItsSUn;(dqR05&{MT!j%YgA&G^v3@_?9-AhdEsMO#RO3+J z`N2DMf~S{l0<7Hy1L!nc{NjIQi%Q<`+-Ixb@eRyuF_9v^AT^h9!YAufQf#y-Mnv)k z<|D{c1P*Ubv|lg%XHOls&XF|q&kvfOcW6niX@VkL@WG2N%uE(eykH+r&?b1h@%8<# zvg(B61ryeVy}_gNS@?&RrEASeO%NnoL32ZMx{H?3roFhlVg|g74GP0EX`)T*EPPe2 zyy`A1M`+!C&7B4P(Vy*m8kzE)TXYFy8NCbz$hxIY?8`o0O(DAL-p`+ZhR%$UPkUV& zArWpj8sOWoE+>C_MfVQTxjnpZdcy&qrUbXOW~*^82Mb-h=gxreriQSf74&rs&ccZi z>?4xowj`DV#We?mODhZnfB+sW#J|({(>v%-I31)%4Fud{&Oii@3PkYG1Y2lnMVt68 z8PF8}dE7Z%5x>8V6SXfnp{u&9ntS*Z5Pxrk0t(}>*D6&eVXvOJtTmA<@9sGqb!hak zd#@f=O>|Re+yuwgTZXNTBMkBW^B@MN-1jC&Zh;q}ar^M9Yk9_53Mik@BH#$oDp;|_ zixBfVK5%8E36U?NG|B$N?&?elG^dSQ{v1L<82*~90N1q`zE;_2h|cUik!xSCX?d4$ zs$1bLn8+t}JmF<=H2eOBkwOO-)D1d`Q=Q>D2HoiY*;GO^j7(gtEJ$(7**7M-es-^f zl>2`ff_>a}dqnEk5>&hf>J2C`u9_$gUoE3J(zpn8zC8~|4w!39zORC+RkmX->~p&L z`RXjK%~G1!68iEG=E@AY7kmz$Sr5EG6}h~edHgoJSUh}c4QXqi-AH^tWK>}{tD)=g z?bv9?Govor-={rg@4oDAdbo^#Oi5^9m1BcRl>>o>BEe=m?`x{x3TMvNm)9q6B zV@O=vrE?F+)9$R2YRO#Db6CSsx!Y}rLe$K@vf=CM#qR5s(-C0@dYkD`} zxU14mO+K69yhO6>o&2rCRc(6RYQsd9>f3~fY?se;ZPZ?6!*AhQ6jkBAzLzl5FoWW{ zR+VR#r7C>$41K9&rcY*vs%7ya#L+`-ZvK6A?>>S2M>(Y?wck%rp>_IEknXt#sgdOE z)q5->>kBxSL&G(1HP@_EfmDxB3%)*!X~LB68ac$v@%!#(2XSdWj;I0=vs%0SxTUC7ASz!joOn-?r#5>00WmFziWG&H06q?H-hKJH$$)JxQ zN^YQ=#$&=^&juqU8lM~epY}}R?j`HJl_Rqq9?mT*?&v|WKBAA`hPC+MSaEY@jM5=j zR=$GVjafoU%er^cZ;B&1WipKQFa>*6%;$WN}Iy4mg<~qVX+j=I11`&N|61+%SEqLC0IF?RQ61(+X@zy1H7+dmvV(^^Bp1p_39=y(3ywwd4fse}Dv|y3Tg46Cq|K~x@ z0@dKElw5v6i=L^Ua*k{j8DG_{8|blnBEQ(mx?A^NHr&1MQ(5<=#b2x)ATXub8)-%_ zpiGf1Y$p}c&Zx3O(0L&q`^JNClrVdwPEQy6QOcT1=V_A? z_9u-26ocbokIA5Si3WVc{M=SD?lyC%qmGAT2zleqp6b3g|gffu5^o zdmFQ7zoMOOGD&laKK6CF+*K!*e_+u7w@k(^k+u`CAT6*x&zso5GfC?$vp+@x`s-kx zJIUhvU@H6Tn;qKs7T?M2i%fYsVFlncNnJCEe>P1{we~n7xTO=h))Mz_=9oT{ny~;* z7D40~ZKWgOQy%gS*Z$!2)P+>Jr zMtJ||U1H}xYQ6X??ZfY>zGbq7x9k}`(dRCiI@_C0t`EjYpHQL)t6ZbY9@xB_srl6n z4{S^&Oz9SPKAT)SgX8a+WNt61be27#tBNOuT&l-4vHyFH8lp;DfSPFam%-68O?cV} zYQFpNRdTGGt`5fPk1|U{UYe(~0d#Ynu~o-X&HbgymTjC3@O>*YD~MHS7n^U2yRMuo zwy|E@{Zu*eY)_`ei18jmxiPLH`|RN{4jo&NsC({bpQ6-nyA+ycE>l6W8>4%lZ&{?Z z9AWIzu{iwOm7n;DqTyhZaeJn%*-&kt-dy@%Ki6Epi&d77rBMY@I{Zy> zd!$jiY0T_3i0l%bSG(vNM|}4-w6{;lucWASK26v5%!!d!wjc$^4Mxs~SKI$={Dsm; z-%+UIAL`3ZJyP&}%Ty9XhSnG*h34;xvcQBqHbJNjw(|=euI>X(FD&C_Hg6Pdj$=2h z^aq#}lP#*H5MaTMpMsxRaz9IPP51XNvvcyfYYo*;R-+l$Y45i)+`+A5RUFJSph4$g z>%#$4Z?md8CVr0Yv3YEsQW3;r<{ApqEM42EHAs1Xv2r|p8sT_}dZl;samm3|=q@vY zjmn9XFnQY{#s6;K$HS|XpeqO|1lzSiBe~k^NW)hP?Xus*Te#1tQ34%SabPLF^+~(0_yuwe9 z42aVW3g$C3x7D8K+cxE_(Q=T)+{x~={9z6@WO7r61^c7#yR@%37&wOYeG#IY;K%-( zsy#9k;6k1l7+{KjtWWri%6}N*kS`Sh39+atO4-c9>&T=kZjU&K+z*r0@I)`dq%yx| zcoIiD&{<$2%PqRi4HTWwkrPN1HX*e(`AK^y6P#&+dN3ID_IXYb#nbyc+^4=a?<97Y z-0-dsrlvytwvm9@Yjlx;BR7}^F>t*1aDH^sh|1WUl+Fg3Q7+sR4|y;b-u>>Q*QIO) z8BoG}ZD8JEs#3l(S~#jjg%{nG5UI_QUI{gTkEYK~RiaIXPIc6s<>LBsQs>VheFw(U;N5!)#F~;#y>lmJq8Ta)Twwg!{i46Q)g07f+Plm2Mth^Q6lom)B#@41m7rW=Wv zSqy&P!&~I&LDdWr`R$_oe#>G&R6_iKx-ypqseZTD8(Dw*yhx{i!Xo{vo9RVJ3al)q z5x;fVB6*!1=#@iidJMH;oUlEs`|*4_OD%*^&>i+d;k#$WDs?40P6S=``R1uXO~$5l zyI1A1`GzR@dn|LFzc=68cxJ&Zslk&a|4>Lr^uk9Rf zi{eTmb07yJ6{BN^OnTAG3C>wEPh_3vIey~90xD=%nov3`c`>*zw|XeZB!bhAXI0rw zh9WsLxH)wuh7#D8^$HlxLra3bSnVR8Bk3yHkpAGow>lJYQFs;Gu9)U8;htF#(18c`#^JS1T;uKhFJyOJGtP&!A7<_zUv zv5dQ?_+4z%ky%#)*xJ7ez6^CtlzQ4v@b=9g>{-J-ff=x^@=p{aV{gNdnE|HB&iwZz zik1zS!OF${BK$ESb!l@3?k${t=i)lx3T?oV9^LmR9ef8W1V{Y&@Zk-c;sr%PHyGSxhWv6Q<^8rwBJY_u&iiOI@-u~ zreJT09HEqf{YCdpQxG4H;e!P|GZ)cRD@*jhShRW7C4K&W98L#JDeW$%S*h%96N_4* zUenP?R#%dnl#>mU|D8 zr%~8zs+}wpSr>bQpnc73tYK2lv+&N0lI~PqJ-|iGq|7xn;OjTLP0jY3`sAmVh^hjqt~b; zElFc@nk80xZ|VHlU-07+tVqqmd_%Ll&}#+t(Y_R8Pj!PyeW$o|Z<7olRoq#P)9)}M z78~gHW;eJo)E3-x<{a*hS^ z$`_1@S6F0AS7905IO_lk15kz*3%beYxftX*-IEn$9yo;Vt)HBTjTtJAeZF+A^OmL9 zjhmps@kY?`*l$TYsUgeo*kH|Fb}v1q>&i9JVu{P|$7K_kD%jYqz1VYj)k3aN2IJFfD zuD!NzEUHInm}3y(*-rRsD1chr^aI*~wSe_R_+e_vAxF7`1+hc+_8{lQ67h%2tZ8y% zrSKhwQ?b0wiw$$$H_s&CjH7ZI=gTzJRD|qo0Fp}$G{>i)D_;?a3Qv}v>yiI>K?=sg ziVE*54*y`FthH=iyL=hN`zH=sb;u+q#CIM2papm9k~4|$WEz0?BuRq5Oe@F_aH`PL zX@CP_#3;!foU{=Kk@&w(5kNGZG8gBPcp>DO_F3SkBOQNHV0s4lxkmFSX8hYZGH<-| z-fx21Z^`9vPYhK8w5BBV?$%{14$}mvRB+KrFA5v$>`b81e>NO^pQqoq}Q_2>Zj*Gzuckc=`SEIUWlWtqS?`j-$?M1MN6E-&B-0~FARJbtXUmj*x%CzqxS6YPtwt%nycrLXD^Nju zv-aHt$Pa<`?luh{=>Dr!Ih+%;$3lRf)NcjkrVu29I(oYGwwq1<6Aq6SXZxc?ZJTmG zg~j%wk9WTv{q}YLH_o0!x*@S@#=}O0;}T0^gUcQ{V(O9%ynu2DQQq&BR#;fp5DBwq z0MADILGn71+I!pYmiG24Oe_dp=)zAB$dl;_MK_rP zsV$L8%T_W^4M)QX&PguDXQmFsOq?LWH@67AODDf%=?kX)4#5qQCQ77zvraV4pSyht;~=Fgt!<($s}hIXXXDc0^^{aY4vvH zvhr2m;HAOC7XRz`?>?`uhX>hPV)S@_WpuQq0U_0K+et4ekZncXv!6084;>^@JR#j( zM-J?i*u0!zy@R7fZ9gXUzX!R4ULE{sX6Q*96i$5xcd;=!$?kuG&Vw^S?5S)Nkp@w4 zH2tMcp{XV@G@X{#J#RCFxGuABo;uy-SmQJLqtfSBn(lxru`4RICGww4j2jJiR1;yo z5cQ-aCMTKQlOxO~@C4xOjx>e-FC1IoVZi8fZQ*h;0f6|mJ7wx{aXm&yNrG|s8~}Ed zkhDxTFu}YW zKR8o1>iq8jL<~mhel7r6rV!v5q{i7kVWK9oiQS+D`!@JAM@B} zI7*IcrED?C9&oLYgtCkJ_h4~{2&WExpuFFanTtZwLEU|(NAEP?#b(MT@ZsqfXSWrw z-q;hcuap8g8xR0oJU@{7&G1)dYYC?1PVW%QdKPo<9sNVRVan{Vawy*HH!W7ZOHA88 z#Bsz^!OBTKgq?!7YTdcGTn(UHdEQu=w!cR8X=JGqxnH=`K+%MadO7G4fsJMB#*N5z z0H*dzdC>mZT_%be{M&yJ#9go@_4;ldt12+gp~D?6mFy{ZOkX2KwqMq;BK{#xlnM=j z?d8@=LAKF#_U;hI0{t%^E8qmQhx74KxcUilNBkdJB63xLc~Su?aWZ;TQ`DJ^Z#D(R z!R+`uiaIQD!@J$p=}dM-$lfakq_3|B%XhqI_FlKLu{i9tx3TH}tiyGswG61_dCFdA z;vG>JUk%LrMNg&a5BXg#gUnU$w`V9dDX;(#Sut0DN@XI$aCKQN(9n0aZ@t{Kttv>E zc>@>NOEpbE=g4!M3G1d_9j#5eUY+3|W%-j#hGJY3q0|(()=iP@_<;0y17}A5FosgsL<;52taQi<$pSFig9dEYndEnN-Lw*#zuuB$JTSwD^sgm{|2QA7aNfc z4`8MK+BbNODu3wC=WnrKT#;>*E>ut0(C-{yezsfksYt*^(X01VYY+fbL0temH0DYk z)6@>szFNgmsLh0loPbtrl*RzHp48lg4v+9d%ti8gAv=)H!l!jyaaroW9iBCYVymGb z>4~E-BEYjzhvJ#&z+O^5tW!RKv0ak;*JIx}H7PQ$ecbVkz^4BBqcN;u0T>b|M-~1W zu5c>k+4 zS%qIRx-kg#<7*LtKCbyVcG4VcKynypH|iiq1r}0HPG*hztdX`87+DuW%Nhg=dhs-y zhf@I^#~Qd>5B}&2Cbb*oqc;n6DjK*pRMii4(W)cRCvb65Hwh^iwqd~S-&e*&*8K0! zXAO1;ohS(|wpC};jx>~GnUkIu^bK!_Js1kht|ph|eLFfbL$P-Kwvf>ZI~%gQMqNja zwDfYaDpZf@)da5eIh|d;*kvH|R_n!rt=g}vxkzl?V*;#F2n9FI<+oKkQwW zS+ILy0Ab;8(@CWL{@Gp@qcR2>>tIyV)ZR*Hmajb1yduh)dTEn<-)`WTa%pSm)-D;| zkCXC#j-{cxi9?lJo-ZG$n=dK2L-^n)?6Eop?YwI``|Ak{UcNJ6AFkeXDNFAct!DEB zX*gck()9Z`VwrO)r2HsHug7{bcyKhE_wfkb6zVab(x8i@Xi%VTyD?pzM^r!cfgTXP zarSJJTzS}m&^0B~-ow)M=%EX%Yov&+5h+GGtmcr_HtFgWQZt35%XD~8e&|3(#xxYV zA@*BOw=yc1!hmk>M=65d?zNHJ$+A4Os(S~bPDfkMupA2y+Ykwg$Z@B7JL*K|iF%ac z4Ks*SqdJ=MT`l;tSJSHlG3aH?s@be-{tElU%kbdld5;(+JGz{Oi@ThO-b_mQM6IwN z8Z$EijD1=OIXFsrQPK7lE-DeYm(+8zJV_z5gBBZQ2x1kOQY231HMqmVGYCpU{?oR{Kx?v8oGn>m%jqJ?h7fe`n(T8n{wP@;_eR(wn zNB}%~Rdk8gaD0XA%RPt_3k>PKQXuDPtxVL=;0JK=>DerEO8ZgVo9F~Yy`0EH=<;$V zvWAj1rDkd4SueZFSw4jmEe*Lmh7Lhy|1PYiNByDcfz=7>{BIrXM}q8*aV&O6=ULP5 zdMJ%HK?RPd?TCKto=G^}2*c>YWBt1w8l1>8`LZtAI{iYu2?(g`_see_YZTLjbw zYE5Y|3(TB-B z>u8%FV2gV>pY)=p9)-AEy<3VW&xn)ld4g{kCb2>9EQY;}7gf<153} z2wA%7CfL@zFPNa7@9WSZ-ow<?<^nUM@FWMms4H6r211bC@kJbX znp9I!jhsWCcjlCnSG7-_Yi#-}xp zFu|`3=Fdg}$iUBlzCQm2SGr!?DYSDeHnvUgK>*b*+|1%YdiM}IHmjr2v6%Ojs4;AjSf%s1 z;x*9%a}l$zN%KqjVK#Qc?YY7bjP_Xw_PPPm8TN$LOv{fQImt=S?+3;dq66H_GatC$ z*EI#?K@D0wfz&Ac#b#R3unGR3JSlwdW?H;yv<=f=NzMmGnLh{Guv5j0BVlh{6eqV* zLf!#2G+3z1P(PqeTynuWAEi9i#Zdvb`o=O7tCL zzoMgKs@4SZTx$NX#bPCc9<*)VjAhYopFh40c9v&p;q5mgQeo+;(DD?ZNTp9E5$))G z>OtPKQjn#+h$z!o1%Hc6ntkpmT$tosmbsM zPJW+U7hzpJ!R7MK#Cf%UHy==-13PK(YE(kC6(c(E=Wm7|R)_&!z9R(D$Nj8}lh%htXlEMX_$em#3LcjuA3;js(^&v@mgt zzyVTI=um&&U=y;#NKjxRf78JG!M()&qEIM4rtP@^&DvM;#pV(X-qLS-MIRk^NYM@V zQN?UbZ5byR@eoOK5;uW#VsRiOp2~+({eykI{`1KOTlG(~YPeBG{i+TJ9c@oXs}XG5 z7^#bi2-Fa2Yjj?U(p0kd$s(s^oij0Nz4k_4ngj~e8>})J7*LmJlAgD)7j!=rr!T=^ z?~=?8VWqL)E^yx_cY`9V*`#xF4 z+lL*|FJ!G`=&-fm=c0Y%cNVYa?oFRoJ}3tM{~LYaCS*OxkGxd77rku9j;RW*C~R}$ zw`AjS8)|Sh(pyRwiRyOwuz!3e8N>?!!Q^N_#q0r#Bepe!Uc%Kx|>q~ZcZ8=X=%a?{)jhGgy`i6nSBFo`|i~=f2luN`2VFD zp#L;hFVC7yBk!5e%gaWu5rV_Gh|<*&6osdbV3bB6uxQ6hpe6?MYCb>&70-Rf(wJ2rCYi?B&0(?Lb|)VLAp6`=x&tm4ryrx zfp;I#`@X;NJkRg_e9k{?_MSbnX4YEQTI-tGsGi@TIb<_t^t^PC64WMl+7GM>jEtjC z>|`PyJy@0vSZyI9M`cptv_w|Dkd@!b3GR8BzPFu#l+>_ndt`U8pTfBA1dV@4N*{3y zqXCqF&G)xK!kf~Nhx$*$rLEoWq0W~RXYb$;81t<%>WkuM5?Ae>-qar7+Y!`-$IwU7 zKt>k{^t!`a>&a~5vl9SMdH~Q=vEQ$U;eyP~!58gEC8%ax#~NlgAm+{f8EE|3VJ}sOa;G@YYEacoAl)}40qO4f6Y5^cEr?AZdfpgqxgUyUVxnXeg7-d#3x zH5AToEvLC&kqY8+C$%hs-mniM%~ImM*wR z{;MoYd!ymE7vMPL$=LcsVtTtiIL(k7C=t)FO^RPMu6^VB`5cyM_#L_!hKrN!=9dN3=LFi3$B$I`de#)V^%|QbGl7Vd z2OB)_WsLC}O)-+}qz@N{NM7~m(ZNu34Zfm2=J%8W{2yFz9ob;jsm1Gh>1A83NO+=O z3V$u#P8qn2Ynu)ZQh^k12BuAHLZDQX8r)jH!5L_ACNYFJ5ogM&i{7hCj2|^+jhtTU z00p-LCnPqpOY7S}hEg<-@%nO)12vMxyj$xu0&~pejb4-k-UJ8^_{_NKCghWjs~O~R zG|pHrmgv3j_w1Gqk?#&++yU1g%r@h_0Ly1826)V`B(|KBgH_~>q15#DaRXJ1aFxmz zCppt}fi)KwHp*@+q+Z=~e+nGy}&C39)%j*JCvbYUu1O9ae>^MKvPAzdwaMeJjlnfh7tZ^6b|}mV{g=w#MZ-)m++lap$RHz4liBQ{p@uO zC4dOF-)qZGY+FOQXaZ`2i*LKZB`zm#--igASnGUTPR*7YZcLiur5<1@nL{=Z)Vv~! zANpcp#6A&rL9419c*G-;am?YYf1&S2OY-AwAnc5DyvE%O5_45EWhJXPYpOwI3!}@I zgf)Vo{nF&4`Bta4sge+&dagGqZTvtJkOOt@;m3e(meuMl*<=vAc9Ayh&vEfh7c9{h zSz_Vu>LsvTL`~p=MpX}Js~_D&tfvDhL2C&p**-{!iwSM*D1W;u7-0jx4v--0i@Ce2 zg@Ll0%)k2{(*~}k9rh0j6wm<%>PD=Vnjb(ekdTs^n5z?x#dy(3Zc%(65=W}=E}91p z@a{{dcudMx(=OAGQ9Nrjb*Ue}6$;^k4qq7Ulc7V+Ma8?f zBb~)rBuwH-D$J`=+5k6?j?A-^81~*V2NU24utBMXt1+I>P75Xg^pv-f@>E4l9iAOk zynu5>uM!;o#)Wb6GV#TS)(r-5JPr*~ra5YKATsC!L=(0(DZr$v7Cc*D2(`QNh%>{RCe6NcElKupltCj}y6X znZghB1s*RkSFIiUXBWMEE(hg|OUU;}vYI(3ZfJ8_5<)c>XF7_uzSIf>mJIrnsOZy8 zlDTG)KFaRFuaw&_Jj$GdOL6kMu}e`(VAyRRr5k8R+)>zE9EH-AjtG}3YFunq4cWr- zzMGB7pg^oVUVOHius!Lmg$BIRrk(l8!4R8lDjXsR7Jy>gU-77aWjKzC0KEaMIDkTB zrrEkHF*}gtH-dhF`bZc6t=_->gH|so@zZIZ07yc-j}HFd9K0`71CU`D2QnH62SXj+ zyjTEV0ot1PKalI9GeknqRzrp|qI({rmZ1UmYByL;UcNe{!ktAw5WvNGd>%ax(IHGK zvx(5@NP1V=+LcCee!x^?j@c@4`2+L>YtAu#R$$&74@w^jFEA32Ix9d$Fn`?M>d^HU zh%PWPgA{h4(`f`P05Th-a*FxrGMy0UsUso?NOrWQq~6~d9)>2JxPysbes*f!kP5G* zR~c9^T8ZNUoZ3cK`dtsB^5eVwS(>>_!b%$_lX+kt+ppqqVDNi=QnA%n?@1^#7Cfjv z0Tc~LsrXRnV2UEkRu_f1~J|S$i9BRP88vm_DLVD>w<7cE;LDHWow(jb`cNr>Jvha zQ|rUj3d2Rswzdj;^W0X8XHgj>GzSZ})ykxi?%+u{+yk+w{Amkh?1$P}?Q16c9{pl* z(xuVEcaEqxo)rr4pz61~k*t;ZU)U7lFX}|^rCRVO6#+6Igefo|_+4+?jBI_zSw;Sn z;U`(8#Oq_BbC}^=;3 zvd(?rPdAXH}k+k=`%# zclZv)8a;p3Y3E-i5yVBvtpD!fd5tE8Rl-8JIKsXLB8Zz(%iDt+h2$RIAlE_$BxpH< zeBSwqd7`FI(ex4J)GAsi`q1TXGS7=e<r+k+x?YUkszIK|#x|1WXBX_oCkN6m z-!9VwAxAmO>NP)RGtbkyFCTtB)r1y@(FTWFg5%CbRuWf+$bGVrcgaT0?p*rect14p z_S)rN4w0w-?DoD73z?-jM$h+ci$3u5GDie}K?U@%)pYlu-H^zQPN*MqunNYI@b;0u z9pi6uM$h8wW5KBES>uXllm#IqirHsxEdB_&7Or7&h*xPOe2K@^X1jP#V~s;!uT$tu z4ho3SkX*19rC}y9f$)eLe*?q-kiq`DA^-^e3_!Fqc(xM?vthxl%7RORO6BZQjoCn2 z2I3$7*T;r!g^&^nRFNxq-p-RMYT-;Jy>FKV92SieQ$FCSCTcZ)^Iidn#BPrS#LNBK zT}x_mpPYiado_hBw-EN8q&!9fpj0bb@ghZx8sJVRxjrKX!KwE>;h9-+$ij z`V&&}GW?IO$gkNIAP^La2N#$0tiQQq-pssXm4@uk6Q_UMuTzTV(zU|#5ZnT&($lhO zStoVzdvaF8Tp<_DHFNgIO+@os{GXs0`u>s?)68`T5o+?`t^QPd1E7~g_YV`A^61ZU zlYKOMmAdlbqz6~GKb02B#jfzk<8C@3ybYL}YV2l5KA1G*0)*({JkL(@Q=_GQkncsY-hOA8 zh2<99rw4DXYy9E@9}&R&6{$07AJ;|N6(0&iARdtt~A!wVwYBSQF~5M-}+_ z4LC;*h{$bHnl^-t_Pe@bVde_O;Y$@K#auNcGj6`yy13A8fq5l8;}g7Z3caoitKmDi zb^!2GVAS5D$18Dw$bHFShbW+U>0P21z|j`>n(;E4v*qCRcl50l`PhU?gx(nioK~*g zJl&@o_IXR=_BglC6WZn*w)2@(zq8Bd&h2U=MWSFYG(Ebpubtg>D{dk=a;mu&6AB9n zzcbEyo5VWBM}e3(($-@(rdzr7!mOkho#J77=0mNzsTE5mAH7k}l+E4IoVy6h*gfm- znjl{+e%q*K^5%1!+#hUmGrJe5VBEk`y{C;d%y{54+lY%{(L+Lx1H(iJWt9c3zUH&a zx%ebOBIRmYlJ8OPmITLULhxk2XmYAkC;>TcOIw25pM3o|dwIGw1Y{*{1p|1|p7XOWNWueTrIhEHo#4~_7-XgN{Eg3iNLq^pLJfeP{ZoN+YC0Bv>sYL>$Ri4 zly{^8RR8B2Wdli)eTfUWEsjC*XDLOc<#0(t6`uJeT?z5bl?>WxsJX?J@(YH#R&?E=1>>^4Wp29aI0Jx;XR(##{?!Bq9K?Df zXfZETa@Rd-EZ)6O&i&T{_SGoI<>`Jg@NUWe&C6H5vSCVmw=r=74t=b5wW%qvm(<21 z6Y|3_Erde4ss#3=BskOWU1-0k3b1Rvn!V88wYoR!ctJpfZfj%B;WH962d8bv)q(~7 zvJ-?jjzNN4jJgz4{4!6i4BU#2IVowv3GaN`r>&8*>}GUKeZiMZ;ykZu0w4l5{r?cdUueB%oaYw{mOsbawAx0s7SP$oIVJyrEpAOq3aQx` zYIjRYOk+Q*GnHB7@W3)zv2h|ENY5H&c$x-KxztrIU~tq+fxC6h^}dEKanN+Qu85l= zfgDgkml}cZlSsPO6C_#}aeH<-qTW#xNg&JPukg9Ll`L^Q3aXf=JIe1+LG1>%VC0V3 zZC$2PgL$WIRli*yr4;Iu=HW>!9@H@cE)bl4;=m4{LQ>JJBU>lxy!7IU#_g2uZI8z7 z2tu8LTF}RrY4=vb_%{zAZn78Z3T-owv2$p*Q=Uo@GjndM=gE^f(w;vPI#^Sq{S8?< z6u+RZta;*FC;0`RF-Z;BS4eB*cqdW^Mi*mo6h=c2H{UGhB!Mleq!BFITJkTv zEfb6%myd~Rb}m}+{0369yW-E6k*r>YS-_*Ko}lJ_;HefI#K2l?eOoEV>T!BZ9-WT_ zP|%bZ1D9T}%mmfBStJw#ydIRU7~(J2{Cssl=n7!~@`1Jt^P9zzC(H3v4#Rz3yp_t% ze3No|IgdG;X#2TY=})JOZR$|2@#64znP6 z$WX#Tmw)fTuPRXnj8;^}*Yk6#lJ8ABkDc*=*_xkFdxiU{U(p|6+zxzm8td8O7Axzj z1l(&A+#+xW-8|yW!SB=O(mYrJBO&DOPZmC=gk^l!?CXww~n@Z1Eb!Fu4maf z;d6WSG$F7rQUZ8E%xPK)u!#lcHR`Ysa$Yy!^G!GLFi}B<%a#=_G_b)Q%ZeLEayFUj zO9r2Cak#)|Io+zrWtT0R;3?n0HUu0hm!9V=4LAW9~g9Vm;jQ)-7m5?H|HLQ)-(_^_KYpM`U z_p;3ByjpN|x1A6|0Qf%No0yPca7@{R-VSr;}MQ1-7YLBL>p zgF$7EU0Pz+!4{~(bRYh93`S=_b>`%-ieFKJRn<5dQhU4mB5*BEHxigY8G_U!8nVc@ zDn_-O9k)tf45tkr_|zwo5k8D9LyBCNMNlY**2gi6z_yNMh`FAIkJN+?b(+Mr#fcQi zv2T;!Z+L}`e*n(LYK9ewXqpa2-VJ$C^z}ziWeMb7q;@zn|w-DyLoz@f8EM z%PoI6ljVBP;NVrX+D6ZeP^>C+K=~lGw>7|oIj_Es}!^tYF*yq_-Pt7 zN%XUnU631j|LINxRb7xO;=8&_)16vv_mPKt-s<^>!Tss{VvGcngJ!WgII6yI%fmnD z@`d3PqVPOR-d4~RIpy!s|LeG@^IrY`5yRiNS3@PD*&_qegtS-U4Hv#nwpa`3Mx^(P`3$8@K!5oKr zxFs4wfV{I@@H)Zu`bhlaoXW&TgjN{EPNd!A?&psYBJV~dkg*_Dv!OUYAKPS1E8xQ? z)L$Ut*$(IfRU{=)j`z(;AF0+h7&??NZ0Tq`7a%g34IYko?;p~e-(%JD&Mb~1HE;~u znjy1m+ao+oFDDXc6YJNM@mc~c(TAbis=0jq25NGz?d%d(ZPL&XmFD7d(LI5MpHDgk zg@kj3!rk1gmN*AOC8iD9HTbvu+&(-!biejBS@}S(QuebuF^VzYz5VujzoI1yK2&87 z>dG!YKq4{~!@Pyy6SBKn*`UH{F*&z))DjeN5YR{vjOsxr17xLtq3pudlbH4R(PQIz zx{S-Z@|v*GunA84q+v$aT^0f3pxK0U1c^(h2l{Aaq_ae>UpHK8zQj&7>Kntz^OT;s zK3z!`Xcqhc)8X5bNUtyxSK)SS&m5>LYWBtb0({#GW<|!8@4Z}~olr--870sz(k6{8 z4>pt^vj~@qZR$_}kq~ZV2T%?f@|J$`8s*VJe_1TmGtp1qd6AkJ3ErMluUi*t4#+FM#$M9p8~*_!$BKOy%nxOLopJqr6vX%>3%0@0w4!YU<7vUKyO zTPp~Y9|QU@q5`MQ8)qA3JXB>O2zk!k2d(6!P9sR=xsYvMdaC7^Z4I2H8(IGQjbOme zJzd$gn@Po`t4hH!jF&+pGKb{MJ)`pA-#=|JDTAzqI#k3%Bh%?4_YMa0NoTKmxIEHMHF_I~!mF`umV~9wmUUn2nBY ztc(5A3c-_q)uD2_RnMO%eOxM)ppMx?7Cr`eE0==BWhBsYMkl~0l$-zGb$52 zrNu+u>-#|}YkqNj=64MH{9ks)r9l6l^Zib`%jf^5AP>r`SBZ!T91jA`G=%xM{2L}R zh&6dl_qPe>oDJZ!v}YlYU$5fhXEblzw5*e=P6+3Vw_OQnJij5H2 zYFpQI=97g;f>Q)j>d?8t@FF0aL^bk~tFImE>hcmNKUcrK#p-+jzR>k4J~Xg$3IKx= zEAS&0z-yWa<}iz*Qd!xmQ7_*&2*1LnqT9;}?Ad!mShh+`n*U855d=T(6GMKh@Z4C` z^#YrCu837?0A`UAB^Wdq9Eb^h)O~X6KB&w8<@JLfYI$5vX@@LJ0L9ly(RHz?ilOXU z2D`{BYp+DY%q7|$A7j>G-X4x$r6}oM*G85aWeQ(~W9C%Ebm5&!f?CA{%i1Sgqs>SJ zlR+~pTF*Fp5Fv6;se8@i~&cJSnWX!gv{`dUbm zfU|u7_^@FE+=gZ^`?Kx->OKlC3cr)60TVdi)C8=2s6l=k+6aErFN${Pk=) z=dc~`7q&i+lXZUyao~|*bnei#57UD(^3KF&iHbCR5F~<({}dgw`gz}>L?2ON6T0xz zWLA5et{b~$YX!`{O9@%&{ z`$aYpmI1s=rC6GpX+Iyx^F@-e4s)yvJwV@a&I+=A@)H96H@W0K>RLBF@vbJD0#8vg z+`QLbT2h`4>BrFHL(;m}B0o&us-zbu+sKJ~FI-5(B`XGO(yZkG^2yLVve?@o+1|>` z6prLN8mv5cPIF<|l(ZqwIhIkgvf3mr*sZI%&vwrAzB{0myUT{2u*|#jLLkS*nIg3X zN@zM#e52t*#J-*5Q;?e-nqQ#$MJ0cgagTzFK{ltnWgGV??}W>k{R3zMEGj z`NtM0^}@~4|L|IuvsGMWjtQXOS(*c!>HPOzZOi(Sq`j5*n`~S|CTY@|FY5PAu=3fq zDi!WS-Xn{?7*g)!OH+#-5i6~~_3*OcZK+;adz!@{%kyK2sz=@#8ea92xtn*6Pe0QB z^gEM=j%(to*rSQ?{v5b2``kcLBT}%%IJsN*fcUg)y2#63dEt`t*bS+|pcK~bSG>ej z+z96OldZg`m8V9Mx?NIN80wV?rJH;UFodsTS^Ayr_$~8$ng?@=1w#ha(LdJ(!9w%r zyNjySy>SjDtZM1tKZDH0HzHuC!wNQg8rSms*SZ2fHe)%M36UgUQQy`Q&4gx8jSo?^ z)heqNUvl|ghJ9k?sc5cXanoi#GK{cFt%)I9IK8Y@L7sKOhhjs_@5YQ6wxfJIKS4KH ze763R`{;-x2VL!sO!KCLgwmU9Vb1Ln6!sEToRoG|C7BMNGNnFiV$8rncnvdfJQ-m! zn-NFNr-K-!Obv-a=jY#>%Ql=bN9iNVtb``yO;tayy_(So#TdLDKcldkiSFqnPew40 zp-jVkVVN90^7HWk|obp{qPce!!3F~up_MLP?2 zc4aIF%F<2nqJ3u8Ae#6zJ|No;dB?`{$z&}xn-}D=F9dv;;w@i}LrJ}b$XAs`Pk#D@ zYq%VrBO2QT=97DKbhxWb1zP}(PSoN0hiR!$*Kko1N6PZd9D-t;z1L7W7RVHNmN?En z$1i}=Rwin0eYD56Q<~0T2T_A)2$R{c9W!59Y+mZzmTE#@6oHRZ5By>{OPC9g;q8s|@ujiCe#X1h&GL5WV+i)(G_96u!$o9p=%|KX%M zA{Wcv`CW$eq|6ss(G;5%(RiY<`yAtV;wSn1-d1Acgv|J0efJ6-kEE6q>~Uk#?I$$B zAu3C|KPHg2G2?>G4tim9$nmi*BCxRYTyrKIRmNgts*9dc1WEhmPhExD2@Ttwn2KMZ znfTBYl4zJYV`R5wzKl27J<$H~%zdV*l~I#Ef8fo{5nki)+|SN3oD2Ih%beHWw_QrM ziA|7Xo5+3}fN@b34VNIr@`6@qQ9^Gb&x4~mdX|D`eMDEl_Lqp#)7`?%9P2#uIsF6s z#dx!<6rJg(yOySJkk3nvi@)c%h2bE)3i(Qc&-cs0-+* z-;=`0HeyW^dYEG#vuhMYZCEHEkx%9bW5`pZ&7QP{w#}Oozw+*G9lU$H9C&w0O2cIu zFoqZm`szC=674UvR+MWcr0EPT8F47n+;b@42dj4#80wxjHUE;ijTc-n|7C7Vx{S5NiC zzj#=dIQ)z!SpRH)pH?G2*YNbRDQ1?YM-FRzv&h3GPJ3FfX^$34QRU0XH#`334kkYp=lEC8sfA9_d+(!rc5eun+Gok;9 zH%xzUL!PXZMI&ok1`i7{^$M{xMsLSq=Qsd!FTqv%Ss!8WSV3%vx>Q6c z2K+DhVSnN{{MgK`djBODYa5gZ1^82*Z4hLao(lvrYzL+F*z#MN6wrcy3BVm65LK>G z1h4GoQ^@XEQ5I+?;K(N6H+s4^#rURIXrdA5x8?fs+ARox7Sx9do6i+?9xH4DKbp3? ziwZsWL(VreKCouMC`yCf0Z$HK3`t(BMx@EcM_7=bm>Vn?Z0Hy;FB+IvD8C$hj5D1* zevtzdojveFjKv82pPu!X36J69AN(cJ?Y97;qBKO}$@h@$1em)oc*RG|e0(%=X ze+kSi@k|mj^WS(_%mXPBKl0#uQvkn)XY_V|!@l|Kev_PFOX#bdO#2h3kOz*#@(_z@oAD|4oy^5cS6$F4Kk(!Kx&Rrg!EFAgCkaMf6Jc%nS3oelTqR83{Bb?O#!+5 z!o4oG5kZ_NqDQd5S2D|M@pQA|J#^jfhm|y7_l5#$8|3RCQffzM&-!N>;`8jiQc{Wh zM)6xfNgF7m=vBSh|Mg|RFg0ELhV}G*SxY$=q0L-*;=E&2S?M}8=?2ydVIr!y7eglU zvGd#%(=VwXODQYGRkq#IQRoBY6|2D?FjwY@^_fSdOL(r4VJxT49$xMx(?{4=g%&JW z2Mf3wZcfW%pHpxzH+ejqg`^9K%F+W9PRNLzNW`YriPl5`5HGvP+f3RJzRqnOrU^!? zXLR+h(M{dDRlG~AHMAUhF|@GYZoXpuVnA?w2mz13w~vX(Z@px)r1ROEiy-xlI6FCM ztaV97iGcI$VzYGN$IhEXJhYfdHMpxzU@Vy;cbcYv(HOM@V&@!mw6xG2FQ& zJ6Evww!f50ng3%;Db7SqS(Rg=9O3!K>THGJTvZ>LaLt|Trl#bKl+3PJ%}P znY+am+QB>|)(s&*!ePZd-2a%ZH#B{9k8nmgLUed$MQb%xuBCU-WQ>Nx(_bGT;*xc) zyp%K1iij{Qo8Ixf<+_m>EM17CGz?c7Qb@)moY`bfv%({ZJBqFZDJCmx}O ziv9PSy5_o5X{0-x_7y2Q&3LE8)9I4y?JWO)Hactvw*$HE|vW`^X8tH3OoO$dH?VazyD3{ET5xZ&IKk!qkud5G_n+e#)7(E>@3=F zwuB(wKl)3vyKa8PxqlnHByhi>z-Yv~w-^lYyW?#1jL+lh~pu$K1D zi1xFJ#yw(vC7@xu3g~T6OR^5+6BUee!LpS}NKk)layxY}lj+96OU4L=)ZbWyTet6B zuM!hkmr(SOU^=2;G@>mVMd;Q`-q8?B7&8ENpzMI?qT7iaw8fn(eR=SqBxIt+pD-xx zuzl>ta+M)FNfX7{uyans7Jmy!(%HDjIATEz0KGk-xC9Lna3YLF)0qFdbfo3eh|ThQe)l1Q`$z`$rpETa8`Yc+hsBlKBNs@Z%kXi{VKK00WMpX%y^ily`BAA_;V68) zZc_kC6g7MCd0E5Wdyo2+2rHa?W5Dk$CN~|wf7VBw1}OgPXm_Ds;}eV?`ut`mx!BDQ z7dc}CIC&LZJqR4WdIB8i;{kk)XgR6CM4UW$V;yRXNz!x|-=e%NzxdrifzxbFw%B^f z`wi=GQ=byPdD-JoD>UFOfQlIT5zSt<7xeAj&CHeP3B@k~`#!EGPoClB3DeX^;dxV2&O-r1b1f{xEx= zQ-3bENp2q^e-7I7rv_-$HCB_(49(e|WLO_uliYHc|vhKxfT&|CBt%%T*{W#)k zJwZlt;YkU+lpvt)8#b*=7*HvM)k zpUMRkKQ~z=Tw}5+E?K|Rc!`N{S9`$e=G*dLuNRxm^{jH~i|EP06*n-MgWDOHre+TCF!v zQ-mrViwy8Jb_NM+2AQ-Odv=NhB#fCgW!LBu{ zo4hvAUXe0M^F^Ys{+_GOw6H`x9!$-z*K<%RE1+@Rpedsq9$LLIxkK2EmOxk{(eSOI z{>xrdy=~^Usj@>)GqRJ|RO45W?;lDE#R4UlY3XYN_KxPa+jrrPqEE!>=Ximv z7~ZSCI>ESrEZfm9MF|Pmq55^~x^6VHu)G2ttH4K61G7J9T{tlkBE(M?qve+H?RQNl zIt%|=56j%5dfd^+465BLbl|&qS7BoAsh=t@EBr_|CFKM{LSrOi_-N-qRZaH|9ucO- z=?<|WHQp4SFXZEXrb3UKzmB2H1M91CGPsK%AQLtn#Z6rHM^S)#EQ*rniY+{@!9J`2 zmyVXDZ{Ipca;#UCfr4>dL%{xYoj!%s3oGnk0KH~r7`a}!x!dMdjN2&6@OLTs5()OZ zfa3C!p~%Qy;rz350xsGEo~w2Ty8^#m!SBdgrjmyGh}n$8UINSC%vbmlvErS*d! z&y~2sw#bcSQxut|rcl6)4F=)9THIm4CtrUn#y)6f^b5I_a`a(yY=)ZY7>5&oMiM@e z2MXy&L|krTlbx+`kqid${SQ2U0s=NNARquTH(b&w3B<46i0hKcEDG@FCo*n68Mm}H zMa%L#xvG<2mWAn$gu=}^s}+h~9=IboF7 z-@h2_Qxp&qRG*?h5$iTjvER4J5ED`l7FZoP*IL+FVJTjDt{+NwO3pwLiiaVezoiS? zgM3@iB}Y{zg*5FxqBZf*+-eNVyql7Ojb$X?PRHt(eYRkVMu6G;^PEZRTf zV@eo*SN7l;Kj(fBP{ zyNOhKd)~TWiet5um{sPFPN;SwClXAdC#)YzSTV$qy*h#@5XJXjkttP@cLJ{JS>NFZ zx5FYrO!VN5hrrrfrXGCp$GTf#wOy|bI1e<{!q8_3SWUONc|y{AxMd5WG4d&HrdH^m z>7k0TiIExr{m|T8Z4ly6siUz_R}RL+YGf?OGCV=Sp6j^;Ta)qpT-GMO z=~SIsqJrJ83+1YRYMJnFQ<*Fi;m%D&-1Ex>(r_|xCt_*T3R zBS3knxg!n4;U?`w4M0BKw~Jl%uP7ToV)}<7P^Ewb{17W2vGy?`|# z?KViQ+|2oU{OOdNaCA*=|Kl~c7~&|3TxApWXxP0l#mAx~2{;;LL~Q?vx~{OQClbXV zKp`z(6zAzo?148Hem+B22$OSUwUxE z_87@)wE+QzawF}Pn6N62xt|3eH{Iz#H*IxlR^X+aHSQ6%0#4ZZt1IBu+Va)VD72?c z^pw?T3w9EWU+kW6zp}JWRdu5&R+j-`=@azOkMbpZ0P*lfR(`5yx_D zOOqghka1q)-Hb-lynGrW8!>xrLIkDsIqoZ97DEg&;7j#Ra+f-7Zr6IYqsRZCiqI5MkmB%4!i667(rhK+^_6!)*_?-bwbzx zbnsNge4aq+q+#UnASw-gd_obA0R>-fx6ZD4&TUuPf$_qQK`Xe+y5agJw$7=mQ?L>35-vJWkcMuzquj8k+3*cW{q3CW3lWu7p|{bnoflNR`ts4SuG7ymLstA^+oYAp zqVrfiTX++3f=Ln`uzL;M0_N%a?D2W-9n@7rFe|j%3+yAU$#FWr%-;I(!T*qQV zxwsm@2U*EgVaw`VNyc7REKUqGk~?y4X1~T(^&{xBwB(Y>co|B)w4G4N0`1K})GgaL z&WnGH5t3G=dZr!W9&TL78m>@AyCqs*BYzRb&ZlYo(UxxjWmejF%+trV-@jPx#xa{Y zO87hQooR+Q_uJ#fONXY1YIq+0NnHB5@lN6C_&Riy)t{wz%&Uf`oEfgDd2e@vt&U&> z&adDOQB*Yuba1@(_XGBcA0sS2E{*~;KC+EG*rKA@fgIkFeL7&mlt!l6uP<+O89^0*pB?-h%bm!zpf%UQn@Z$;6&aYgu@cP6-T zJNwYF?Em0TiSO@3=MjgJ_4zjE>N)McS$X6(_R-v0WaQ@N5O(S5+NHk99}!@RSZ8N@_3KeSx54c+J{|HKFQQPvsBD*`?Z_)WYIOYZ zh_>vv70jTiuAIQv#Xb+CS9W{ORhnB`XPI!N38rdj-5Fm}#kYJxfyn11$N5e*qp)r8-TgTrQ_X|^VNz~9` z+o&NaAC);sSVvOW4C`J^Eym66ZI_8bJMNf@i zvbgcMfq@LXt)DX{=*>-~c+nFhbi=|ga@Yq1sMV(!;-7+uE7R?Kia88KSp4a^~8 zd#-c=lr^ z?M73fd+t|65lW`bIF8IX9P+!O;5cGu$+0kzpnfTQor2?M+UW5qHX(ghQOmKiB^}d2 zdwlahGFq+$#UzllCaW(rkc2UpHwNc5{@2vkpBo|hPq?GL7JIp2yC2zjeiBj60QAs6 zf32MT&|BMIy?rbifTm)MuDl;y8bn^KVD>bc>=1Ajz^ICZqsc|EHDJ~t!~p|U$21*; zzY@_vn-$t)2j}_d#TR}QW{_C}{2rO8*r<3dBkLe3+0|Ob`dJ>Q;1B3DV+IR$pQ! zvFebze;eq{^@@+b)Oc>gqCqgqqz=cV%B@zV=?hTse^8NMR19~7xm{_%)x!U8KBMeh z;n<++eUumCfY@Q=6qVkT2o8QR6R5FKx>`ljl$uqS9`Ux2HRjyHfja*k2T|6>f#P3y zj7>XYKk`YU+Rd&swFk|ekS4Dh>7}lamss_WXSc$}CeZ*=i$$ThqLm7y{n}8i5g@+d zGEr;Nh9v%b;Vy_Q^EL4Q*zzVCKM{=NsTS*lTM?&x;-=sk49-O7uBxuWHg zAjKXajyz;EfpiU5Z`bCGy>pw2u|TbP3stt};QiAO^9Vx4vX|=p`Fk7PvjjPnew!R* zGsPk0YYV0C@_Cez=F1Ft8ACaQ>oOeCe&ES8C#?yC$jn9kbV4kRC(G$@;DVK1a)#9K zPx1bk7>P|s3j=F@PHAW)bV;wC$>MJ*wS`W#D_1@1QjfD+H8mRcd|Kn_OigknIgJ#j z=K12#HD2a95X{u^-b|Bo`$xiZ0~&l5)_%QvOp!JzuQED3DuWD(BES*VrO+_=4-Q8#@DE-&f@xqDU6 zb`O5NR;$K5K4#1#oR|I!oLBiZtIqWYGme(92zyM&TeLWo*_7$doW1{BcvOAi_PwM$ zqMCI}N6#PMEPU1QQi?($M1}hqE*?m+9+2IM1`gj-#C2;Z+!${&S5M6i>+d8_r;Ohv z{LCQx=AFe_dqf1yA%#CS`ydrGOuRE?zUCBX1xsD0HLfES@9kM|GiheZpjn^8{^Ava z32#+ZTW7JH!)B~`w8<)wi&W4Ypv{=upm#_v#8(6Za&3I2wSs>IHMaH?eZ$PH!FaL2 zs*as#WSZMmda%>@8OIrp6`h#nGYD>nswae~&IdTI0-yL_sn6Z<^MCEpu6QBsQ8dD` z4KCXGjqU&;(;FAAkf>^A^=tf=fJF40;^(FPkDbKmKT@FnatraEdq1v*uskq)s@=Y~ zxrzHIpMQBuZgatldY}vYZh8Tif|0O${%{V7N9?`uYqJMF6%at45k5zwpfQ%cL^%d( zwjvQ)KVCVzwk<33FV9zj?emq(b>B_zJ5`^1Hp=i@cZ;vfJumi}Hy^UI5jHtFqU>EV zvy?kC8t41%qiBN{g>wX`TJ;9yz9nqdh|j!nMCI*NIngo6xcagc&Y1-gn z{0mQlL()7?L*NU$2TEk#N>f*XMY_!D)?#(^i2A@YgbqfciNr04a%aW{>e2q?JmTYx zB=~&FWLFM+n~Y$=Z-g#Y$;y>2;(oTJMrMUxp3#=d91Y2urH)@Pc9k#CsA9y(BUVca zU9R0{(i%w0EW#lOhtXrwU3-_Z!#NUd;(YR`YzodxGNm{YwuS{tBM+YCR9z3QVb21G zY5!{rI0dE<-yZitUVr#!8<1GK_dB=s1yNlb`=Du}&fvPbh^p=JTxnW&rC{_WBiH$tWcfXM4P)UZ1zi3&VZ}jIV&EwwR-Dn$I+i*k|mgIL3K> zQB^$s3%uIrxb5UTcuYtljy`Gwf&9_n$`%H05l6-v5yeT3a{$7s%vO~RE>!9d4QP=u zTf?}zcZj>L3_i*Y0uTOs00_w*-P*062;1LHmoo4r9|zgzn`O>(TUz~A|5+X5Ao{yW z+XA{ugPd(5mJ=z_VzBPOM+GgXNgV|-<81I~v{G(hY0?o+cGGdCGX_oG`)@%nBM#0B z$?U_kT>Xn9im{xZa7asdkX~D0Q*w0ky_q8Tg+1idj+q`{3&107;4-mal%{@Iq}l(g z^+_(Cc|aq5Yecxz7=Z2ie?lX}$}IrCOMV-1Q(1KT{bXrmSzP98XRU+LyTWN^q)%-% z+W4A;^DloEArdz&b2cOwgr`S+d?N)ZQUr6enA`u)bs-zzb4%5O@?O^y0Job!*28`= ziS!8$YB&w-4?}n1CTRu}q!Oy+d@Nkl-RpR)+JK9Ng%0LL;CSSQ{JBprmoRmAfsE8I zTFL)duzxaUx8iZ7qtWBK5ze)F5i8F>P+)RXxrte^CT~@5g~{A$ZRb0fLUzdb!!)tE z+5^#*VMB_w!qSDYCt*}fISM%|?f@X!5CZ8EA{X2LQV$zbo}z4iYtL;>X(tkZU*WGB zwakqFw)(39Izv1%k=!$_dVRk&=k(hAdZ`aF+9n(D9vC{i5db?3U@QP^+jN?0t~V69 zCkJyikWcCsMSaO)f8cVA`2&@+;}1K$)q{}Jmz$ysOo)T$vhuwW*2?$HS*j&}_!6=G zf2EyySj=4;$9a^cMT5wsMWsb6)54%)RH8*ZTGUV^(Y}aCMNLG?l$z4YV@i}3H7Tt` z4K30#kBDd^sUF%;)4cbYnHJCUUhn%}*V`YuuKZ?x=l8qsbKmzl=leNlC+V6J^>uuW zbZMAtI^~)iy@ScG^rhCr?uu*aCcTw;Wd<9b5TijtK>|yBgng`kwzI|qZxIZF>p82z zTSVXuy}%urcx_ACQ&X1))8aiRE59o=dR%-t+LPc(lGCBP9l`~< zFAmGeP15&FDm19Eh^JdAtgr3|tw>|NF7q~PI83chWJ&9z69`b)^|ykjN%cEPqiEcjQ4q1uQY_ES*V2;-+!UH z2sH@pM=t3PpS|OQx|0{f|9rFfY&72QC*-q7nprhX^n}94*V-v(hiG_2poMe ziCv?$rj9wtVwT%uu?sg1y(&2~!q;K(=r9g5+y$Xxdj9x4zNZi!k*1yeT&aACrUa|Q zb|MU6Rwn|6>Nc?Y;H2GSvcUvLiG-u^VZ2AoK0O->;><0FU+*aldeQ`{q4iM_bx53k z@WkW?p}E;QHyNh%D|YM~ za_8W?_Fig@6X9_eG0P5eDALGcEX~MmpcW|HOLMqc`uWJJ5Nkg_&D0{gjT1Gj#F%c( zZ7m4tIB$lixL$oI=zTw-+9?lHL$G$Ggjj|1-nQ3V;nXeaxkp(qUL~^U4{IZ9lNwSj z%uHx<{e!Ld@9N-w9n?VJ=tx~C@jqV@e|DCra9#DiM`B|*=nx#XK}5*AO?1Y(wk5t& z1E$lofPnyeibVX~RU{+e02A|OY>VGqKGCgqI`R@`FPssRcLDDv51M~31D)|Nd5G28 zD5~OeXf7NEyJ*&D_;r82ys85dK(UMFalK0kRUkab<~fBpg_5V7g`sL-0~X zEJ8gm3OkpvW1xT$Kaz4_DYz$I1o`Mk=nqH?ijhj0lx3#AkXK`mDoJkq?Vxk-K z8Vrf{gQ=~ew0nvLPHEb$(bvs(yZ4RAM1Ek`1;~@?gA(U>V6?us0-RPUIf-FLdmnn? zCRxG7)Rc!im4&d*jnPY8-@0ze^z=}=2u{W}u=pjTK-O3wi(%t_6MS7p-8Uk^;hfm1 zEgE}xTf2Uby~wj^)CA|WEkQ&m>g9#GnYIr3+iiLyuAE!y-4?-NgR&6i5{!3q=W23$ zq05l*(vIsBU!bKiexdF^I>0f>+g$>F=7v_ zvW{Ne-_F0uWDfXh?Ls~B+NT)8QP2pBI(QLrOOw2aiK?TC>l#NXZu?7EIt|BvgJvHQ z@JN62NP_>s##cY=77z?!ERBLpyeU4bf$8$HucRYsgxFlM*_a2u^vc|bQ6A-W4Z?IS zzIUoOlF#vy$ZqW5af%^8?qsY;ZLzA?;-mS<^Mm!Pwn}dmR9+ZnhTjKgQqvTrsQlcR zAL7+!m|fp=9{P*@>K&z$-{E-l1L@|@8nFy(Cv$?K2!{@G{)WW$x;E4!ZxX`aN#Ah0 z@$9d=4>o+&`5nv>$V1IT&c$vHQ90#8cb%8;!{Z%8TijR|a7S^C7@Z zi@G7`wR)@xw=xFicGjn7!W`QgsC=6WYcnEb6b6kJqNvF(2%tqM49c>j=By`}^<7*l z%|T)OOOD#XvaxUcDid9@lVxM?b`Osv91QO#kuylMTeo&+HfFdK@&|zUc*d7%)oTAi zMo!zw*bX?B2s-dop4pomeEw4>0KfgWqkDsPuK(b?I**ax+*T_e&N8C=Ak8`V z<<#qIi7`7w%B@smKW$qm)oC`HfE%dcXo*RQu`BPQ3==R`+^(+#scYwTF-x3!H2oP{ zOoyzKRuLwmW(F4h$^`*XM&Ot~N&HUS55MK}TODKd{@MLGKm+)W*H=zYno2N$A#&2N z<3BH{#Z}W5+#lpkGT_2@;N;=Ii16IFjGI?db<5jul^9bvJ|^EnF~TR)^OU7~rFG+J z%g0rx>c;7VnVbWuXK6Py+x}8ElJU8F!$oze{6$X#1MSz<05&EP71;HXX z{UKE_r%>3jRY3~MMfN>UwfkFIppn->zkb?oogYtDHRZcht7e~Y!gpuI%LO0I$`;-1 z*LXTK=k9P-Me*EItKMK6^eFuo?tIW{-fQmOb}#phv7IAfGfrUFB3FFY`;Qk6JBIdL z_+zd~No6|nCE<>nqWsQ3MgI^%MyU31uX~No31X&vg|e=6@aW@@;=t>RQPt z0;`F>V7rbYKb$;U5O&9^C90WzIOc(Vb>?W>ZWRY}mlk6`+>o7*!=~`wRQfIjS+ROg z@#gS+Yo*)3;vQc?%2#f_OUO%wYH<;s7at&V4CkcMdKXhet2$b|fsb~#!9|MHOwLMlW(Ts?RBti2{DYOy4T0%Yc=nxYvj>PU!EB|T*-KRvU7CIRnKDE z@%B=_I-*MQs>W+i%9a`AX%{ofT0$aZgpnO@uddFNEXaNDOPf#8+_afiWi>(&9PHGv zSttcDnE`UPx`PJBP4~q|cr>pyho~AF&_tJR9bZMUw2XNj&}j1M^GH>keL;>Iljoto zvd}GAleI^;#$8uycMW`D0YgMcO95_}!>w<4v-#33Uue)M)6s09!c>_m7tI-N1Ob=pk6jM!Hj7h~>4>~YfkH|ZFZ=|H;9hHu276C;LJ zfSoL-MkNaoV#^+q%|>iFQ5Rao&iHaE97P)dzGP<@jG(bWc;NSof#0F#SzU$-XR`Bq z0Df;JG9wp|@$7^Hk6h1zj8FLLqDVo=;_WH?a~`J^7_Z|fenLK>Re(N^`&S}(fA#|Q sD}*wjkq%=XfODbE7$A{-wrDe13?7O7+CmDK=D^QReN(+Gf?d$R0B7#DfdBvi literal 0 HcmV?d00001 diff --git a/http/frameworks/innerkitsimpl/netconnmanager/src/inet_addr.cpp b/http/frameworks/innerkitsimpl/netconnmanager/src/inet_addr.cpp new file mode 100644 index 000000000..c5b55ba1e --- /dev/null +++ b/http/frameworks/innerkitsimpl/netconnmanager/src/inet_addr.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 "inet_addr.h" +#include "netmgr_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 str; // print the member values of the INetAddr class + str.append("\n"); + str.append(tab); + str.append("[INetAddr]"); + + str.append("\n"); + str.append(tab); + str.append("type_ = "); + str.append(std::to_string(type_)); + + str.append("\n"); + str.append(tab); + str.append("family_ = "); + str.append(std::to_string(family_)); + + str.append("\n"); + str.append(tab); + str.append("prefixlen_ = "); + str.append(std::to_string(prefixlen_)); + + str.append("\n"); + str.append(tab); + str.append("address_ = "); + str.append(address_); + + str.append("\n"); + str.append(tab); + str.append("netMask_ = "); + str.append(netMask_); + + str.append("\n"); + str.append(tab); + str.append("hostName_ = "); + str.append(hostName_); + + return str; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/http/frameworks/innerkitsimpl/netconnmanager/src/net_conn_manager.cpp b/http/frameworks/innerkitsimpl/netconnmanager/src/net_conn_manager.cpp new file mode 100644 index 000000000..b4c2a4a40 --- /dev/null +++ b/http/frameworks/innerkitsimpl/netconnmanager/src/net_conn_manager.cpp @@ -0,0 +1,156 @@ +/* + * 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_manager.h" + +#include "system_ability_definition.h" +#include "iservice_registry.h" + +#include "netmgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +NetConnManager::NetConnManager() : NetConnService_(nullptr), deathRecipient_(nullptr) {} + +NetConnManager::~NetConnManager() {} + +int32_t NetConnManager::SystemReady() +{ + sptr proxy = getProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + + return proxy->SystemReady(); +} + +int32_t NetConnManager::RegisterNetProvider(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->RegisterNetProvider(netType, ident, netCapabilities); +} + +int32_t NetConnManager::UnregisterNetProvider(uint32_t providerId) +{ + sptr proxy = getProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + + return proxy->UnregisterNetProvider(providerId); +} + +int32_t NetConnManager::UpdateNetProviderInfo(uint32_t providerId, const sptr &netProviderInfo) +{ + sptr proxy = getProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + + return proxy->UpdateNetProviderInfo(providerId, netProviderInfo); +} + +int32_t NetConnManager::UpdateNetCapabilities(uint32_t providerId, uint64_t netCapabilities) +{ + sptr proxy = getProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + + return proxy->UpdateNetCapabilities(providerId, netCapabilities); +} + +int32_t NetConnManager::UpdateNetLinkInfo(uint32_t providerId, const sptr &netLinkInfo) +{ + sptr proxy = getProxy(); + if (proxy == nullptr) { + NETMGR_LOGE("proxy is nullptr"); + return IPC_PROXY_ERR; + } + + return proxy->UpdateNetLinkInfo(providerId, netLinkInfo); +} + +sptr NetConnManager::getProxy() +{ + std::lock_guard lock(mutex_); + + if (NetConnService_) { + NETMGR_LOGD("get proxy is ok"); + return NetConnService_; + } + + NETMGR_LOGD("execute GetSystemAbilityManager"); + sptr sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (sam == nullptr) { + NETMGR_LOGE("NetConnManager::getProxy(), get SystemAbilityManager failed"); + return nullptr; + } + + sptr remote = sam->CheckSystemAbility(COMMUNICATION_NET_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 NetConnManager::OnRemoteDied(const wptr &remote) +{ + NETMGR_LOGD("on remote died"); + if (remote == nullptr) { + NETMGR_LOGE("remote object is nullptr"); + return; + } + + std::lock_guard lock(mutex_); + if (NetConnService_ == nullptr) { + NETMGR_LOGE("NetConnService_ is nullptr"); + return; + } + + sptr local = NetConnService_->AsObject(); + if (local != remote.promote()) { + NETMGR_LOGE("proxy and stub is not same remote object"); + return; + } + + local->RemoveDeathRecipient(deathRecipient_); + NetConnService_ = nullptr; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/http/frameworks/innerkitsimpl/netconnmanager/src/net_link_info.cpp b/http/frameworks/innerkitsimpl/netconnmanager/src/net_link_info.cpp new file mode 100644 index 000000000..383b8cede --- /dev/null +++ b/http/frameworks/innerkitsimpl/netconnmanager/src/net_link_info.cpp @@ -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. + */ + +#include "net_link_info.h" +#include "netmgr_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/http/frameworks/innerkitsimpl/netconnmanager/src/net_provider_info.cpp b/http/frameworks/innerkitsimpl/netconnmanager/src/net_provider_info.cpp new file mode 100644 index 000000000..a6c044be1 --- /dev/null +++ b/http/frameworks/innerkitsimpl/netconnmanager/src/net_provider_info.cpp @@ -0,0 +1,125 @@ +/* + * 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 "netmgr_log_wrapper.h" +#include "net_provider_info.h" + +namespace OHOS { +namespace NetManagerStandard { +bool NetProviderInfo::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 NetProviderInfo::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 NetProviderInfo::Marshalling(Parcel &parcel, const sptr &object) +{ + if (object == nullptr) { + NETMGR_LOGE("NetProviderInfo 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 NetProviderInfo::ToString(const std::string &tab) const +{ + std::string str; + str.append("\n"); + str.append(tab); + str.append("[NetProviderInfo]"); + + 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/http/frameworks/innerkitsimpl/netconnmanager/src/net_specifier.cpp b/http/frameworks/innerkitsimpl/netconnmanager/src/net_specifier.cpp new file mode 100644 index 000000000..ef19dfc34 --- /dev/null +++ b/http/frameworks/innerkitsimpl/netconnmanager/src/net_specifier.cpp @@ -0,0 +1,107 @@ +/* + * 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 "netmgr_log_wrapper.h" +#include "net_specifier.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/http/frameworks/innerkitsimpl/netconnmanager/src/route.cpp b/http/frameworks/innerkitsimpl/netconnmanager/src/route.cpp new file mode 100644 index 000000000..1c13f9cb5 --- /dev/null +++ b/http/frameworks/innerkitsimpl/netconnmanager/src/route.cpp @@ -0,0 +1,126 @@ +/* + * 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 "netmgr_log_wrapper.h" +#include "route.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/http/frameworks/js/napi/BUILD.gn b/http/frameworks/js/napi/BUILD.gn new file mode 100644 index 000000000..25244245c --- /dev/null +++ b/http/frameworks/js/napi/BUILD.gn @@ -0,0 +1,108 @@ +# 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") + +SUBSYSTEM_DIR = "//foundation/communication" +NETMANAGER_NAPI_ROOT = "$SUBSYSTEM_DIR/netstack/http/frameworks/js/napi/" + +ohos_shared_library("http") { + include_dirs = [ + "//third_party/node/src", + "//foundation/ace/napi/interfaces/kits", + "$NETMANAGER_NAPI_ROOT/http/include", + "//foundation/communication/netstack/http/utils/log/include", + "//third_party/curl/include" + ] + + sources = [ + "$NETMANAGER_NAPI_ROOT/http/src/http_napi.cpp", + "$NETMANAGER_NAPI_ROOT/http/src/http_request.cpp", + "$NETMANAGER_NAPI_ROOT/http/src/napi_util.cpp", + ] + + deps = [ + "//foundation/ace/napi/:ace_napi", + "//utils/native/base:utils", + "//third_party/curl:curl" + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] + + relative_install_dir = "module/net" + part_name = "netstack/http" + subsystem_name = "communication" +} + +ohos_shared_library("socket") { + include_dirs = [ + "//third_party/node/src", + "//foundation/ace/napi/interfaces/kits", + "$NETMANAGER_NAPI_ROOT/http/include", + "$NETMANAGER_NAPI_ROOT/socket/include", + "//foundation/communication/netstack/http/utils/log/include", + "//third_party" + ] + + sources = [ + "$NETMANAGER_NAPI_ROOT/http/src/napi_util.cpp", + "$NETMANAGER_NAPI_ROOT/socket/src/socket_napi.cpp", + "$NETMANAGER_NAPI_ROOT/socket/src/udp_socket.cpp", + "$NETMANAGER_NAPI_ROOT/socket/src/tcp_socket.cpp", + ] + + deps = [ + "//foundation/ace/napi/:ace_napi", + "//utils/native/base:utils" + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] + + relative_install_dir = "module/net" + part_name = "netstack/http" + subsystem_name = "communication" +} + +ohos_shared_library("websocket") { + include_dirs = [ + "//third_party/node/src", + "//foundation/ace/napi/interfaces/kits", + "$NETMANAGER_NAPI_ROOT/http/include", + "$NETMANAGER_NAPI_ROOT/websocket/include", + "//foundation/communication/netstack/http/utils/log/include", + ] + + sources = [ + "$NETMANAGER_NAPI_ROOT/websocket/src/websocket_napi.cpp", + ] + + deps = [ + "//foundation/ace/napi/:ace_napi", + "//utils/native/base:utils" + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] + + relative_install_dir = "module/net" + part_name = "netstack/http" + subsystem_name = "communication" +} diff --git a/http/frameworks/js/napi/http/include/http_base_context.h b/http/frameworks/js/napi/http/include/http_base_context.h new file mode 100644 index 000000000..a3f45f9cc --- /dev/null +++ b/http/frameworks/js/napi/http/include/http_base_context.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 HTTP_BASE_CONTEXT_H +#define HTTP_BASE_CONTEXT_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "napi_util.h" + +namespace OHOS { +namespace NetManagerStandard { +class HttpBaseContext { +public: + napi_async_work work_ = nullptr; + napi_deferred deferred_ = nullptr; + napi_ref callbackRef_ = nullptr; + int32_t errorCode_ = ERROR_DEFAULT; + bool resolved_ = false; + napi_value result_ = 0; + bool isCallback_ = false; + +public: + HttpBaseContext() {} + ~HttpBaseContext() {} +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // HTTP_BASE_CONTEXT_H \ No newline at end of file diff --git a/http/frameworks/js/napi/http/include/http_enum_define.h b/http/frameworks/js/napi/http/include/http_enum_define.h new file mode 100644 index 000000000..802ffd358 --- /dev/null +++ b/http/frameworks/js/napi/http/include/http_enum_define.h @@ -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. + */ + +#ifndef HTTP_ENUM_DEFINE_H +#define HTTP_ENUM_DEFINE_H + +namespace OHOS { +namespace NetManagerStandard { + +enum RequestMethod { OPTIONS = 0, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT }; + +enum ResponseCode { + OK = 200, + CREATED, + ACCEPTED, + NOT_AUTHORITATIVE, + NO_CONTENT, + RESET, + PARTIAL, + MULT_CHOICE = 300, + MOVED_PERM, + MOVED_TEMP, + SEE_OTHER, + NOT_MODIFIED, + USE_PROXY, + BAD_REQUEST = 400, + UNAUTHORIZED, + PAYMENT_REQUIRED, + FORBIDDEN, + NOT_FOUND, + BAD_METHOD, + NOT_ACCEPTABLE, + PROXY_AUTH, + CLIENT_TIMEOUT, + CONFLICT, + GONE, + LENGTH_REQUIRED, + PRECON_FAILED, + ENTITY_TOO_LARGE, + REQ_TOO_LONG, + UNSUPPORTED_TYPE, + INTERNAL_ERROR = 500, + NOT_IMPLEMENTED, + BAD_GATEWAY, + UNAVAILABLE, + GATEWAY_TIMEOUT, + VERSION +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // HTTP_ENUM_DEFINE_H \ No newline at end of file diff --git a/http/frameworks/js/napi/http/include/http_event_list.h b/http/frameworks/js/napi/http/include/http_event_list.h new file mode 100644 index 000000000..7fb5647f6 --- /dev/null +++ b/http/frameworks/js/napi/http/include/http_event_list.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 HTTP_EVENT_LIST_H +#define HTTP_EVENT_LIST_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace NetManagerStandard { +class HttpRequest; +struct EventListener { + napi_env env_; + int32_t eventType_; + bool isOnce_; + napi_ref callbackRef_; + HttpRequest *httpRequestInfo_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // HTTP_EVENT_LIST_H \ No newline at end of file diff --git a/http/frameworks/js/napi/http/include/http_napi.h b/http/frameworks/js/napi/http/include/http_napi.h new file mode 100644 index 000000000..fd6235f7d --- /dev/null +++ b/http/frameworks/js/napi/http/include/http_napi.h @@ -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. + */ + +#ifndef HTTP_NAPI_H +#define HTTP_NAPI_H + +#include "napi_util.h" +#include "http_request.h" +#include "http_event_list.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace OHOS { +namespace NetManagerStandard { +const int32_t MAX_URL_LENGTH = 1024; +constexpr int32_t URL_ARRAY_LENGTH = 256; +constexpr int32_t MAX_HTTP_OBJ_COUNT = 100; + +constexpr int32_t NONE_EVENT_TYPE = 0; +constexpr int32_t LISTEN_HTTP_WORK_STATE = 1; + +constexpr std::int32_t CREATE_MAX_PARA = 2; +constexpr std::int32_t SUBSCRIBE_MAX_PARA = 2; +constexpr std::int32_t UNSUBSCRIBE_MAX_PARA = 2; +constexpr std::int32_t PUBLISH_MAX_PARA_BY_PUBLISHDATA = 3; + +const std::string HEADER_RECEIVE = "headerReceive"; + +static std::mutex g_map_mutex_; + +static napi_value g_HttpRequestConstructorJS; +static std::map httpRequestInstances; +static std::list g_eventListenerList; + +napi_value CreateHttp(napi_env env, napi_callback_info info); +napi_value Request(napi_env env, napi_callback_info info); +napi_value Destroy(napi_env env, napi_callback_info info); +napi_value On(napi_env env, napi_callback_info info); +napi_value Off(napi_env env, napi_callback_info info); +napi_value HttpRequestConstructor(napi_env env, napi_callback_info info); +napi_value CreateHttp(napi_env env, napi_callback_info info); + +} // namespace NetManagerStandard +} // namespace OHOS +#endif // HTTP_NAPI_H \ No newline at end of file diff --git a/http/frameworks/js/napi/http/include/http_request.h b/http/frameworks/js/napi/http/include/http_request.h new file mode 100644 index 000000000..bdceb47d6 --- /dev/null +++ b/http/frameworks/js/napi/http/include/http_request.h @@ -0,0 +1,82 @@ +/* + * 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 HTTP_REQUEST_H +#define HTTP_REQUEST_H + +#include "netmgr_log_wrapper.h" +#include "base/security/deviceauth/hals/inc/linux/hc_log.h" + +#include "http_request_options_context.h" + +#include + +#include +#include + +#define HTTP_CURL_EASY_SET_OPTION(handle, opt, data) \ + do { \ + CURLcode result = curl_easy_setopt(handle, opt, data); \ + if (result != CURLE_OK) { \ + NETMGR_LOGE("curl set option failed! error code %{public}d", result); \ + return false; \ + } \ + } while (0) + +namespace OHOS { +namespace NetManagerStandard { +constexpr int32_t URL_PREFIX_LENGTH = 8; + +class HttpRequest { +public: + HttpRequest(); + ~HttpRequest(); + + bool Initialize(); + void SetOptionURL(CURL *curl, HttpRequestOptionsContext *asyncContext); + bool GetCurlWriteData(HttpRequestOptionsContext *asyncContext); + void SetHeaders(std::string headersStr); + void SetHeader(CURL *curl); + void SetMethod(CURL *curl, HttpRequestOptionsContext *asyncContext); + bool SetOptionForPost(CURL *curl, HttpRequestOptionsContext *asyncContext); + bool SetOptionForGet(CURL *curl, HttpRequestOptionsContext *asyncContext); + void EmitHeader(HttpRequest *obj, const std::string &header); + + bool NativeRequest(HttpRequestOptionsContext *asyncContext); + void NativeDestroy(); + void NativeOn(); + void NativeOff(); + +private: + static size_t OnWritingMemoryBody(const void *data, size_t size, size_t memBytes, void *userData) + { + ((std::string *)userData)->append((char *)data, 0, size * memBytes); + NETMGR_LOGD("OnWritingMemoryBody"); + return size * memBytes; + } + static size_t OnWritingMemoryHeader(const void *data, size_t size, size_t memBytes, void *userData) + { + ((std::string *)userData)->append((char *)data, 0, size * memBytes); + NETMGR_LOGD("OnWritingMemoryHeader"); + return size * memBytes; + } + bool IsCaFile(const std::string &caFlie); + std::mutex mutex_; + bool initialized_ = false; + std::map headers_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // HTTP_REQUEST_H \ No newline at end of file diff --git a/http/frameworks/js/napi/http/include/http_request_options_context.h b/http/frameworks/js/napi/http/include/http_request_options_context.h new file mode 100644 index 000000000..61724e56c --- /dev/null +++ b/http/frameworks/js/napi/http/include/http_request_options_context.h @@ -0,0 +1,148 @@ +/* + * 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 HTTP_REQUEST_OPTIONS_CONTEXT_H +#define HTTP_REQUEST_OPTIONS_CONTEXT_H + +#include "http_base_context.h" +#include "http_enum_define.h" +#include "http_response.h" + +namespace OHOS { +namespace NetManagerStandard { +class HttpRequest; +class HttpRequestOptionsContext : public HttpBaseContext { +public: + HttpRequest *httpRequestInfo_; + +public: + HttpRequestOptionsContext() {} + ~HttpRequestOptionsContext() {} + + void SetRequestMethod(RequestMethod method) + { + this->method_ = method; + } + RequestMethod GetRequestMethod() + { + return this->method_; + } + + void SetExtraData(const std::string &extraData) + { + this->extraData_ = extraData; + } + std::string GetExtraData() + { + return this->extraData_; + } + + void SetHeader(const std::string &header) + { + this->header_ = header; + } + std::string GetHeader() + { + return this->header_; + } + + void SetReadTimeout(const int32_t &readTimeout) + { + this->readTimeout_ = readTimeout; + } + int32_t GetReadTimeout() + { + return this->readTimeout_; + } + + void SetConnectTimeout(const int32_t &connectTimeout) + { + this->connectTimeout_ = connectTimeout; + } + int32_t GetConnectTimeout() + { + return this->connectTimeout_; + } + + void SetIfModifiedSince(const int32_t &ifModifiedSince) + { + this->ifModifiedSince_ = ifModifiedSince; + } + int32_t GetIfModifiedSince() + { + return this->ifModifiedSince_; + } + + void SetUsingCache(const bool &usingCache) + { + this->usingCache_ = usingCache; + } + bool GetUsingCache() + { + return this->usingCache_; + } + + void SetFixedLengthStreamingMode(const int32_t &fixedLengthStreamingMode) + { + this->fixedLengthStreamingMode_ = fixedLengthStreamingMode; + } + int32_t GetFixedLengthStreamingMode() + { + return this->fixedLengthStreamingMode_; + } + + void SetUrl(const std::string &url) + { + this->url_ = url; + } + std::string GetUrl() + { + return this->url_; + } + + void SetResponseData(HttpResponse &responseData) + { + this->responseData_ = responseData; + } + HttpResponse GetResponseData() + { + return this->responseData_; + } + + void SetCaFile(const std::string &caFile) + { + this->cafile_ = caFile; + } + std::string GetCaFile() + { + return this->cafile_; + } + +private: + enum RequestMethod method_ = GET; + std::string extraData_ = ""; + std::string header_ = ""; + int32_t readTimeout_ = 60; + int32_t connectTimeout_ = 60; + int32_t ifModifiedSince_ = 0; + bool usingCache_ = true; + int32_t fixedLengthStreamingMode_ = -1; + std::string url_ = ""; + HttpResponse responseData_; + std::string cafile_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // HTTP_REQUEST_OPTIONS_CONTEXT_H \ No newline at end of file diff --git a/http/frameworks/js/napi/http/include/http_response.h b/http/frameworks/js/napi/http/include/http_response.h new file mode 100644 index 000000000..6d654f719 --- /dev/null +++ b/http/frameworks/js/napi/http/include/http_response.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 HTTP_RESPONSE_H +#define HTTP_RESPONSE_H + +#include "http_base_context.h" + +#include +#include + +namespace OHOS { +namespace NetManagerStandard { +class HttpResponse : public HttpBaseContext { +public: + HttpResponse() {} + ~HttpResponse() {} + + void SetResult(const std::string &result) + { + this->result_ = result; + } + std::string GetResult() + { + return this->result_; + } + void SetResponseCode(ResponseCode responseCode) + { + this->responseCode_ = responseCode; + } + ResponseCode GetResponseCode() + { + return this->responseCode_; + } + void SetHeader(const std::string &header) + { + this->header_ = header; + } + std::string GetHeader() + { + return this->header_; + } + void SetCookies(const std::vector &cookies) + { + this->cookies_ = cookies; + } + std::vector GetCookies() + { + return this->cookies_; + } + +private: + std::string result_ = ""; + enum ResponseCode responseCode_; + std::string header_ = ""; + std::vector cookies_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // HTTP_RESPONSE_H \ No newline at end of file diff --git a/http/frameworks/js/napi/http/include/napi_util.h b/http/frameworks/js/napi/http/include/napi_util.h new file mode 100644 index 000000000..aa1fafd94 --- /dev/null +++ b/http/frameworks/js/napi/http/include/napi_util.h @@ -0,0 +1,93 @@ +/* + * 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 HTTP_NAPI_NAPI_UTIL_H +#define HTTP_NAPI_NAPI_UTIL_H + +#include +#include +#include +#include + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace NetManagerStandard { +using vecNapiType = std::vector; +constexpr int32_t MAX_CHAR_LENGTH = 64; +constexpr int32_t ERROR_DEFAULT = -1; +constexpr int32_t maxUrlLength = 1024; + +class NapiUtil { +public: + static const int32_t MAX_TEXT_LENGTH = 4096; + static std::string ToUtf8(std::u16string str16); + static std::u16string ToUtf16(std::string str); + static napi_value CreateErrorMessage(napi_env env, std::string message, int32_t errorCode = ERROR_DEFAULT); + static napi_value CreateUndefined(napi_env env); + static bool MatchValueType(napi_env env, napi_value value, napi_valuetype targetType); + static bool MatchParameters( + napi_env env, const napi_value parameters[], std::initializer_list valueTypes); + static void SetPropertyInt32(napi_env env, napi_value object, std::string name, int32_t value); + static void SetPropertyStringUtf8(napi_env env, napi_value object, std::string name, std::string value); + static void SetPropertyBoolean(napi_env env, napi_value object, std::string name, bool value); + static napi_value ToInt32Value(napi_env env, int value); + static bool HasNamedProperty(napi_env env, napi_value object, std::string propertyName); + static bool HasNamedTypeProperty( + napi_env env, napi_value object, napi_valuetype type, std::string propertyName); + static bool MatchObjectProperty( + napi_env env, napi_value object, std::initializer_list> pairList); + static bool MatchOptionPropertyType( + napi_env env, napi_value object, napi_valuetype type, std::string propertyName); + static std::string GetStringFromValue(napi_env env, napi_value value); + static napi_value GetNamedProperty(napi_env env, napi_value object, std::string propertyName); + static bool MatchHttpRequestDataParameters(napi_env env, const napi_value parameters[], size_t parameterCount); + static bool MatchHttpOnDataParameters(napi_env env, const napi_value parameters[], size_t parameterCount); + static bool MatchHttpOffDataParameters(napi_env env, const napi_value parameters[], size_t parameterCount); + static void SetPropertyArray(napi_env env, napi_value object, std::string name, std::vector pdu); + static int32_t GetIntProperty(napi_env env, napi_value object, const std::string &propertyName); + static std::string GetStringProperty(napi_env env, napi_value object, const std::string &propertyName); +}; + +template +bool MatchParameters( + napi_env env, const napi_value argv[], size_t argc, std::tuple &theTuple, const vecNapiType &typeStd) +{ + bool typeMatched = false; + if (argc == typeStd.size()) { + vecNapiType paraType; + paraType.reserve(argc); + for (size_t i = 0; i < argc; i++) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[i], &valueType); + paraType.emplace_back(valueType); + } + + if (paraType == typeStd) { + std::apply( + [env, argc, &argv](Ts &...tupleArgs) { + size_t index {0}; + ((index < argc ? NapiValueConverted(env, argv[index++], tupleArgs) : napi_ok), ...); + }, + theTuple); + typeMatched = true; + } + } + return typeMatched; +} +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NAPI_UTIL_H \ No newline at end of file diff --git a/http/frameworks/js/napi/http/src/http_napi.cpp b/http/frameworks/js/napi/http/src/http_napi.cpp new file mode 100644 index 000000000..ff012df1c --- /dev/null +++ b/http/frameworks/js/napi/http/src/http_napi.cpp @@ -0,0 +1,619 @@ +/* + * 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 "http_napi.h" + +#include +#include +#include + +namespace OHOS { +namespace NetManagerStandard { + +static int32_t FindMethodIndex(const std::string &key) +{ + std::vector methodVector = { + "OPTIONS ", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT"}; + + int32_t result = -1; + std::vector::iterator it = find(methodVector.begin(), methodVector.end(), key); + if (it == methodVector.end()) { + NETMGR_LOGE("Get Method enum error"); + } else { + result = distance(methodVector.begin(), it); + } + return result; +} + +static void GetRequestInfo(napi_env env, napi_value objValue, HttpRequestOptionsContext *asyncContext) +{ + enum RequestMethod method = GET; + bool result = NapiUtil::HasNamedTypeProperty(env, objValue, napi_string, "method"); + if (result) { + method = static_cast(FindMethodIndex(NapiUtil::GetStringProperty(env, objValue, "method"))); + } + asyncContext->SetRequestMethod(method); + + std::string extraData = ""; + result = NapiUtil::HasNamedTypeProperty(env, objValue, napi_string, "extraData"); + if (result) { + extraData = NapiUtil::GetStringProperty(env, objValue, "extraData"); + } + asyncContext->SetExtraData(extraData); + + std::string header = std::string("'content-type': 'application/json'"); + result = NapiUtil::HasNamedTypeProperty(env, objValue, napi_string, "header"); + if (result) { + header = NapiUtil::GetStringProperty(env, objValue, "header"); + } + asyncContext->SetHeader(header); + + int32_t readTimeout = 60; + result = NapiUtil::HasNamedTypeProperty(env, objValue, napi_number, "readTimeout"); + if (result) { + readTimeout = NapiUtil::GetIntProperty(env, objValue, "readTimeout"); + } + asyncContext->SetReadTimeout(readTimeout); + + int32_t connectTimeout = 60; + result = NapiUtil::HasNamedTypeProperty(env, objValue, napi_number, "connectTimeout"); + if (result) { + connectTimeout = NapiUtil::GetIntProperty(env, objValue, "connectTimeout"); + } + asyncContext->SetConnectTimeout(connectTimeout); + + int32_t ifModifiedSince = 0; + result = NapiUtil::HasNamedTypeProperty(env, objValue, napi_number, "ifModifiedSince"); + if (result) { + ifModifiedSince = NapiUtil::GetIntProperty(env, objValue, "ifModifiedSince"); + } + asyncContext->SetIfModifiedSince(ifModifiedSince); + + bool usingCache = true; + result = NapiUtil::HasNamedTypeProperty(env, objValue, napi_number, "usingCache"); + if (result) { + usingCache = NapiUtil::GetIntProperty(env, objValue, "usingCache"); + } + asyncContext->SetUsingCache(usingCache); + + int32_t fixedLengthStreamingMode = -1; + result = NapiUtil::HasNamedTypeProperty(env, objValue, napi_number, "fixedLengthStreamingMode"); + if (result) { + fixedLengthStreamingMode = NapiUtil::GetIntProperty(env, objValue, "fixedLengthStreamingMode"); + } + asyncContext->SetFixedLengthStreamingMode(fixedLengthStreamingMode); + + std::string caFile = std::string("/etc/ssl/cacert.pem"); + result = NapiUtil::HasNamedTypeProperty(env, objValue, napi_string, "caFile"); + if (result) { + caFile = NapiUtil::GetStringProperty(env, objValue, "caFile"); + } + asyncContext->SetCaFile(caFile); +} + +/* + * native request + */ +static void NativeRequest(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeRequest formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + asyncContext->resolved_ = asyncContext->httpRequestInfo_->NativeRequest(asyncContext); +} + +/* + * request callback + */ +static void RequestCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("RequestCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + /* + Assemble return values into object callbackValue + */ + napi_create_object(env, &callbackValue); + std::string result = asyncContext->GetResponseData().GetResult(); + ResponseCode responseCode = asyncContext->GetResponseData().GetResponseCode(); + std::string header = asyncContext->GetResponseData().GetHeader(); + std::vector cookie; + + NapiUtil::SetPropertyStringUtf8(env, callbackValue, "result", result); + NapiUtil::SetPropertyInt32(env, callbackValue, "responseCode", responseCode); + NapiUtil::SetPropertyStringUtf8(env, callbackValue, "header", header); + NapiUtil::SetPropertyArray(env, callbackValue, "cookie", cookie); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, "Request failed"); + NETMGR_LOGE("Request failed"); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + NETMGR_LOGD("Resolves deferred"); + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + NETMGR_LOGD("Rejects deferred"); + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + napi_delete_async_work(env, asyncContext->work_); +} + +napi_value CreateHttp(napi_env env, napi_callback_info info) +{ + size_t argc = CREATE_MAX_PARA; + napi_value argv[CREATE_MAX_PARA]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + napi_value result = nullptr; + napi_value argvArray[] = {nullptr}; + napi_new_instance(env, g_HttpRequestConstructorJS, 0, argvArray, &result); + + return result; +} + +/* + * http Request interface + */ +napi_value Request(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + size_t paraCount = 3; + napi_value parameters[3] = {nullptr, nullptr, nullptr}; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶Count, parameters, &thisVar, nullptr)); + NAPI_ASSERT(env, NapiUtil::MatchHttpRequestDataParameters(env, parameters, paraCount), "type mismatch"); + + HttpRequest *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + if (objectInfo == nullptr) { + NETMGR_LOGE("Http Request address is null"); + return nullptr; + } + NETMGR_LOGD("Http address is %{public}p", objectInfo); + + char url[OHOS::NetManagerStandard::URL_ARRAY_LENGTH] = {0}; + size_t strLen = 0; + + NAPI_CALL(env, + napi_get_value_string_utf8( + env, parameters[0], url, OHOS::NetManagerStandard::URL_ARRAY_LENGTH - 1, &strLen)); + + HttpRequestOptionsContext *asyncContext = nullptr; + { + auto requestKey = httpRequestInstances.find(objectInfo); + if (requestKey != httpRequestInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("httpRequestInstances add HttpRequest pointer"); + return nullptr; + } + } + + asyncContext->SetUrl(std::string(url, strLen)); + + if (paraCount == 2) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } else if (NapiUtil::MatchValueType(env, parameters[1], napi_object)) { + GetRequestInfo(env, parameters[1], asyncContext); + } + } else if (paraCount == 3 && NapiUtil::MatchValueType(env, parameters[1], napi_object)) { + GetRequestInfo(env, parameters[2], asyncContext); + NAPI_CALL(env, napi_create_reference(env, parameters[2], 1, &(asyncContext->callbackRef_))); + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "Request", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeRequest, RequestCallback, (void *)asyncContext, + &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("Queue Async Work Successful"); + } + return result; +} + +/* + * http Destroy interface + */ +napi_value Destroy(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + size_t paraCount = 2; + napi_value parameters[2] = {nullptr, nullptr}; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶Count, parameters, &thisVar, nullptr)); + NAPI_ASSERT(env, NapiUtil::MatchHttpOnDataParameters(env, parameters, paraCount), "type mismatch"); + + HttpRequest *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + if (objectInfo == nullptr) { + NETMGR_LOGE("Destroy address is null"); + return nullptr; + } + + HttpRequestOptionsContext *asyncContext = nullptr; + auto requestKey = httpRequestInstances.find(objectInfo); + if (requestKey != httpRequestInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("Destroy add HttpRequest pointer"); + return thisVar; + } + HttpRequest *httpRequest = requestKey->first; + httpRequestInstances.erase(requestKey); + g_eventListenerList.remove_if([objectInfo](EventListener listener)->bool { + napi_delete_reference(listener.env_, listener.callbackRef_); + return listener.httpRequestInfo_ == objectInfo; + }); + + delete asyncContext; + delete httpRequest; + + return thisVar; +} + +bool MatchEventType(const std::string &type, const std::string &goalTypeStr) +{ + return goalTypeStr.compare(type) == 0; +} + +int32_t GetEventType(const std::string &type) +{ + if (MatchEventType(type, HEADER_RECEIVE)) { + return LISTEN_HTTP_WORK_STATE; + } + return NONE_EVENT_TYPE; +} + +/* + * http On interface + */ +napi_value On(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + size_t paraCount = 2; + napi_value parameters[2] = {nullptr, nullptr}; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶Count, parameters, &thisVar, nullptr)); + NAPI_ASSERT(env, NapiUtil::MatchHttpOnDataParameters(env, parameters, paraCount), "type mismatch"); + + HttpRequest *objectInfo = nullptr; + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + if (objectInfo == nullptr) { + NETMGR_LOGE("On address is null"); + return nullptr; + } + + HttpRequestOptionsContext *asyncContext = nullptr; + auto requestKey = httpRequestInstances.find(objectInfo); + if (requestKey != httpRequestInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("On add HttpRequest pointer"); + return thisVar; + } + + char eventTypeChars[OHOS::NetManagerStandard::URL_ARRAY_LENGTH] = {0}; + size_t strLen = 0; + + NAPI_CALL(env, + napi_get_value_string_utf8( + env, parameters[0], eventTypeChars, OHOS::NetManagerStandard::URL_ARRAY_LENGTH - 1, &strLen)); + NETMGR_LOGD("On Start napi_get_cb_info %{public}s, %{public}d", eventTypeChars, (int32_t)strLen); + napi_ref callbackRef = nullptr; + + if (paraCount == 2) { + napi_create_reference(env, parameters[1], 1, &callbackRef); + } + napi_value result = nullptr; + uint32_t eventType = GetEventType(eventTypeChars); + struct EventListener listener = {env, eventType, true, callbackRef, objectInfo}; + if (eventType != NONE_EVENT_TYPE) { + g_eventListenerList.push_back(listener); + result = thisVar; + NETMGR_LOGD("ON Finish = %{public}d", (int32_t)g_eventListenerList.size()); + } + + return thisVar; +} + +/* + * http Off interface + */ +napi_value Off(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + size_t paraCount = 2; + napi_value parameters[2] = {nullptr, nullptr}; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶Count, parameters, &thisVar, nullptr)); + NAPI_ASSERT(env, NapiUtil::MatchHttpOnDataParameters(env, parameters, paraCount), "type mismatch"); + + HttpRequest *objectInfo = nullptr; + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + if (objectInfo == nullptr) { + NETMGR_LOGE("Off address is null"); + return nullptr; + } + + HttpRequestOptionsContext *asyncContext = nullptr; + auto requestKey = httpRequestInstances.find(objectInfo); + if (requestKey != httpRequestInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("Off add HttpRequest pointer"); + return thisVar; + } + + char eventTypeChars[OHOS::NetManagerStandard::URL_ARRAY_LENGTH] = {0}; + size_t strLen = 0; + + NAPI_CALL(env, + napi_get_value_string_utf8( + env, parameters[0], eventTypeChars, OHOS::NetManagerStandard::URL_ARRAY_LENGTH - 1, &strLen)); + + napi_ref callbackRef = nullptr; + if (paraCount == 2) { + napi_create_reference(env, parameters[1], 1, &callbackRef); + } + napi_value result = nullptr; + uint32_t eventType = GetEventType(eventTypeChars); + struct EventListener listener = {env, eventType, true, callbackRef, objectInfo}; + if (eventType != NONE_EVENT_TYPE) { + napi_delete_reference(env, listener.callbackRef_); + g_eventListenerList.remove_if([objectInfo](EventListener listener)->bool { + return listener.httpRequestInfo_ == objectInfo; + }); + result = thisVar; + } + + return thisVar; +} + +napi_value HttpRequestConstructor(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1]; + napi_value thisVar = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr)); + auto objectInfo = new HttpRequest(); + auto asyncContext = new HttpRequestOptionsContext(); + if (httpRequestInstances.size() <= MAX_HTTP_OBJ_COUNT) { + asyncContext->httpRequestInfo_ = objectInfo; + httpRequestInstances[objectInfo] = asyncContext; + } else { + NETMGR_LOGE("HTTP object count max 100"); + return thisVar; + } + napi_wrap( + env, thisVar, objectInfo, + [](napi_env env, void *data, void *hint) { + HttpRequest *objectInfo = (HttpRequest *)data; + if (objectInfo) { + delete objectInfo; + objectInfo = nullptr; + } + }, + nullptr, nullptr); + + return thisVar; +} + +EXTERN_C_START +napi_value HttpFunctionInit(napi_env env, napi_value exports) +{ + napi_property_descriptor properties[] = { + DECLARE_NAPI_FUNCTION("request", Request), + DECLARE_NAPI_FUNCTION("destroy", Destroy), + DECLARE_NAPI_FUNCTION("on", On), + DECLARE_NAPI_FUNCTION("off", Off), + }; + NAPI_CALL(env, + napi_define_class(env, "HttpRequest", NAPI_AUTO_LENGTH, HttpRequestConstructor, nullptr, + sizeof(properties) / sizeof(*properties), properties, &g_HttpRequestConstructorJS)); + + return exports; +} + +napi_value HttpPropertyInit(napi_env env, napi_value exports) +{ + napi_value ok = nullptr; + napi_value created = nullptr; + napi_value accepted = nullptr; + napi_value not_authoritative = nullptr; + napi_value no_content = nullptr; + napi_value reset = nullptr; + napi_value partial = nullptr; + napi_value mult_choice = nullptr; + napi_value moved_perm = nullptr; + napi_value moved_temp = nullptr; + napi_value see_other = nullptr; + napi_value not_modified = nullptr; + napi_value use_proxy = nullptr; + napi_value bad_request = nullptr; + napi_value unauthorized = nullptr; + napi_value payment_required = nullptr; + napi_value forbidden = nullptr; + napi_value not_found = nullptr; + napi_value bad_method = nullptr; + napi_value not_acceptable = nullptr; + napi_value proxy_auth = nullptr; + napi_value client_timeou = nullptr; + napi_value conflict = nullptr; + napi_value gone = nullptr; + napi_value length_required = nullptr; + napi_value precon_failed = nullptr; + napi_value entity_too_large = nullptr; + napi_value req_too_long = nullptr; + napi_value unsupported = nullptr; + napi_value internal = nullptr; + napi_value not_implemented = nullptr; + napi_value bad_gateway = nullptr; + napi_value unavailable = nullptr; + napi_value gateway_timeout = nullptr; + napi_value version = nullptr; + + napi_create_int32(env, OK, &ok); + napi_create_int32(env, CREATED, &created); + napi_create_int32(env, ACCEPTED, &accepted); + napi_create_int32(env, NOT_AUTHORITATIVE, ¬_authoritative); + napi_create_int32(env, NO_CONTENT, &no_content); + napi_create_int32(env, RESET, &reset); + napi_create_int32(env, PARTIAL, &partial); + napi_create_int32(env, MULT_CHOICE, &mult_choice); + napi_create_int32(env, MOVED_PERM, &moved_perm); + napi_create_int32(env, MOVED_TEMP, &moved_temp); + napi_create_int32(env, SEE_OTHER, &see_other); + napi_create_int32(env, NOT_MODIFIED, ¬_modified); + napi_create_int32(env, USE_PROXY, &use_proxy); + napi_create_int32(env, BAD_REQUEST, &bad_request); + napi_create_int32(env, UNAUTHORIZED, &unauthorized); + napi_create_int32(env, PAYMENT_REQUIRED, &payment_required); + napi_create_int32(env, FORBIDDEN, &forbidden); + napi_create_int32(env, NOT_FOUND, ¬_found); + napi_create_int32(env, BAD_METHOD, &bad_method); + napi_create_int32(env, NOT_ACCEPTABLE, ¬_acceptable); + napi_create_int32(env, PROXY_AUTH, &proxy_auth); + napi_create_int32(env, CLIENT_TIMEOUT, &client_timeou); + napi_create_int32(env, CONFLICT, &conflict); + napi_create_int32(env, GONE, &gone); + napi_create_int32(env, LENGTH_REQUIRED, &length_required); + napi_create_int32(env, PRECON_FAILED, &precon_failed); + napi_create_int32(env, ENTITY_TOO_LARGE, &entity_too_large); + napi_create_int32(env, REQ_TOO_LONG, &req_too_long); + napi_create_int32(env, UNSUPPORTED_TYPE, &unsupported); + napi_create_int32(env, INTERNAL_ERROR, &internal); + napi_create_int32(env, NOT_IMPLEMENTED, ¬_implemented); + napi_create_int32(env, BAD_GATEWAY, &bad_gateway); + napi_create_int32(env, UNAVAILABLE, &unavailable); + napi_create_int32(env, GATEWAY_TIMEOUT, &gateway_timeout); + napi_create_int32(env, VERSION, &version); + + napi_property_descriptor desc[] = {DECLARE_NAPI_FUNCTION("createHttp", CreateHttp), + DECLARE_NAPI_STATIC_PROPERTY("OK", ok), DECLARE_NAPI_STATIC_PROPERTY("CREATED", created), + DECLARE_NAPI_STATIC_PROPERTY("ACCEPTED", accepted), + DECLARE_NAPI_STATIC_PROPERTY("NOT_AUTHORITATIVE", not_authoritative), + DECLARE_NAPI_STATIC_PROPERTY("NO_CONTENT", no_content), DECLARE_NAPI_STATIC_PROPERTY("RESET", reset), + DECLARE_NAPI_STATIC_PROPERTY("PARTIAL", partial), DECLARE_NAPI_STATIC_PROPERTY("MULT_CHOICE", mult_choice), + DECLARE_NAPI_STATIC_PROPERTY("MOVED_PERM", moved_perm), + DECLARE_NAPI_STATIC_PROPERTY("MOVED_TEMP", moved_temp), + DECLARE_NAPI_STATIC_PROPERTY("SEE_OTHER", see_other), + DECLARE_NAPI_STATIC_PROPERTY("NOT_MODIFIED", not_modified), + DECLARE_NAPI_STATIC_PROPERTY("USE_PROXY", use_proxy), + DECLARE_NAPI_STATIC_PROPERTY("BAD_REQUEST", bad_request), + DECLARE_NAPI_STATIC_PROPERTY("UNAUTHORIZED", unauthorized), + DECLARE_NAPI_STATIC_PROPERTY("PAYMENT_REQUIRED", payment_required), + DECLARE_NAPI_STATIC_PROPERTY("FORBIDDEN", forbidden), DECLARE_NAPI_STATIC_PROPERTY("NOT_FOUND", not_found), + DECLARE_NAPI_STATIC_PROPERTY("BAD_METHOD", bad_method), + DECLARE_NAPI_STATIC_PROPERTY("NOT_ACCEPTABLE", not_acceptable), + DECLARE_NAPI_STATIC_PROPERTY("PROXY_AUTH", proxy_auth), + DECLARE_NAPI_STATIC_PROPERTY("CLIENT_TIMEOUT", client_timeou), + DECLARE_NAPI_STATIC_PROPERTY("CONFLICT", conflict), DECLARE_NAPI_STATIC_PROPERTY("GONE", gone), + DECLARE_NAPI_STATIC_PROPERTY("LENGTH_REQUIRED", length_required), + DECLARE_NAPI_STATIC_PROPERTY("PRECON_FAILED", precon_failed), + DECLARE_NAPI_STATIC_PROPERTY("ENTITY_TOO_LARGE", entity_too_large), + DECLARE_NAPI_STATIC_PROPERTY("REQ_TOO_LONG", req_too_long), + DECLARE_NAPI_STATIC_PROPERTY("UNSUPPORTED_TYPE", unsupported), + DECLARE_NAPI_STATIC_PROPERTY("INTERNAL_ERROR", internal), + DECLARE_NAPI_STATIC_PROPERTY("NOT_IMPLEMENTED", not_implemented), + DECLARE_NAPI_STATIC_PROPERTY("BAD_GATEWAY", bad_gateway), + DECLARE_NAPI_STATIC_PROPERTY("UNAVAILABLE", unavailable), + DECLARE_NAPI_STATIC_PROPERTY("GATEWAY_TIMEOUT", gateway_timeout), + DECLARE_NAPI_STATIC_PROPERTY("VERSION", version)}; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + NETMGR_LOGD("HttpPropertyInit End"); + return exports; +} + +/* + * Module export function + */ +static napi_value Init(napi_env env, napi_value exports) +{ + /* + * Propertise define + */ + HttpFunctionInit(env, exports); + HttpPropertyInit(env, exports); + + return exports; +} +EXTERN_C_END + +/* + * Module define + */ +static napi_module g_httpModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "net.http", + .nm_priv = ((void *)0), + .reserved = {(void *)0}, +}; + +extern "C" __attribute__((constructor)) void RegisterHttpModule(void) +{ + napi_module_register(&g_httpModule); +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/http/frameworks/js/napi/http/src/http_request.cpp b/http/frameworks/js/napi/http/src/http_request.cpp new file mode 100644 index 000000000..702662dfb --- /dev/null +++ b/http/frameworks/js/napi/http/src/http_request.cpp @@ -0,0 +1,334 @@ +/* + * 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 "http_request.h" +#include "http_napi.h" +#include "napi_util.h" +#include "http_event_list.h" + +#include + +namespace OHOS { +namespace NetManagerStandard { +std::string URL_SEPARATOR = "?"; +std::string URL_DELIMITER = "&"; + +HttpRequest::HttpRequest() +{ + headers_.clear(); + Initialize(); +} + +HttpRequest::~HttpRequest() +{ + curl_global_cleanup(); + NETMGR_LOGD("~HttpRequest"); +} +/* + * Init curl all thread only + */ +bool HttpRequest::Initialize() +{ + std::lock_guard lock(mutex_); + if (initialized_) { + return true; + } + + if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { + NETMGR_LOGD("curl_global_init function initialize failed"); + return false; + } + return true; +} + +void HttpRequest::SetHeaders(std::string headersStr) +{ + if (headersStr.empty()) { + headers_.clear(); + return; + } + + const char separator = '\n'; + size_t posSeparator = headersStr.find(separator); + while (std::string::npos != posSeparator) { + std::string header = headersStr.substr(0, posSeparator - 1); + if (header == "") { + break; + } + size_t posColon = header.find(':'); + if (std::string::npos == posColon) { + headers_["null"] = "[\"" + header + "\"]"; + } else { + headers_["\"" + header.substr(0, posColon) + "\""] = "[\"" + header.substr(posColon + 2) + "\"]"; + } + headersStr = headersStr.substr(posSeparator + 1); + posSeparator = headersStr.find(separator); + } +} + +void HttpRequest::SetHeader(CURL *curl) +{ + struct curl_slist *header = nullptr; + if (!headers_.empty()) { + std::map::iterator iter; + for (iter = headers_.begin(); iter != headers_.end(); iter++) { + header = curl_slist_append(header, (iter->first + ":" + iter->second).c_str()); + } + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); + } +} + +void HttpRequest::SetOptionURL(CURL *curl, HttpRequestOptionsContext *asyncContext) +{ + if (curl == nullptr || asyncContext == nullptr) { + NETMGR_LOGE("set curl url option, pointer address in null"); + return; + } + std::string url(asyncContext->GetUrl()); + NETMGR_LOGD("SetOptionURL : %{public}s", url.c_str()); + std::size_t index = url.find(URL_SEPARATOR); + std::string caFile(asyncContext->GetCaFile()); + bool isCaFile = IsCaFile(caFile); + if (index != std::string::npos) { + int32_t offset = url.rfind(URL_SEPARATOR); + std::string uri = url.substr(0, offset); + std::string param = url.substr(offset + 1); + NETMGR_LOGD("final url : %{public}s, (%{public}s)", uri.c_str(), param.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, param.c_str()); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + if (url.substr(0, URL_PREFIX_LENGTH) == std::string("https://")) { + if (!isCaFile) { + curl_easy_setopt(curl, CURLOPT_CAINFO, "/etc/ssl/cacert.pem"); + NETMGR_LOGD("Default CA filepath : /data/cacert.pem"); + } else { + curl_easy_setopt(curl, CURLOPT_CAINFO, caFile.c_str()); + NETMGR_LOGD("Input CA filepath : %{public}s", caFile.c_str()); + } + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + } + } else { + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + if (url.substr(0, URL_PREFIX_LENGTH) == std::string("https://")) { + if (!isCaFile) { + curl_easy_setopt(curl, CURLOPT_CAINFO, "/etc/ssl/cacert.pem"); + } else { + curl_easy_setopt(curl, CURLOPT_CAINFO, caFile.c_str()); + } + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + } + } + + curl_easy_setopt(curl, CURLOPT_HEADER, 0L); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, asyncContext->GetConnectTimeout()); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, asyncContext->GetReadTimeout()); +} + +void HttpRequest::SetMethod(CURL *curl, HttpRequestOptionsContext *asyncContext) +{ + if (curl == nullptr || asyncContext == nullptr) { + NETMGR_LOGE("SetMethod failed"); + return; + } + RequestMethod method = asyncContext->GetRequestMethod(); + if (method == OPTIONS || method == GET || method == HEAD || method == DELETE || method == TRACE || + method == CONNECT) { + SetOptionForGet(curl, asyncContext); + } else if (method == POST || method == PUT) { + SetOptionForPost(curl, asyncContext); + } else { + NETMGR_LOGE("SetMethod ErrorCode : COMMON_ERROR_CODE"); + } +} + +bool HttpRequest::SetOptionForPost(CURL *curl, HttpRequestOptionsContext *asyncContext) +{ + if (curl == nullptr || asyncContext == nullptr) { + NETMGR_LOGE("set curl url option, pointer address in null"); + return false; + } + HTTP_CURL_EASY_SET_OPTION(curl, CURLOPT_URL, asyncContext->GetUrl().c_str()); + HTTP_CURL_EASY_SET_OPTION(curl, CURLOPT_POST, 1L); + return true; +} + +bool HttpRequest::SetOptionForGet(CURL *curl, HttpRequestOptionsContext *asyncContext) +{ + if (curl == nullptr || asyncContext == nullptr) { + NETMGR_LOGE("set curl url option, pointer address in null"); + return false; + } + NETMGR_LOGD("begin to set option for get and encode final url %{public}s, extraData %{public}s", + asyncContext->GetUrl().c_str(), asyncContext->GetExtraData().c_str()); + std::string url(asyncContext->GetUrl()); + if (!asyncContext->GetExtraData().empty()) { + std::size_t index = url.find(URL_SEPARATOR); + if (index != std::string::npos) { + std::string param = url.substr(0, url.rfind(URL_SEPARATOR) + 1); + std::string encodeIn = param + URL_DELIMITER + asyncContext->GetExtraData(); + char *encodeOut = curl_easy_escape(curl, encodeIn.c_str(), 0); + if (encodeOut != nullptr) { + url = param + encodeOut; + curl_free(encodeOut); + } + } else { + char *encodeOut = curl_easy_escape(curl, asyncContext->GetExtraData().c_str(), 0); + if (encodeOut != nullptr) { + url = url + URL_SEPARATOR + encodeOut; + curl_free(encodeOut); + } + } + HTTP_CURL_EASY_SET_OPTION(curl, CURLOPT_URL, url.c_str()); + } else { + std::size_t index = url.find(URL_SEPARATOR); + if (index != std::string::npos) { + int32_t offset = url.rfind(URL_SEPARATOR); + std::string uri = url.substr(0, offset); + std::string param = url.substr(offset + 1); + NETMGR_LOGD("final url : %{public}s, (%{public}s)", uri.c_str(), param.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, param.c_str()); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + } + } + NETMGR_LOGD("final url : %{public}s, (%{public}d)", url.c_str(), (int32_t)url.length()); + + return true; +} + +bool HttpRequest::GetCurlWriteData(HttpRequestOptionsContext *asyncContext) +{ + NETMGR_LOGD("GetCurlWriteData Begin"); + if (asyncContext == nullptr) { + return false; + } + + CURL *curl = curl_easy_init(); + if (curl == nullptr) { + NETMGR_LOGD("GetCurlWriteData curl handle is null pointer"); + return false; + } + SetOptionURL(curl, asyncContext); + + std::string responseBody; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWritingMemoryBody); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBody); + + std::string responseHeader; + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, OnWritingMemoryHeader); + curl_easy_setopt(curl, CURLOPT_HEADERDATA, &responseHeader); + curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + int32_t responseCode; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode); + + CURLcode res = curl_easy_perform(curl); + if (res != CURLE_OK) { + NETMGR_LOGE("GetCurlWriteData, error : %{public}s, num: %{public}d", curl_easy_strerror(res), res); + curl_easy_cleanup(curl); + return false; + } + HttpResponse responseData = asyncContext->GetResponseData(); + responseData.SetResult(responseBody); + responseData.SetHeader(responseHeader); + responseData.SetResponseCode((enum ResponseCode)responseCode); + + asyncContext->SetResponseData(responseData); + EmitHeader(asyncContext->httpRequestInfo_, responseHeader); + + curl_easy_cleanup(curl); + return true; +} + +void HttpRequest::EmitHeader(HttpRequest *obj, const std::string &header) +{ + NETMGR_LOGD("EmitHeader --------------- count = %{public}d", (int32_t)g_eventListenerList.size()); + struct EventListener *eventListener = nullptr; + for (std::list::iterator listenerIterator = g_eventListenerList.begin(); + listenerIterator != g_eventListenerList.end(); ++listenerIterator) { + NETMGR_LOGD( + "EmitHeader --------------- obj %{public}p, %{public}p", obj, listenerIterator->httpRequestInfo_); + if (listenerIterator->httpRequestInfo_ == obj) { + struct EventListener eventListtmp = *listenerIterator; + eventListener = &eventListtmp; + napi_env env = listenerIterator->env_; + napi_handle_scope scope = nullptr; + napi_open_handle_scope(env, &scope); + napi_value undefine = nullptr; + napi_get_undefined(env, &undefine); + napi_ref callbackRef = listenerIterator->callbackRef_; + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, callbackRef, &callbackFunc); + napi_value callbackValues[2] = {0}; + + callbackValues[0] = NapiUtil::CreateUndefined(env); + napi_value object = nullptr; + napi_create_object(env, &object); + NapiUtil::SetPropertyStringUtf8(env, object, "header", header); + + callbackValues[1] = object; + napi_value callbackResult = nullptr; + napi_call_function(env, undefine, callbackFunc, 2, callbackValues, &callbackResult); + napi_close_handle_scope(env, scope); + napi_delete_reference(env, listenerIterator->callbackRef_); + break; + } + } + if (eventListener != nullptr) { + g_eventListenerList.remove_if( + [obj](EventListener listener) -> bool { return listener.httpRequestInfo_ == obj; }); + } +} + +bool HttpRequest::NativeRequest(HttpRequestOptionsContext *asyncContext) +{ + return GetCurlWriteData(asyncContext); +} + +void HttpRequest::NativeDestroy() +{ + NETMGR_LOGD("destroy start"); +} + +void HttpRequest::NativeOn() +{ + NETMGR_LOGD("on start"); +} + +void HttpRequest::NativeOff() +{ + NETMGR_LOGD("off start"); +} + +bool HttpRequest::IsCaFile(const std::string &caFile) +{ + if (caFile.empty()) { + return false; + } + if (access(caFile.c_str(), F_OK) == -1) { + return false; + } + return true; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/http/frameworks/js/napi/http/src/napi_util.cpp b/http/frameworks/js/napi/http/src/napi_util.cpp new file mode 100644 index 000000000..19c23f812 --- /dev/null +++ b/http/frameworks/js/napi/http/src/napi_util.cpp @@ -0,0 +1,262 @@ +/* + * 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_util.h" + +#include +#include +#include +#include +#include + +#include "netmgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { + +std::string NapiUtil::ToUtf8(std::u16string str16) +{ + return std::wstring_convert, char16_t> {}.to_bytes(str16); +} + +std::u16string NapiUtil::ToUtf16(std::string str) +{ + return std::wstring_convert, char16_t> {}.from_bytes(str); +} + +napi_value NapiUtil::CreateErrorMessage(napi_env env, std::string msg, int32_t errorCode) +{ + napi_value result = nullptr; + napi_value message = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, msg.c_str(), msg.length(), &message)); + napi_value codeValue = nullptr; + std::string errCode = std::to_string(errorCode); + NAPI_CALL(env, napi_create_string_utf8(env, errCode.c_str(), errCode.length(), &codeValue)); + NAPI_CALL(env, napi_create_error(env, codeValue, message, &result)); + return result; +} + +napi_value NapiUtil::CreateUndefined(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_get_undefined(env, &result)); + return result; +} + +bool NapiUtil::MatchValueType(napi_env env, napi_value value, napi_valuetype targetType) +{ + napi_valuetype valueType = napi_undefined; + NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false); + return valueType == targetType; +} + +bool NapiUtil::MatchParameters( + napi_env env, const napi_value parameters[], std::initializer_list valueTypes) +{ + if (parameters == nullptr) { + return false; + } + int i = 0; + for (auto beg = valueTypes.begin(); beg != valueTypes.end(); ++beg) { + if (!MatchValueType(env, parameters[i], *beg)) { + return false; + } + ++i; + } + return true; +} + +void NapiUtil::SetPropertyInt32(napi_env env, napi_value object, std::string name, int32_t value) +{ + napi_value propertyValue = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, value, &propertyValue)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, object, name.c_str(), propertyValue)); +} + +void NapiUtil::SetPropertyStringUtf8(napi_env env, napi_value object, std::string name, std::string value) +{ + napi_value propertyValue = nullptr; + char *valueChars = (char *)value.c_str(); + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, valueChars, std::strlen(valueChars), &propertyValue)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, object, name.c_str(), propertyValue)); +} + +void NapiUtil::SetPropertyBoolean(napi_env env, napi_value object, std::string name, bool value) +{ + napi_value propertyValue = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, value, &propertyValue)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, object, name.c_str(), propertyValue)); +} + +napi_value NapiUtil::ToInt32Value(napi_env env, int32_t value) +{ + napi_value staticValue = nullptr; + NAPI_CALL(env, napi_create_int32(env, value, &staticValue)); + return staticValue; +} + +bool NapiUtil::HasNamedProperty(napi_env env, napi_value object, std::string propertyName) +{ + bool hasProperty = false; + NAPI_CALL_BASE(env, napi_has_named_property(env, object, propertyName.data(), &hasProperty), false); + return hasProperty; +} + +bool NapiUtil::HasNamedTypeProperty(napi_env env, napi_value object, napi_valuetype type, std::string propertyName) +{ + bool hasProperty = false; + NAPI_CALL_BASE(env, napi_has_named_property(env, object, propertyName.data(), &hasProperty), false); + if (hasProperty) { + napi_value value = nullptr; + NAPI_CALL_BASE(env, napi_get_named_property(env, object, propertyName.data(), &value), false); + return MatchValueType(env, value, type); + } + return false; +} + +bool NapiUtil::MatchObjectProperty( + napi_env env, napi_value object, std::initializer_list> pairList) +{ + if (object == nullptr) { + return false; + } + for (auto beg = pairList.begin(); beg != pairList.end(); ++beg) { + if (!HasNamedTypeProperty(env, object, beg->second, beg->first)) { + return false; + } + } + return true; +} + +bool NapiUtil::MatchOptionPropertyType( + napi_env env, napi_value object, napi_valuetype type, std::string propertyName) +{ + bool hasProperty = false; + NAPI_CALL_BASE(env, napi_has_named_property(env, object, propertyName.data(), &hasProperty), false); + if (hasProperty) { + napi_value value = nullptr; + NAPI_CALL_BASE(env, napi_get_named_property(env, object, propertyName.data(), &value), false); + return MatchValueType(env, value, type); + } + return true; +} + +std::string NapiUtil::GetStringFromValue(napi_env env, napi_value value) +{ + char msgChars[MAX_TEXT_LENGTH] = {0}; + size_t msgLength = 0; + NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, msgChars, MAX_TEXT_LENGTH, &msgLength), ""); + NETMGR_LOGD("NapiUtil GetStringFromValue msgLength = %{public}d", msgLength); + if (msgLength > 0) { + return std::string(msgChars, 0, msgLength); + } else { + return ""; + } +} + +napi_value NapiUtil::GetNamedProperty(napi_env env, napi_value object, std::string propertyName) +{ + napi_value value = nullptr; + NAPI_CALL(env, napi_get_named_property(env, object, propertyName.data(), &value)); + return value; +} + +bool NapiUtil::MatchHttpRequestDataParameters(napi_env env, const napi_value parameters[], size_t parameterCount) +{ + switch (parameterCount) { + case 0: + return true; + case 1: + return MatchParameters(env, parameters, {napi_string}); + case 2: + if (MatchParameters(env, parameters, {napi_string, napi_function}) + || MatchParameters(env, parameters, {napi_string, napi_object})) { + return true; + } + return false; + case 3: + return MatchParameters(env, parameters, {napi_string, napi_object, napi_function}); + default: + return false; + } +} +bool NapiUtil::MatchHttpOnDataParameters(napi_env env, const napi_value parameters[], size_t parameterCount) +{ + switch (parameterCount) { + case 0: + return true; + case 1: + return false; + case 2: + return MatchParameters(env, parameters, {napi_string, napi_function}); + default: + return false; + } +} +bool NapiUtil::MatchHttpOffDataParameters(napi_env env, const napi_value parameters[], size_t parameterCount) +{ + switch (parameterCount) { + case 0: + return true; + case 1: + return MatchParameters(env, parameters, {napi_string}); + case 2: + return MatchParameters(env, parameters, {napi_string, napi_function}); + default: + return false; + } +} +void NapiUtil::SetPropertyArray(napi_env env, napi_value object, std::string name, std::vector pdu) +{ + napi_value array = nullptr; + napi_create_array(env, &array); + int size = pdu.size(); + for (int i = 0; i < size; i++) { + napi_value element = nullptr; + std::string tmp = pdu.at(i); + napi_create_string_utf8(env, tmp.c_str(), tmp.size(), &element); + napi_set_element(env, array, i, element); + } + napi_set_named_property(env, object, name.c_str(), array); +} +int32_t NapiUtil::GetIntProperty(napi_env env, napi_value object, const std::string &propertyName) +{ + int32_t intValue = 0; + napi_value value = nullptr; + napi_status getNameStatus = napi_get_named_property(env, object, propertyName.c_str(), &value); + if (getNameStatus == napi_ok) { + napi_status getIntStatus = napi_get_value_int32(env, value, &intValue); + if (getIntStatus == napi_ok) { + return intValue; + } + } + return intValue; +} +std::string NapiUtil::GetStringProperty(napi_env env, napi_value object, const std::string &propertyName) +{ + napi_value value = nullptr; + napi_status getNameStatus = napi_get_named_property(env, object, propertyName.c_str(), &value); + if (getNameStatus == napi_ok) { + char buf[maxUrlLength] = {0}; + size_t bufLength = 0; + napi_status getStringStatus = napi_get_value_string_utf8(env, value, buf, maxUrlLength, &bufLength); + if (getStringStatus == napi_ok && bufLength > 0) { + return std::string(buf, bufLength); + } + } + return ""; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/extra_options_base.h b/http/frameworks/js/napi/socket/include/extra_options_base.h new file mode 100644 index 000000000..2c434e01f --- /dev/null +++ b/http/frameworks/js/napi/socket/include/extra_options_base.h @@ -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. + */ + +#ifndef EXTRA_OPTIONS_BASE_H +#define EXTRA_OPTIONS_BASE_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "napi_util.h" + +namespace OHOS { +namespace NetManagerStandard { +class ExtraOptionsBase { +public: + ExtraOptionsBase() {} + ~ExtraOptionsBase() {} + + int32_t GetReceiveBufferSize() + { + return receiveBufferSize_; + } + + void SetReceiveBufferSize(int32_t receiveBufferSize) + { + this->receiveBufferSize_ = receiveBufferSize; + } + + int32_t GetSendBufferSize() + { + return sendBufferSize_; + } + + void SetSendBufferSize(int32_t sendBufferSize) + { + this->sendBufferSize_ = sendBufferSize; + } + + int32_t GetReuseAddress() + { + return reuseAddress_; + } + + void SetReuseAddress(int32_t reuseAddress) + { + this->reuseAddress_ = reuseAddress; + } + + int32_t GetSocketTimeout() + { + return socketTimeout_; + } + + void SetSocketTimeout(int32_t socketTimeout) + { + this->socketTimeout_ = socketTimeout; + } +private: + int32_t receiveBufferSize_ = 0; + int32_t sendBufferSize_ = 0; + int32_t reuseAddress_ = 0; + int32_t socketTimeout_ = 0; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // EXTRA_OPTIONS_BASE_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/netaddress.h b/http/frameworks/js/napi/socket/include/netaddress.h new file mode 100644 index 000000000..884fbb77b --- /dev/null +++ b/http/frameworks/js/napi/socket/include/netaddress.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 NETADDRESS_H +#define NETADDRESS_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +#include + +namespace OHOS { +namespace NetManagerStandard { +enum SocketFamily { IPV4 = 1, IPV6 = 2 }; +struct NetAddress { + std::string ipAddress = ""; + int32_t family = 1; // IPv4 = 1; IPv6 = 2, default is IPv4 + int32_t port = 8080; // [0, 65535] +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NETADDRESS_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/socket_base_context.h b/http/frameworks/js/napi/socket/include/socket_base_context.h new file mode 100644 index 000000000..e5114ecd8 --- /dev/null +++ b/http/frameworks/js/napi/socket/include/socket_base_context.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 SOCKET_BASE_CONTEXT_H +#define SOCKET_BASE_CONTEXT_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "napi_util.h" + +namespace OHOS { +namespace NetManagerStandard { +class SocketBaseContext { +public: + napi_async_work work_ = nullptr; + napi_deferred deferred_ = nullptr; + napi_ref callbackRef_ = nullptr; + int32_t errorCode_ = ERROR_DEFAULT; + bool resolved_ = false; + napi_value result_ = 0; + bool isCallback_ = false; +public: + SocketBaseContext() {} + ~SocketBaseContext() {} +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // SOCKET_BASE_CONTEXT_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/socket_napi.h b/http/frameworks/js/napi/socket/include/socket_napi.h new file mode 100644 index 000000000..307e63c11 --- /dev/null +++ b/http/frameworks/js/napi/socket/include/socket_napi.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 SOCKET_NAPI_H +#define SOCKET_NAPI_H + +#include "musl/include/sys/socket.h" +#include "musl/porting/liteos_m/kernel/include/unistd.h" +#include "musl/porting/liteos_m/kernel/include/sys/socket.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "tcp_event_list.h" +#include "udp_event_list.h" + +#include +#include +#include +#include +#include + +namespace OHOS { +namespace NetManagerStandard { + const int32_t ERROR_NONE = 0; + const int32_t ERROR_SERVICE_UNAVAILABLE = -2; + const int32_t ERROR_PARAMETER_VALUE_INVALID = -3; + const int32_t ERROR_NATIVE_API_EXECUTE_FAIL = -4; + const int32_t NORMAL_STRING_SIZE = 64; + constexpr int32_t PARAMS_COUNT = 2; + + static const std::int32_t STR_MAX_SIZE = 64; + static const std::int32_t PORT_MIN_SIZE = 0; + static const std::int32_t PORT_MAX_SIZE = 65535; + static const std::int32_t defaultValue = -1; + + static std::list g_udpEventListenerList; + static std::list g_tcpEventListenerList; + + // UDP extern interface + napi_value CreateUDPSocket(napi_env env, napi_callback_info info); + napi_value UdpBind(napi_env env, napi_callback_info info); + napi_value UdpConnect(napi_env env, napi_callback_info info); + napi_value UdpSend(napi_env env, napi_callback_info info); + napi_value UdpClose(napi_env env, napi_callback_info info); + napi_value UdpGetState(napi_env env, napi_callback_info info); + napi_value UdpSetExtraOptions(napi_env env, napi_callback_info info); + napi_value UdpOn(napi_env env, napi_callback_info info); + napi_value UdpOff(napi_env env, napi_callback_info info); + // TCP extern interface + napi_value CreateTCPSocket(napi_env env, napi_callback_info info); + napi_value TcpBind(napi_env env, napi_callback_info info); + napi_value TcpConnect(napi_env env, napi_callback_info info); + napi_value TcpSend(napi_env env, napi_callback_info info); + napi_value TcpClose(napi_env env, napi_callback_info info); + napi_value TcpGetRemoteAddress(napi_env env, napi_callback_info info); + napi_value TcpGetState(napi_env env, napi_callback_info info); + napi_value TcpSetExtraOptions(napi_env env, napi_callback_info info); + napi_value TcpOn(napi_env env, napi_callback_info info); + napi_value TcpOff(napi_env env, napi_callback_info info); +} // namespace NetManagerStandard +} // namespace OHOS +#endif // SOCKET_NAPI_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/socket_remote_info.h b/http/frameworks/js/napi/socket/include/socket_remote_info.h new file mode 100644 index 000000000..f0c2710c8 --- /dev/null +++ b/http/frameworks/js/napi/socket/include/socket_remote_info.h @@ -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. + */ + +#ifndef SOCKET_REMOTE_INFO_H +#define SOCKET_REMOTE_INFO_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "napi_util.h" + +namespace OHOS { +namespace NetManagerStandard { +class SocketRemoteInfo { +public: + SocketRemoteInfo() {} + ~SocketRemoteInfo() {} + + std::string GetAddress() + { + return address_; + } + + void SetAddress(const std::string& address) + { + this->address_ = address; + } + + std::string GetFamily() + { + return family_; + } + + void SetFamily(const std::string& family) + { + this->family_ = family; + } + + int32_t GetPort() + { + return port_; + } + + void SetPort(int32_t port) + { + this->port_ = port; + } + + int32_t GetSize() + { + return size_; + } + + void SetSize(int32_t size) + { + this->size_ = size; + } +private: + std::string address_ = ""; + std::string family_ = "IPv4"; + int32_t port_ = 0; + int32_t size_ = 0; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // SOCKET_REMOTE_INFO_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/socket_state_base.h b/http/frameworks/js/napi/socket/include/socket_state_base.h new file mode 100644 index 000000000..005f6f838 --- /dev/null +++ b/http/frameworks/js/napi/socket/include/socket_state_base.h @@ -0,0 +1,66 @@ +/* + * 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 SOCKET_BASE_CONTEXT_H +#define SOCKET_BASE_CONTEXT_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "napi_util.h" + +namespace OHOS { +namespace NetManagerStandard { +class SocketStateBase { +public: + SocketStateBase() {} + ~SocketStateBase() {} + + bool GetBound() + { + return isBound_; + } + + void SetBound(bool bound) + { + this->isBound_ = bound; + } + + bool GetClose() + { + return isClose_; + } + + void SetClose(bool close) + { + this->isClose_ = close; + } + + bool GetConnected() + { + return isConnected_; + } + + void SetConnected(bool connected) + { + this->isConnected_ = connected; + } +private: + bool isBound_ = false; + bool isClose_ = false; + bool isConnected_ = false; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // SOCKET_BASE_CONTEXT_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/tcp_connect_options.h b/http/frameworks/js/napi/socket/include/tcp_connect_options.h new file mode 100644 index 000000000..31d9952d0 --- /dev/null +++ b/http/frameworks/js/napi/socket/include/tcp_connect_options.h @@ -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. + */ + +#ifndef TCP_CONNECT_OPTIONS_H +#define TCP_CONNECT_OPTIONS_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "netaddress.h" + +namespace OHOS { +namespace NetManagerStandard { +class TCPConnectOptions { +public: + TCPConnectOptions() {} + ~TCPConnectOptions() {} + + struct NetAddress GetReceiveBufferSize() + { + return address_; + } + + void SetReceiveBufferSize(struct NetAddress address) + { + this->address_ = address; + } + + int32_t GetTimeout() + { + return timeout_; + } + + void SetTimeout(int32_t timeout) + { + this->timeout_ = timeout; + } +private: + struct NetAddress address_ = {}; + int32_t timeout_ = 0; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // TCP_CONNECT_OPTIONS_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/tcp_event_list.h b/http/frameworks/js/napi/socket/include/tcp_event_list.h new file mode 100644 index 000000000..5672d9bcc --- /dev/null +++ b/http/frameworks/js/napi/socket/include/tcp_event_list.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 TCP_EVENT_LIST_H +#define TCP_EVENT_LIST_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace NetManagerStandard { +class TCPSocket; +struct TcpEventListener { + napi_env env_; + int32_t eventType_; + bool isOnce_; + napi_ref callbackRef_; + TCPSocket *tcpSocket_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // TCP_EVENT_LIST_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/tcp_extra_options.h b/http/frameworks/js/napi/socket/include/tcp_extra_options.h new file mode 100644 index 000000000..a73f4527a --- /dev/null +++ b/http/frameworks/js/napi/socket/include/tcp_extra_options.h @@ -0,0 +1,92 @@ +/* + * 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 TCP_EXTRA_OPTIONS_H +#define TCP_EXTRA_OPTIONS_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "extra_options_base.h" + +namespace OHOS { +namespace NetManagerStandard { +class TCPExtraOptions : public ExtraOptionsBase { +public: + TCPExtraOptions() {} + ~TCPExtraOptions() {} + + class SocketLinger { + public: + bool on_ = true; + int32_t linger_ = 0; + } socketLinger_; + + bool GetKeepAlive() + { + return keepAlive_; + } + + void SetKeepAlive(bool keepAlive) + { + this->keepAlive_ = keepAlive; + } + + bool GetOOBInline() + { + return OOBInline_; + } + + void SetOOBInline(bool OOBInline) + { + this->OOBInline_ = OOBInline; + } + + bool GetTCPNoDelay() + { + return TCPNoDelay_; + } + + void SetTCPNoDelay(bool TCPNoDelay) + { + this->TCPNoDelay_ = TCPNoDelay; + } + + bool GetSocketLingerOn() + { + return socketLinger_.on_; + } + + void SetSocketLingerOn(bool on) + { + this->socketLinger_.on_ = on; + } + + int32_t GetSocketLingerLinger() + { + return socketLinger_.linger_; + } + + void SetSocketLingerLinger(int32_t linger) + { + this->socketLinger_.linger_ = linger; + } +private: + bool keepAlive_ = false; + bool OOBInline_ = false; + bool TCPNoDelay_ = false; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // TCP_EXTRA_OPTIONS_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/tcp_send_options.h b/http/frameworks/js/napi/socket/include/tcp_send_options.h new file mode 100644 index 000000000..1bb4a59f9 --- /dev/null +++ b/http/frameworks/js/napi/socket/include/tcp_send_options.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 TCP_SEND_OPTIONS_H +#define TCP_SEND_OPTIONS_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +#include + +namespace OHOS { +namespace NetManagerStandard { +class TCPSendOptions { +public: + TCPSendOptions() {} + ~TCPSendOptions() {} + + std::string GetData() + { + return data_; + } + + void SetData(std::string data) + { + this->data_ = data; + } + + std::string GetEncoding() + { + return encoding_; + } + + void SetEncoding(std::string encoding) + { + this->encoding_ = encoding; + } +private: + std::string data_ = ""; + std::string encoding_ = ""; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // TCP_SEND_OPTIONS_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/tcp_socket.h b/http/frameworks/js/napi/socket/include/tcp_socket.h new file mode 100644 index 000000000..99493324a --- /dev/null +++ b/http/frameworks/js/napi/socket/include/tcp_socket.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 TCP_SOCKET_H +#define TCP_SOCKET_H + +#include "musl/include/sys/socket.h" +#include "musl/porting/liteos_m/kernel/include/unistd.h" +#include "musl/porting/liteos_m/kernel/include/sys/socket.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "netaddress.h" +#include "socket_napi.h" +#include "tcp_extra_options.h" + +#include +#include +#include +#include + +namespace OHOS { +namespace NetManagerStandard { +class TCPSocket; +struct TcpBaseContext : NetAddress { + napi_async_work work_ = nullptr; + napi_deferred deferred_ = nullptr; + napi_ref callbackRef_ = nullptr; + bool resolved_ = false; + int32_t errorCode_ = 0; + int32_t socketfd_ = -1; + std::string data = ""; + std::string errorString_ = ""; + bool isBound = false; + bool isClose = true; + bool isConnected = false; + bool broadcast = false; + int type = 0; + TCPExtraOptions tcpExtraOptions_; + TCPSocket *tcpSocket_; +}; + +class TCPSocket { +public: + TCPSocket(TcpBaseContext remInfo); + ~TCPSocket(); + + int TcpSocket(int domain, int type, int protocol); + int TcpBind(int fd, const struct sockaddr *addr, socklen_t len); + int TcpConnect(int fd, const struct sockaddr *addr, socklen_t len); + int TcpSend(int fd, const void *buf, size_t len, int flags); + int TcpClose(int fd); + int TcpSetSockopt(int fd, int level, int optname, const void *optval, socklen_t optlen); + void GetJSParameter(napi_env &env, napi_value *parameters, TcpBaseContext *&asyncContext); + void GetSocketInfo(struct sockaddr_in &addr, TcpBaseContext *&asyncContext); + void GetExOpGetJSParameter(napi_env &env, napi_value *parameters, TcpBaseContext *&asyncContext); + TcpBaseContext tcpbaseContext_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // TCP_SOCKET_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/udp_event_list.h b/http/frameworks/js/napi/socket/include/udp_event_list.h new file mode 100644 index 000000000..905a9698d --- /dev/null +++ b/http/frameworks/js/napi/socket/include/udp_event_list.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 UDP_EVENT_LIST_H +#define UDP_EVENT_LIST_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace NetManagerStandard { +class UDPSocket; +struct UdpEventListener { + napi_env env_; + int32_t eventType_; + bool isOnce_; + napi_ref callbackRef_; + UDPSocket *udpSocket_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // UDP_EVENT_LIST_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/udp_extra_options.h b/http/frameworks/js/napi/socket/include/udp_extra_options.h new file mode 100644 index 000000000..49b29f223 --- /dev/null +++ b/http/frameworks/js/napi/socket/include/udp_extra_options.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 UDP_EXTRA_OPTIONS_H +#define UDP_EXTRA_OPTIONS_H + +#include "extra_options_base.h" + +namespace OHOS { +namespace NetManagerStandard { +class UDPExtraOptions : public ExtraOptionsBase { +public: + UDPExtraOptions () {} + ~UDPExtraOptions() {} + + bool GetBroadcast() + { + return broadcast_; + } + + void SetBroadcast(bool broadcast) + { + this->broadcast_ = broadcast; + } +private: + bool broadcast_ = false; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // UDP_EXTRA_OPTIONS_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/udp_send_options.h b/http/frameworks/js/napi/socket/include/udp_send_options.h new file mode 100644 index 000000000..f5e6379b3 --- /dev/null +++ b/http/frameworks/js/napi/socket/include/udp_send_options.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 UDP_SEND_OPTIONS_H +#define UDP_SEND_OPTIONS_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "napi_util.h" + +namespace OHOS { +namespace NetManagerStandard { +class UDPSendOptions { +public: + UDPSendOptions() {} + ~UDPSendOptions() {} + + std::string GetData() + { + return data_; + } + + void SetData(const std::string& data) + { + this->data_ = data; + } +private: + std::string data_ = ""; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // UDP_SEND_OPTIONS_H \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/include/udp_socket.h b/http/frameworks/js/napi/socket/include/udp_socket.h new file mode 100644 index 000000000..c35bf1361 --- /dev/null +++ b/http/frameworks/js/napi/socket/include/udp_socket.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 UDP_SOCKET_H +#define UDP_SOCKET_H + +#include "musl/include/sys/socket.h" +#include "musl/porting/liteos_m/kernel/include/unistd.h" +#include "musl/porting/liteos_m/kernel/include/sys/socket.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "netaddress.h" +#include "socket_napi.h" + +#include +#include +#include +#include + +namespace OHOS { +namespace NetManagerStandard { +class UDPSocket; + +struct Baseinfo : NetAddress { + napi_async_work work_ = nullptr; + napi_deferred deferred_ = nullptr; + napi_ref callbackRef_ = nullptr; + bool resolved_ = false; + int32_t errorCode = 0; + int32_t socketfd = -1; + std::string data = ""; + bool isBound = false; + bool isClose = true; + bool isConnected = false; + bool broadcast = false; + int type = 0; + UDPSocket *udpRequestInfo_; +}; + +struct NetState : NetAddress { + bool isBound = false; + bool isClose = false; + bool isConnected = false; +}; + +class UDPSocket { +public: + UDPSocket(Baseinfo remInfo); + ~UDPSocket(); + + int UdpSocket(int domain, int type, int protocol); + int UdpBind(int fd, const struct sockaddr *addr, socklen_t len); + int UdpConnect(int fd, const struct sockaddr *addr, socklen_t len); + int UdpSend(int fd, const void *buf, size_t len, int flags); + int UdpClose(int fd); + void GetJSParameter(napi_env &env, napi_value *parameters, Baseinfo *&asyncContext); + void GetSocketInfo(struct sockaddr_in &addr, Baseinfo *&asyncContext); + + Baseinfo remInfo; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // UDP_SOCKET_H diff --git a/http/frameworks/js/napi/socket/src/socket_napi.cpp b/http/frameworks/js/napi/socket/src/socket_napi.cpp new file mode 100644 index 000000000..0b5ceb525 --- /dev/null +++ b/http/frameworks/js/napi/socket/src/socket_napi.cpp @@ -0,0 +1,2215 @@ +/* + * 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 "socket_napi.h" + +#include "napi_util.h" +#include "netmgr_log_wrapper.h" +#include "node_api_types.h" + +#include "tcp_socket.h" +#include "udp_socket.h" + +#include +#include +#include +#include + +namespace OHOS { +namespace NetManagerStandard { +static napi_value g_UdpSocketConstructorJS; +static napi_value g_TcpSocketConstructorJS; +std::vector g_onInfoList; +std::vector g_tcpSocketList; +static std::map udpSocketInstances; +static std::map tcpSocketInstances; +constexpr int32_t INVALID_SOCKET = -1; +constexpr int32_t EVENT_ARRAY_LENGTH = 64; + +constexpr int32_t NONE_EVENT_TYPE = 0; +constexpr int32_t MESSAGE_SOCKET_STATE = 1; +constexpr int32_t LISTENING_SOCKET_STATE = 2; +constexpr int32_t CLOSE_SOCKET_STATE = 3; +constexpr int32_t ERROR_SOCKET_STATE = 4; +constexpr int32_t CONNECT_SOCKET_STATE = 5; + +const std::string MESSAGE_RECEIVE = "message"; +const std::string LISTENING_RECEIVE = "listening"; +const std::string CLOSE_RECEIVE = "close"; +const std::string ERROR_RECEIVE = "error"; +const std::string CONNECT_RECEIVE = "connect"; + +constexpr int32_t MAX_SOCKET_OBJ_COUNT = 100; + +bool MatchSocketEventType(const std::string &type, const std::string &goalTypeStr) +{ + return goalTypeStr.compare(type) == 0; +} + +int32_t GetSocketEventType(const std::string &type) +{ + NETMGR_LOGD("GetSocketEventType %{public}s", type.c_str()); + if (MatchSocketEventType(type, MESSAGE_RECEIVE)) { + return MESSAGE_SOCKET_STATE; + } else if (MatchSocketEventType(type, LISTENING_RECEIVE)) { + return LISTENING_SOCKET_STATE; + } else if (MatchSocketEventType(type, CLOSE_RECEIVE)) { + return CLOSE_SOCKET_STATE; + } else if (MatchSocketEventType(type, ERROR_RECEIVE)) { + return ERROR_SOCKET_STATE; + } else if (MatchSocketEventType(type, CONNECT_RECEIVE)) { + return CONNECT_SOCKET_STATE; + } + return NONE_EVENT_TYPE; +} + +static void EmitUdpEvent(UDPSocket *obj, const std::string &type, const std::string &message) +{ + int32_t eventType = GetSocketEventType(type); + NETMGR_LOGD("EmitUdpEvent UDP count = %{public}d", (int32_t)g_udpEventListenerList.size()); + for (std::list::iterator listenerIterator = g_udpEventListenerList.begin(); + listenerIterator != g_udpEventListenerList.end(); ++listenerIterator) { + NETMGR_LOGD("EmitUdpEvent obj %{public}p, %{public}p", obj, listenerIterator->udpSocket_); + if (listenerIterator->udpSocket_ == obj && listenerIterator->eventType_ == eventType) { + napi_env env = listenerIterator->env_; + napi_handle_scope scope = nullptr; + napi_open_handle_scope(env, &scope); + napi_value undefine = nullptr; + napi_get_undefined(env, &undefine); + napi_ref callbackRef = listenerIterator->callbackRef_; + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, callbackRef, &callbackFunc); + napi_value callbackValues[2] = {0}; + + callbackValues[0] = NapiUtil::CreateUndefined(env); + napi_value object = nullptr; + napi_create_object(env, &object); + NapiUtil::SetPropertyStringUtf8(env, object, type, message); + + callbackValues[1] = object; + napi_value callbackResult = nullptr; + napi_call_function(env, undefine, callbackFunc, PARAMS_COUNT, callbackValues, &callbackResult); + napi_close_handle_scope(env, scope); + napi_delete_reference(env, listenerIterator->callbackRef_); + break; + } + } +} + +static void NativeUdpBind(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeUdpBind formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + struct sockaddr_in addr; + asyncContext->udpRequestInfo_->GetSocketInfo(addr, asyncContext); + + if (!asyncContext->isBound && asyncContext->isClose && !asyncContext->isConnected) { + asyncContext->errorCode = asyncContext->udpRequestInfo_->UdpBind(asyncContext->socketfd, + (struct sockaddr *)&addr, sizeof(struct sockaddr)); + } + if (asyncContext->errorCode >= 0) { + asyncContext->isBound = true; + asyncContext->resolved_ = true; + std::string listening("listening"); + EmitUdpEvent(asyncContext->udpRequestInfo_, "listening", listening); + } else { + std::string error("error"); + EmitUdpEvent(asyncContext->udpRequestInfo_, "error", error); + } + NETMGR_LOGD("NativeUdpBind errorCode:%{public}d", asyncContext->errorCode); +} + +static void UdpBindCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("UdpBindCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyInt32(env, callbackValue, "errorCode", asyncContext->errorCode); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, "bind failed"); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +static void NativeUdpConnect(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeUdpConnect formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + struct sockaddr_in addr; + asyncContext->udpRequestInfo_->GetSocketInfo(addr, asyncContext); + // the init isclose=true and if fd close we can bind also + if (!asyncContext->isBound && asyncContext->isClose && !asyncContext->isConnected) { + asyncContext->errorCode = asyncContext->udpRequestInfo_->UdpConnect(asyncContext->socketfd, + (struct sockaddr *)&addr, sizeof(struct sockaddr)); + } + if (asyncContext->errorCode >= 0) { + asyncContext->isConnected = true; + // Once Connect Success ,the close state must false + asyncContext->isClose = false; + } +} + +static void UdpConnectCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("UdpConnectCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyInt32(env, callbackValue, "errorCode", asyncContext->errorCode); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, "udp connect failed"); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +static void NativeUdpSend(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeUdpBind formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + + struct sockaddr_in addr; + asyncContext->udpRequestInfo_->GetSocketInfo(addr, asyncContext); + NETMGR_LOGD("send data:%{public}s", asyncContext->data.c_str()); + + if (!asyncContext->isClose) { + asyncContext->errorCode = asyncContext->udpRequestInfo_->UdpSend(asyncContext->socketfd, + asyncContext->data.c_str(), asyncContext->data.size(), 0); + } + + if (asyncContext->errorCode >= 0) { + std::string message("message"); + EmitUdpEvent(asyncContext->udpRequestInfo_, "message", message); + } else { + std::string error("error"); + EmitUdpEvent(asyncContext->udpRequestInfo_, "error", error); + } + NETMGR_LOGD("NativeUdpSend errorCode:%{public}d", asyncContext->errorCode); +} + +static void UdpSendCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("UdpSendCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyInt32(env, callbackValue, "errorCode", asyncContext->errorCode); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, "Request failed"); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +static void NativeUdpClose(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeUdpClose formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + + if (!asyncContext->isClose) { + asyncContext->errorCode = asyncContext->udpRequestInfo_->UdpClose(asyncContext->socketfd); + std::string close("close"); + EmitUdpEvent(asyncContext->udpRequestInfo_, "close", close); + } else { + std::string error("error"); + EmitUdpEvent(asyncContext->udpRequestInfo_, "error", error); + } + NETMGR_LOGD("NativeUdpClose errorCode:%{public}d", asyncContext->errorCode); +} + +static void UdpCloseCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("UdpCloseCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyInt32(env, callbackValue, "errorCode", asyncContext->errorCode); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, "udp socket close failed"); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +static void NativeUdpGetState(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeUdpGetState formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + asyncContext->resolved_ = true; +} + +static void UdpGetStateCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("UdpGetStateCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyInt32(env, callbackValue, "isBound", asyncContext->isBound); + NapiUtil::SetPropertyInt32(env, callbackValue, "isClose", asyncContext->isClose); + NapiUtil::SetPropertyInt32(env, callbackValue, "isConnected", asyncContext->isConnected); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, "udp socket getState failed"); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID(env, napi_call_function(env, undefined, callback, PARAMS_COUNT, callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +static void NativeUdpSetExtraOptions(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeSetExtraOptionsSend formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + + struct sockaddr_in addr; + asyncContext->udpRequestInfo_->GetSocketInfo(addr, asyncContext); +} + +static void UdpSetExtraOptionsCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("UdpSetExtraOptionsCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyInt32(env, callbackValue, "errorCode", asyncContext->errorCode); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, "udp socket SetExtraOptions failed"); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +napi_value CreateUDPSocket(napi_env env, napi_callback_info info) +{ + std::size_t argc = 2; + napi_value args[2] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); + + napi_value result = nullptr; + napi_value argvArray[] = {nullptr}; + napi_new_instance(env, g_UdpSocketConstructorJS, 0, argvArray, &result); + + return result; +} + +napi_value UdpBind(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + uint32_t flag = 0; + bool isFdExist = false; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + Baseinfo *asyncContext = nullptr; + UDPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = udpSocketInstances.find(objectInfo); + if (requestKey != udpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("udpSocketInstances add udp socket pointer"); + return nullptr; + } + + objectInfo->GetJSParameter(env, parameters, asyncContext); + for (int i = 0; i < g_onInfoList.size(); i++) { + if (objectInfo->remInfo.socketfd == g_onInfoList.at(i).socketfd) { + flag = i; + isFdExist = true; + break; + } + } + if (!isFdExist) { + if (asyncContext->family == IPV6) { + asyncContext->socketfd = objectInfo->UdpSocket(AF_INET6, SOCK_DGRAM, 0); + } else { + asyncContext->socketfd = objectInfo->UdpSocket(AF_INET, SOCK_DGRAM, 0); + } + if (asyncContext->socketfd < 0) { + return nullptr; + } + } + + if (!isFdExist) { + objectInfo->remInfo = *asyncContext; + g_onInfoList.push_back(objectInfo->remInfo); + } else { + g_onInfoList[flag] = *asyncContext; + objectInfo->remInfo = *asyncContext; + } + + NETMGR_LOGD("GetSubscribeInfo parameterCount = %{public}d objectInfo = %{public}p, asyncContext = %{public}p", + (int32_t)parameterCount, objectInfo, asyncContext); + + if (parameterCount == PARAMS_COUNT) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "udpBind", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeUdpBind, UdpBindCallback, (void *)asyncContext, + &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("Udp bind Async Work Successful"); + } + return result; +} + +napi_value UdpConnect(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + uint32_t flag = 0; + bool isFdExist = false; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + Baseinfo *asyncContext = nullptr; + UDPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = udpSocketInstances.find(objectInfo); + if (requestKey != udpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("UdpConnect not find socket pointer"); + return nullptr; + } + + objectInfo->GetJSParameter(env, parameters, asyncContext); + for (int i = 0; i < g_onInfoList.size(); i++) { + if (objectInfo->remInfo.socketfd == g_onInfoList.at(i).socketfd) { + flag = i; + isFdExist = true; + break; + } + } + if (!isFdExist) { + return nullptr; + } + + g_onInfoList[flag] = *asyncContext; + objectInfo->remInfo = *asyncContext; + + if (parameterCount == PARAMS_COUNT) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "udpConnect", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeUdpConnect, UdpConnectCallback, (void *)asyncContext, + &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("Udp connect Async Work Successful"); + } + return result; +} + +napi_value UdpSend(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + uint32_t flag = 0; + bool isFdExist = false; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + Baseinfo *asyncContext = nullptr; + UDPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = udpSocketInstances.find(objectInfo); + if (requestKey != udpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("UdpSend not find socket pointer"); + return nullptr; + } + + for (int i = 0; i < g_onInfoList.size(); i++) { + if (objectInfo->remInfo.socketfd == g_onInfoList.at(i).socketfd) { + flag = i; + isFdExist = true; + break; + } + } + if (!isFdExist) { + return nullptr; + } + + objectInfo->GetJSParameter(env, parameters, asyncContext); + + g_onInfoList.at(flag) = *asyncContext; + objectInfo->remInfo = *asyncContext; + + if (parameterCount == PARAMS_COUNT) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "udpSend", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeUdpSend, UdpSendCallback, (void *)asyncContext, + &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("Udp send Async Work Successful"); + } + return result; +} + +napi_value UdpClose(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + uint32_t flag = 0; + bool isFdExist = false; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + Baseinfo *asyncContext = nullptr; + UDPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = udpSocketInstances.find(objectInfo); + if (requestKey != udpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("UdpClose not find socket pointer"); + return nullptr; + } + + for (int i = 0; i < g_onInfoList.size(); i++) { + if (objectInfo->remInfo.socketfd == g_onInfoList.at(i).socketfd) { + flag = i; + isFdExist = true; + break; + } + } + if (!isFdExist) { + return nullptr; + } + + g_onInfoList[flag] = *asyncContext; + objectInfo->remInfo = *asyncContext; + + if (parameterCount == PARAMS_COUNT) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "udpClose", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeUdpClose, UdpCloseCallback, (void *)asyncContext, + &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("Udp send Async Work Successful"); + } + return result; +} + +napi_value UdpGetState(napi_env env, napi_callback_info info) +{ + NETMGR_LOGD("udpGetState start"); + std::size_t parameterCount = 1; + napi_value parameters[1] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + uint32_t flag = 0; + bool isFdExist = false; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + Baseinfo *asyncContext = nullptr; + UDPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = udpSocketInstances.find(objectInfo); + if (requestKey != udpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("UdpGetState not find socket pointer"); + return nullptr; + } + + for (int i = 0; i < g_onInfoList.size(); i++) { + if (objectInfo->remInfo.socketfd == g_onInfoList.at(i).socketfd) { + flag = i; + isFdExist = true; + break; + } + } + if (!isFdExist) { + return nullptr; + } + + if (parameterCount == 1) { + napi_valuetype valuetype1; + NAPI_CALL(env, napi_typeof(env, parameters[0], &valuetype1)); + if (NapiUtil::MatchValueType(env, parameters[0], napi_function)) { + NETMGR_LOGD("MatchValueType is true"); + NAPI_CALL(env, napi_create_reference(env, parameters[0], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "udpGetState", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeUdpGetState, UdpGetStateCallback, (void *)asyncContext, + &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("Udp GetState Async Work Successful"); + } + + return result; +} + +napi_value UdpSetExtraOptions(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + uint32_t flag = 0; + bool isFdExist = false; + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + Baseinfo *asyncContext = nullptr; + UDPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = udpSocketInstances.find(objectInfo); + if (requestKey != udpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("udpSocketInstances add udp socket pointer"); + return nullptr; + } + + for (int i = 0; i < g_onInfoList.size(); i++) { + if (objectInfo->remInfo.socketfd == g_onInfoList.at(i).socketfd) { + flag = i; + isFdExist = true; + asyncContext = &g_onInfoList.at(i); + break; + } + } + if (!isFdExist) { + return nullptr; + } + asyncContext->ipAddress = "255.255.255.255"; + asyncContext->broadcast = true; + + g_onInfoList[flag] = *asyncContext; + objectInfo->remInfo = *asyncContext; + + if (parameterCount == PARAMS_COUNT) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "udpSetExtraOptions", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeUdpSetExtraOptions, UdpSetExtraOptionsCallback, + (void *)asyncContext, &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("Udp SetExtraOptions Async Work Successful"); + } + return result; +} + +napi_value UdpRequestConstructor(napi_env env, napi_callback_info info) +{ + std::size_t argc = 1; + napi_value argv[1]; + napi_value thisVar = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr)); + + auto asyncContext = new Baseinfo(); + auto objectInfo = new UDPSocket(*asyncContext); + + if (udpSocketInstances.size() <= MAX_SOCKET_OBJ_COUNT) { + asyncContext->udpRequestInfo_ = objectInfo; + udpSocketInstances[objectInfo] = asyncContext; + } else { + NETMGR_LOGE("UDP object count max 100"); + return thisVar; + } + + napi_wrap(env, + thisVar, + objectInfo, + [](napi_env env, void *data, void *hint) { + UDPSocket *objectInfo = (UDPSocket *)data; + if (objectInfo) { + delete objectInfo; + objectInfo = nullptr; + } + }, + nullptr, + nullptr); + return thisVar; +} + +napi_value UdpOn(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {nullptr, nullptr}; + napi_value thisVar = nullptr; + void *data = nullptr; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + Baseinfo *asyncContext = nullptr; + UDPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = udpSocketInstances.find(objectInfo); + if (requestKey != udpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("udpSocketInstances add udp socket pointer"); + return nullptr; + } + + char eventTypeChars[OHOS::NetManagerStandard::EVENT_ARRAY_LENGTH] = {0}; + size_t strLen = 0; + + NAPI_CALL(env, + napi_get_value_string_utf8( + env, parameters[0], eventTypeChars, OHOS::NetManagerStandard::EVENT_ARRAY_LENGTH - 1, &strLen)); + + napi_ref callbackRef = nullptr; + + if (parameterCount == PARAMS_COUNT) { + napi_create_reference(env, parameters[1], 1, &callbackRef); + } + napi_value result = nullptr; + uint32_t eventType = GetSocketEventType(eventTypeChars); + struct UdpEventListener listener = {env, eventType, true, callbackRef, objectInfo}; + if (eventType != NONE_EVENT_TYPE) { + g_udpEventListenerList.push_back(listener); + result = thisVar; + NETMGR_LOGD("ON Finish = %{public}d", (int32_t)g_udpEventListenerList.size()); + } + + return thisVar; +} + +napi_value UdpOff(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + Baseinfo *asyncContext = nullptr; + UDPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = udpSocketInstances.find(objectInfo); + if (requestKey != udpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("udpSocketInstances add udp socket pointer"); + return nullptr; + } + + char eventTypeChars[OHOS::NetManagerStandard::EVENT_ARRAY_LENGTH] = {0}; + size_t strLen = 0; + + NAPI_CALL(env, + napi_get_value_string_utf8( + env, parameters[0], eventTypeChars, OHOS::NetManagerStandard::EVENT_ARRAY_LENGTH - 1, &strLen)); + + napi_ref callbackRef = nullptr; + if (parameterCount == PARAMS_COUNT) { + napi_create_reference(env, parameters[1], 1, &callbackRef); + } + napi_value result = nullptr; + uint32_t eventType = GetSocketEventType(eventTypeChars); + + struct UdpEventListener listener = {env, eventType, true, callbackRef, objectInfo}; + if (eventType != NONE_EVENT_TYPE) { + napi_delete_reference(env, listener.callbackRef_); + g_udpEventListenerList.remove_if([objectInfo, eventType](UdpEventListener listener)->bool { + return (listener.udpSocket_ == objectInfo && listener.eventType_ == eventType); + }); + result = thisVar; + NETMGR_LOGD("Off Finish"); + } + + return thisVar; +} + +static void EmitTcpEvent(TCPSocket *obj, const std::string &type, const std::string &message) +{ + int32_t eventType = GetSocketEventType(type); + NETMGR_LOGD("EmitTcpEvent count = %{public}d", (int32_t)g_tcpEventListenerList.size()); + for (std::list::iterator listenerIterator = g_tcpEventListenerList.begin(); + listenerIterator != g_tcpEventListenerList.end(); ++listenerIterator) { + NETMGR_LOGD("EmitTcpEvent obj %{public}p, %{public}p", obj, listenerIterator->tcpSocket_); + if (listenerIterator->tcpSocket_ == obj && listenerIterator->eventType_ == eventType) { + napi_env env = listenerIterator->env_; + napi_handle_scope scope = nullptr; + napi_open_handle_scope(env, &scope); + napi_value undefine = nullptr; + napi_get_undefined(env, &undefine); + napi_ref callbackRef = listenerIterator->callbackRef_; + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, callbackRef, &callbackFunc); + napi_value callbackValues[2] = {0}; + + callbackValues[0] = NapiUtil::CreateUndefined(env); + napi_value object = nullptr; + napi_create_object(env, &object); + NapiUtil::SetPropertyStringUtf8(env, object, type, message); + + callbackValues[1] = object; + napi_value callbackResult = nullptr; + napi_call_function(env, undefine, callbackFunc, PARAMS_COUNT, callbackValues, &callbackResult); + napi_close_handle_scope(env, scope); + napi_delete_reference(env, listenerIterator->callbackRef_); + break; + } + } +} + +static void NativeTcpBind(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeTcpBind formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + + struct sockaddr_in addr; + asyncContext->tcpSocket_->GetSocketInfo(addr, asyncContext); + + if (asyncContext->socketfd_ == INVALID_SOCKET && asyncContext->tcpSocket_ != nullptr) { + if (asyncContext->family == IPV6) { + asyncContext->socketfd_ = asyncContext->tcpSocket_->TcpSocket(AF_INET6, SOCK_STREAM, 0); + } else { + asyncContext->socketfd_ = asyncContext->tcpSocket_->TcpSocket(AF_INET, SOCK_STREAM, 0); + } + if (asyncContext->socketfd_ < 0) { + return; + } + } + + if (!asyncContext->isBound && asyncContext->isClose && !asyncContext->isConnected) { + asyncContext->errorCode_ = asyncContext->tcpSocket_->TcpBind(asyncContext->socketfd_, + (struct sockaddr *)&addr, sizeof(struct sockaddr)); + } + if (asyncContext->errorCode_ >= 0) { + asyncContext->isBound = true; + asyncContext->resolved_ = true; + asyncContext->errorString_.clear(); + } else { + asyncContext->errorString_ = strerror(errno); + std::string error = asyncContext->errorString_; + EmitTcpEvent(asyncContext->tcpSocket_, "error", error); + } + + NETMGR_LOGD("NativeTcpBind errorCode:%{public}d", asyncContext->errorCode_); +} + +static void TcpBindCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("TcpBindCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyInt32(env, callbackValue, "errorCode", asyncContext->errorCode_); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, asyncContext->errorString_); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +static void NativeTcpConnect(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeTcpConnect formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + + struct sockaddr_in addr; + asyncContext->tcpSocket_->GetSocketInfo(addr, asyncContext); + + if (asyncContext->socketfd_ == INVALID_SOCKET && asyncContext->tcpSocket_ != nullptr) { + if (asyncContext->family == IPV6) { + asyncContext->socketfd_ = asyncContext->tcpSocket_->TcpSocket(AF_INET6, SOCK_STREAM, 0); + } else { + asyncContext->socketfd_ = asyncContext->tcpSocket_->TcpSocket(AF_INET, SOCK_STREAM, 0); + } + if (asyncContext->socketfd_ < 0) { + return; + } + } + + if (!asyncContext->isBound && asyncContext->isClose && !asyncContext->isConnected) { + asyncContext->errorCode_ = asyncContext->tcpSocket_->TcpConnect(asyncContext->socketfd_, + (struct sockaddr *)&addr, sizeof(struct sockaddr)); + } + if (asyncContext->errorCode_ >= 0) { + asyncContext->isConnected = true; + asyncContext->isClose = false; // Once Connect Success ,the close state must false + std::string connect("connect"); + EmitTcpEvent(asyncContext->tcpSocket_, "connect", connect); + } else { + asyncContext->errorString_ = strerror(errno); + std::string error = asyncContext->errorString_; + EmitTcpEvent(asyncContext->tcpSocket_, "error", error); + } + + NETMGR_LOGD("NativeTcpConnect errorCode:%{public}d", asyncContext->errorCode_); +} + +static void TcpConnectCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("TcpConnectCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyInt32(env, callbackValue, "errorCode", asyncContext->errorCode_); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, asyncContext->errorString_); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +static void NativeTcpSend(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeUdpBind formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + + struct sockaddr_in addr; + asyncContext->tcpSocket_->GetSocketInfo(addr, asyncContext); + NETMGR_LOGD("send data:%{public}s", asyncContext->data.c_str()); + + if (!asyncContext->isClose) { + asyncContext->errorCode_ = asyncContext->tcpSocket_->TcpSend(asyncContext->socketfd_, + asyncContext->data.c_str(), asyncContext->data.size(), 0); + std::string message("message"); + EmitTcpEvent(asyncContext->tcpSocket_, "message", message); + } else { + asyncContext->errorString_ = strerror(errno); + std::string error = asyncContext->errorString_; + EmitTcpEvent(asyncContext->tcpSocket_, "error", error); + } + + NETMGR_LOGD("NativeTcpSend errorCode:%{public}d", asyncContext->errorCode_); +} + +static void TcpSendCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("TcpSendCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyInt32(env, callbackValue, "errorCode", asyncContext->errorCode_); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, asyncContext->errorString_); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +static void NativeTcpClose(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeTcpClose formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + + if (!asyncContext->isClose) { + asyncContext->errorCode_ = asyncContext->tcpSocket_->TcpClose(asyncContext->socketfd_); + } + + if (asyncContext->errorCode_ >= 0) { + std::string close("close"); + EmitTcpEvent(asyncContext->tcpSocket_, "close", close); + } else { + std::string error("error"); + EmitTcpEvent(asyncContext->tcpSocket_, "error", error); + } + + NETMGR_LOGD("NativeTcpClose errorCode:%{public}d", asyncContext->errorCode_); +} + +static void TcpCloseCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("TcpCloseCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyInt32(env, callbackValue, "errorCode", asyncContext->errorCode_); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, "tcp socket close failed"); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +static void NativeTcpGetRemoteAddress(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeTcpGetState formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + asyncContext->resolved_ = true; + asyncContext->errorString_.clear(); +} + +static void TcpGetRemoteAddressCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("TcpGetRemoteAddressCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyStringUtf8(env, callbackValue, "ipAddress", asyncContext->ipAddress); + NapiUtil::SetPropertyInt32(env, callbackValue, "family", asyncContext->family); + NapiUtil::SetPropertyInt32(env, callbackValue, "port", asyncContext->port); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, "tcp socket getRemoteAddress failed"); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +static void NativeTcpGetState(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeTcpGetState formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + asyncContext->resolved_ = true; + asyncContext->errorString_.clear(); +} + +static void TcpGetStateCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("TcpGetStateCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyInt32(env, callbackValue, "isBound", asyncContext->isBound); + NapiUtil::SetPropertyInt32(env, callbackValue, "isClose", asyncContext->isClose); + NapiUtil::SetPropertyInt32(env, callbackValue, "isConnected", asyncContext->isConnected); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, "tcp socket getState failed"); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +static void NativeTcpSetExtraOptions(napi_env env, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("NativeSetExtraOptionsSend formal parameter data is null"); + return; + } + auto asyncContext = static_cast(data); + + struct sockaddr_in addr; + asyncContext->tcpSocket_->GetSocketInfo(addr, asyncContext); + + if (asyncContext->socketfd_ == INVALID_SOCKET && asyncContext->tcpSocket_ != nullptr) { + if (asyncContext->family == IPV6) { + asyncContext->socketfd_ = asyncContext->tcpSocket_->TcpSocket(AF_INET6, SOCK_STREAM, 0); + } else { + asyncContext->socketfd_ = asyncContext->tcpSocket_->TcpSocket(AF_INET, SOCK_STREAM, 0); + } + if (asyncContext->socketfd_ < 0) { + return; + } + } + + bool keepAlive = asyncContext->tcpExtraOptions_.GetKeepAlive(); + if (keepAlive) { + asyncContext->errorCode_ = asyncContext->tcpSocket_->TcpSetSockopt(asyncContext->socketfd_, + SOL_SOCKET, SO_KEEPALIVE, (void *) &keepAlive, sizeof (keepAlive)); + } + NETMGR_LOGD("NativeSetExtraOptionsSend keepAlive errorCode:%{public}d", asyncContext->errorCode_); + + bool OOBInline = asyncContext->tcpExtraOptions_.GetOOBInline(); + if (OOBInline) { + asyncContext->errorCode_ = asyncContext->tcpSocket_->TcpSetSockopt(asyncContext->socketfd_, + SOL_SOCKET, SO_OOBINLINE, (void *) &OOBInline, sizeof (OOBInline)); + } + NETMGR_LOGD("NativeSetExtraOptionsSend OOBInline errorCode:%{public}d", asyncContext->errorCode_); + + bool TCPNoDelay = asyncContext->tcpExtraOptions_.GetTCPNoDelay(); + if (TCPNoDelay) { + asyncContext->errorCode_ = asyncContext->tcpSocket_->TcpSetSockopt(asyncContext->socketfd_, + IPPROTO_TCP, TCP_NODELAY, (void *) &TCPNoDelay, sizeof (TCPNoDelay)); + } + NETMGR_LOGD("NativeSetExtraOptionsSend TCPNoDelay errorCode:%{public}d", asyncContext->errorCode_); + + bool on = asyncContext->tcpExtraOptions_.GetSocketLingerOn(); + int32_t intLinger = asyncContext->tcpExtraOptions_.GetSocketLingerLinger(); + if (on) { + struct linger linger; + linger.l_onoff = on; + linger.l_linger = intLinger; + asyncContext->errorCode_ = asyncContext->tcpSocket_->TcpSetSockopt(asyncContext->socketfd_, + SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof (linger)); + } + NETMGR_LOGD("NativeSetExtraOptionsSend errorCode:%{public}d", asyncContext->errorCode_); + + if (asyncContext->errorCode_ < 0) { + std::string error = strerror(errno); + EmitTcpEvent(asyncContext->tcpSocket_, "error", error); + } else { + asyncContext->errorString_.clear(); + asyncContext->resolved_ = true; + std::string message("message"); + EmitTcpEvent(asyncContext->tcpSocket_, "message", message); + } +} + +static void TcpSetExtraOptionsCallback(napi_env env, napi_status status, void *data) +{ + if (data == nullptr) { + NETMGR_LOGE("TcpSetExtraOptionsCallback data parameter address is nullptr"); + return; + } + auto asyncContext = static_cast(data); + napi_value callbackValue = nullptr; + + if (asyncContext->resolved_) { + napi_create_object(env, &callbackValue); + NapiUtil::SetPropertyInt32(env, callbackValue, "errorCode", asyncContext->errorCode_); + } else { + callbackValue = NapiUtil::CreateErrorMessage(env, "tcp socket SetExtraOptions failed"); + } + if (asyncContext->callbackRef_ != nullptr) { + napi_value callbackFunc = nullptr; + napi_get_reference_value(env, asyncContext->callbackRef_, &callbackFunc); + napi_value callbackValues[] = {nullptr, nullptr}; + callbackValues[0] = asyncContext->resolved_ ? NapiUtil::CreateUndefined(env) : callbackValue; + callbackValues[1] = asyncContext->resolved_ ? callbackValue : NapiUtil::CreateUndefined(env); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value result = nullptr; + NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncContext->callbackRef_, &callback)); + NAPI_CALL_RETURN_VOID( + env, napi_call_function(env, undefined, callback, std::size(callbackValues), callbackValues, &result)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, asyncContext->callbackRef_)); + } else if (asyncContext->deferred_ != nullptr) { + if (asyncContext->resolved_) { + napi_resolve_deferred(env, asyncContext->deferred_, callbackValue); + } else { + napi_reject_deferred(env, asyncContext->deferred_, callbackValue); + } + } + + napi_delete_async_work(env, asyncContext->work_); +} + +napi_value CreateTCPSocket(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + std::size_t argc = 2; + napi_value args[2] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr)); + + napi_value result = nullptr; + napi_value argvArray[] = {nullptr}; + napi_new_instance(env, g_TcpSocketConstructorJS, 0, argvArray, &result); + + return result; +} + +napi_value TcpBind(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + TcpBaseContext *asyncContext = nullptr; + TCPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = tcpSocketInstances.find(objectInfo); + if (requestKey != tcpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("tcpSocketInstances add udp socket pointer"); + return nullptr; + } + + objectInfo->GetJSParameter(env, parameters, asyncContext); + + if (parameterCount == PARAMS_COUNT) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "tcpBind", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeTcpBind, TcpBindCallback, (void *)asyncContext, + &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("Tcp bind Async Work Successful"); + } + + return result; +} + +napi_value TcpConnect(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + TcpBaseContext *asyncContext = nullptr; + TCPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = tcpSocketInstances.find(objectInfo); + if (requestKey != tcpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("tcpSocketInstances add udp socket pointer"); + return nullptr; + } + + objectInfo->GetJSParameter(env, parameters, asyncContext); + + if (parameterCount == PARAMS_COUNT) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "tcpConnect", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeTcpConnect, TcpConnectCallback, (void *)asyncContext, + &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("Tcp connect Async Work Successful"); + } + + return result; +} + +napi_value TcpSend(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + TcpBaseContext *asyncContext = nullptr; + TCPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = tcpSocketInstances.find(objectInfo); + if (requestKey != tcpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("tcpSocketInstances add udp socket pointer"); + return nullptr; + } + + objectInfo->GetJSParameter(env, parameters, asyncContext); + + if (parameterCount == PARAMS_COUNT) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "tcpBind", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeTcpSend, TcpSendCallback, (void *)asyncContext, + &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("Udp bind Async Work Successful"); + } + + return result; +} + +napi_value TcpClose(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + TcpBaseContext *asyncContext = nullptr; + TCPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = tcpSocketInstances.find(objectInfo); + if (requestKey != tcpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("tcpClose not find socket pointer"); + return nullptr; + } + + objectInfo->GetJSParameter(env, parameters, asyncContext); + + struct sockaddr_in addr; + objectInfo->GetSocketInfo(addr, asyncContext); + + if (parameterCount == PARAMS_COUNT) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "tcpClose", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeTcpClose, TcpCloseCallback, (void *)asyncContext, + &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("Udp close Async Work Successful"); + } + + return result; +} + +napi_value TcpGetRemoteAddress(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + TcpBaseContext *asyncContext = nullptr; + TCPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = tcpSocketInstances.find(objectInfo); + if (requestKey != tcpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("tcpGetRemoteAddress not find socket pointer"); + return nullptr; + } + + objectInfo->GetJSParameter(env, parameters, asyncContext); + + if (parameterCount == PARAMS_COUNT) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "tcpGetRemoteAddress", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeTcpGetRemoteAddress, TcpGetRemoteAddressCallback, + (void *)asyncContext, &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("GetRemoteAddress Async Work Successful"); + } + + return result; +} + +napi_value TcpGetState(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + TcpBaseContext *asyncContext = nullptr; + TCPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = tcpSocketInstances.find(objectInfo); + if (requestKey != tcpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("tcpGetState not find socket pointer"); + return nullptr; + } + + objectInfo->GetJSParameter(env, parameters, asyncContext); + + if (parameterCount == PARAMS_COUNT) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "tcpGetState", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeTcpGetState, TcpGetStateCallback, (void *)asyncContext, + &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("tcpGetState Async Work Successful"); + } + + return result; +} + +napi_value TcpSetExtraOptions(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + TcpBaseContext *asyncContext = nullptr; + TCPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = tcpSocketInstances.find(objectInfo); + if (requestKey != tcpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("tcpSetExtraOptions not find socket pointer"); + return nullptr; + } + + asyncContext->ipAddress = "255.255.255.255"; + asyncContext->broadcast = true; + + objectInfo->GetJSParameter(env, parameters, asyncContext); + + objectInfo->GetExOpGetJSParameter(env, parameters, asyncContext); + + if (parameterCount == PARAMS_COUNT) { + if (NapiUtil::MatchValueType(env, parameters[1], napi_function)) { + NAPI_CALL(env, napi_create_reference(env, parameters[1], 1, &(asyncContext->callbackRef_))); + } + } + + napi_value result = nullptr; + + if (asyncContext->callbackRef_ == nullptr) { + NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred_, &result)); + } else { + NAPI_CALL(env, napi_get_undefined(env, &result)); + } + napi_value resourceName = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "tcpSetExtraOptions", NAPI_AUTO_LENGTH, &resourceName)); + + NAPI_CALL(env, + napi_create_async_work(env, nullptr, resourceName, NativeTcpSetExtraOptions, TcpSetExtraOptionsCallback, + (void *)asyncContext, &(asyncContext->work_))); + napi_status resultStatus = napi_queue_async_work(env, asyncContext->work_); + if (resultStatus == napi_ok) { + NETMGR_LOGD("tcpSetExtraOptions Async Work Successful"); + } + return result; +} + +napi_value TcpOn(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + TcpBaseContext *asyncContext = nullptr; + TCPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = tcpSocketInstances.find(objectInfo); + if (requestKey != tcpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("tcpSocketInstances add udp socket pointer"); + return nullptr; + } + + char eventTypeChars[OHOS::NetManagerStandard::EVENT_ARRAY_LENGTH] = { 0 }; + size_t strLen = 0; + + NAPI_CALL(env, + napi_get_value_string_utf8( + env, parameters[0], eventTypeChars, OHOS::NetManagerStandard::EVENT_ARRAY_LENGTH - 1, &strLen)); + + napi_ref callbackRef = nullptr; + + if (parameterCount == PARAMS_COUNT) { + napi_create_reference(env, parameters[1], 1, &callbackRef); + } + napi_value result = nullptr; + uint32_t eventType = GetSocketEventType(eventTypeChars); + + struct TcpEventListener listener = {env, eventType, true, callbackRef, objectInfo}; + if (eventType != NONE_EVENT_TYPE) { + g_tcpEventListenerList.push_back(listener); + result = thisVar; + NETMGR_LOGD("ON Finish = %{public}d", (int32_t)g_tcpEventListenerList.size()); + } + + return thisVar; +} + +napi_value TcpOff(napi_env env, napi_callback_info info) +{ + std::size_t parameterCount = 2; + napi_value parameters[2] = {0}; + napi_value thisVar = nullptr; + void *data = nullptr; + + NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data)); + + TcpBaseContext *asyncContext = nullptr; + TCPSocket *objectInfo = nullptr; + napi_valuetype valuetype; + + NAPI_CALL(env, napi_typeof(env, thisVar, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type for arg0. Subscribe expected."); + napi_unwrap(env, thisVar, (void **)&objectInfo); + + auto requestKey = tcpSocketInstances.find(objectInfo); + if (requestKey != tcpSocketInstances.end()) { + asyncContext = requestKey->second; + } else { + NETMGR_LOGE("tcpOff not find socket pointer"); + return nullptr; + } + + char eventTypeChars[OHOS::NetManagerStandard::EVENT_ARRAY_LENGTH] = {0}; + size_t strLen = 0; + + NAPI_CALL(env, + napi_get_value_string_utf8( + env, parameters[0], eventTypeChars, OHOS::NetManagerStandard::EVENT_ARRAY_LENGTH - 1, &strLen)); + + napi_ref callbackRef = nullptr; + if (parameterCount == PARAMS_COUNT) { + napi_create_reference(env, parameters[1], 1, &callbackRef); + } + napi_value result = nullptr; + uint32_t eventType = GetSocketEventType(eventTypeChars); + struct TcpEventListener listener = {env, eventType, true, callbackRef, objectInfo}; + if (eventType != NONE_EVENT_TYPE) { + napi_delete_reference(env, listener.callbackRef_); + g_tcpEventListenerList.remove_if([objectInfo, eventType](TcpEventListener listener)->bool { + return (listener.tcpSocket_ == objectInfo && listener.eventType_ == eventType); + }); + result = thisVar; + NETMGR_LOGD("Off Finish"); + } + + return thisVar; +} + +napi_value TcpRequestConstructor(napi_env env, napi_callback_info info) +{ + std::size_t argc = 1; + napi_value argv[1]; + napi_value thisVar = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr)); + + auto asyncContext = new TcpBaseContext(); + auto objectInfo = new TCPSocket(*asyncContext); + + if (tcpSocketInstances.size() <= MAX_SOCKET_OBJ_COUNT) { + asyncContext->tcpSocket_ = objectInfo; + tcpSocketInstances[objectInfo] = asyncContext; + } else { + return thisVar; + } + + napi_wrap(env, + thisVar, + objectInfo, + [](napi_env env, void *data, void *hint) { + TCPSocket *objectInfo = (TCPSocket *)data; + if (objectInfo) { + delete objectInfo; + objectInfo = nullptr; + } + }, + nullptr, + nullptr); + return thisVar; +} + +EXTERN_C_START +/* + * UDP Socket register + */ +napi_value RegisterUdpObjectFunction(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("bind", UdpBind), + DECLARE_NAPI_FUNCTION("connect", UdpConnect), + DECLARE_NAPI_FUNCTION("send", UdpSend), + DECLARE_NAPI_FUNCTION("close", UdpClose), + DECLARE_NAPI_FUNCTION("getState", UdpGetState), + DECLARE_NAPI_FUNCTION("setExtraOptions", UdpSetExtraOptions), + DECLARE_NAPI_FUNCTION("on", UdpOn), + DECLARE_NAPI_FUNCTION("off", UdpOff), + }; + + NAPI_CALL(env, + napi_define_class(env, + "UDPSocket", + NAPI_AUTO_LENGTH, + UdpRequestConstructor, + nullptr, + sizeof(desc) / sizeof(desc[0]), + desc, + &g_UdpSocketConstructorJS)); + return exports; +} + +napi_value CreateUdpObjectFunction(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("constructUDPSocketInstance", CreateUDPSocket), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + + return exports; +} + +/* + * TCP Socket register + */ +napi_value RegisterTcpObjectFunction(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("bind", TcpBind), + DECLARE_NAPI_FUNCTION("connect", TcpConnect), + DECLARE_NAPI_FUNCTION("send", TcpSend), + DECLARE_NAPI_FUNCTION("close", TcpClose), + DECLARE_NAPI_FUNCTION("getRemoteAddress", TcpGetRemoteAddress), + DECLARE_NAPI_FUNCTION("getState", TcpGetState), + DECLARE_NAPI_FUNCTION("setExtraOptions", TcpSetExtraOptions), + DECLARE_NAPI_FUNCTION("on", TcpOn), + DECLARE_NAPI_FUNCTION("off", TcpOff), + }; + + NAPI_CALL(env, + napi_define_class(env, + "TCPSocket", + NAPI_AUTO_LENGTH, + TcpRequestConstructor, + nullptr, + sizeof(desc) / sizeof(desc[0]), + desc, + &g_TcpSocketConstructorJS)); + return exports; +} + +napi_value CreateTcpObjectFunction(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("constructTCPSocketInstance", CreateTCPSocket), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + + return exports; +} +/* + * Module export function + */ +static napi_value Init(napi_env env, napi_value exports) +{ + RegisterUdpObjectFunction(env, exports); + CreateUdpObjectFunction(env, exports); + RegisterTcpObjectFunction(env, exports); + CreateTcpObjectFunction(env, exports); + + return exports; +} + +EXTERN_C_END + +static napi_module g_socketModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "net.socket", + .nm_priv = ((void *)0), + .reserved = {(void *)0}, +}; +/* + * Module register function + */ +extern "C" __attribute__((constructor)) void RegisterSocketModule(void) +{ + napi_module_register(&g_socketModule); +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/src/tcp_socket.cpp b/http/frameworks/js/napi/socket/src/tcp_socket.cpp new file mode 100644 index 000000000..9f0377119 --- /dev/null +++ b/http/frameworks/js/napi/socket/src/tcp_socket.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 "tcp_socket.h" + +#include "napi_util.h" +#include "netmgr_log_wrapper.h" +#include "node_api_types.h" + +namespace OHOS { +namespace NetManagerStandard { +TCPSocket::TCPSocket(TcpBaseContext remInfo) +{ + this->tcpbaseContext_ = remInfo; +} + +TCPSocket::~TCPSocket() +{ + TcpClose(this->tcpbaseContext_.socketfd_); + NETMGR_LOGD("~TCPSocket"); +} + +void TCPSocket::GetJSParameter(napi_env &env, napi_value *parameters, TcpBaseContext*&asyncContext) +{ + napi_value addressvalue = NapiUtil::GetNamedProperty(env, parameters[0], "address"); + if (addressvalue != nullptr) { + asyncContext->ipAddress = NapiUtil::GetStringFromValue(env, addressvalue); + } + napi_value familyValue = NapiUtil::GetNamedProperty(env, parameters[0], "family"); + if (familyValue != nullptr) { + napi_get_value_int32(env, familyValue, &asyncContext->family); + } + napi_value portValue = NapiUtil::GetNamedProperty(env, parameters[0], "port"); + if (portValue != nullptr) { + napi_get_value_int32(env, portValue, &asyncContext->port); + } + napi_value dataValue = NapiUtil::GetNamedProperty(env, parameters[0], "data"); + if (dataValue != nullptr) { + asyncContext->data = NapiUtil::GetStringFromValue(env, dataValue); + } +} + +void TCPSocket::GetSocketInfo(struct sockaddr_in &addr, TcpBaseContext *&asyncContext) +{ + addr.sin_addr.s_addr = inet_addr(asyncContext->ipAddress.c_str()); + if (asyncContext->family == IPV6) { + addr.sin_family = AF_INET6; + } else { + addr.sin_family = AF_INET; + } + addr.sin_port = htons(asyncContext->port); +} + +int TCPSocket::TcpSocket(int domain, int type, int protocol) +{ + this->tcpbaseContext_.socketfd_ = socket(domain, type, protocol); + return this->tcpbaseContext_.socketfd_; +} + +int TCPSocket::TcpBind(int fd, const struct sockaddr *addr, socklen_t len) +{ + if (fd != this->tcpbaseContext_.socketfd_) { + return -1; + } + return bind(fd, addr, len); +} + +int TCPSocket::TcpConnect(int fd, const struct sockaddr *addr, socklen_t len) +{ + if (fd != this->tcpbaseContext_.socketfd_) { + return -1; + } + return connect(fd, addr, len); +} + +int TCPSocket::TcpSend(int fd, const void *buf, size_t len, int flags) +{ + if (fd != this->tcpbaseContext_.socketfd_) { + return -1; + } + return send(fd, buf, len, flags); +} + +int TCPSocket::TcpClose(int fd) +{ + if (fd != this->tcpbaseContext_.socketfd_) { + return -1; + } + return close(fd); +} + +int TCPSocket::TcpSetSockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) +{ + if (fd != this->tcpbaseContext_.socketfd_) { + return -1; + } + return setsockopt(fd, level, optname, optval, optlen); +} + +void TCPSocket::GetExOpGetJSParameter(napi_env &env, napi_value *parameters, TcpBaseContext*&asyncContext) +{ + bool value = false; + napi_value keepAliveValue = NapiUtil::GetNamedProperty(env, parameters[0], "keepAlive"); + if (keepAliveValue != nullptr) { + napi_get_value_bool(env, keepAliveValue, &value); + } + asyncContext->tcpExtraOptions_.SetKeepAlive(value); + + napi_value OOBInlineValue = NapiUtil::GetNamedProperty(env, parameters[0], "OOBInline"); + if (OOBInlineValue != nullptr) { + napi_get_value_bool(env, OOBInlineValue, &value); + } + asyncContext->tcpExtraOptions_.SetOOBInline(value); + + napi_value TCPNoDelayValue = NapiUtil::GetNamedProperty(env, parameters[0], "TCPNoDelay"); + if (TCPNoDelayValue != nullptr) { + napi_get_value_bool(env, TCPNoDelayValue, &value); + } + asyncContext->tcpExtraOptions_.SetTCPNoDelay(value); + + napi_value socketLingerValue = NapiUtil::GetNamedProperty(env, parameters[0], "socketLinger"); + if (socketLingerValue != nullptr) { + napi_value socktLingerOnValue = NapiUtil::GetNamedProperty(env, socketLingerValue, "on"); + if (socktLingerOnValue != nullptr) { + napi_get_value_bool(env, socktLingerOnValue, &value); + } + asyncContext->tcpExtraOptions_.SetSocketLingerOn(value); + + int32_t intValue = 0; + napi_value socktLingerLingerValue = NapiUtil::GetNamedProperty(env, socketLingerValue, "linger"); + if (socktLingerLingerValue != nullptr) { + napi_get_value_int32(env, socktLingerLingerValue, &intValue); + } + asyncContext->tcpExtraOptions_.SetSocketLingerLinger(value); + } +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/http/frameworks/js/napi/socket/src/udp_socket.cpp b/http/frameworks/js/napi/socket/src/udp_socket.cpp new file mode 100644 index 000000000..a72a23c43 --- /dev/null +++ b/http/frameworks/js/napi/socket/src/udp_socket.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 "udp_socket.h" +#include "napi_util.h" +#include "netmgr_log_wrapper.h" +#include "node_api_types.h" + +namespace OHOS { +namespace NetManagerStandard { +UDPSocket::UDPSocket(Baseinfo remInfo) +{ + this->remInfo = remInfo; +} + +UDPSocket::~UDPSocket() +{ + UdpClose(this->remInfo.socketfd); + NETMGR_LOGD("~UDPSocket"); +} + +void UDPSocket::GetJSParameter(napi_env &env, napi_value *parameters, Baseinfo*&asyncContext) +{ + napi_value addressvalue = NapiUtil::GetNamedProperty(env, parameters[0], "address"); + if (addressvalue != nullptr) { + asyncContext->ipAddress = NapiUtil::GetStringFromValue(env, addressvalue); + } + napi_value familyValue = NapiUtil::GetNamedProperty(env, parameters[0], "family"); + if (familyValue != nullptr) { + napi_get_value_int32(env, familyValue, &asyncContext->family); + } + napi_value portValue = NapiUtil::GetNamedProperty(env, parameters[0], "port"); + if (portValue != nullptr) { + napi_get_value_int32(env, portValue, &asyncContext->port); + } + napi_value dataValue = NapiUtil::GetNamedProperty(env, parameters[0], "data"); + if (dataValue != nullptr) { + asyncContext->data = NapiUtil::GetStringFromValue(env, dataValue); + } +} + +void UDPSocket::GetSocketInfo(struct sockaddr_in &addr, Baseinfo *&asyncContext) +{ + addr.sin_addr.s_addr = inet_addr(asyncContext->ipAddress.c_str()); + if (asyncContext->family == IPV6) { + addr.sin_family = AF_INET6; + } else { + addr.sin_family = AF_INET; + } + addr.sin_port = htons(asyncContext->port); +} + +int UDPSocket::UdpSocket(int domain, int type, int protocol) +{ + this->remInfo.socketfd = socket(domain, type, protocol); + return this->remInfo.socketfd; +} + +int UDPSocket::UdpBind(int fd, const struct sockaddr *addr, socklen_t len) +{ + if (fd != this->remInfo.socketfd) { + return -1; + } + return bind(fd, addr, len); +} + +int UDPSocket::UdpConnect(int fd, const struct sockaddr *addr, socklen_t len) +{ + if (fd != this->remInfo.socketfd) { + return -1; + } + return connect(fd, addr, len); +} + +int UDPSocket::UdpSend(int fd, const void *buf, size_t len, int flags) +{ + if (fd != this->remInfo.socketfd) { + return -1; + } + return send(fd, buf, len, flags); +} + +int UDPSocket::UdpClose(int fd) +{ + if (fd != this->remInfo.socketfd) { + return -1; + } + return close(fd); +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/http/frameworks/js/napi/websocket/include/websocket_napi.h b/http/frameworks/js/napi/websocket/include/websocket_napi.h new file mode 100644 index 000000000..4dfdaf199 --- /dev/null +++ b/http/frameworks/js/napi/websocket/include/websocket_napi.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 WEBSOCKET_NAPI_H +#define WEBSOCKET_NAPI_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace NetManagerStandard { + +} // namespace NetManagerStandard +} // namespace OHOS +#endif // WEBSOCKET_NAPI_H \ No newline at end of file diff --git a/http/frameworks/js/napi/websocket/src/websocket_napi.cpp b/http/frameworks/js/napi/websocket/src/websocket_napi.cpp new file mode 100644 index 000000000..0097029c4 --- /dev/null +++ b/http/frameworks/js/napi/websocket/src/websocket_napi.cpp @@ -0,0 +1,24 @@ +/* + * 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 "websocket_napi.h" +#include "netmgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +//DEFINE_NETMANAGER_NAPI_LOG_LABEL("WebSocketNapi"); + +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/http/interfaces/innerkits/native/netconnmanager/BUILD.gn b/http/interfaces/innerkits/native/netconnmanager/BUILD.gn new file mode 100644 index 000000000..e343bfb80 --- /dev/null +++ b/http/interfaces/innerkits/native/netconnmanager/BUILD.gn @@ -0,0 +1,82 @@ +# 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") + +SUBSYSTEM_DIR = "//foundation/communication" +NETMANAGER_ROOT = "$SUBSYSTEM_DIR/netstack/http" +NETCONNMANAGER_INNERKITS_ROOT = "$SUBSYSTEM_DIR/netstack/http/interfaces/innerkits" +NETCONNMANAGER_INNERKITS_SOURCE_DIR = "$NETMANAGER_ROOT//frameworks/innerkitsimpl/netconnmanager" +NETCONNMANAGER_SERVICES_SOURCE_DIR = "$NETMANAGER_ROOT//services/netconnmanager" +config("net_conn_manager_if_config") { + # header file path + include_dirs = [ + "$NETCONNMANAGER_SERVICES_SOURCE_DIR/include/ipc", + "$NETCONNMANAGER_INNERKITS_ROOT/native/netconnmanager/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_conn_manager_if") { + sources = [ + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/inet_addr.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/net_link_info.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/net_provider_info.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/net_specifier.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/route.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/net_conn_manager.cpp", + "$NETCONNMANAGER_SERVICES_SOURCE_DIR/src/ipc/net_conn_service_proxy.cpp" + ] + + include_dirs = [ + "$NETCONNMANAGER_SERVICES_SOURCE_DIR/include/", + ] + + public_configs = [ ":net_conn_manager_if_config" ] + + deps = [ + "$NETMANAGER_ROOT/utils:net_manager_common", + ] + + external_deps = [ + "safwk:system_ability_fwk", + "ipc:ipc_core", + "samgr_L2:samgr_proxy" + ] + + defines = [ + "NETMGR_LOG_TAG = \"NetConnManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netstack" + subsystem_name = "communication" +} diff --git a/http/interfaces/innerkits/native/netconnmanager/include/inet_addr.h b/http/interfaces/innerkits/native/netconnmanager/include/inet_addr.h new file mode 100644 index 000000000..9c9951ecd --- /dev/null +++ b/http/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/http/interfaces/innerkits/native/netconnmanager/include/net_conn_constants.h b/http/interfaces/innerkits/native/netconnmanager/include/net_conn_constants.h new file mode 100644 index 000000000..256086d51 --- /dev/null +++ b/http/interfaces/innerkits/native/netconnmanager/include/net_conn_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 NET_CONN_CONSTANTS_H +#define NET_CONN_CONSTANTS_H + +namespace OHOS { +namespace NetManagerStandard { +enum ErrCode { + NET_CONN_ERR_NONE = 0, + NET_CONN_ERR_INVALID_PROVIDER_ID = (-1), +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONN_CONSTANTS_H \ No newline at end of file diff --git a/http/interfaces/innerkits/native/netconnmanager/include/net_conn_manager.h b/http/interfaces/innerkits/native/netconnmanager/include/net_conn_manager.h new file mode 100644 index 000000000..60c6368f0 --- /dev/null +++ b/http/interfaces/innerkits/native/netconnmanager/include/net_conn_manager.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 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 NetConnManager { + DECLARE_DELAYED_SINGLETON(NetConnManager) + +public: + int32_t SystemReady(); + int32_t RegisterNetProvider(uint32_t netType, const std::string &ident, uint64_t netCapabilities); + int32_t UnregisterNetProvider(uint32_t providerId); + int32_t UpdateNetProviderInfo(uint32_t providerId, const sptr &netProviderInfo); + int32_t UpdateNetCapabilities(uint32_t providerId, uint64_t netCapabilities); + int32_t UpdateNetLinkInfo(uint32_t providerId, const sptr &netLinkInfo); + +private: + class NetConnDeathRecipient : public IRemoteObject::DeathRecipient { + public: + explicit NetConnDeathRecipient(NetConnManager &client) : client_(client) {} + ~NetConnDeathRecipient() override = default; + void OnRemoteDied(const wptr &remote) override + { + client_.OnRemoteDied(remote); + } + + private: + NetConnManager &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/http/interfaces/innerkits/native/netconnmanager/include/net_link_info.h b/http/interfaces/innerkits/native/netconnmanager/include/net_link_info.h new file mode 100644 index 000000000..2fa7e262f --- /dev/null +++ b/http/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_; + + 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/http/interfaces/innerkits/native/netconnmanager/include/net_provider_info.h b/http/interfaces/innerkits/native/netconnmanager/include/net_provider_info.h new file mode 100644 index 000000000..423b1c3f0 --- /dev/null +++ b/http/interfaces/innerkits/native/netconnmanager/include/net_provider_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_PROVIDER_INFO_H +#define NET_PROVIDER_INFO_H + +#include + +#include "parcel.h" + +namespace OHOS { +namespace NetManagerStandard { +struct NetProviderInfo : 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_PROVIDER_INFO_H \ No newline at end of file diff --git a/http/interfaces/innerkits/native/netconnmanager/include/net_specifier.h b/http/interfaces/innerkits/native/netconnmanager/include/net_specifier.h new file mode 100644 index 000000000..fa5f31040 --- /dev/null +++ b/http/interfaces/innerkits/native/netconnmanager/include/net_specifier.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 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, +} NetCapabilities; + +typedef enum { + NET_TYPE_UNKNOWN, + NET_TYPE_CELLULAR, + 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; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif \ No newline at end of file diff --git a/http/interfaces/innerkits/native/netconnmanager/include/route.h b/http/interfaces/innerkits/native/netconnmanager/include/route.h new file mode 100644 index 000000000..c76de7083 --- /dev/null +++ b/http/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/http/interfaces/kits/js/@ohos.net.http.d.ts b/http/interfaces/kits/js/@ohos.net.http.d.ts new file mode 100644 index 000000000..98ba93ee9 --- /dev/null +++ b/http/interfaces/kits/js/@ohos.net.http.d.ts @@ -0,0 +1,191 @@ +/* + * 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 {AsyncCallback, Callback} from "./basic"; + +/** + * Provides http related APIs. + * + * @since 6 + * @sysCap SystemCapability.Communication.NetManager + * @devices phone, tablet, tv, wearable, car + */ +declare namespace http { + function createHttp(): HttpRequest; + + export interface HttpRequestOptions { + method?: RequestMethod; // default is GET + /** + * extraData can be a string or an Object (API 6) or an ArrayBuffer(API 8). + */ + extraData?: string | Object | ArrayBuffer; + header?: Object; // default is 'content-type': 'application/json' + readTimeout?: number; // default is 60s + connectTimeout?: number; // default is 60s. + /** + * @since 8 + */ + ifModifiedSince?: number; // "If-Modified-Since", default is 0. + /** + * @since 8 + */ + fixedLengthStreamingMode?: number; // default is -1 means disabled. + } + + export interface HttpRequest { + request(url: string, callback: AsyncCallback): void; + request(url: string, options: HttpRequestOptions, callback: AsyncCallback): void; + request(url: string, options?: HttpRequestOptions): Promise; + + destroy(): void; + + /** + * @deprecated use once() instead since 8. + */ + on(type: "headerReceive", callback: AsyncCallback): void; + /** + * @since 8 + */ + once(type: "headerReceive", callback: Callback): void; + /** + * @deprecated use once() instead since 8. + */ + off(type: "headerReceive", callback?: AsyncCallback): void; + } + + export enum RequestMethod { + OPTIONS = "OPTIONS", + GET = "GET", + HEAD = "HEAD", + POST = "POST", + PUT = "PUT", + DELETE = "DELETE", + TRACE = "TRACE", + CONNECT = "CONNECT" + } + + export enum ResponseCode { + OK = 200, + CREATED, + ACCEPTED, + NOT_AUTHORITATIVE, + NO_CONTENT, + RESET, + PARTIAL, + MULT_CHOICE = 300, + MOVED_PERM, + MOVED_TEMP, + SEE_OTHER, + NOT_MODIFIED, + USE_PROXY, + BAD_REQUEST = 400, + UNAUTHORIZED, + PAYMENT_REQUIRED, + FORBIDDEN, + NOT_FOUND, + BAD_METHOD, + NOT_ACCEPTABLE, + PROXY_AUTH, + CLIENT_TIMEOUT, + CONFLICT, + GONE, + LENGTH_REQUIRED, + PRECON_FAILED, + ENTITY_TOO_LARGE, + REQ_TOO_LONG, + UNSUPPORTED_TYPE, + INTERNAL_ERROR = 500, + NOT_IMPLEMENTED, + BAD_GATEWAY, + UNAVAILABLE, + GATEWAY_TIMEOUT, + VERSION + } + + export interface HttpResponse { + /** + * result can be a string or an Object (API 6) or an ArrayBuffer(API 8). + */ + result: string | Object | ArrayBuffer; + responseCode: ResponseCode | number; + header: Object; + /** + * @since 8 + */ + cookies: string; + } + + /** + * Creates a default {@code HttpResponseCache} object to store the responses of HTTP access requests. + * + * @param options {@code HttpResponseCacheOptions} + * @param callback the newly-installed cache + * @since 8 + */ + function createHttpResponseCache(options: HttpResponseCacheOptions, callback: AsyncCallback): void; + function createHttpResponseCache(options: HttpResponseCacheOptions): Promise; + + /** + * Obtains the {@code HttpResponseCache} object. + * + * @param callback Returns the {@code HttpResponseCache} object. + * @since 8 + */ + function getInstalledHttpResponseCache(callback: AsyncCallback): void; + function getInstalledHttpResponseCache(): Promise; + + /** + * @since 8 + */ + export interface HttpResponseCacheOptions { + /** + * Indicates the full directory for storing the cached data. + */ + filePath: string; + /** + * Indicates the child directory for storing the cached data. It is an optional parameter. + */ + fileChildPath?: string; + /** + * Indicates the maximum size of the cached data. + */ + cacheSize: number; + } + + /** + * @since 8 + */ + export interface HttpResponseCache { + /** + * Writes data in the cache to the file system so that all the cached data can be accessed in the next HTTP request. + */ + flush(callback: AsyncCallback): void; + flush(): Promise; + + /** + * Disables a cache without changing the data in it. + */ + close(callback: AsyncCallback): void; + close(): Promise; + + /** + * Disables a cache and deletes the data in it. + */ + delete(callback: AsyncCallback): void; + delete(): Promise; + } +} + +export default http; \ No newline at end of file diff --git a/http/interfaces/kits/js/@ohos.net.socket.d.ts b/http/interfaces/kits/js/@ohos.net.socket.d.ts new file mode 100644 index 000000000..a3b443948 --- /dev/null +++ b/http/interfaces/kits/js/@ohos.net.socket.d.ts @@ -0,0 +1,137 @@ +/* +* 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 {AsyncCallback, Callback, ErrorCallback} from "./basic"; +import connection from "./@ohos.net.connection"; + +/** + * Provides TCP and UDP Socket APIs. + * + * @since 7 + * @sysCap SystemCapability.Communication.NetManager + * @devices phone, tablet, tv, wearable, car + */ +declare namespace socket { + export import NetAddress = connection.NetAddress; + + function constructUDPSocketInstance(): UDPSocket; + function constructTCPSocketInstance(): TCPSocket; + + export interface UDPSendOptions { + data: string | ArrayBuffer; + address: NetAddress; + } + + export interface ExtraOptionsBase { + receiveBufferSize?: number; + sendBufferSize?: number; + reuseAddress?: boolean; + socketTimeout?: number; + } + + export interface UDPExtraOptions extends ExtraOptionsBase { + broadcast?: boolean; + } + + export interface SocketStateBase { + isBound: boolean; + isClose: boolean; + isConnected: boolean; + } + + export interface SocketRemoteInfo { + address: string; + family: 'IPv4' | 'IPv6'; + port: number; + size: number; + } + + export interface UDPSocket { + bind(address: NetAddress, callback: AsyncCallback): void; + bind(address: NetAddress): Promise; + + send(options: UDPSendOptions, callback: AsyncCallback): void; + send(options: UDPSendOptions): Promise; + + close(callback: AsyncCallback): void; + close(): Promise; + + getState(callback: AsyncCallback): void; + getState(): Promise; + + setExtraOptions(options: UDPExtraOptions, callback: AsyncCallback): void; + setExtraOptions(options: UDPExtraOptions): Promise; + + on(type: 'message', callback: Callback<{message: ArrayBuffer, remoteInfo: SocketRemoteInfo}>): void; + off(type: 'message', callback?: Callback<{message: ArrayBuffer, remoteInfo: SocketRemoteInfo}>): void; + + on(type: 'listening' | 'close', callback: Callback): void; + off(type: 'listening' | 'close', callback?: Callback): void; + + on(type: 'error', callback: ErrorCallback): void; + off(type: 'error', callback?: ErrorCallback): void; + } + + export interface TCPConnectOptions { + address: NetAddress; + timeout?: number; + } + + export interface TCPSendOptions { + data: string | ArrayBuffer; + encoding?: string; + } + + export interface TCPExtraOptions extends ExtraOptionsBase { + keepAlive?: boolean; + OOBInline?: boolean; + TCPNoDelay?: boolean; + socketLinger: {on: boolean, linger: number}; + } + + export interface TCPSocket { + bind(address: NetAddress, callback: AsyncCallback): void; + bind(address: NetAddress): Promise; + + connect(options: TCPConnectOptions, callback: AsyncCallback): void; + connect(options: TCPConnectOptions): Promise; + + send(options: TCPSendOptions, callback: AsyncCallback): void; + send(options: TCPSendOptions): Promise; + + close(callback: AsyncCallback): void; + close(): Promise; + + getRemoteAddress(callback: AsyncCallback): void; + getRemoteAddress(): Promise; + + getState(callback: AsyncCallback): void; + getState(): Promise; + + setExtraOptions(options: TCPExtraOptions, callback: AsyncCallback): void; + setExtraOptions(options: TCPExtraOptions): Promise; + + on(type: 'message', callback: Callback<{message: ArrayBuffer, remoteInfo: SocketRemoteInfo}>): void; + off(type: 'message', callback?: Callback<{message: ArrayBuffer, remoteInfo: SocketRemoteInfo}>): void; + + on(type: 'connect' | 'close', callback: Callback): void; + off(type: 'connect' | 'close', callback?: Callback): void; + + on(type: 'error', callback: ErrorCallback): void; + off(type: 'error', callback?: ErrorCallback): void; + } +} + +export default socket; \ No newline at end of file diff --git a/http/interfaces/kits/js/@ohos.net.webSocket.d.ts b/http/interfaces/kits/js/@ohos.net.webSocket.d.ts new file mode 100644 index 000000000..472b6093d --- /dev/null +++ b/http/interfaces/kits/js/@ohos.net.webSocket.d.ts @@ -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. +*/ + +import {AsyncCallback, ErrorCallback} from "./basic"; + +/** + * Provides WebSocket APIs. + * + * @since 6 + * @sysCap SystemCapability.Communication.NetManager + * @devices phone, tablet, tv, wearable, car + */ +declare namespace webSocket { + function createWebSocket(): WebSocket; + + export interface WebSocketRequestOptions { + header?: Object; + } + + export interface WebSocketCloseOptions { + code?: number; + reason?: string; + } + + export interface WebSocket { + connect(url: string, callback: AsyncCallback): void; + connect(url: string, options: WebSocketRequestOptions, callback: AsyncCallback): void; + connect(url: string, options?: WebSocketRequestOptions): Promise; + + /** + * Transmits data using the WebSocket connection. data can be a string(API 6) or an ArrayBuffer(API 8). + */ + send(data: string | ArrayBuffer, callback: AsyncCallback): void; + send(data: string | ArrayBuffer): Promise; + + /** + * Closes the WebSocket connection, optionally using code as the the WebSocket connection close code + * and reason as the the WebSocket connection close reason. + */ + close(callback: AsyncCallback): void; + close(options: WebSocketCloseOptions, callback: AsyncCallback): void; + close(options?: WebSocketCloseOptions): Promise; + + on(type: 'open', callback: AsyncCallback): void; + off(type: 'open', callback?: AsyncCallback): void; + + /** + * data in AsyncCallback can be a string(API 6) or an ArrayBuffer(API 8). + */ + on(type: 'message', callback: AsyncCallback): void; + off(type: 'message', callback?: AsyncCallback): void; + + on(type: 'close', callback: AsyncCallback<{ code: number, reason: string }>): void; + off(type: 'close', callback?: AsyncCallback<{ code: number, reason: string }>): void; + + on(type: 'error', callback: ErrorCallback): void; + off(type: 'error', callback?: ErrorCallback): void; + } +} + +export default webSocket; \ No newline at end of file diff --git a/http/interfaces/kits/js/basic.d.ts b/http/interfaces/kits/js/basic.d.ts new file mode 100644 index 000000000..09a3400c3 --- /dev/null +++ b/http/interfaces/kits/js/basic.d.ts @@ -0,0 +1,16 @@ +// basic.d.ts +export interface AsyncCallback { + (err: BusinessError, data: T): void; +} + +export interface BusinessError extends Error { + code: number; +} + +export interface ErrorCallback { + (err: BusinessError): void; +} + +export interface Callback { + (data: T): void; +} diff --git a/http/netmanager_config.gni b/http/netmanager_config.gni new file mode 100644 index 000000000..313e7ee05 --- /dev/null +++ b/http/netmanager_config.gni @@ -0,0 +1,26 @@ +# 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_ROOT = "$SUBSYSTEM_DIR/netstack/http" +NETMANAGERNATIVE_ROOT = "$NETMANAGER_ROOT/services/netmanagernative" +INNERKITS_ROOT = "$NETMANAGER_ROOT/interfaces/innerkits" +NETCONNMANAGER_INNERKITS_SOURCE_DIR = "$NETMANAGER_ROOT/frameworks/innerkitsimpl/netconnmanager" +NETCONNMANAGER_SOURCE_DIR = "$NETMANAGER_ROOT/services/netconnmanager" +NETCONNMANAGER_COMMON_DIR = "$NETMANAGER_ROOT/services/common" +NETMANAGER_PREBUILTS_DIR = "$NETMANAGER_ROOT/prebuilts" + +use_js_debug = false +declare_args() { + enable_netmgr_debug = false +} diff --git a/http/ohos.build b/http/ohos.build new file mode 100644 index 000000000..bfbfc99c0 --- /dev/null +++ b/http/ohos.build @@ -0,0 +1,19 @@ +{ + "subsystem": "communication", + "parts": { + "netstack/http": { + "variants": [ + "phone", + "wearable", + "ivi" + ], + "module_list": [ + "//foundation/communication/netstack/http/services/etc/init:netmanager_standard.rc", + "//foundation/communication/netstack/http/sa_profile:net_conn_profile", + "//foundation/communication/netstack/http/frameworks/js/napi:http", + "//foundation/communication/netstack/http/frameworks/js/napi:socket", + "//foundation/communication/netstack/http/frameworks/js/napi:websocket" + ] + } + } +} diff --git a/http/sa_profile/1151.xml b/http/sa_profile/1151.xml new file mode 100644 index 000000000..92c4fc95f --- /dev/null +++ b/http/sa_profile/1151.xml @@ -0,0 +1,27 @@ + + + + netmanager + + 1151 + libnet_conn_manager.z.so + + + true + false + 1 + + diff --git a/http/sa_profile/BUILD.gn b/http/sa_profile/BUILD.gn new file mode 100644 index 000000000..3526cd9f0 --- /dev/null +++ b/http/sa_profile/BUILD.gn @@ -0,0 +1,22 @@ +# 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_conn_profile") { + sources = [ + "1151.xml" + ] + + part_name = "netstack/http" +} diff --git a/http/services/etc/init/BUILD.gn b/http/services/etc/init/BUILD.gn new file mode 100644 index 000000000..05f234be4 --- /dev/null +++ b/http/services/etc/init/BUILD.gn @@ -0,0 +1,26 @@ +# 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_standard.rc to /system/etc/init/netstack/http.rc +ohos_prebuilt_etc("netmanager_standard.rc") { + if (use_musl) { + source = "netmanager_standard.cfg" + } else { + source = "netmanager_standard.rc" + } + + relative_install_dir = "init" + part_name = "netstack" + subsystem_name = "communication" +} diff --git a/http/services/etc/init/netmanager_standard.cfg b/http/services/etc/init/netmanager_standard.cfg new file mode 100644 index 000000000..a60a19ea4 --- /dev/null +++ b/http/services/etc/init/netmanager_standard.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" : "root", + "gid" : ["root", "shell"] + } + ] +} diff --git a/http/services/etc/init/netmanager_standard.rc b/http/services/etc/init/netmanager_standard.rc new file mode 100644 index 000000000..3d3c2a7a0 --- /dev/null +++ b/http/services/etc/init/netmanager_standard.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/http/services/netconnmanager/BUILD.gn b/http/services/netconnmanager/BUILD.gn new file mode 100644 index 000000000..16ba0afe2 --- /dev/null +++ b/http/services/netconnmanager/BUILD.gn @@ -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. +import("//build/ohos.gni") + +SUBSYSTEM_DIR = "//foundation/communication" +NETMANAGER_ROOT = "$SUBSYSTEM_DIR/netstack/http" +NETMANAGERNATIVE_ROOT = "$NETMANAGER_ROOT/services/netmanagernative" +INNERKITS_ROOT = "$NETMANAGER_ROOT/interfaces/innerkits" +NETCONNMANAGER_SOURCE_DIR = "$NETMANAGER_ROOT/services/netconnmanager" + +ohos_shared_library("net_conn_manager") { + sources = [ + "$NETCONNMANAGER_SOURCE_DIR/src/ipc/net_conn_service_stub.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_id_manager.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_conn_service.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_service.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_provider.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_controller/telephony_controller.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_controller/net_controller_factory.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/network.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/netd_controller.cpp" + ] + + include_dirs = [ + "$NETCONNMANAGER_SOURCE_DIR/include", + "$NETCONNMANAGER_SOURCE_DIR/include/ipc", + "$NETCONNMANAGER_SOURCE_DIR/include/net_controller", + "$INNERKITS_ROOT/native/netconnmanager/include", + "$NETMANAGERNATIVE_ROOT/net_mgr_native/include", + "$NETMANAGERNATIVE_ROOT/common/include", + "//foundation/communication/netstack/http/services/netmanagernative/common/include" + ] + + deps = [ + "$NETMANAGER_ROOT/utils:net_manager_common", + "$INNERKITS_ROOT/native/netconnmanager:net_conn_manager_if", + "//utils/native/base:utils", + "$NETMANAGER_ROOT/services/netmanagernative:net_manager_native" + ] + + external_deps = [ + "safwk:system_ability_fwk", + "appexecfwk_standard:libeventhandler", + "samgr_L2:samgr_proxy", + "ipc:ipc_core", + "aafwk_standard:want", + "cellular_data:tel_cellular_data_api" + ] + + defines = [ + "NETMGR_LOG_TAG = \"NetConnManager\"", + "LOG_DOMAIN = 0xD0015B0" + ] + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netstack" + subsystem_name = "communication" +} diff --git a/http/services/netconnmanager/include/ipc/i_net_conn_service.h b/http/services/netconnmanager/include/ipc/i_net_conn_service.h new file mode 100644 index 000000000..989210733 --- /dev/null +++ b/http/services/netconnmanager/include/ipc/i_net_conn_service.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 I_NET_CONNECTION_SERVICE_H +#define I_NET_CONNECTION_SERVICE_H + +#include + +#include "iremote_broker.h" +#include "iremote_object.h" +#include "message_parcel.h" + +#include "net_specifier.h" +#include "net_provider_info.h" +#include "net_link_info.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_PROVIDER, + CMD_NM_SYSTEM_READY, + CMD_NM_REG_NET_PROVIDER, + CMD_NM_UNREG_NETWORK, + CMD_NM_SET_NET_PROVIDER_INFO, + CMD_NM_SET_NET_CAPABILTITES, + CMD_NM_SET_NET_LINK_INFO, + CMD_NM_END, + }; + +public: + virtual int32_t SystemReady() = 0; + virtual int32_t RegisterNetProvider(uint32_t netType, const std::string &ident, uint32_t netCapabilities) = 0; + virtual int32_t UnregisterNetProvider(uint32_t providerId) = 0; + virtual int32_t UpdateNetProviderInfo(uint32_t providerId, const sptr &netProviderInfo) = 0; + virtual int32_t UpdateNetCapabilities(uint32_t providerId, uint32_t netCapabilities) = 0; + virtual int32_t UpdateNetLinkInfo(uint32_t providerId, const sptr &netLinkInfo) = 0; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // I_NET_CONNECTION_SERVICE_H diff --git a/http/services/netconnmanager/include/ipc/net_conn_service_proxy.h b/http/services/netconnmanager/include/ipc/net_conn_service_proxy.h new file mode 100644 index 000000000..81fd72c43 --- /dev/null +++ b/http/services/netconnmanager/include/ipc/net_conn_service_proxy.h @@ -0,0 +1,43 @@ +/* + * 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 RegisterNetProvider(uint32_t netType, const std::string &ident, uint32_t netCapabilities) override; + int32_t UnregisterNetProvider(uint32_t providerId) override; + int32_t UpdateNetProviderInfo(uint32_t providerId, const sptr &netProviderInfo) override; + int32_t UpdateNetCapabilities(uint32_t providerId, uint32_t netCapabilities) override; + int32_t UpdateNetLinkInfo(uint32_t providerId, 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/http/services/netconnmanager/include/ipc/net_conn_service_stub.h b/http/services/netconnmanager/include/ipc/net_conn_service_stub.h new file mode 100644 index 000000000..fee52b9a3 --- /dev/null +++ b/http/services/netconnmanager/include/ipc/net_conn_service_stub.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 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 OnRegisterNetProvider(MessageParcel &data, MessageParcel &reply); + int32_t OnUnregisterNetProvider(MessageParcel &data, MessageParcel &reply); + int32_t OnUpdateNetProviderInfo(MessageParcel &data, MessageParcel &reply); + int32_t OnUpdateNetCapabilities(MessageParcel &data, MessageParcel &reply); + int32_t OnUpdateNetLinkInfo(MessageParcel &data, MessageParcel &reply); + +private: + std::map memberFuncMap_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONN_SERVICE_STUB_H diff --git a/http/services/netconnmanager/include/net_conn_service.h b/http/services/netconnmanager/include/net_conn_service.h new file mode 100644 index 000000000..4094676ef --- /dev/null +++ b/http/services/netconnmanager/include/net_conn_service.h @@ -0,0 +1,131 @@ +/* + * 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 "singleton.h" +#include "system_ability.h" + +#include "ipc/net_conn_service_stub.h" +#include "net_service.h" +#include "network.h" +#include "net_provider.h" + +namespace OHOS { +namespace NetManagerStandard { +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_PROVIDER_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 provider + * + * @return The id of the network provider + */ + int32_t RegisterNetProvider(uint32_t netType, const std::string &ident, uint32_t netCapabilities) override; + + /** + * @brief The interface is unregister the network + * + * @param providerId The id of the network provider + * + * @return Returns 0, unregister the network successfully, otherwise it will fail + */ + int32_t UnregisterNetProvider(uint32_t providerId) override; + + /** + * @brief The interface is update network connection status information + * + * @param providerId The id of the network provider + * @param netProviderInfo network connection status information + * + * @return Returns 0, successfully update the network connection status information, otherwise it will fail + */ + int32_t UpdateNetProviderInfo(uint32_t providerId, const sptr &netProviderInfo) override; + + /** + * @brief The interface is Create or delete network services based on the providerId and the netCapabilities + * + * @param providerId The id of the network provider + * @param netCapabilities Network capabilities registered by the network provider + * + * @return Returns 0, successfully create network service or delete network service, otherwise fail + */ + int32_t UpdateNetCapabilities(uint32_t providerId, uint32_t netCapabilities) override; + + /** + * @brief The interface is update network link attribute information + * + * @param providerId The id of the network provider + * @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 providerId, const sptr &netLinkInfo) override; + +private: + bool Init(); + sptr GetNetProviderFromList(uint32_t netType, const std::string &ident); + sptr GetNetProviderFromListById(uint32_t providerId); + sptr GetNetworkFromListByProviderId(uint32_t providerId); + void DeleteProviderFromListById(uint32_t providerId); + void DeleteNetworkFromListByProviderId(uint32_t providerId); + bool DeleteServiceFromListByCap(int32_t netId, const NetCapabilities &netCapability); + void DeleteServiceFromListByNet(const Network &network); + bool IsServiceInList(int32_t netId, const NetCapabilities &netCapability) const; + +private: + enum ServiceRunningState { + STATE_STOPPED = 0, + STATE_RUNNING, + }; + + bool registerToService_; + ServiceRunningState state_; + sptr defaultNetService_ = nullptr; + + std::mutex mtx_; + NET_SERVICE_LIST netServices_; + NET_NETWORK_LIST networks_; + NET_PROVIDER_LIST netProviders_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONN_SERVICE_H diff --git a/http/services/netconnmanager/include/net_conn_types.h b/http/services/netconnmanager/include/net_conn_types.h new file mode 100644 index 000000000..b3298fefc --- /dev/null +++ b/http/services/netconnmanager/include/net_conn_types.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 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_PROVIDER = (-10), + ERR_NO_NETWORK = (-11), + ERR_INVALID_PARAMS = (-12), + ERR_INVALID_NETORK_TYPE = (-13) +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONN_TYPES_H diff --git a/http/services/netconnmanager/include/net_controller/i_net_controller.h b/http/services/netconnmanager/include/net_controller/i_net_controller.h new file mode 100644 index 000000000..3316e22cc --- /dev/null +++ b/http/services/netconnmanager/include/net_controller/i_net_controller.h @@ -0,0 +1,30 @@ +/* + * 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_provider_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/http/services/netconnmanager/include/net_controller/net_controller_factory.h b/http/services/netconnmanager/include/net_controller/net_controller_factory.h new file mode 100644 index 000000000..18730d7c2 --- /dev/null +++ b/http/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(uint16_t netType); + +private: + sptr GetNetControllerFromMap(uint16_t netType); + std::map> netControllers; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_CONTROLLER_FACTORY_H \ No newline at end of file diff --git a/http/services/netconnmanager/include/net_controller/telephony_controller.h b/http/services/netconnmanager/include/net_controller/telephony_controller.h new file mode 100644 index 000000000..c9135c58b --- /dev/null +++ b/http/services/netconnmanager/include/net_controller/telephony_controller.h @@ -0,0 +1,51 @@ +/* + * 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/http/services/netconnmanager/include/net_id_manager.h b/http/services/netconnmanager/include/net_id_manager.h new file mode 100644 index 000000000..35edb9fcb --- /dev/null +++ b/http/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/http/services/netconnmanager/include/net_provider.h b/http/services/netconnmanager/include/net_provider.h new file mode 100644 index 000000000..4ea75988f --- /dev/null +++ b/http/services/netconnmanager/include/net_provider.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_PROVIDER_H +#define NET_PROVIDER_H + +#include + +#include "net_specifier.h" +#include "i_net_controller.h" + +namespace OHOS { +namespace NetManagerStandard { +class Network; +class NetService; +class NetProvider : public virtual RefBase { +public: + NetProvider(); + NetProvider(NetworkType netProviderType, const std::string &netProviderIdent); + ~NetProvider() = default; + bool operator==(const NetProvider &netProvider) const; + NetworkType GetNetProviderType() const; + std::string GetNetProviderIdent() const; + bool ProviderConnection(NetCapabilities netCapabilities); + bool ProviderDisconnection(NetCapabilities netCapabilities); + void UpdateNetProviderInfo(const NetProviderInfo &netProviderInfo); + uint32_t GetProviderId() const; + bool GetConnected() const; + bool GetAvailable() const; + bool GetRoaming() const; + bool GetStrength() const; + bool GetFrequency() const; + +private: + sptr netController_; + NetworkType netProviderType_; + std::string netProviderIdent_; + uint32_t providerId_ = 0; + uint16_t frequency_ = 0x00; + uint8_t strength_ = 0x00; + bool connected_ = false; + bool isAvailable_ = false; // whether the network is available + bool isRoaming_ = false; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_PROVIDER_H diff --git a/http/services/netconnmanager/include/net_service.h b/http/services/netconnmanager/include/net_service.h new file mode 100644 index 000000000..5e5ab8da6 --- /dev/null +++ b/http/services/netconnmanager/include/net_service.h @@ -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. + */ + +#ifndef NET_SERVICE_H +#define NET_SERVICE_H + +#include + +#include "network.h" +#include "net_link_info.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 provider + * + * @return Return ERR_SERVICE_REQUEST_SUCCESS, Succeed + */ + int32_t ServiceConnect(); + + /** + * @brief Initiate a disconnect request to the network service of the network provider + * + * @return Return ERR_SERVICE_DISCONNECTED_SUCCESS, Succeed + */ + int32_t ServiceDisConnect(); + + /** + * @brief Automatically initiate a network connection request to the network service of the network provider + * + * @return Return ERR_SERVICE_REQUEST_SUCCESS, Succeed + */ + int32_t ServiceAutoConnect(); + +private: + int32_t ConnectTimeout(); + int32_t NetworkConnect(); + int32_t NetworkDisConnect(); + void UpdateServiceState(ServiceState serviceState); + bool IsConnecting(); + bool IsConnected(); + +private: + std::string ident_; + NetworkType networkType_ = NET_TYPE_UNKNOWN; + ServiceState state_ = SERVICE_STATE_IDLE; + + NetCapabilities netCapability_ = NET_CAPABILITIES_NONE; + sptr network_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NET_SERVICE_H \ No newline at end of file diff --git a/http/services/netconnmanager/include/netd_controller.h b/http/services/netconnmanager/include/netd_controller.h new file mode 100644 index 000000000..556105201 --- /dev/null +++ b/http/services/netconnmanager/include/netd_controller.h @@ -0,0 +1,182 @@ +/* + * 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 + +#include "native_netd_service.h" + +#include "fwmark_server.h" +#include "dnsresolv_service.h" +#include "netlink_manager.h" +#ifdef NATIVE_NETD_FEATURE + +#endif +#include "route.h" +#include "netmgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +class NetdController { + DECLARE_DELAYED_SINGLETON(NetdController) +public: + void Init(); + + /** + * @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 addrString 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 &addrString, int32_t prefixLength); + + /** + * @brief Delete ip address + * + * @param ifName Network port device name + * @param addrString 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 &addrString, 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); + +private: + std::unique_ptr netdService_ = nullptr; + + std::unique_ptr manager_ = nullptr; + std::unique_ptr fwmarkServer_ = nullptr; + std::unique_ptr dnsResolvService_ = nullptr; +#ifdef NATIVE_NETD_FEATURE + +#endif +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NETD_CONTROLLER_H diff --git a/http/services/netconnmanager/include/network.h b/http/services/netconnmanager/include/network.h new file mode 100644 index 000000000..b88d57349 --- /dev/null +++ b/http/services/netconnmanager/include/network.h @@ -0,0 +1,74 @@ +/* + * 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 +#include + +#include "net_provider.h" +#include "net_service.h" +#include "inet_addr.h" +#include "route.h" +#include "net_link_info.h" +#include "net_specifier.h" + +namespace OHOS { +namespace NetManagerStandard { +class Network : public virtual RefBase { +public: + Network(sptr &provider); + ~Network() = default; + 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 GetNetProvider() const; + bool UpdateNetProviderInfo(const NetProviderInfo &netProviderInfo); + 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 provider_; + int32_t netId_; +}; +} // namespace NetManagerStandard +} // namespace OHOS +#endif // NETWORK_H diff --git a/http/services/netconnmanager/src/ipc/net_conn_service_proxy.cpp b/http/services/netconnmanager/src/ipc/net_conn_service_proxy.cpp new file mode 100644 index 000000000..9b37a3f29 --- /dev/null +++ b/http/services/netconnmanager/src/ipc/net_conn_service_proxy.cpp @@ -0,0 +1,237 @@ +/* + * 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 "string_ex.h" +#include "ipc_types.h" +#include "net_conn_constants.h" +#include "netmgr_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::RegisterNetProvider( + uint32_t netType, const std::string &ident, uint32_t netCapabilities) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return NET_CONN_ERR_INVALID_PROVIDER_ID; + } + + NETMGR_LOGD("proxy netType[%{public}d], ident[%{public}s], netCapabilities[%{public}d]", netType, + ident.c_str(), netCapabilities); + if (!data.WriteUint32(netType)) { + NETMGR_LOGE("proxy netType[%{public}d] write to parcel failed", netType); + return NET_CONN_ERR_INVALID_PROVIDER_ID; + } + if (!data.WriteString(ident)) { + NETMGR_LOGE("proxy ident[%{public}s] write to parcel failed", ident.c_str()); + return NET_CONN_ERR_INVALID_PROVIDER_ID; + } + if (!data.WriteUint32(netCapabilities)) { + NETMGR_LOGE("proxy netCapabilities[%{public}d] write to parcel failed", netCapabilities); + return NET_CONN_ERR_INVALID_PROVIDER_ID; + } + + sptr remote = Remote(); + if (remote == nullptr) { + NETMGR_LOGE("Remote is null"); + return NET_CONN_ERR_INVALID_PROVIDER_ID; + } + int32_t error = remote->SendRequest(CMD_NM_REG_NET_PROVIDER, data, reply, option); + if (error != ERR_NONE) { + NETMGR_LOGE("proxy SendRequest failed, error code: [%{public}d]", error); + return NET_CONN_ERR_INVALID_PROVIDER_ID; + } + + return reply.ReadInt32(); +} + +int32_t NetConnServiceProxy::UnregisterNetProvider(uint32_t providerId) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return ERR_FLATTEN_OBJECT; + } + + NETMGR_LOGD("proxy providerId[%{public}d]", providerId); + if (!data.WriteUint32(providerId)) { + NETMGR_LOGE("proxy providerId[%{public}d] write to parcel failed", providerId); + 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::UpdateNetProviderInfo( + uint32_t providerId, const sptr &netProviderInfo) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return ERR_FLATTEN_OBJECT; + } + + NETMGR_LOGD("proxy providerId[%{public}d]", providerId); + if (!data.WriteUint32(providerId)) { + NETMGR_LOGE("proxy providerId[%{public}d] write to parcel failed", providerId); + return ERR_FLATTEN_OBJECT; + } + NETMGR_LOGD("proxy providerId[%{public}d] Marshalling success", providerId); + if (!netProviderInfo->Marshalling(data)) { + NETMGR_LOGE("proxy Marshalling failed"); + return ERR_FLATTEN_OBJECT; + } + NETMGR_LOGD("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_PROVIDER_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 providerId, uint32_t netCapabilities) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return IPC_PROXY_ERR; + } + + NETMGR_LOGD("proxy providerId[%{public}d], netCapabilities[%{public}d]", providerId, netCapabilities); + if (!data.WriteUint32(providerId)) { + NETMGR_LOGE("proxy providerId[%{public}d] write to parcel failed", providerId); + return ERR_FLATTEN_OBJECT; + } + if (!data.WriteUint32(netCapabilities)) { + NETMGR_LOGE("proxy netCapabilities[%{public}d] write to parcel failed", netCapabilities); + return ERR_FLATTEN_OBJECT; + } + NETMGR_LOGD("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 providerId, const sptr &netLinkInfo) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (!WriteInterfaceToken(data)) { + NETMGR_LOGE("WriteInterfaceToken failed"); + return IPC_PROXY_ERR; + } + + NETMGR_LOGD("proxy providerId[%{public}d]", providerId); + if (!data.WriteUint32(providerId)) { + NETMGR_LOGE("proxy providerId[%{public}d] write to parcel faield", providerId); + return IPC_PROXY_ERR; + } + NETMGR_LOGD("proxy providerId[%{public}d] Marshalling success", providerId); + + 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/http/services/netconnmanager/src/ipc/net_conn_service_stub.cpp b/http/services/netconnmanager/src/ipc/net_conn_service_stub.cpp new file mode 100644 index 000000000..b023bfb8c --- /dev/null +++ b/http/services/netconnmanager/src/ipc/net_conn_service_stub.cpp @@ -0,0 +1,189 @@ +/* + * 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 + +#include "string_ex.h" +#include "ipc_types.h" +#include "iservice_registry.h" +#include "ipc_skeleton.h" +#include "if_system_ability_manager.h" +#include "system_ability_definition.h" + +#include "netmgr_log_wrapper.h" +#include "net_conn_types.h" +#include "net_conn_constants.h" + +namespace OHOS { +namespace NetManagerStandard { +NetConnServiceStub::NetConnServiceStub() +{ + memberFuncMap_[CMD_NM_SYSTEM_READY] = &NetConnServiceStub::OnSystemReady; + memberFuncMap_[CMD_NM_REG_NET_PROVIDER] = &NetConnServiceStub::OnRegisterNetProvider; + memberFuncMap_[CMD_NM_UNREG_NETWORK] = &NetConnServiceStub::OnUnregisterNetProvider; + memberFuncMap_[CMD_NM_SET_NET_PROVIDER_INFO] = &NetConnServiceStub::OnUpdateNetProviderInfo; + 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_LOGD("stub call start, code = [%{public}d]", code); + + std::u16string myDescripter = NetConnServiceStub::GetDescriptor(); + std::u16string remoteDescripter = data.ReadInterfaceToken(); + if (myDescripter != remoteDescripter) { + NETMGR_LOGD("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_LOGD("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::OnRegisterNetProvider(MessageParcel &data, MessageParcel &reply) +{ + NETMGR_LOGD("stub processing"); + uint32_t netType; + std::string ident; + uint32_t netCapabilities; + if (!data.ReadUint32(netType)) { + NETMGR_LOGE("stub read netType[%{public}d] from parcel failed", netType); + return ERR_FLATTEN_OBJECT; + } + + if (!data.ReadString(ident)) { + NETMGR_LOGE("stub read ident[%{public}s] from parcel failed", ident.c_str()); + return ERR_FLATTEN_OBJECT; + } + + if (!data.ReadUint32(netCapabilities)) { + NETMGR_LOGE("stub read netCapabilities[%{public}d] from parcel failed", netCapabilities); + return ERR_FLATTEN_OBJECT; + } + + int32_t ret = RegisterNetProvider(netType, ident, netCapabilities); + if (ret == ERR_NO_NETWORK || ret == ERR_NO_PROVIDER) { + NETMGR_LOGE("Register network provider failed, error code:[%{public}d].", ret); + ret = NET_CONN_ERR_INVALID_PROVIDER_ID; + } + if (!reply.WriteInt32(ret)) { + NETMGR_LOGE("stub write ret[%{public}d] to parcel failed", ret); + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetConnServiceStub::OnUnregisterNetProvider(MessageParcel &data, MessageParcel &reply) +{ + uint32_t providerId; + if (!data.ReadUint32(providerId)) { + NETMGR_LOGE("stub read providerId[%{public}d] from parcel failed", providerId); + return ERR_FLATTEN_OBJECT; + } + + int32_t ret = UnregisterNetProvider(providerId); + if (!reply.WriteInt32(ret)) { + NETMGR_LOGE("stub write[%{public}d] ret to parcel failed", ret); + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetConnServiceStub::OnUpdateNetProviderInfo(MessageParcel &data, MessageParcel &reply) +{ + uint32_t providerId; + if (!data.ReadUint32(providerId)) { + NETMGR_LOGE("stub read providerId[%{public}d] from parcel failed", providerId); + return ERR_FLATTEN_OBJECT; + } + + sptr netProviderInfo = NetProviderInfo::Unmarshalling(data); + int32_t ret = UpdateNetProviderInfo(providerId, netProviderInfo); + if (!reply.WriteInt32(ret)) { + NETMGR_LOGE("stub write ret[%{public}d] to parcel failed", ret); + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetConnServiceStub::OnUpdateNetCapabilities(MessageParcel &data, MessageParcel &reply) +{ + uint32_t providerId; + uint32_t netCapabilities; + + if (!data.ReadUint32(providerId)) { + NETMGR_LOGE("stbu read providerId[%{public}d] from parcel failed", providerId); + return ERR_FLATTEN_OBJECT; + } + + if (!data.ReadUint32(netCapabilities)) { + NETMGR_LOGE("stbu read netCapabilities[%{public}d] from parcel failed", netCapabilities); + return ERR_FLATTEN_OBJECT; + } + + NETMGR_LOGD("stub execute UpdateNetCapabilities"); + int32_t ret = UpdateNetCapabilities(providerId, netCapabilities); + if (!reply.WriteInt32(ret)) { + NETMGR_LOGE("stub write ret[%{public}d] to parcel failed", ret); + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} + +int32_t NetConnServiceStub::OnUpdateNetLinkInfo(MessageParcel &data, MessageParcel &reply) +{ + uint32_t providerId; + + if (!data.ReadUint32(providerId)) { + NETMGR_LOGE("stub read providerId[%{public}d] from parcel failed", providerId); + return ERR_FLATTEN_OBJECT; + } + + sptr netLinkInfo = NetLinkInfo::Unmarshalling(data); + + int32_t ret = UpdateNetLinkInfo(providerId, netLinkInfo); + if (!reply.WriteInt32(ret)) { + NETMGR_LOGE("stub write ret[%{public}d] to parcel failed", ret); + return ERR_FLATTEN_OBJECT; + } + + return ERR_NONE; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/http/services/netconnmanager/src/net_conn_service.cpp b/http/services/netconnmanager/src/net_conn_service.cpp new file mode 100644 index 000000000..5e7f3e8ed --- /dev/null +++ b/http/services/netconnmanager/src/net_conn_service.cpp @@ -0,0 +1,398 @@ +/* + * 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 +#include +#include +#include +#include +#include "string_ex.h" +#include "system_ability_definition.h" +#include "ipc_skeleton.h" +#include "net_conn_types.h" +#include "netmgr_log_wrapper.h" +#include "net_service.h" +#include "net_provider.h" +#include "netd_controller.h" + +namespace OHOS { +namespace NetManagerStandard { +const bool REGISTER_LOCAL_RESULT = + SystemAbility::MakeAndRegisterAbility(DelayedSingleton::GetInstance().get()); + +NetConnService::NetConnService() + : SystemAbility(COMMUNICATION_NET_MANAGER_SYS_ABILITY_ID, true), registerToService_(false), + state_(STATE_STOPPED) +{} + +NetConnService::~NetConnService() {} + +void NetConnService::OnStart() +{ + if (state_ == STATE_RUNNING) { + NETMGR_LOGD("the state is already running"); + return; + } + if (!Init()) { + NETMGR_LOGE("init failed"); + return; + } + state_ = STATE_RUNNING; +} + +void NetConnService::OnStop() +{ + state_ = STATE_STOPPED; + registerToService_ = false; +} + +int32_t NetConnService::SystemReady() +{ + NETMGR_LOGD("System ready."); + return 0; +} + +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; + } + + DelayedSingleton::GetInstance()->Init(); + return true; +} + +int32_t NetConnService::RegisterNetProvider(uint32_t netType, const std::string &ident, uint32_t netCapabilities) +{ + NETMGR_LOGD("register provider, netType[%{public}d] ident[%{public}s] netCapabilities[%{public}d]", netType, + ident.c_str(), netCapabilities); + // According to netType, ident, get the provider from the list and save the providerId in the list + // if (netType >= NET_TYPE_MAX) { + // NETMGR_LOGE("netType parameter invalid"); + // return ERR_INVALID_NETORK_TYPE; + //} + + // sptr provider = GetNetProviderFromList(netType, ident); + // if (provider != nullptr) { + // NETMGR_LOGD("provider already exists."); + // return provider->GetProviderId(); + //} + + // If there is no provider in the list, create a provider + // provider = (std::make_unique(static_cast(netType), ident)).release(); + + // if (provider == nullptr) { + // NETMGR_LOGE("provider is nullptr"); + // return ERR_NO_PROVIDER; + //} + + // create network + // sptr network = (std::make_unique(provider)).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 provider, network to list + // netProviders_.push_back(provider); + // networks_.push_back(network); + // NETMGR_LOGD("netProviders_ size[%{public}d] networks_ size[%{public}d] netServices_ size[%{public}d]", + // netProviders_.size(), networks_.size(), netServices_.size()); + + // if (defaultNetService_ != nullptr) { + // NETMGR_LOGD("service is connecting..."); + // defaultNetService_->ServiceConnect(); + //} + NETMGR_LOGD("dnsresolvService setResolverConfig begin"); + const OHOS::nmd::dnsresolver_params param = { + OHOS::nmd::NETID_UNSET, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + DelayedSingleton::GetInstance()->SetResolverConfig( + param.netId, param.baseTimeoutMsec, param.retryCount, param.servers, param.domains); + + NETMGR_LOGD("dnsresolvService setResolverConfig end"); + + std::string ifName = ""; + std::string addrString = ""; + int32_t prefixLength = 0; + DelayedSingleton::GetInstance()->InterfaceDelAddress(ifName, addrString, prefixLength); + // return provider->GetProviderId(); + return 0; +} + +int32_t NetConnService::UnregisterNetProvider(uint32_t providerId) +{ + NETMGR_LOGD("UnregisterNetProvider providerId[%{public}d]", providerId); + // Remove provider from the list based on providerId + // sptr provider = GetNetProviderFromListById(providerId); + // if (provider == nullptr) { + // NETMGR_LOGE("provider doesn't exist."); + // return ERR_NO_PROVIDER; + //} + + // sptr network = GetNetworkFromListByProviderId(providerId); + // if (network == nullptr) { + // NETMGR_LOGE("GetNetworkFromListByProviderId get error, network is nullptr"); + // DeleteProviderFromListById(providerId); + // return ERR_NO_NETWORK; + //} + + // DeleteServiceFromListByNet(*network); + // DeleteNetworkFromListByProviderId(providerId); + // DeleteProviderFromListById(providerId); + // NETMGR_LOGD("netProviders_ size[%{public}d], networks_ size[%{public}d], netServices_ size[%{public}d]", + // netProviders_.size(), networks_.size(), netServices_.size()); + + std::string ifName = ""; + std::string addrString = ""; + int32_t prefixLength = 0; + DelayedSingleton::GetInstance()->InterfaceAddAddress(ifName, addrString, prefixLength); + return ERR_NONE; +} + +int32_t NetConnService::UpdateNetProviderInfo(uint32_t providerId, const sptr &netProviderInfo) +{ + NETMGR_LOGD("Update provider info: providerId[%{public}d]", providerId); + if (netProviderInfo == nullptr) { + NETMGR_LOGE("netProviderInfo is nullptr"); + return ERR_INVALID_PARAMS; + } + + NETMGR_LOGD("Update provider info: netProviderInfo[%{public}s]", netProviderInfo->ToString("").c_str()); + + // According to providerId, get the provider from the list + sptr provider = GetNetProviderFromListById(providerId); + if (provider == nullptr) { + NETMGR_LOGE("provider is nullptr"); + return ERR_NO_PROVIDER; + } + + // Call NetProvider class to update network connection status information + sptr network = GetNetworkFromListByProviderId(provider->GetProviderId()); + if (network == nullptr) { + NETMGR_LOGE("network is nullptr"); + return ERR_NO_NETWORK; + } + network->UpdateNetProviderInfo(*netProviderInfo); + + return ERR_NONE; +} + +int32_t NetConnService::UpdateNetCapabilities(uint32_t providerId, uint32_t netCapabilities) +{ + NETMGR_LOGD("providerId[%{public}d] netCapabilities[%{public}d]", providerId, netCapabilities); + // According to providerId, get the provider from the list + sptr provider = GetNetProviderFromListById(providerId); + if (provider == nullptr) { + NETMGR_LOGE("provider is nullptr"); + return ERR_NO_PROVIDER; + } + + // According to netId, get network from the list + sptr network = GetNetworkFromListByProviderId(provider->GetProviderId()); + if (network == nullptr) { + NETMGR_LOGE("network is nullptr"); + return ERR_NO_NETWORK; + } + auto type = provider->GetNetProviderType(); + auto ident = provider->GetNetProviderIdent(); + // 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_LOGD("netProviders_ size[%{public}d], networks_ size[%{public}d], netServices_ size[%{public}d]", + netProviders_.size(), networks_.size(), netServices_.size()); + return ERR_NONE; +} + +int32_t NetConnService::UpdateNetLinkInfo(uint32_t providerId, const sptr &netLinkInfo) +{ + NETMGR_LOGD("providerId[%{public}d]", providerId); + if (netLinkInfo == nullptr) { + NETMGR_LOGE("netLinkInfo is nullptr"); + return ERR_INVALID_PARAMS; + } + + NETMGR_LOGD("Update netlink info: netLinkInfo[%{public}s]", netLinkInfo->ToString("").c_str()); + // According to providerId, get the provider from the list + sptr provider = GetNetProviderFromListById(providerId); + if (provider == nullptr) { + NETMGR_LOGE("provider is nullptr"); + return ERR_NO_PROVIDER; + } + // According to provider id, get network from the list + sptr network = GetNetworkFromListByProviderId(provider->GetProviderId()); + 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::GetNetProviderFromList(uint32_t netType, const std::string &ident) +{ + for (auto it = netProviders_.begin(); it != netProviders_.end(); ++it) { + auto providerType = (*it)->GetNetProviderType(); + auto providerIdent = (*it)->GetNetProviderIdent(); + if ((netType == providerType) && (ident.compare(providerIdent) == 0)) { + return *it; + } + } + + NETMGR_LOGE("net provider is nullptr"); + return nullptr; +} + +sptr NetConnService::GetNetProviderFromListById(uint32_t providerId) +{ + for (auto it = netProviders_.begin(); it != netProviders_.end(); ++it) { + auto id = (*it)->GetProviderId(); + if (providerId == id) { + return *it; + } + } + + NETMGR_LOGE("net provider is nullptr"); + return nullptr; +} + +void NetConnService::DeleteProviderFromListById(uint32_t providerId) +{ + for (auto it = netProviders_.begin(); it != netProviders_.end(); ++it) { + auto id = (*it)->GetProviderId(); + if (providerId == id) { + netProviders_.erase(it); + return; + } + } +} + +void NetConnService::DeleteNetworkFromListByProviderId(uint32_t providerId) +{ + for (auto it = networks_.begin(); it != networks_.end(); ++it) { + sptr netProvider = (*it)->GetNetProvider(); + if ((netProvider != nullptr) && (netProvider->GetProviderId() == providerId)) { + networks_.erase(it); + return; + } + } +} + +sptr NetConnService::GetNetworkFromListByProviderId(uint32_t providerId) +{ + for (auto it = networks_.begin(); it != networks_.end(); ++it) { + sptr netProvider = (*it)->GetNetProvider(); + if ((netProvider != nullptr) && (netProvider->GetProviderId() == providerId)) { + 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/http/services/netconnmanager/src/net_controller/net_controller_factory.cpp b/http/services/netconnmanager/src/net_controller/net_controller_factory.cpp new file mode 100644 index 000000000..d6b5d560f --- /dev/null +++ b/http/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 "netmgr_log_wrapper.h" +#include "telephony_controller.h" +#include "net_specifier.h" + +namespace OHOS { +namespace NetManagerStandard { +NetControllerFactory::NetControllerFactory() {} +NetControllerFactory::~NetControllerFactory() {} + +sptr NetControllerFactory::MakeNetController(uint16_t netType) +{ + NETMGR_LOGD("make controller netType[%{public}d]", netType); + sptr netController = GetNetControllerFromMap(netType); + if (netController != nullptr) { + return netController; + } + NETMGR_LOGD("factory need create netController"); + + switch (netType) { + case NET_TYPE_CELLULAR: + NETMGR_LOGD("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(uint16_t netType) +{ + auto it = netControllers.find(netType); + if (it != netControllers.end()) { + return it->second; + } + NETMGR_LOGD("INetController* is not found, return null"); + return nullptr; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netconnmanager/src/net_controller/telephony_controller.cpp b/http/services/netconnmanager/src/net_controller/telephony_controller.cpp new file mode 100644 index 000000000..ca831770a --- /dev/null +++ b/http/services/netconnmanager/src/net_controller/telephony_controller.cpp @@ -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. + */ +#include "telephony_controller.h" +#include "cellular_data_manager.h" +#include "netmgr_log_wrapper.h" + +namespace OHOS { +namespace NetManagerStandard { +TelephonyController::TelephonyController() {}; + +int32_t TelephonyController::RequestNetwork(const std::string &ident, NetCapabilities netCapabilitiy) +{ + NETMGR_LOGD("Request telephony network."); + return Telephony::CellularDataManager::GetInstance().RequestNet(ident, static_cast(netCapabilitiy)); +} + +int32_t TelephonyController::ReleaseNetwork(const std::string &ident, NetCapabilities netCapabilitiy) +{ + NETMGR_LOGD("Release telephony network."); + return Telephony::CellularDataManager::GetInstance().ReleaseNet(ident, static_cast(netCapabilitiy)); +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/http/services/netconnmanager/src/net_id_manager.cpp b/http/services/netconnmanager/src/net_id_manager.cpp new file mode 100644 index 000000000..cd1a613ed --- /dev/null +++ b/http/services/netconnmanager/src/net_id_manager.cpp @@ -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. + */ + +#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/http/services/netconnmanager/src/net_provider.cpp b/http/services/netconnmanager/src/net_provider.cpp new file mode 100644 index 000000000..1f73cdf47 --- /dev/null +++ b/http/services/netconnmanager/src/net_provider.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 "net_provider.h" +#include +#include "netmgr_log_wrapper.h" +#include "network.h" +#include "net_service.h" +#include "net_controller_factory.h" +#include "telephony_controller.h" + +namespace OHOS { +namespace NetManagerStandard { +static std::atomic g_nextNetProviderId = 0x03EB; +static const int32_t REG_OK = 1; + +NetProvider::NetProvider(NetworkType netProviderType, const std::string &netProviderIdent) +{ + sptr netController = + DelayedSingleton::GetInstance().get()->MakeNetController(netProviderType); + if (netController != nullptr) { + netController_ = netController; + } + netProviderType_ = netProviderType; + netProviderIdent_ = netProviderIdent; + providerId_ = g_nextNetProviderId++; +} + +bool NetProvider::operator==(const NetProvider &netProvider) const +{ + return providerId_ == netProvider.providerId_ && netProviderType_ == netProvider.netProviderType_ && + netProviderIdent_ == netProvider.netProviderIdent_; +} + +NetworkType NetProvider::GetNetProviderType() const +{ + return netProviderType_; +} + +std::string NetProvider::GetNetProviderIdent() const +{ + return netProviderIdent_; +} + +bool NetProvider::ProviderConnection(NetCapabilities netCapabilities) +{ + NETMGR_LOGD("param ident[%{public}s] netCapabilities[%{public}d]", netProviderIdent_.c_str(), + static_cast(netCapabilities)); + if (netController_ == nullptr) { + NETMGR_LOGE("netController_ is nullptr"); + return false; + } + NETMGR_LOGD("execute RequestNetwork"); + int32_t errCode = netController_->RequestNetwork(netProviderIdent_, netCapabilities); + NETMGR_LOGD("RequestNetwork errCode[%{public}d]", errCode); + if (errCode == REG_OK) { + connected_ = true; + return true; + } + + return false; +} + +bool NetProvider::ProviderDisconnection(NetCapabilities netCapabilities) +{ + NETMGR_LOGD("param ident_[%{public}s] netCapabilities[%{public}d]", netProviderIdent_.c_str(), + static_cast(netCapabilities)); + if (netController_ == nullptr) { + NETMGR_LOGE("netController_ is nullptr"); + return false; + } + NETMGR_LOGD("execute ReleaseNetwork"); + int32_t errCode = netController_->ReleaseNetwork(netProviderIdent_, netCapabilities); + NETMGR_LOGD("ReleaseNetwork errCode[%{public}d]", errCode); + if (errCode == REG_OK) { + connected_ = false; + return true; + } + return false; +} + +void NetProvider::UpdateNetProviderInfo(const NetProviderInfo &netProviderInfo) +{ + isAvailable_ = netProviderInfo.isAvailable_; + isRoaming_ = netProviderInfo.isRoaming_; + strength_ = netProviderInfo.strength_; + frequency_ = netProviderInfo.frequency_; + NETMGR_LOGD( + "isAvailable_[%{public}d] isRoaming_[%{public}d] strength_[%{public}d] " + "frequency_[%{public}d]", + isAvailable_, isRoaming_, strength_, frequency_); +} + +uint32_t NetProvider::GetProviderId() const +{ + return providerId_; +} + +bool NetProvider::GetConnected() const +{ + return connected_; +} + +bool NetProvider::GetAvailable() const +{ + return isAvailable_; +} + +bool NetProvider::GetRoaming() const +{ + return isRoaming_; +} + +bool NetProvider::GetStrength() const +{ + return strength_; +} + +bool NetProvider::GetFrequency() const +{ + return frequency_; +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netconnmanager/src/net_service.cpp b/http/services/netconnmanager/src/net_service.cpp new file mode 100644 index 000000000..4feacf4fd --- /dev/null +++ b/http/services/netconnmanager/src/net_service.cpp @@ -0,0 +1,238 @@ +/* + * 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 "netmgr_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_LOGD("service connect"); + if (IsConnecting()) { + NETMGR_LOGD("this service is connecting"); + return ERR_SERVICE_CONNECTING; + } + if (IsConnected()) { + NETMGR_LOGD("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_LOGD("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_LOGD("this service request network is successful"); + + return ERR_SERVICE_REQUEST_SUCCESS; +} + +int32_t NetService::ServiceDisConnect() +{ + NETMGR_LOGD("service disconnect"); + if (state_ == SERVICE_STATE_DISCONNECTING) { + NETMGR_LOGD("this service is disconnecting"); + return ERR_SERVICE_DISCONNECTING; + } + if (state_ == SERVICE_STATE_DISCONNECTED) { + NETMGR_LOGD("this service has been disconnected"); + return ERR_SERVICE_DISCONNECTED_SUCCESS; + } + + UpdateServiceState(SERVICE_STATE_DISCONNECTING); + NETMGR_LOGD("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_LOGD("this service successfully disconnected"); + + return ERR_SERVICE_DISCONNECTED_SUCCESS; +} + +int32_t NetService::ServiceAutoConnect() +{ + NETMGR_LOGD("service auto connect"); + return ServiceConnect(); +} + +int32_t NetService::NetworkConnect() +{ + int32_t retCode = -1; + + UpdateServiceState(SERVICE_STATE_CONNECTING); + NETMGR_LOGD("execute NetworkConnect()"); + // Call Network class activate the network + if (network_->NetworkConnect(netCapability_)) { + retCode = 0; + } + NETMGR_LOGD("connect is [%{public}s]", retCode ? "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_LOGD("disconnect is [%{public}s]", retCode ? "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; + } + NETMGR_LOGD("serviceState is [%{public}d]", state_); +} + +bool NetService::IsConnecting() +{ + 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_LOGD("isConnecting is [%{public}d]", isConnecting); + return isConnecting; +} + +bool NetService::IsConnected() +{ + 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_LOGD("isConnected is [%{public}d]", isConnected); + return isConnected; +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/http/services/netconnmanager/src/netd_controller.cpp b/http/services/netconnmanager/src/netd_controller.cpp new file mode 100644 index 000000000..899d14468 --- /dev/null +++ b/http/services/netconnmanager/src/netd_controller.cpp @@ -0,0 +1,337 @@ +/* + * 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 +#include +#ifdef NATIVE_NETD_FEATURE + +#include "net_conn_types.h" +#endif + +namespace OHOS { +namespace NetManagerStandard { +NetdController::NetdController() {} + +NetdController::~NetdController() {} + +void ExitHandler(int32_t signum) +{ + exit(1); +} + +void NetdController::Init() +{ + NETMGR_LOGD("netd Init"); + + signal(SIGTERM, ExitHandler); + signal(SIGABRT, ExitHandler); + 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(); +#ifdef NATIVE_NETD_FEATURE +#else + return; +#endif +} + +int32_t NetdController::NetworkCreatePhysical(int32_t netId, int32_t permission) +{ + NETMGR_LOGD("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_LOGD("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_LOGD("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_LOGD("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_LOGD("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 + return 0; +#endif +} + +int32_t NetdController::NetworkRemoveRoute( + int32_t netId, const std::string &ifName, const std::string &destination, const std::string &nextHop) +{ + NETMGR_LOGD( + "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_LOGD("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_LOGD("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_LOGD("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_LOGD("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_LOGD("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 + int ret = netdService_->interfaceDelAddress("eth1", "192.168.0.12", 32); + if (ret != 0) { + NETNATIVE_LOGE("interfaceDelAddress error: %{public}s", gai_strerror(ret)); + return 0; + } + ret = netdService_->networkRemoveInterface(1, "eth1"); + if (ret != 0) { + NETNATIVE_LOGE("networkAddInterface error: %{public}s", gai_strerror(ret)); + return 0; + } + nmd::mark_mask_parcel testFwmark = netdService_->getFwmarkForNetwork(12); + // EXPECT_EQ(12, testFwmark.mark); + // EXPECT_EQ(65535, testFwmark.mask); + NETNATIVE_LOGE("getFwmarkForNetwork testFwmark: %{public}d", testFwmark.mark); + return 0; +#endif +} + +int32_t NetdController::InterfaceAddAddress( + const std::string &ifName, const std::string &addrString, int32_t prefixLength) +{ + NETMGR_LOGD("Add address: ifName[%{public}s],addrString[%{public}s], prefixLength[%{public}d]", + ifName.c_str(), addrString.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, addrString, prefixLength); +#else + int ret = netdService_->networkCreatePhysical(1, OHOS::nmd::NetworkPermission::PERMISSION_NONE); + if (ret != 0) { + NETNATIVE_LOGE("networkCreatePhysical error: %{public}s", gai_strerror(ret)); + return 0; + } + ret = netdService_->networkAddInterface(1, "eth1"); + if (ret != 0) { + NETNATIVE_LOGE("networkAddInterface error: %{public}s", gai_strerror(ret)); + return 0; + } + ret = netdService_->interfaceAddAddress("eth1", "192.168.0.12", 32); + if (ret != 0) { + NETNATIVE_LOGE("interfaceAddAddress error: %{public}s", gai_strerror(ret)); + return 0; + } + return 0; +#endif +} + +int32_t NetdController::InterfaceDelAddress( + const std::string &ifName, const std::string &addrString, int32_t prefixLength) +{ + NETMGR_LOGD("Delete address: ifName[%{public}s],addrString[%{public}s], prefixLength[%{public}d]", + ifName.c_str(), addrString.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, addrString, prefixLength); +#else + nmd::dnsresolver_params params; + params.netId = 0; + params.baseTimeoutMsec = 0; + params.retryCount = 1; + nmd::dns_res_params res; + dnsResolvService_->getResolverInfo(params.netId, params.servers, params.domains, res); + NETMGR_LOGD("Get resolver config: "); + for (auto itr = params.servers.begin(); itr != params.servers.end(); itr++) { + NETMGR_LOGI("dns server is %{public}s", itr->c_str()); + } + for (auto itr = params.domains.begin(); itr != params.domains.end(); itr++) { + NETMGR_LOGI("dns domains is %{public}s", itr->c_str()); + } + NETMGR_LOGI("baseTimeoutMsec is %{public}d and retryCount is %{public}d", res.baseTimeoutMsec, res.retryCount); + + NETMGR_LOGI("getaddrinfo:: begin"); + struct addrinfo *res1; + struct addrinfo hints; + bzero(&hints, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + std::string hostName = "www.baidu.com"; + res1 = nullptr; + NETMGR_LOGI("getaddrinfo error: %{public}s", hostName.c_str()); + return 0; +#endif +} + +int32_t NetdController::SetResolverConfig(uint16_t netId, uint16_t baseTimeoutMsec, uint8_t retryCount, + const std::vector &servers, const std::vector &domains) +{ + NETMGR_LOGD("Set resolver config: netId[%{public}d]", netId); + //#ifdef NATIVE_NETD_FEATURE + if (dnsResolvService_ == nullptr) { + NETMGR_LOGE("dnsResolvService_ is null"); + return 0; + } + dnsResolvService_->createNetworkCache(netId); + const nmd::dnsresolver_params params = {netId, baseTimeoutMsec, retryCount, servers, domains}; + return dnsResolvService_->setResolverConfig(params); + //#else + // return 0; + //#endif +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netconnmanager/src/network.cpp b/http/services/netconnmanager/src/network.cpp new file mode 100644 index 000000000..b5aa1cfeb --- /dev/null +++ b/http/services/netconnmanager/src/network.cpp @@ -0,0 +1,236 @@ +/* + * 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 "netmgr_log_wrapper.h" +#include "net_service.h" +#include "netd_controller.h" + +namespace OHOS { +namespace NetManagerStandard { +Network::Network(sptr &provider) : provider_(provider) +{ + netId_ = DelayedSingleton::GetInstance()->ReserveNetId(); +} + +bool Network::operator==(const Network &network) const +{ + return (provider_ != nullptr && network.provider_ != nullptr) && *provider_ == *(network.provider_) && + netId_ == network.netId_; +} + +bool Network::NetworkConnect(const NetCapabilities &netCapability) +{ + NETMGR_LOGD("provider is connecting"); + if (isConnected_) { + NETMGR_LOGD("provider is connected"); + return true; + } + + // Call NetProvider class to activate the network + NETMGR_LOGD("ProviderConnection processing"); + bool ret = provider_->ProviderConnection(netCapability); + if (!ret) { + NETMGR_LOGD("connect failed"); + return ret; + } + + isConnecting_ = true; + isConnected_ = true; + return ret; +} + +bool Network::NetworkDisconnect(const NetCapabilities &netCapability) +{ + NETMGR_LOGD("provider is disConnecting"); + if (!isConnecting_ && !isConnected_) { + NETMGR_LOGD("no connecting or connected"); + return false; + } + + // Call NetProvider class to deactivate the network + NETMGR_LOGD("ProviderDisconnection processing"); + bool ret = provider_->ProviderDisconnection(netCapability); + if (!ret) { + NETMGR_LOGD("disconnect failed"); + } + + return ret; +} + +bool Network::UpdateNetLinkInfo(const NetLinkInfo &netLinkInfo) +{ + NETMGR_LOGD("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::GetNetProvider() const +{ + return provider_; +} + +bool Network::UpdateNetProviderInfo(const NetProviderInfo &netProviderInfo) +{ + NETMGR_LOGD("process strart"); + provider_->UpdateNetProviderInfo(netProviderInfo); + + if (!isPhyNetCreated_) { + std::string permission; + // Create a physical network + DelayedSingleton::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()) { + DelayedSingleton::GetInstance()->NetworkAddInterface(netId_, netLinkInfo.ifaceName_); + } + if (!netLinkInfo_.ifaceName_.empty()) { + DelayedSingleton::GetInstance()->NetworkRemoveInterface(netId_, netLinkInfo_.ifaceName_); + } +} + +static bool NetAddrCmp(const INetAddr &netAddr1, const INetAddr &netAddr2) +{ + return netAddr1.type_ == netAddr2.type_ && netAddr1.family_ == netAddr2.family_ && + netAddr1.prefixlen_ == netAddr2.prefixlen_ && netAddr1.address_ == netAddr2.address_ && + netAddr1.netMask_ == netAddr2.netMask_ && netAddr1.hostName_ == netAddr2.hostName_; +} + +void Network::UpdateRoutes(const NetLinkInfo &netLinkInfo) +{ + for (auto it = netLinkInfo.routeList_.begin(); it != netLinkInfo.routeList_.end(); ++it) { + auto route = *it; + if (std::find_if(netLinkInfo_.routeList_.begin(), netLinkInfo_.routeList_.end(), [route](auto another) { + return another.iface_ == route.iface_ && NetAddrCmp(another.destination_, route.destination_) && + NetAddrCmp(another.gateway_, route.gateway_); + }) == netLinkInfo_.routeList_.end()) { + DelayedSingleton::GetInstance()->NetworkAddRoute( + netId_, route.iface_, route.destination_.address_, route.gateway_.address_); + } + } + + for (auto it = netLinkInfo_.routeList_.begin(); it != netLinkInfo_.routeList_.end(); ++it) { + auto route = *it; + if (std::find_if(netLinkInfo.routeList_.begin(), netLinkInfo.routeList_.end(), [route](auto another) { + return another.iface_ == route.iface_ && NetAddrCmp(another.destination_, route.destination_) && + NetAddrCmp(another.gateway_, route.gateway_); + }) == netLinkInfo.routeList_.end()) { + DelayedSingleton::GetInstance()->NetworkRemoveRoute( + netId_, route.iface_, route.destination_.address_, route.gateway_.address_); + } + } +} + +void Network::UpdateDnses(const NetLinkInfo &netLinkInfo) +{ + std::vector addDnses; + if (netLinkInfo.domain_ == netLinkInfo_.domain_ && netLinkInfo.dnsList_.size() == netLinkInfo_.dnsList_.size()) { + for (auto it = netLinkInfo.dnsList_.begin(); it != netLinkInfo.dnsList_.end(); ++it) { + auto dns = *it; + if (std::find_if(netLinkInfo_.dnsList_.begin(), netLinkInfo_.dnsList_.end(), + [dns](auto another) { return NetAddrCmp(dns, another); }) != netLinkInfo_.dnsList_.end()) { + addDnses.push_back(dns.address_); + } + } + } + + std::vector addDoamains; + addDoamains.push_back(netLinkInfo.domain_); + // Call netd to set dns + DelayedSingleton::GetInstance()->SetResolverConfig(netId_, 0, 0, addDnses, addDoamains); +} + +void Network::updateMtu(const NetLinkInfo &netLinkInfo) +{ + if (netLinkInfo.mtu_ == netLinkInfo_.mtu_) { + return; + } + + DelayedSingleton::GetInstance()->InterfaceSetMtu(netLinkInfo.ifaceName_, netLinkInfo.mtu_); +} +} // namespace NetManagerStandard +} // namespace OHOS diff --git a/http/services/netconnmanager/test/BUILD.gn b/http/services/netconnmanager/test/BUILD.gn new file mode 100644 index 000000000..8103987de --- /dev/null +++ b/http/services/netconnmanager/test/BUILD.gn @@ -0,0 +1,23 @@ +# 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/http/services/netconnmanager/test/local_test/BUILD.gn b/http/services/netconnmanager/test/local_test/BUILD.gn new file mode 100644 index 000000000..6244abbee --- /dev/null +++ b/http/services/netconnmanager/test/local_test/BUILD.gn @@ -0,0 +1,78 @@ +# 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") + +SUBSYSTEM_DIR = "//foundation/communication" +NETMANAGER_ROOT = "$SUBSYSTEM_DIR/netstack/http" +INNERKITS_ROOT = "$NETMANAGER_ROOT/interfaces/innerkits" +NETCONNMANAGER_INNERKITS_SOURCE_DIR = "$NETMANAGER_ROOT/frameworks/innerkitsimpl/netconnmanager" +NETCONNMANAGER_SOURCE_DIR = "$NETMANAGER_ROOT/services/netconnmanager" + +ohos_executable("net_conn_manager_local_test") { + sources = [ + "test.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/net_specifier.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/net_provider_info.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/net_link_info.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/inet_addr.cpp", + "$NETCONNMANAGER_INNERKITS_SOURCE_DIR/src/route.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/ipc/net_conn_service_proxy.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_service.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/network.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_provider.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_controller/telephony_controller.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_controller/net_controller_factory.cpp", + "$NETCONNMANAGER_SOURCE_DIR/src/net_id_manager.cpp" + ] + + include_dirs = [ + "$NETCONNMANAGER_SOURCE_DIR/include", + "$INNERKITS_ROOT/native/netconnmanager/include", + "$NETCONNMANAGER_SOURCE_DIR/include/ipc", + "//foundation/aafwk/standard/frameworks/kits/ability/native/include", + "$NETMANAGER_ROOT/utils/log/include", + "$NETCONNMANAGER_SOURCE_DIR/include/net_controller", + "//base/telephony/cellular_data/interfaces/kits/include/", + "//base/telephony/core_service/interfaces/innerkits/cellular_data/proxy", + "$NETMANAGER_ROOT/services/netmanagernative/net_mgr_native/include", + "//foundation/communication/netstack/http/services/netmanagernative/common/include" + ] + + deps = [ + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "$NETMANAGER_ROOT/utils:net_manager_common", + ] + + external_deps = [ + "safwk:system_ability_fwk", + "appexecfwk_standard:libeventhandler", + "samgr_L2:samgr_proxy", + "ipc:ipc_core", + "aafwk_standard:want", + "cellular_data:tel_cellular_data_api" + ] + + defines = [ + "NETMGR_LOG_TAG = \"NetConnManagerTest\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netstack" + subsystem_name = "communication" +} diff --git a/http/services/netconnmanager/test/local_test/test.cpp b/http/services/netconnmanager/test/local_test/test.cpp new file mode 100644 index 000000000..51e7386ec --- /dev/null +++ b/http/services/netconnmanager/test/local_test/test.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 +#include "i_net_conn_service.h" +#include "net_service.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace NetManagerStandard { +sptr g_NetConnService = nullptr; +sptr netService = nullptr; +sptr network = nullptr; +sptr netProvider = nullptr; +uint32_t providerId = 0; + +const int32_t INPUT_REG_NET_PROVIDER = 0; +const int32_t INPUT_UPT_NET_PROVIDER = 1; +const int32_t INPUT_UPT_NET_LINK_INFO = 2; +const int32_t INPUT_CREAT_NET_SERVICE = 3; +const int32_t INPUT_NS_CONNECT = 4; +const int32_t INPUT_NS_DISCONNECT = 5; +const int32_t INPUT_UNREG_NET_PROVIDER = 6; +const int32_t INPUT_UPT_NET_CAPABILITIES = 7; +const int32_t INPUT_QUIT = 100; +using NsTestFunc = void (*)(); +std::map g_memberFuncMap; + +int32_t GetInputData() +{ + int32_t input; + std::cin >> input; + while (std::cin.fail()) { + std::cin.clear(); + std::cin.ignore(); + printf("Input error, please input number again\n"); + std::cin >> input; + } + return input; +} + +void TestRegisterNetProvider() +{ + printf("please input netType_ NET_TYPE_UNKNOWN(%d) or NET_TYPE_CELLULAR(%d)\n", NET_TYPE_UNKNOWN, + NET_TYPE_CELLULAR); + uint16_t nT = GetInputData(); + NetworkType networkType = static_cast(nT); + + printf("please input ident\n"); + std::string ident; + std::cin >> ident; + + printf("please input netCapabilities NET_CAPABILITIES_INTERNET(%d) or NET_CAPABILITIES_MMS(%d)\n", + NET_CAPABILITIES_INTERNET, NET_CAPABILITIES_MMS); + uint32_t netCapabilities = GetInputData(); + + uint32_t id = g_NetConnService->RegisterNetProvider(networkType, ident, netCapabilities); + printf("RegisterNetProvider providerId:%d\n", id); + providerId = id; + + return; +} + +void TestUnRegisterNetProvider() +{ + uint32_t result = g_NetConnService->UnregisterNetProvider(providerId); + providerId = 0; + printf("TestUnRegisterNetProvider result:%d\n", result); + return; +} + +void TestUpdateNetCapabilities() +{ + printf("please input netCapabilities NET_CAPABILITIES_INTERNET(%d) or NET_CAPABILITIES_MMS(%d)\n", + NET_CAPABILITIES_INTERNET, NET_CAPABILITIES_MMS); + uint32_t netCapabilities = GetInputData(); + + uint32_t result = g_NetConnService->UpdateNetCapabilities(providerId, netCapabilities); + printf("TestSetNetCapabilities result:%d\n", result); + return; +} + +void TestUpdateNetProviderInfo() +{ + sptr netProviderInfo = (std::make_unique()).release(); + netProviderInfo->isAvailable_ = true; + netProviderInfo->isRoaming_ = true; + netProviderInfo->strength_ = 100; + netProviderInfo->frequency_ = 16; + uint32_t result = g_NetConnService->UpdateNetProviderInfo(providerId, netProviderInfo); + printf("TestUpdateNetProviderInfo result:%d\n", result); + // test to do + return; +} + +INetAddr GetINetAddrSample1() +{ + INetAddr addr1; + addr1.type_ = 0XFF; + addr1.family_ = 0x02; + addr1.prefixlen_ = 0x03; + addr1.address_ = "str03"; + addr1.netMask_ = "str04"; + addr1.hostName_ = "str05"; + return addr1; +} + +INetAddr GetINetAddrSample2() +{ + INetAddr addr2; + addr2.type_ = 0XFE; + addr2.family_ = 0x04; + addr2.prefixlen_ = 0x05; + addr2.address_ = "str06"; + addr2.netMask_ = "str07"; + addr2.hostName_ = "str08"; + return addr2; +} + +INetAddr GetDnsSample1() +{ + INetAddr dns1; + dns1.type_ = 0XFD; + dns1.family_ = 0x06; + dns1.prefixlen_ = 0x07; + dns1.address_ = "str09"; + dns1.netMask_ = "str10"; + dns1.hostName_ = "str11"; + return dns1; +} + +INetAddr GetDnsSample2() +{ + INetAddr dns2; + dns2.type_ = 0XFC; + dns2.family_ = 0x08; + dns2.prefixlen_ = 0x09; + dns2.address_ = "str12"; + dns2.netMask_ = "str13"; + dns2.hostName_ = "str14"; + return dns2; +} + +Route GetRouteSample1() +{ + Route route1; + route1.iface_ = "str15"; + route1.destination_.type_ = 0XFB; + route1.destination_.family_ = 0x0A; + route1.destination_.prefixlen_ = 0x0B; + route1.destination_.address_ = "str16"; + route1.destination_.netMask_ = "str17"; + route1.destination_.hostName_ = "str18"; + route1.gateway_.type_ = 0XFA; + route1.gateway_.family_ = 0x0C; + route1.gateway_.prefixlen_ = 0x0D; + route1.gateway_.address_ = "str19"; + route1.gateway_.netMask_ = "str20"; + route1.gateway_.hostName_ = "str21"; + return route1; +} + +Route GetRouteSample2() +{ + Route route2; + route2.iface_ = "str22"; + route2.destination_.type_ = 0XF9; + route2.destination_.family_ = 0x0E; + route2.destination_.prefixlen_ = 0x0F; + route2.destination_.address_ = "str23"; + route2.destination_.netMask_ = "str24"; + route2.destination_.hostName_ = "str25"; + route2.gateway_.type_ = 0XF8; + route2.gateway_.family_ = 0x10; + route2.gateway_.prefixlen_ = 0x11; + route2.gateway_.address_ = "str26"; + route2.gateway_.netMask_ = "str27"; + route2.gateway_.hostName_ = "str28"; + return route2; +} + +void TestUpdateNetLinkInfo() +{ + sptr netLinkInfo = (std::make_unique()).release(); + netLinkInfo->ifaceName_ = "str01"; + netLinkInfo->domain_ = "str02"; + netLinkInfo->netAddrList_.push_back(GetINetAddrSample1()); + netLinkInfo->netAddrList_.push_back(GetINetAddrSample2()); + netLinkInfo->dnsList_.push_back(GetDnsSample1()); + netLinkInfo->dnsList_.push_back(GetDnsSample2()); + netLinkInfo->routeList_.push_back(GetRouteSample1()); + netLinkInfo->routeList_.push_back(GetRouteSample2()); + netLinkInfo->mtu_ = 0x13; + + uint32_t result = g_NetConnService->UpdateNetLinkInfo(providerId, netLinkInfo); + printf("TestUpdateNetProviderInfo result:%d\n", result); + return; +} + +void TestCreateNetService() +{ + printf("please input netType_ NET_TYPE_UNKNOWN(%d) or NET_TYPE_CELLULAR(%d)\n", NET_TYPE_UNKNOWN, + NET_TYPE_CELLULAR); + uint16_t nT = GetInputData(); + NetworkType networkType = static_cast(nT); + + printf("please input ident\n"); + std::string ident; + std::cin >> ident; + + printf("please input netCapabilities NET_CAPABILITIES_INTERNET(%d) or NET_CAPABILITIES_MMS(%d)\n", + NET_CAPABILITIES_INTERNET, NET_CAPABILITIES_MMS); + uint32_t netCapabilities = GetInputData(); + + netProvider = (std::make_unique(networkType, ident)).release(); + if (netProvider == nullptr) { + printf("netProvider make error\n"); + return; + } + + network = (std::make_unique(netProvider)).release(); + if (network == nullptr) { + printf("network make error\n"); + return; + } + NetCapabilities netCapability = static_cast(netCapabilities); + netService = (std::make_unique(ident, networkType, netCapability, network)).release(); + if (netService == nullptr) { + printf("netService make shared error\n"); + return; + } +} + +void TestNetServiceConnect() +{ + netService->ServiceConnect(); +} + +void TestNetServiceDisConnect() +{ + netService->ServiceDisConnect(); +} + +sptr GetProxy() +{ + printf("NetConnService GetProxy ... "); + sptr systemAbilityMgr = + SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (systemAbilityMgr == nullptr) { + printf("NetConnService Get ISystemAbilityManager failed ... "); + return nullptr; + } + + sptr remote = systemAbilityMgr->CheckSystemAbility(COMMUNICATION_NET_MANAGER_SYS_ABILITY_ID); + if (remote) { + sptr NetConnService = iface_cast(remote); + printf("NetConnService Get COMMUNICATION_NET_MANAGER_SYS_ABILITY_ID success ... "); + return NetConnService; + } else { + printf("NetConnService Get COMMUNICATION_NET_MANAGER_SYS_ABILITY_ID fail ... "); + return nullptr; + } +} + +void Prompt() +{ + printf( + "\n-----------start test remote api--------------\n" + "0 TestRegisterNetProvider\n" + "1 TestUpdateNetProviderInfo\n" + "2 TestUpdateNetLinkInfo\n" + "3 TestCreateNetService\n" + "4 TestNetServiceConnect\n" + "5 TestNetServiceDisConnect\n" + "6 TestUnRegisterNetProvider\n" + "7 TestUpdateNetCapabilities\n" + "100:exit \n"); +} + +void ProcessInput(bool &loopFlag) +{ + int32_t inputCMD = GetInputData(); + auto itFunc = g_memberFuncMap.find(inputCMD); + if (itFunc != g_memberFuncMap.end()) { + auto memberFunc = itFunc->second; + if (memberFunc != nullptr) { + (*memberFunc)(); + return; + } + } + printf("inputCMD is:[%d]\n", inputCMD); + switch (inputCMD) { + case INPUT_QUIT: { + loopFlag = false; + printf("exit...\n"); + break; + } + default: + printf("please input correct number...\n"); + break; + } +} + +void TestInputQuit(bool &loopFlag) +{ + loopFlag = false; +} + +void Init() +{ + g_memberFuncMap[INPUT_REG_NET_PROVIDER] = TestRegisterNetProvider; + g_memberFuncMap[INPUT_UPT_NET_PROVIDER] = TestUpdateNetProviderInfo; + g_memberFuncMap[INPUT_UPT_NET_LINK_INFO] = TestUpdateNetLinkInfo; + + g_memberFuncMap[INPUT_UPT_NET_CAPABILITIES] = TestUpdateNetCapabilities; + g_memberFuncMap[INPUT_CREAT_NET_SERVICE] = TestCreateNetService; + g_memberFuncMap[INPUT_NS_CONNECT] = TestNetServiceConnect; + g_memberFuncMap[INPUT_NS_DISCONNECT] = TestNetServiceDisConnect; + g_memberFuncMap[INPUT_UNREG_NET_PROVIDER] = TestUnRegisterNetProvider; +} +} // namespace NetManagerStandard +} // namespace OHOS + +using namespace OHOS::NetManagerStandard; + +int main() +{ + Init(); + g_NetConnService = GetProxy(); + if (g_NetConnService == nullptr) { + printf("g_NetConnService is nullptr"); + } + bool loopFlag = true; + while (loopFlag) { + Prompt(); + ProcessInput(loopFlag); + } + printf("...exit test..."); +} diff --git a/http/services/netconnmanager/test/mock/BUILD.gn b/http/services/netconnmanager/test/mock/BUILD.gn new file mode 100644 index 000000000..85dd84c34 --- /dev/null +++ b/http/services/netconnmanager/test/mock/BUILD.gn @@ -0,0 +1,14 @@ +# 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/http/services/netconnmanager/test/unittest/net_conn_manager_test/BUILD.gn b/http/services/netconnmanager/test/unittest/net_conn_manager_test/BUILD.gn new file mode 100644 index 000000000..2b086dc48 --- /dev/null +++ b/http/services/netconnmanager/test/unittest/net_conn_manager_test/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/test.gni") + +SUBSYSTEM_DIR = "//foundation/communication" +NETMANAGER_ROOT = "$SUBSYSTEM_DIR/netstack/http" +INNERKITS_ROOT = "$NETMANAGER_ROOT/interfaces/innerkits" +NETCONNMANAGER_SOURCE_DIR = "$NETMANAGER_ROOT/services/netconnmanager" + +ohos_unittest("net_conn_manager_test") { + module_out_path = "netmanager_standard/net_conn_manager_test" + + sources = [ + "net_conn_manager_test.cpp", + ] + + include_dirs = [ + "$INNERKITS_ROOT/native/netconnmanager/include", + "$NETCONNMANAGER_SOURCE_DIR/include/ipc", + ] + + deps = [ + "$NETMANAGER_ROOT/utils:net_manager_common", + "$INNERKITS_ROOT/native/netconnmanager:net_conn_manager_if", + ] + + external_deps = [ + "ipc:ipc_core", + ] + + defines = [ + "NETMGR_LOG_TAG = \"NetConnManager\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netstack" + subsystem_name = "communication" +} + +group("unittest") { + testonly = true + deps = [ ":net_conn_manager_test" ] +} diff --git a/http/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_manager_test.cpp b/http/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_manager_test.cpp new file mode 100644 index 000000000..c7abefbb4 --- /dev/null +++ b/http/services/netconnmanager/test/unittest/net_conn_manager_test/net_conn_manager_test.cpp @@ -0,0 +1,220 @@ +/* + * 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 "netmgr_log_wrapper.h" +#include "net_conn_manager.h" + +namespace OHOS { +namespace NetManagerStandard { +using namespace testing::ext; +class NetConnManagerTest : public testing::Test { +public: + enum { + NO_ERROR = 0, + ERROR = 1, + }; + + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + sptr GetUpdateLinkInfoSample(); +}; + +bool g_initState = false; + +void NetConnManagerTest::SetUpTestCase() {} + +void NetConnManagerTest::TearDownTestCase() {} + +void NetConnManagerTest::SetUp() {} + +void NetConnManagerTest::TearDown() {} + +sptr NetConnManagerTest::GetUpdateLinkInfoSample() +{ + 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_ = 23; + 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_ = 23; + 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_ = 23; + 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_ = 23; + 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_ = 1234; + + return netLinkInfo; +} +/** + * @tc.name: NetConnManager001 + * @tc.desc: Test NetConnManager ready. + * @tc.type: FUNC + */ +HWTEST_F(NetConnManagerTest, NetConnManager001, TestSize.Level0) +{ + if (DelayedSingleton::GetInstance() == nullptr) { + NETMGR_LOGE("NetConnManager init failed"); + return; + } + NETMGR_LOGD("NetConnManager init success."); + g_initState = true; +} + +/** + * @tc.name: NetConnManager002 + * @tc.desc: Test NetConnManager SystemReady. + * @tc.type: FUNC + */ +HWTEST_F(NetConnManagerTest, NetConnManager002, TestSize.Level0) +{ + if (!g_initState) { + NETMGR_LOGE("NetConnManager init failed"); + return; + } + int32_t result = DelayedSingleton::GetInstance()->SystemReady(); + if (result != 0) { + NETMGR_LOGE("SystemReady test failed"); + return; + } + NETMGR_LOGD("SystemReady test success."); +} + +/** + * @tc.name: NetConnManager00 + * @tc.desc: Test NetConnManager RegisterNetProvider. + * @tc.type: FUNC + */ +HWTEST_F(NetConnManagerTest, NetConnManager003, TestSize.Level0) +{ + if (!g_initState) { + NETMGR_LOGE("NetConnManager init failed"); + return; + } + uint32_t netCapabilities = 0x00; + netCapabilities |= NET_CAPABILITIES_INTERNET; + netCapabilities |= NET_CAPABILITIES_MMS; + + std::string ident = "ident01"; + int32_t result = DelayedSingleton::GetInstance()->RegisterNetProvider( + NET_TYPE_CELLULAR, ident, netCapabilities); + if (result != 0) { + NETMGR_LOGE("RegisterNetProvider test failed"); + return; + } + NETMGR_LOGD("RegisterNetProvider test success."); +} + +/** + * @tc.name: NetConnManager004 + * @tc.desc: Test NetConnManager UnregisterNetProvider. + * @tc.type: FUNC + */ +HWTEST_F(NetConnManagerTest, NetConnManager004, TestSize.Level0) +{ + if (!g_initState) { + NETMGR_LOGE("NetConnManager init failed"); + return; + } + uint32_t providerId = 0x00; + + int32_t result = DelayedSingleton::GetInstance()->UnregisterNetProvider(providerId); + if (result != 0) { + NETMGR_LOGE("UnregisterNetProvider test failed"); + return; + } + NETMGR_LOGD("UnregisterNetProvider test success."); +} + +/** + * @tc.name: NetConnManager005 + * @tc.desc: Test NetConnManager UpdateNetProviderInfo. + * @tc.type: FUNC + */ + +HWTEST_F(NetConnManagerTest, NetConnManager005, TestSize.Level0) +{ + if (!g_initState) { + NETMGR_LOGE("NetConnManager init failed"); + return; + } + uint32_t providerId = 0x01; + sptr netProviderInfo = new NetProviderInfo; + netProviderInfo->isAvailable_ = true; + netProviderInfo->isRoaming_ = true; + netProviderInfo->strength_ = 100; + netProviderInfo->frequency_ = 16; + int32_t result = + DelayedSingleton::GetInstance()->UpdateNetProviderInfo(providerId, netProviderInfo); + if (result != 0) { + NETMGR_LOGE("UpdateNetProviderInfo test failed"); + return; + } + NETMGR_LOGD("UpdateNetProviderInfo test success."); +} + +/** + * @tc.name: NetConnManager006 + * @tc.desc: Test NetConnManager UpdateNetLinkInfo. + * @tc.type: FUNC + */ +HWTEST_F(NetConnManagerTest, NetConnManager006, TestSize.Level0) +{ + if (!g_initState) { + NETMGR_LOGE("NetConnManager init failed"); + return; + } + uint32_t providerId = 0x1; + sptr netLinkInfo = GetUpdateLinkInfoSample(); + int32_t result = DelayedSingleton::GetInstance()->UpdateNetLinkInfo(providerId, netLinkInfo); + if (result != 0) { + NETMGR_LOGE("UpdateNetLinkInfo test failed"); + return; + } + NETMGR_LOGD("UpdateNetLinkInfo test success."); +} +} // namespace NetManagerStandard +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netmanagernative/BUILD.gn b/http/services/netmanagernative/BUILD.gn new file mode 100644 index 000000000..965ecc4fa --- /dev/null +++ b/http/services/netmanagernative/BUILD.gn @@ -0,0 +1,90 @@ +# 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/appexecfwk/standard/appexecfwk.gni") + +SUBSYSTEM_DIR = "//foundation/communication" +NETMANAGERNATIVE_ROOT = "$SUBSYSTEM_DIR/netstack/http/services/netmanagernative" +NETMANAGERNATIVE_SOURCE_DIR = "$NETMANAGERNATIVE_ROOT/net_mgr_native" +NETMANAGERNATIVE_COMMON_SOURCE_DIR = "$NETMANAGERNATIVE_ROOT/common" + +ohos_shared_library("net_manager_native") { + sources = [ + "$NETMANAGERNATIVE_SOURCE_DIR/src/iptables_process.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/native_netd_service.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/route_controller.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/interface_controller.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/netlink_event.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/netlink_handler.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/netlink_manager.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/netlink_listener.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/netlink_socket.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/event_reporter.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/sock_diag.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/network.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/netlink_msg.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/fwmark_server.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/traffic_controller.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/dnsresolv_service.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/dnsresolv_controller.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/dnsresolv_cache.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/get_addr_info.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/src/network_controller.cpp", + "$NETMANAGERNATIVE_COMMON_SOURCE_DIR/src/interface_utils.cpp", + "$NETMANAGERNATIVE_COMMON_SOURCE_DIR/src/error_code.cpp", + "$NETMANAGERNATIVE_COMMON_SOURCE_DIR/src/server_template.cpp", + "$NETMANAGERNATIVE_COMMON_SOURCE_DIR/src/server_socket.cpp", + "$NETMANAGERNATIVE_COMMON_SOURCE_DIR/src/socket_base.cpp", + "$NETMANAGERNATIVE_COMMON_SOURCE_DIR/src/thread_pool.cpp", + "$NETMANAGERNATIVE_COMMON_SOURCE_DIR/src/net_utils.cpp", + "$NETMANAGERNATIVE_COMMON_SOURCE_DIR/src/rwlock.cpp", + "$NETMANAGERNATIVE_COMMON_SOURCE_DIR/src/utils.cpp", + "$NETMANAGERNATIVE_SOURCE_DIR/client/src/dnsresolv_client.cpp", + ] + + include_dirs = [ + "$NETMANAGERNATIVE_SOURCE_DIR/include", + "$NETMANAGERNATIVE_COMMON_SOURCE_DIR/include", + "$NETMANAGERNATIVE_SOURCE_DIR/client/include", + ] + + deps = [ + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//utils/native/base:utils", + "${aafwk_path}/interfaces/innerkits/base:base", + "${aafwk_path}/interfaces/innerkits/want:want", + + ] + + libs = [ + "pthread", + "resolv" + ] + + external_deps = [ + ] + + defines = [ + "NETMGR_LOG_TAG = \"NetManagerNative\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + subsystem_name = "communication" + part_name = "netstack" +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/include/securec.h b/http/services/netmanagernative/common/huawei_secure_c/include/securec.h new file mode 100644 index 000000000..b279b1a67 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/include/securec.h @@ -0,0 +1,635 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef __SECUREC_H__5D13A042_DC3F_4ED9_A8D1_882811274C27 +#define __SECUREC_H__5D13A042_DC3F_4ED9_A8D1_882811274C27 + +#include "securectype.h" +#ifndef SECUREC_HAVE_STDARG_H +#define SECUREC_HAVE_STDARG_H 1 +#endif + +#if SECUREC_HAVE_STDARG_H +#include +#endif + +#ifndef SECUREC_HAVE_ERRNO_H +#if SECUREC_IN_KERNEL +#define SECUREC_HAVE_ERRNO_H 0 +#else +#define SECUREC_HAVE_ERRNO_H 1 +#endif +#endif + +/* EINVAL ERANGE may defined in errno.h */ +#if SECUREC_HAVE_ERRNO_H +#include +#endif + +/* Define error code */ +#if defined(SECUREC_NEED_ERRNO_TYPE) || !defined(__STDC_WANT_LIB_EXT1__) || \ + (defined(__STDC_WANT_LIB_EXT1__) && (__STDC_WANT_LIB_EXT1__ == 0)) +#ifndef SECUREC_DEFINED_ERRNO_TYPE +#define SECUREC_DEFINED_ERRNO_TYPE +/* Just check whether macrodefinition exists. */ +#ifndef errno_t +typedef int errno_t; +#endif +#endif +#endif + +/* Success */ +#ifndef EOK +#define EOK 0 +#endif + +#ifndef EINVAL +/* The src buffer is not correct and destination buffer cant not be reset */ +#define EINVAL 22 +#endif + +#ifndef EINVAL_AND_RESET +/* Once the error is detected, the dest buffer must be reseted! */ +#define EINVAL_AND_RESET (22 | 128) +#endif + +#ifndef ERANGE +/* The destination buffer is not long enough and destination buffer can not be reset */ +#define ERANGE 34 +#endif + +#ifndef ERANGE_AND_RESET +/* Once the error is detected, the dest buffer must be reseted! */ +#define ERANGE_AND_RESET (34 | 128) +#endif + +#ifndef EOVERLAP_AND_RESET +/* Once the buffer overlap is detected, the dest buffer must be reseted! */ +#define EOVERLAP_AND_RESET (54 | 128) +#endif + +/* If you need export the function of this library in Win32 dll, use __declspec(dllexport) */ +#ifndef SECUREC_API +#if defined(SECUREC_DLL_EXPORT) +#define SECUREC_API __declspec(dllexport) +#elif defined(SECUREC_DLL_IMPORT) +#define SECUREC_API __declspec(dllimport) +#else +/* + * Standardized function declaration. If a security function is declared in the your code, + * it may cause a compilation alarm,Please delete the security function you declared. + * Adding extern under windows will cause the system to have inline functions to expand, + * so do not add the extern in default + */ +#if defined(_MSC_VER) +#define SECUREC_API +#else +#define SECUREC_API extern +#endif +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif +/* + * Description: The GetHwSecureCVersion function get SecureC Version string and version number. + * Parameter: verNumber - to store version number + * Return: version string + */ +SECUREC_API const char *GetHwSecureCVersion(unsigned short *verNumber); + +#if SECUREC_ENABLE_MEMSET +/* + * Description: The memset_s function copies the value of c (converted to an unsigned char) into each of + * the first count characters of the object pointed to by dest. + * Parameter: dest - destination address + * Parameter: destMax - The maximum length of destination buffer + * Parameter: c - the value to be copied + * Parameter: count - copies count bytes of value to dest + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t memset_s(void *dest, size_t destMax, int c, size_t count); +#endif + +#ifndef SECUREC_ONLY_DECLARE_MEMSET +#define SECUREC_ONLY_DECLARE_MEMSET 0 +#endif + +#if SECUREC_ONLY_DECLARE_MEMSET == 0 + +#if SECUREC_ENABLE_MEMMOVE +/* + * Description: The memmove_s function copies n characters from the object pointed to by src + * into the object pointed to by dest. + * Parameter: dest - destination address + * Parameter: destMax - The maximum length of destination buffer + * Parameter: src - source address + * Parameter: count - copies count bytes from the src + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t memmove_s(void *dest, size_t destMax, const void *src, size_t count); +#endif + +#if SECUREC_ENABLE_MEMCPY +/* + * Description: The memcpy_s function copies n characters from the object pointed to + * by src into the object pointed to by dest. + * Parameter: dest - destination address + * Parameter: destMax - The maximum length of destination buffer + * Parameter: src - source address + * Parameter: count - copies count bytes from the src + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t memcpy_s(void *dest, size_t destMax, const void *src, size_t count); +#endif + +#if SECUREC_ENABLE_STRCPY +/* + * Description: The strcpy_s function copies the string pointed to by strSrc (including + * the terminating null character) into the array pointed to by strDest + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating null character) + * Parameter: strSrc - source address + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t strcpy_s(char *strDest, size_t destMax, const char *strSrc); +#endif + +#if SECUREC_ENABLE_STRNCPY +/* + * Description: The strncpy_s function copies not more than n successive characters (not including + * the terminating null character) from the array pointed to by strSrc to the array pointed to by strDest. + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating null character) + * Parameter: strSrc - source address + * Parameter: count - copies count characters from the src + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t strncpy_s(char *strDest, size_t destMax, const char *strSrc, size_t count); +#endif + +#if SECUREC_ENABLE_STRCAT +/* + * Description: The strcat_s function appends a copy of the string pointed to by strSrc (including + * the terminating null character) to the end of the string pointed to by strDest. + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating null wide character) + * Parameter: strSrc - source address + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t strcat_s(char *strDest, size_t destMax, const char *strSrc); +#endif + +#if SECUREC_ENABLE_STRNCAT +/* + * Description: The strncat_s function appends not more than n successive characters (not including + * the terminating null character) + * from the array pointed to by strSrc to the end of the string pointed to by strDest. + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating null character) + * Parameter: strSrc - source address + * Parameter: count - copies count characters from the src + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count); +#endif + +#if SECUREC_ENABLE_VSPRINTF +/* + * Description: The vsprintf_s function is equivalent to the vsprintf function except for the parameter destMax + * and the explicit runtime-constraints violation + * Parameter: strDest - produce output according to a format ,write to the character string strDest. + * Parameter: destMax - The maximum length of destination buffer(including the terminating null wide characte) + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of characters printed(not including the terminating null byte '\0'), + * If an error occurred Return: -1. + */ +SECUREC_API int vsprintf_s(char *strDest, size_t destMax, const char *format, va_list argList) + SECUREC_ATTRIBUTE(3, 0); +#endif + +#if SECUREC_ENABLE_SPRINTF +/* + * Description: The sprintf_s function is equivalent to the sprintf function except for the parameter destMax + * and the explicit runtime-constraints violation + * Parameter: strDest - produce output according to a format ,write to the character string strDest. + * Parameter: destMax - The maximum length of destination buffer(including the terminating null byte '\0') + * Parameter: format - fromat string + * Return: the number of characters printed(not including the terminating null byte '\0'), + * If an error occurred Return: -1. + */ +SECUREC_API int sprintf_s(char *strDest, size_t destMax, const char *format, ...) SECUREC_ATTRIBUTE(3, 4); +#endif + +#if SECUREC_ENABLE_VSNPRINTF +/* + * Description: The vsnprintf_s function is equivalent to the vsnprintf function except for + * the parameter destMax/count and the explicit runtime-constraints violation + * Parameter: strDest - produce output according to a format ,write to the character string strDest. + * Parameter: destMax - The maximum length of destination buffer(including the terminating null byte '\0') + * Parameter: count - do not write more than count bytes to strDest(not including the terminating null byte '\0') + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of characters printed(not including the terminating null byte '\0'), + * If an error occurred Return: -1.Pay special attention to returning -1 when truncation occurs + */ +SECUREC_API int vsnprintf_s(char *strDest, size_t destMax, size_t count, const char *format, va_list argList) + SECUREC_ATTRIBUTE(4, 0); +#endif + +#if SECUREC_ENABLE_SNPRINTF +/* + * Description: The snprintf_s function is equivalent to the snprintf function except for + * the parameter destMax/count and the explicit runtime-constraints violation + * Parameter: strDest - produce output according to a format ,write to the character string strDest. + * Parameter: destMax - The maximum length of destination buffer(including the terminating null byte '\0') + * Parameter: count - do not write more than count bytes to strDest(not including the terminating null byte '\0') + * Parameter: format - fromat string + * Return: the number of characters printed(not including the terminating null byte '\0'), + * If an error occurred Return: -1.Pay special attention to returning -1 when truncation occurs + */ +SECUREC_API int snprintf_s(char *strDest, size_t destMax, size_t count, const char *format, ...) + SECUREC_ATTRIBUTE(4, 5); +#endif + +#if SECUREC_SNPRINTF_TRUNCATED +/* + * Description: The vsnprintf_truncated_s function is equivalent to the vsnprintf_s function except + * no count parameter and return value + * Parameter: strDest - produce output according to a format ,write to the character string strDest + * Parameter: destMax - The maximum length of destination buffer(including the terminating null byte '\0') + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of characters printed(not including the terminating null byte '\0'), + * If an error occurred Return: -1.Pay special attention to returning destMax - 1 when truncation occurs + */ +SECUREC_API int vsnprintf_truncated_s(char *strDest, size_t destMax, const char *format, va_list argList) + SECUREC_ATTRIBUTE(3, 0); + +/* + * Description: The snprintf_truncated_s function is equivalent to the snprintf_2 function except + * no count parameter and return value + * Parameter: strDest - produce output according to a format ,write to the character string strDest. + * Parameter: destMax - The maximum length of destination buffer(including the terminating null byte '\0') + * Parameter: format - fromat string + * Return: the number of characters printed(not including the terminating null byte '\0'), + * If an error occurred Return: -1.Pay special attention to returning destMax - 1 when truncation occurs + */ +SECUREC_API int snprintf_truncated_s(char *strDest, size_t destMax, const char *format, ...) + SECUREC_ATTRIBUTE(3, 4); +#endif + +#if SECUREC_ENABLE_SCANF +/* + * Description: The scanf_s function is equivalent to fscanf_s with the argument stdin + * interposed before the arguments to scanf_s + * Parameter: format - fromat string + * Return: the number of input items assigned, If an error occurred Return: -1. + */ +SECUREC_API int scanf_s(const char *format, ...); +#endif + +#if SECUREC_ENABLE_VSCANF +/* + * Description: The vscanf_s function is equivalent to scanf_s, with the variable argument list replaced by argList + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of input items assigned, If an error occurred Return: -1. + */ +SECUREC_API int vscanf_s(const char *format, va_list argList); +#endif + +#if SECUREC_ENABLE_SSCANF +/* + * Description: The sscanf_s function is equivalent to fscanf_s, except that input is obtained from a + * string (specified by the argument buffer) rather than from a stream + * Parameter: buffer - read character from buffer + * Parameter: format - fromat string + * Return: the number of input items assigned, If an error occurred Return: -1. + */ +SECUREC_API int sscanf_s(const char *buffer, const char *format, ...); +#endif + +#if SECUREC_ENABLE_VSSCANF +/* + * Description: The vsscanf_s function is equivalent to sscanf_s, with the variable argument list + * replaced by argList + * Parameter: buffer - read character from buffer + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of input items assigned, If an error occurred Return: -1. + */ +SECUREC_API int vsscanf_s(const char *buffer, const char *format, va_list argList); +#endif + +#if SECUREC_ENABLE_FSCANF +/* + * Description: The fscanf_s function is equivalent to fscanf except that the c, s, and [ conversion specifiers + * apply to a pair of arguments (unless assignment suppression is indicated by a*) + * Parameter: stream - stdio file stream + * Parameter: format - fromat string + * Return: the number of input items assigned, If an error occurred Return: -1. + */ +SECUREC_API int fscanf_s(FILE *stream, const char *format, ...); +#endif + +#if SECUREC_ENABLE_VFSCANF +/* + * Description: The vfscanf_s function is equivalent to fscanf_s, with the variable argument list + * replaced by argList + * Parameter: stream - stdio file stream + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of input items assigned, If an error occurred Return: -1. + */ +SECUREC_API int vfscanf_s(FILE *stream, const char *format, va_list argList); +#endif + +#if SECUREC_ENABLE_STRTOK +/* + * Description: The strtok_s function parses a string into a sequence of strToken, + * replace all characters in strToken string that match to strDelimit set with 0. + * On the first call to strtok_s the string to be parsed should be specified in strToken. + * In each subsequent call that should parse the same string, strToken should be NULL + * Parameter: strToken - the string to be delimited + * Parameter: strDelimit - specifies a set of characters that delimit the tokens in the parsed string + * Parameter: context - is a pointer to a char * variable that is used internally by strtok_s function + * Return: On the first call returns the address of the first non \0 character, otherwise NULL is returned. + * In subsequent calls, the strtoken is set to NULL, and the context set is the same as the previous call, + * return NULL if the *context string length is equal 0, otherwise return *context. + */ +SECUREC_API char *strtok_s(char *strToken, const char *strDelimit, char **context); +#endif + +#if SECUREC_ENABLE_GETS && SECUREC_IN_KERNEL == 0 +/* + * Description: The gets_s function reads at most one less than the number of characters specified + * by destMax from the stream pointed to by stdin, into the array pointed to by buffer + * Parameter: buffer - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating null character) + * Return: buffer if there was no runtime-constraint violation,If an error occurred Return: NULL. + */ +SECUREC_API char *gets_s(char *buffer, size_t destMax); +#endif + +#if SECUREC_ENABLE_WCHAR_FUNC +#if SECUREC_ENABLE_MEMCPY +/* + * Description: The wmemcpy_s function copies n successive wide characters from the object pointed to + * by src into the object pointed to by dest. + * Parameter: dest - destination address + * Parameter: destMax - The maximum length of destination buffer + * Parameter: src - source address + * Parameter: count - copies count wide characters from the src + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t wmemcpy_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count); +#endif + +#if SECUREC_ENABLE_MEMMOVE +/* + * Description: The wmemmove_s function copies n successive wide characters from the object + * pointed to by src into the object pointed to by dest. + * Parameter: dest - destination address + * Parameter: destMax - The maximum length of destination buffer + * Parameter: src - source address + * Parameter: count - copies count wide characters from the src + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t wmemmove_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count); +#endif + +#if SECUREC_ENABLE_STRCPY +/* + * Description: The wcscpy_s function copies the wide string pointed to by strSrc (including theterminating + * null wide character) into the array pointed to by strDest + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer + * Parameter: strSrc - source address + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t wcscpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc); +#endif + +#if SECUREC_ENABLE_STRNCPY +/* + * Description: The wcsncpy_s function copies not more than n successive wide characters (not including the + * terminating null wide character) from the array pointed to by strSrc to the array pointed to by strDest + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating wide character) + * Parameter: strSrc - source address + * Parameter: count - copies count wide characters from the src + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t wcsncpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count); +#endif + +#if SECUREC_ENABLE_STRCAT +/* + * Description: The wcscat_s function appends a copy of the wide string pointed to by strSrc (including the + * terminating null wide character) to the end of the wide string pointed to by strDest + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating wide character) + * Parameter: strSrc - source address + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t wcscat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc); +#endif + +#if SECUREC_ENABLE_STRNCAT +/* + * Description: The wcsncat_s function appends not more than n successive wide characters (not including the + * terminating null wide character) from the array pointed to by strSrc to the end of the wide string pointed to + * by strDest. + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating wide character) + * Parameter: strSrc - source address + * Parameter: count - copies count wide characters from the src + * Return: EOK if there was no runtime-constraint violation + */ +SECUREC_API errno_t wcsncat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count); +#endif + +#if SECUREC_ENABLE_STRTOK +/* + * Description: The wcstok_s function is the wide-character equivalent of the strtok_s function + * Parameter: strToken - the string to be delimited + * Parameter: strDelimit - specifies a set of characters that delimit the tokens in the parsed string + * Parameter: context - is a pointer to a char * variable that is used internally by strtok_s function + * Return: a pointer to the first character of a token, or a null pointer if there is no token + * or there is a runtime-constraint violation. + */ +SECUREC_API wchar_t *wcstok_s(wchar_t *strToken, const wchar_t *strDelimit, wchar_t **context); +#endif + +#if SECUREC_ENABLE_VSPRINTF +/* + * Description: The vswprintf_s function is the wide-character equivalent of the vsprintf_s function + * Parameter: strDest - produce output according to a format ,write to the character string strDest + * Parameter: destMax - The maximum length of destination buffer(including the terminating null ) + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of characters printed(not including the terminating null wide characte), + * If an error occurred Return: -1. + */ +SECUREC_API int vswprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, va_list argList); +#endif + +#if SECUREC_ENABLE_SPRINTF + +/* + * Description: The swprintf_s function is the wide-character equivalent of the sprintf_s function + * Parameter: strDest - produce output according to a format ,write to the character string strDest + * Parameter: destMax - The maximum length of destination buffer(including the terminating null ) + * Parameter: format - fromat string + * Return: the number of characters printed(not including the terminating null wide characte), + * If an error occurred Return: -1. + */ +SECUREC_API int swprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, ...); +#endif + +#if SECUREC_ENABLE_FSCANF +/* + * Description: The fwscanf_s function is the wide-character equivalent of the fscanf_s function + * Parameter: stream - stdio file stream + * Parameter: format - fromat string + * Return: the number of input items assigned, If an error occurred Return: -1. + */ +SECUREC_API int fwscanf_s(FILE *stream, const wchar_t *format, ...); +#endif + +#if SECUREC_ENABLE_VFSCANF +/* + * Description: The vfwscanf_s function is the wide-character equivalent of the vfscanf_s function + * Parameter: stream - stdio file stream + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of input items assigned, If an error occurred Return: -1. + */ +SECUREC_API int vfwscanf_s(FILE *stream, const wchar_t *format, va_list argList); +#endif + +#if SECUREC_ENABLE_SCANF +/* + * Description: The wscanf_s function is the wide-character equivalent of the scanf_s function + * Parameter: format - fromat string + * Return: the number of input items assigned, If an error occurred Return: -1. + */ +SECUREC_API int wscanf_s(const wchar_t *format, ...); +#endif + +#if SECUREC_ENABLE_VSCANF +/* + * Description: The vwscanf_s function is the wide-character equivalent of the vscanf_s function + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of input items assigned, If an error occurred Return: -1. + */ +SECUREC_API int vwscanf_s(const wchar_t *format, va_list argList); +#endif + +#if SECUREC_ENABLE_SSCANF +/* + * Description: The swscanf_s function is the wide-character equivalent of the sscanf_s function + * Parameter: buffer - read character from buffer + * Parameter: format - fromat string + * Return: the number of input items assigned, If an error occurred Return: -1. + */ +SECUREC_API int swscanf_s(const wchar_t *buffer, const wchar_t *format, ...); +#endif + +#if SECUREC_ENABLE_VSSCANF +/* + * Description: The vswscanf_s function is the wide-character equivalent of the vsscanf_s function + * Parameter: buffer - read character from buffer + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of input items assigned, If an error occurred Return: -1. + */ +SECUREC_API int vswscanf_s(const wchar_t *buffer, const wchar_t *format, va_list argList); +#endif +#endif /* SECUREC_ENABLE_WCHAR_FUNC */ +#endif + +/* Those functions are used by macro ,must declare hare , also for without function declaration warning */ +extern errno_t strncpy_error(char *strDest, size_t destMax, const char *strSrc, size_t count); +extern errno_t strcpy_error(char *strDest, size_t destMax, const char *strSrc); + +#if SECUREC_WITH_PERFORMANCE_ADDONS +/* Those functions are used by macro */ +extern errno_t memset_sOptAsm(void *dest, size_t destMax, int c, size_t count); +extern errno_t memset_sOptTc(void *dest, size_t destMax, int c, size_t count); +extern errno_t memcpy_sOptAsm(void *dest, size_t destMax, const void *src, size_t count); +extern errno_t memcpy_sOptTc(void *dest, size_t destMax, const void *src, size_t count); + +/* The strcpy_sp is a macro, not a function in performance optimization mode. */ +#define strcpy_sp(dest, destMax, src) \ + ((__builtin_constant_p((destMax)) && __builtin_constant_p((src))) ? \ + SECUREC_STRCPY_SM((dest), (destMax), (src)) : \ + strcpy_s((dest), (destMax), (src))) + +/* The strncpy_sp is a macro, not a function in performance optimization mode. */ +#define strncpy_sp(dest, destMax, src, count) \ + ((__builtin_constant_p((count)) && __builtin_constant_p((destMax)) && __builtin_constant_p((src))) ? \ + SECUREC_STRNCPY_SM((dest), (destMax), (src), (count)) : \ + strncpy_s((dest), (destMax), (src), (count))) + +/* The strcat_sp is a macro, not a function in performance optimization mode. */ +#define strcat_sp(dest, destMax, src) \ + ((__builtin_constant_p((destMax)) && __builtin_constant_p((src))) ? \ + SECUREC_STRCAT_SM((dest), (destMax), (src)) : \ + strcat_s((dest), (destMax), (src))) + +/* The strncat_sp is a macro, not a function in performance optimization mode. */ +#define strncat_sp(dest, destMax, src, count) \ + ((__builtin_constant_p((count)) && __builtin_constant_p((destMax)) && __builtin_constant_p((src))) ? \ + SECUREC_STRNCAT_SM((dest), (destMax), (src), (count)) : \ + strncat_s((dest), (destMax), (src), (count))) + +/* The memcpy_sp is a macro, not a function in performance optimization mode. */ +#define memcpy_sp(dest, destMax, src, count) \ + (__builtin_constant_p((count)) ? \ + (SECUREC_MEMCPY_SM((dest), (destMax), (src), (count))) : \ + (__builtin_constant_p((destMax)) ? \ + (((size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_MEM_MAX_LEN)) ? \ + memcpy_sOptTc((dest), (destMax), (src), (count)) : \ + ERANGE) : \ + memcpy_sOptAsm((dest), (destMax), (src), (count)))) + +/* The memset_sp is a macro, not a function in performance optimization mode. */ +#define memset_sp(dest, destMax, c, count) \ + (__builtin_constant_p((count)) ? \ + (SECUREC_MEMSET_SM((dest), (destMax), (c), (count))) : \ + (__builtin_constant_p((destMax)) ? \ + (((((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_MEM_MAX_LEN)) ? \ + memset_sOptTc((dest), (destMax), (c), (count)) : \ + ERANGE) : \ + memset_sOptAsm((dest), (destMax), (c), (count)))) +#else +#define strcpy_sp strcpy_s +#define strncpy_sp strncpy_s +#define strcat_sp strcat_s +#define strncat_sp strncat_s +#define memcpy_sp memcpy_s +#define memset_sp memset_s +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __SECUREC_H__5D13A042_DC3F_4ED9_A8D1_882811274C27 */ diff --git a/http/services/netmanagernative/common/huawei_secure_c/include/securectype.h b/http/services/netmanagernative/common/huawei_secure_c/include/securectype.h new file mode 100644 index 000000000..eb1662ffd --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/include/securectype.h @@ -0,0 +1,566 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +/* + * [Standardize-exceptions]: Performance-sensitive + * [reason]: Strict parameter verification has been done before use + */ + +#ifndef __SECURECTYPE_H__A7BBB686_AADA_451B_B9F9_44DACDAE18A7 +#define __SECURECTYPE_H__A7BBB686_AADA_451B_B9F9_44DACDAE18A7 + +#ifndef SECUREC_USING_STD_SECURE_LIB +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#if defined(__STDC_WANT_SECURE_LIB__) && __STDC_WANT_SECURE_LIB__ == 0 +/* Security functions have been provided since vs2005, default use of system library functions */ +#define SECUREC_USING_STD_SECURE_LIB 0 +#else +#define SECUREC_USING_STD_SECURE_LIB 1 +#endif +#else +#define SECUREC_USING_STD_SECURE_LIB 0 +#endif +#endif + +/* Compatibility with older Secure C versions, shielding VC symbol redefinition warning */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 && SECUREC_USING_STD_SECURE_LIB == 0 +#ifndef SECUREC_DISABLE_CRT_FUNC +#define SECUREC_DISABLE_CRT_FUNC 1 +#endif +#ifndef SECUREC_DISABLE_CRT_IMP +#define SECUREC_DISABLE_CRT_IMP 1 +#endif +#else /* MSC VER */ +#ifndef SECUREC_DISABLE_CRT_FUNC +#define SECUREC_DISABLE_CRT_FUNC 0 +#endif +#ifndef SECUREC_DISABLE_CRT_IMP +#define SECUREC_DISABLE_CRT_IMP 0 +#endif +#endif + +#if SECUREC_DISABLE_CRT_FUNC +#ifdef __STDC_WANT_SECURE_LIB__ +#undef __STDC_WANT_SECURE_LIB__ +#endif +#define __STDC_WANT_SECURE_LIB__ 0 +#endif + +#if SECUREC_DISABLE_CRT_IMP +#ifdef _CRTIMP_ALTERNATIVE +#undef _CRTIMP_ALTERNATIVE +#endif +#define _CRTIMP_ALTERNATIVE /* Comment microsoft *_s function */ +#endif + +/* Compile in kernel under macro control */ +#ifndef SECUREC_IN_KERNEL +#ifdef __KERNEL__ +#define SECUREC_IN_KERNEL 1 +#else +#define SECUREC_IN_KERNEL 0 +#endif +#endif + +#if SECUREC_IN_KERNEL +#ifndef SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_SCANF_FILE 0 +#endif +#ifndef SECUREC_ENABLE_WCHAR_FUNC +#define SECUREC_ENABLE_WCHAR_FUNC 0 +#endif +#else /* SECUREC_IN_KERNEL */ +#ifndef SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_SCANF_FILE 1 +#endif +#ifndef SECUREC_ENABLE_WCHAR_FUNC +#define SECUREC_ENABLE_WCHAR_FUNC 1 +#endif +#endif + +/* Default secure function declaration, default declarations for non-standard functions */ +#ifndef SECUREC_SNPRINTF_TRUNCATED +#define SECUREC_SNPRINTF_TRUNCATED 1 +#endif + +#if SECUREC_USING_STD_SECURE_LIB +#if defined(_MSC_VER) && _MSC_VER >= 1400 +/* Declare secure functions that are not available in the VS compiler */ +#ifndef SECUREC_ENABLE_MEMSET +#define SECUREC_ENABLE_MEMSET 1 +#endif +/* VS 2005 have vsnprintf_s function */ +#ifndef SECUREC_ENABLE_VSNPRINTF +#define SECUREC_ENABLE_VSNPRINTF 0 +#endif +#ifndef SECUREC_ENABLE_SNPRINTF +/* VS 2005 have vsnprintf_s function Adapt the snprintf_s of the security function */ +#define snprintf_s _snprintf_s +#define SECUREC_ENABLE_SNPRINTF 0 +#endif +/* Before VS 2010 do not have v functions */ +#if _MSC_VER <= 1600 || defined(SECUREC_FOR_V_SCANFS) +#ifndef SECUREC_ENABLE_VFSCANF +#define SECUREC_ENABLE_VFSCANF 1 +#endif +#ifndef SECUREC_ENABLE_VSCANF +#define SECUREC_ENABLE_VSCANF 1 +#endif +#ifndef SECUREC_ENABLE_VSSCANF +#define SECUREC_ENABLE_VSSCANF 1 +#endif +#endif + +#else /* MSC VER */ +#ifndef SECUREC_ENABLE_MEMSET +#define SECUREC_ENABLE_MEMSET 0 +#endif +#ifndef SECUREC_ENABLE_SNPRINTF +#define SECUREC_ENABLE_SNPRINTF 0 +#endif +#ifndef SECUREC_ENABLE_VSNPRINTF +#define SECUREC_ENABLE_VSNPRINTF 0 +#endif +#endif + +#ifndef SECUREC_ENABLE_MEMMOVE +#define SECUREC_ENABLE_MEMMOVE 0 +#endif +#ifndef SECUREC_ENABLE_MEMCPY +#define SECUREC_ENABLE_MEMCPY 0 +#endif +#ifndef SECUREC_ENABLE_STRCPY +#define SECUREC_ENABLE_STRCPY 0 +#endif +#ifndef SECUREC_ENABLE_STRNCPY +#define SECUREC_ENABLE_STRNCPY 0 +#endif +#ifndef SECUREC_ENABLE_STRCAT +#define SECUREC_ENABLE_STRCAT 0 +#endif +#ifndef SECUREC_ENABLE_STRNCAT +#define SECUREC_ENABLE_STRNCAT 0 +#endif +#ifndef SECUREC_ENABLE_SPRINTF +#define SECUREC_ENABLE_SPRINTF 0 +#endif +#ifndef SECUREC_ENABLE_VSPRINTF +#define SECUREC_ENABLE_VSPRINTF 0 +#endif +#ifndef SECUREC_ENABLE_SSCANF +#define SECUREC_ENABLE_SSCANF 0 +#endif +#ifndef SECUREC_ENABLE_VSSCANF +#define SECUREC_ENABLE_VSSCANF 0 +#endif +#ifndef SECUREC_ENABLE_SCANF +#define SECUREC_ENABLE_SCANF 0 +#endif +#ifndef SECUREC_ENABLE_VSCANF +#define SECUREC_ENABLE_VSCANF 0 +#endif + +#ifndef SECUREC_ENABLE_FSCANF +#define SECUREC_ENABLE_FSCANF 0 +#endif +#ifndef SECUREC_ENABLE_VFSCANF +#define SECUREC_ENABLE_VFSCANF 0 +#endif +#ifndef SECUREC_ENABLE_STRTOK +#define SECUREC_ENABLE_STRTOK 0 +#endif +#ifndef SECUREC_ENABLE_GETS +#define SECUREC_ENABLE_GETS 0 +#endif + +#else /* SECUREC USE STD SECURE LIB */ + +#ifndef SECUREC_ENABLE_MEMSET +#define SECUREC_ENABLE_MEMSET 1 +#endif +#ifndef SECUREC_ENABLE_MEMMOVE +#define SECUREC_ENABLE_MEMMOVE 1 +#endif +#ifndef SECUREC_ENABLE_MEMCPY +#define SECUREC_ENABLE_MEMCPY 1 +#endif +#ifndef SECUREC_ENABLE_STRCPY +#define SECUREC_ENABLE_STRCPY 1 +#endif +#ifndef SECUREC_ENABLE_STRNCPY +#define SECUREC_ENABLE_STRNCPY 1 +#endif +#ifndef SECUREC_ENABLE_STRCAT +#define SECUREC_ENABLE_STRCAT 1 +#endif +#ifndef SECUREC_ENABLE_STRNCAT +#define SECUREC_ENABLE_STRNCAT 1 +#endif +#ifndef SECUREC_ENABLE_SPRINTF +#define SECUREC_ENABLE_SPRINTF 1 +#endif +#ifndef SECUREC_ENABLE_VSPRINTF +#define SECUREC_ENABLE_VSPRINTF 1 +#endif +#ifndef SECUREC_ENABLE_SNPRINTF +#define SECUREC_ENABLE_SNPRINTF 1 +#endif +#ifndef SECUREC_ENABLE_VSNPRINTF +#define SECUREC_ENABLE_VSNPRINTF 1 +#endif +#ifndef SECUREC_ENABLE_SSCANF +#define SECUREC_ENABLE_SSCANF 1 +#endif +#ifndef SECUREC_ENABLE_VSSCANF +#define SECUREC_ENABLE_VSSCANF 1 +#endif +#ifndef SECUREC_ENABLE_SCANF +#if SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_SCANF 1 +#else +#define SECUREC_ENABLE_SCANF 0 +#endif +#endif +#ifndef SECUREC_ENABLE_VSCANF +#if SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_VSCANF 1 +#else +#define SECUREC_ENABLE_VSCANF 0 +#endif +#endif + +#ifndef SECUREC_ENABLE_FSCANF +#if SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_FSCANF 1 +#else +#define SECUREC_ENABLE_FSCANF 0 +#endif +#endif +#ifndef SECUREC_ENABLE_VFSCANF +#if SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_VFSCANF 1 +#else +#define SECUREC_ENABLE_VFSCANF 0 +#endif +#endif + +#ifndef SECUREC_ENABLE_STRTOK +#define SECUREC_ENABLE_STRTOK 1 +#endif +#ifndef SECUREC_ENABLE_GETS +#define SECUREC_ENABLE_GETS 1 +#endif +#endif /* SECUREC_USE_STD_SECURE_LIB */ + +#if SECUREC_ENABLE_SCANF_FILE == 0 +#if SECUREC_ENABLE_FSCANF +#undef SECUREC_ENABLE_FSCANF +#define SECUREC_ENABLE_FSCANF 0 +#endif +#if SECUREC_ENABLE_VFSCANF +#undef SECUREC_ENABLE_VFSCANF +#define SECUREC_ENABLE_VFSCANF 0 +#endif +#if SECUREC_ENABLE_SCANF +#undef SECUREC_ENABLE_SCANF +#define SECUREC_ENABLE_SCANF 0 +#endif +#if SECUREC_ENABLE_FSCANF +#undef SECUREC_ENABLE_FSCANF +#define SECUREC_ENABLE_FSCANF 0 +#endif + +#endif + +#if SECUREC_IN_KERNEL +#include +#include +#else +#ifndef SECUREC_HAVE_STDIO_H +#define SECUREC_HAVE_STDIO_H 1 +#endif +#ifndef SECUREC_HAVE_STRING_H +#define SECUREC_HAVE_STRING_H 1 +#endif +#ifndef SECUREC_HAVE_STDLIB_H +#define SECUREC_HAVE_STDLIB_H 1 +#endif +#if SECUREC_HAVE_STDIO_H +#include +#endif +#if SECUREC_HAVE_STRING_H +#include +#endif +#if SECUREC_HAVE_STDLIB_H +#include +#endif +#endif + +/* + * If you need high performance, enable the SECUREC_WITH_PERFORMANCE_ADDONS macro, default is enable. + * The macro is automatically closed on the windows platform and linux kernel + */ +#ifndef SECUREC_WITH_PERFORMANCE_ADDONS +#if SECUREC_IN_KERNEL +#define SECUREC_WITH_PERFORMANCE_ADDONS 0 +#else +#define SECUREC_WITH_PERFORMANCE_ADDONS 1 +#endif +#endif + +/* If enable SECUREC_COMPATIBLE_WIN_FORMAT, the output format will be compatible to Windows. */ +#if (defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)) && !defined(SECUREC_COMPATIBLE_LINUX_FORMAT) +#ifndef SECUREC_COMPATIBLE_WIN_FORMAT +#define SECUREC_COMPATIBLE_WIN_FORMAT +#endif +#endif + +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) +/* On windows platform, can't use optimized function for there is no __builtin_constant_p like function */ +/* If need optimized macro, can define this: define __builtin_constant_p(x) 0 */ +#ifdef SECUREC_WITH_PERFORMANCE_ADDONS +#undef SECUREC_WITH_PERFORMANCE_ADDONS +#define SECUREC_WITH_PERFORMANCE_ADDONS 0 +#endif +#endif + +#if defined(__VXWORKS__) || defined(__vxworks) || defined(__VXWORKS) || defined(_VXWORKS_PLATFORM_) || \ + defined(SECUREC_VXWORKS_VERSION_5_4) +#ifndef SECUREC_VXWORKS_PLATFORM +#define SECUREC_VXWORKS_PLATFORM +#endif +#endif + +/* If enable SECUREC_COMPATIBLE_LINUX_FORMAT, the output format will be compatible to Linux. */ +#if !defined(SECUREC_COMPATIBLE_WIN_FORMAT) && !defined(SECUREC_VXWORKS_PLATFORM) +#ifndef SECUREC_COMPATIBLE_LINUX_FORMAT +#define SECUREC_COMPATIBLE_LINUX_FORMAT +#endif +#endif + +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT +#ifndef SECUREC_HAVE_STDDEF_H +#define SECUREC_HAVE_STDDEF_H 1 +#endif +/* Some system may no stddef.h */ +#if SECUREC_HAVE_STDDEF_H +#include +#endif +#endif + +/* + * Add the -DSECUREC_SUPPORT_FORMAT_WARNING compiler option to supoort -Wformat. + * Default does not check the format is that the same data type in the actual code. + * In the product is different in the original data type definition of VxWorks and Linux. + */ +#ifndef SECUREC_SUPPORT_FORMAT_WARNING +#define SECUREC_SUPPORT_FORMAT_WARNING 0 +#endif + +/* SECUREC_PCLINT for tool do not recognize __attribute__ just for pclint */ +#if SECUREC_SUPPORT_FORMAT_WARNING && !defined(SECUREC_PCLINT) +#define SECUREC_ATTRIBUTE(x, y) __attribute__((format(printf, (x), (y)))) +#else +#define SECUREC_ATTRIBUTE(x, y) +#endif + +/* SECUREC_PCLINT for tool do not recognize __builtin_expect, just for pclint */ +#if defined(__GNUC__) && ((__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3))) && !defined(SECUREC_PCLINT) +/* + * This is a built-in function that can be used without a declaration, if you encounter an undeclared compilation + * alarm, you can add -DSECUREC_NEED_BUILTIN_EXPECT_DECLARE to complier options + */ +#ifdef SECUREC_NEED_BUILTIN_EXPECT_DECLARE +long __builtin_expect(long exp, long c); +#endif +#define SECUREC_LIKELY(x) __builtin_expect(!!(x), 1) +#define SECUREC_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define SECUREC_LIKELY(x) (x) +#define SECUREC_UNLIKELY(x) (x) +#endif + +/* Define the max length of the string */ +#ifndef SECUREC_STRING_MAX_LEN +#define SECUREC_STRING_MAX_LEN 0x7fffffffUL +#endif +#define SECUREC_WCHAR_STRING_MAX_LEN (SECUREC_STRING_MAX_LEN / sizeof(wchar_t)) + +/* Add SECUREC_MEM_MAX_LEN for memcpy and memmove */ +#ifndef SECUREC_MEM_MAX_LEN +#define SECUREC_MEM_MAX_LEN 0x7fffffffUL +#endif +#define SECUREC_WCHAR_MEM_MAX_LEN (SECUREC_MEM_MAX_LEN / sizeof(wchar_t)) + +#if SECUREC_STRING_MAX_LEN > 0x7fffffff +#error "max string is 2G" +#endif + +#if (defined(__GNUC__) && defined(__SIZEOF_POINTER__)) +#if (__SIZEOF_POINTER__ != 4) && (__SIZEOF_POINTER__ != 8) +#error "unsupported system" +#endif +#endif + +#if defined(_WIN64) || defined(WIN64) || defined(__LP64__) || defined(_LP64) +#define SECUREC_ON_64BITS +#endif + +#if (!defined(SECUREC_ON_64BITS) && defined(__GNUC__) && defined(__SIZEOF_POINTER__)) +#if __SIZEOF_POINTER__ == 8 +#define SECUREC_ON_64BITS +#endif +#endif + +#if defined(__SVR4) || defined(__svr4__) +#define SECUREC_ON_SOLARIS +#endif + +#if (defined(__hpux) || defined(_AIX) || defined(SECUREC_ON_SOLARIS)) +#define SECUREC_ON_UNIX +#endif + +/* + * Codes should run under the macro SECUREC_COMPATIBLE_LINUX_FORMAT in unknow system on default, + * and strtold. + * The function strtold is referenced first at ISO9899:1999(C99), and some old compilers can + * not support these functions. Here provides a macro to open these functions: + * SECUREC_SUPPORT_STRTOLD -- If defined, strtold will be used + */ +#ifndef SECUREC_SUPPORT_STRTOLD +#define SECUREC_SUPPORT_STRTOLD 0 +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) +#if defined(__USE_ISOC99) || (defined(_AIX) && defined(_ISOC99_SOURCE)) || (defined(__hpux) && defined(__ia64)) || \ + (defined(SECUREC_ON_SOLARIS) && (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \ + defined(_STDC_C99) || defined(__EXTENSIONS__)) +#undef SECUREC_SUPPORT_STRTOLD +#define SECUREC_SUPPORT_STRTOLD 1 +#endif +#endif +#if ((defined(SECUREC_WRLINUX_BELOW4) || defined(_WRLINUX_BELOW4_))) +#undef SECUREC_SUPPORT_STRTOLD +#define SECUREC_SUPPORT_STRTOLD 0 +#endif +#endif + +#if SECUREC_WITH_PERFORMANCE_ADDONS + +#ifndef SECUREC_TWO_MIN +#define SECUREC_TWO_MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* For strncpy_s performance optimization */ +#define SECUREC_STRNCPY_SM(dest, destMax, src, count) \ + (((void *)(dest) != NULL && (void *)(src) != NULL && (size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN) && \ + (SECUREC_TWO_MIN((size_t)(count), strlen(src)) + 1) <= (size_t)(destMax)) ? \ + (((size_t)(count) < strlen(src)) ? \ + (memcpy((dest), (src), (count)), *((char *)(dest) + (count)) = '\0', EOK) : \ + (memcpy((dest), (src), strlen(src) + 1), EOK)) : \ + (strncpy_error((dest), (destMax), (src), (count)))) + +#define SECUREC_STRCPY_SM(dest, destMax, src) \ + (((void *)(dest) != NULL && (void *)(src) != NULL && (size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN) && \ + (strlen(src) + 1) <= (size_t)(destMax)) ? \ + (memcpy((dest), (src), strlen(src) + 1), EOK) : \ + (strcpy_error((dest), (destMax), (src)))) + +/* For strcat_s performance optimization */ +#if defined(__GNUC__) +#define SECUREC_STRCAT_SM(dest, destMax, src) \ + ({ \ + int catRet = EOK; \ + if ((void *)(dest) != NULL && (void *)(src) != NULL && (size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN)) { \ + char *catTmpDst = (char *)(dest); \ + size_t catRestSize = (destMax); \ + while (catRestSize > 0 && *catTmpDst != '\0') { \ + ++catTmpDst; \ + --catRestSize; \ + } \ + if (catRestSize == 0) { \ + catRet = EINVAL; \ + } else if ((strlen(src) + 1) <= catRestSize) { \ + memcpy(catTmpDst, (src), strlen(src) + 1); \ + catRet = EOK; \ + } else { \ + catRet = ERANGE; \ + } \ + if (catRet != EOK) { \ + catRet = strcat_s((dest), (destMax), (src)); \ + } \ + } else { \ + catRet = strcat_s((dest), (destMax), (src)); \ + } \ + catRet; \ + }) +#else +#define SECUREC_STRCAT_SM(dest, destMax, src) strcat_s((dest), (destMax), (src)) +#endif + +/* For strncat_s performance optimization */ +#if defined(__GNUC__) +#define SECUREC_STRNCAT_SM(dest, destMax, src, count) \ + ({ \ + int ncatRet = EOK; \ + if ((void *)(dest) != NULL && (void *)(src) != NULL && (size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN) && \ + (((unsigned long long)(count) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN)) { \ + char *ncatTmpDest = (char *)(dest); \ + size_t ncatRestSize = (size_t)(destMax); \ + while (ncatRestSize > 0 && *ncatTmpDest != '\0') { \ + ++ncatTmpDest; \ + --ncatRestSize; \ + } \ + if (ncatRestSize == 0) { \ + ncatRet = EINVAL; \ + } else if ((SECUREC_TWO_MIN((count), strlen(src)) + 1) <= ncatRestSize) { \ + if ((size_t)(count) < strlen(src)) { \ + memcpy(ncatTmpDest, (src), (count)); \ + *(ncatTmpDest + (count)) = '\0'; \ + } else { \ + memcpy(ncatTmpDest, (src), strlen(src) + 1); \ + } \ + } else { \ + ncatRet = ERANGE; \ + } \ + if (ncatRet != EOK) { \ + ncatRet = strncat_s((dest), (destMax), (src), (count)); \ + } \ + } else { \ + ncatRet = strncat_s((dest), (destMax), (src), (count)); \ + } \ + ncatRet; \ + }) +#else +#define SECUREC_STRNCAT_SM(dest, destMax, src, count) strncat_s((dest), (destMax), (src), (count)) +#endif + +/* This macro do not check buffer overlap by default */ +#define SECUREC_MEMCPY_SM(dest, destMax, src, count) \ + (!(((size_t)(destMax) == 0) || \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) > SECUREC_MEM_MAX_LEN) || \ + ((size_t)(count) > (size_t)(destMax)) || ((void *)(dest)) == NULL || ((void *)(src) == NULL)) ? \ + (memcpy((dest), (src), (count)), EOK) : \ + (memcpy_s((dest), (destMax), (src), (count)))) + +#define SECUREC_MEMSET_SM(dest, destMax, c, count) \ + (!((((unsigned long long)(destMax) & (unsigned long long)(-2)) > SECUREC_MEM_MAX_LEN) || \ + ((void *)(dest) == NULL) || ((size_t)(count) > (size_t)(destMax))) ? \ + (memset((dest), (c), (count)), EOK) : \ + (memset_s((dest), (destMax), (c), (count)))) + +#endif +#endif /* __SECURECTYPE_H__A7BBB686_AADA_451B_B9F9_44DACDAE18A7 */ diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/fscanf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/fscanf_s.c new file mode 100644 index 000000000..ff607f232 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/fscanf_s.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securec.h" + +/* + * + * The fscanf_s function is equivalent to fscanf except that the c, s, + * and [ conversion specifiers apply to a pair of arguments (unless assignment suppression is indicated by a*) + * The fscanf function reads data from the current position of stream into + * the locations given by argument (if any). Each argument must be a pointer + * to a variable of a type that corresponds to a type specifier in format. + * format controls the interpretation of the input fields and has the same + * form and function as the format argument for scanf. + * + * + * stream Pointer to FILE structure. + * format Format control string, see Format Specifications. + * ... Optional arguments. + * + * + * ... The convered value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int fscanf_s(FILE *stream, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vfscanf_s(stream, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/fwscanf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/fwscanf_s.c new file mode 100644 index 000000000..e60b3a5df --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/fwscanf_s.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securec.h" + +/* + * + * The fwscanf_s function is the wide-character equivalent of the fscanf_s function + * The fwscanf_s function reads data from the current position of stream into + * the locations given by argument (if any). Each argument must be a pointer + * to a variable of a type that corresponds to a type specifier in format. + * format controls the interpretation of the input fields and has the same + * form and function as the format argument for scanf. + * + * + * stream Pointer to FILE structure. + * format Format control string, see Format Specifications. + * ... Optional arguments. + * + * + * ... The converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int fwscanf_s(FILE *stream, const wchar_t *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vfwscanf_s(stream, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/gets_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/gets_s.c new file mode 100644 index 000000000..95bd72ea2 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/gets_s.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securecutil.h" + +SECUREC_INLINE void SecTrimCRLF(char *buffer, size_t len) +{ + int i; + /* No need to determine whether integer overflow exists */ + for (i = (int)(len - 1); i >= 0 && (buffer[i] == '\r' || buffer[i] == '\n'); --i) { + buffer[i] = '\0'; + } +} + +/* + * + * The gets_s function reads at most one less than the number of characters + * specified by destMax from the std input stream, into the array pointed to by buffer + * The line consists of all characters up to and including + * the first newline character ('\n'). gets_s then replaces the newline + * character with a null character ('\0') before returning the line. + * If the first character read is the end-of-file character, a null character + * is stored at the beginning of buffer and NULL is returned. + * + * + * buffer Storage location for input string. + * numberOfElements The size of the buffer. + * + * + * buffer is updated + * + * + * buffer Successful operation + * NULL Improper parameter or read fail + */ +char *gets_s(char *buffer, size_t numberOfElements) +{ + size_t len; +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT + size_t bufferSize = ((numberOfElements == (size_t)-1) ? SECUREC_STRING_MAX_LEN : numberOfElements); +#else + size_t bufferSize = numberOfElements; +#endif + + if (buffer == NULL || bufferSize == 0 || bufferSize > SECUREC_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_PARAMTER("gets_s"); + return NULL; + } + + if (fgets(buffer, (int)bufferSize, SECUREC_STREAM_STDIN) == NULL) { + return NULL; + } + + len = strlen(buffer); + if (len > 0 && len < bufferSize) { + SecTrimCRLF(buffer, len); + } + + return buffer; +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/input.inl b/http/services/netmanagernative/common/huawei_secure_c/src/input.inl new file mode 100644 index 000000000..95320973e --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/input.inl @@ -0,0 +1,2188 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +/* + * [Standardize-exceptions] Use unsafe function: Performance-sensitive + * [reason] Always used in the performance critical path, + * and sufficient input validation is performed before calling + */ + +#ifndef INPUT_INL_5D13A042_DC3F_4ED9_A8D1_882811274C27 +#define INPUT_INL_5D13A042_DC3F_4ED9_A8D1_882811274C27 + +#if SECUREC_IN_KERNEL +#if !defined(SECUREC_CTYPE_MACRO_ADAPT) +#include +#endif +#ifndef EOF +#define EOF (-1) +#endif +#else +#if !defined(SECUREC_SYSAPI4VXWORKS) && !defined(SECUREC_CTYPE_MACRO_ADAPT) +#include +#ifdef SECUREC_FOR_WCHAR +#include /* For iswspace */ +#endif +#endif +#endif + +#define SECUREC_NUM_WIDTH_SHORT 0 +#define SECUREC_NUM_WIDTH_INT 1 +#define SECUREC_NUM_WIDTH_LONG 2 +#define SECUREC_NUM_WIDTH_LONG_LONG 3 /* Also long double */ + +#define SECUREC_BUFFERED_BLOK_SIZE 1024 + +#if defined(SECUREC_VXWORKS_PLATFORM) && !defined(va_copy) && !defined(__va_copy) +/* The name is the same as system macro. */ +#define __va_copy(d, s) do { \ + size_t size_of_d = (size_t)sizeof(d); \ + size_t size_of_s = (size_t)sizeof(s); \ + if (size_of_d != size_of_s) { \ + (void)memcpy((d), (s), sizeof(va_list)); \ + } else { \ + (void)memcpy(&(d), &(s), sizeof(va_list)); \ + } \ +} SECUREC_WHILE_ZERO +#endif + + +#define SECUREC_MULTI_BYTE_MAX_LEN 6 + +/* Compatibility macro name cannot be modifie */ +#ifndef UNALIGNED +#if !(defined(_M_IA64)) && !(defined(_M_AMD64)) +#define UNALIGNED +#else +#define UNALIGNED __unaligned +#endif +#endif + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) +/* Max 64bit value is 0xffffffffffffffff */ +#define SECUREC_MAX_64BITS_VALUE 18446744073709551615ULL +#define SECUREC_MAX_64BITS_VALUE_DIV_TEN 1844674407370955161ULL +#define SECUREC_MAX_64BITS_VALUE_CUT_LAST_DIGIT 18446744073709551610ULL +#define SECUREC_MIN_64BITS_NEG_VALUE 9223372036854775808ULL +#define SECUREC_MAX_64BITS_POS_VALUE 9223372036854775807ULL +#define SECUREC_MIN_32BITS_NEG_VALUE 2147483648ULL +#define SECUREC_MAX_32BITS_POS_VALUE 2147483647ULL +#define SECUREC_MAX_32BITS_VALUE 4294967295ULL +#define SECUREC_MAX_32BITS_VALUE_INC 4294967296ULL +#define SECUREC_MAX_32BITS_VALUE_DIV_TEN 429496729ULL +#define SECUREC_LONG_BIT_NUM ((unsigned int)(sizeof(long) << 3U)) +/* Use ULL to clean up cl6x compilation alerts */ +#define SECUREC_MAX_LONG_POS_VALUE ((unsigned long)(1ULL << (SECUREC_LONG_BIT_NUM - 1)) - 1) +#define SECUREC_MIN_LONG_NEG_VALUE ((unsigned long)(1ULL << (SECUREC_LONG_BIT_NUM - 1))) + +/* Covert to long long to clean up cl6x compilation alerts */ +#define SECUREC_LONG_HEX_BEYOND_MAX(number) (((unsigned long long)(number) >> (SECUREC_LONG_BIT_NUM - 4U)) > 0) +#define SECUREC_LONG_OCTAL_BEYOND_MAX(number) (((unsigned long long)(number) >> (SECUREC_LONG_BIT_NUM - 3U)) > 0) + +#define SECUREC_QWORD_HEX_BEYOND_MAX(number) (((number) >> (64U - 4U)) > 0) +#define SECUREC_QWORD_OCTAL_BEYOND_MAX(number) (((number) >> (64U - 3U)) > 0) + +#define SECUREC_LP64_BIT_WIDTH 64 +#define SECUREC_LP32_BIT_WIDTH 32 +#endif + +#define SECUREC_CHAR(x) (x) +#define SECUREC_BRACE '{' /* [ to { */ + +#ifdef SECUREC_FOR_WCHAR +/* Bits for all wchar, size is 65536/8, only supports wide characters with a maximum length of two bytes */ +#define SECUREC_BRACKET_TABLE_SIZE 8192 +#define SECUREC_EOF WEOF +#define SECUREC_MB_LEN 16 /* Max. # bytes in multibyte char ,see MB_LEN_MAX */ +#else +/* Bits for all char, size is 256/8 */ +#define SECUREC_BRACKET_TABLE_SIZE 32 +#define SECUREC_EOF EOF +#endif + +#if SECUREC_HAVE_WCHART +#define SECUREC_ARRAY_WIDTH_IS_WRONG(spec) ((spec).arrayWidth == 0 || \ + ((spec).isWCharOrLong <= 0 && (spec).arrayWidth > SECUREC_STRING_MAX_LEN) || \ + ((spec).isWCharOrLong > 0 && (spec).arrayWidth > SECUREC_WCHAR_STRING_MAX_LEN)) +#else +#define SECUREC_ARRAY_WIDTH_IS_WRONG(spec) ((spec).arrayWidth == 0 || \ + ((spec).isWCharOrLong <= 0 && (spec).arrayWidth > SECUREC_STRING_MAX_LEN)) +#endif + +/* For next %n */ +#define SECUREC_MEET_EOF_BEFORE_NEXT_N(ch, format) (((ch) == SECUREC_EOF) && \ + ((*(format) != SECUREC_CHAR('%')) || (*((format) + 1) != SECUREC_CHAR('n')))) + +typedef struct { +#ifdef SECUREC_FOR_WCHAR + unsigned char *table; /* Default NULL */ +#else + unsigned char table[SECUREC_BRACKET_TABLE_SIZE]; /* Array length is large enough in application scenarios */ +#endif + unsigned char mask; /* Default 0 */ +} SecBracketTable; + +#ifdef SECUREC_FOR_WCHAR +#define SECUREC_INIT_BRACKET_TABLE { NULL, 0 } +#else +#define SECUREC_INIT_BRACKET_TABLE { {0}, 0 } +#endif + +#if SECUREC_ENABLE_SCANF_FLOAT +typedef struct { + size_t floatStrTotalLen; /* Initialization must be length of buffer in charater */ + size_t floatStrUsedLen; /* Store float string len */ + SecChar buffer[SECUREC_FLOAT_BUFSIZE + 1]; + SecChar *floatStr; /* Initialization must point to buffer */ + SecChar *allocatedFloatStr; /* Initialization must be NULL to store alloced point */ +} SecFloatSpec; +#endif + +typedef struct { + SecInt ch; /* Char read from input */ + int charCount; /* Number of characters processed */ + SecUnsignedInt64 number64; + unsigned long number; + int numberWidth; /* 0 = SHORT, 1 = int, > 1 long or L_DOUBLE */ + int isInt64Arg; /* 1 for 64-bit integer, 0 otherwise */ + int negative; /* 0 is positive */ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + int beyondMax; /* Non-zero means beyond */ +#endif + void *argPtr; /* Variable parameter pointer */ + size_t arrayWidth; /* Length of pointer Variable parameter, in charaters */ + int width; /* Width number in format */ + int widthSet; /* 0 is not set width in format */ + int convChr; /* Lowercase format conversion characters */ + int oriConvChr; /* Store original format conversion, convChr may change when parsing integers */ + signed char isWCharOrLong; /* -1/0 not wchar or long, 1 for wchar or long */ + char suppress; /* 0 is not have %* in format */ +} SecScanSpec; + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) +#define SECUREC_INIT_NUMBER_SPEC { 0, 0, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0 } +#else +#define SECUREC_INIT_NUMBER_SPEC { 0, 0, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0 } +#endif + +#ifdef SECUREC_FOR_WCHAR +#define SECUREC_GETC fgetwc +#define SECUREC_UN_GETC ungetwc +#define SECUREC_CHAR_MASK 0xffff +#else +#define SECUREC_GETC fgetc +#define SECUREC_UN_GETC ungetc +#define SECUREC_CHAR_MASK 0xff +#endif + +/* Record a flag for each bit */ +#define SECUREC_BRACKET_INDEX(x) ((unsigned int)(x) >> 3) +#define SECUREC_BRACKET_VALUE(x) ((unsigned char)(1 << ((unsigned int)(x) & 7))) + +/* + * Set char in %[xxx] into table, only supports wide characters with a maximum length of two bytes + */ +SECUREC_INLINE void SecBracketSetBit(unsigned char *table, SecUnsignedChar ch) +{ + unsigned int tableIndex = SECUREC_BRACKET_INDEX(((unsigned int)(int)(ch) & SECUREC_CHAR_MASK)); + unsigned int tableValue = SECUREC_BRACKET_VALUE(((unsigned int)(int)(ch) & SECUREC_CHAR_MASK)); + /* Do not use |= optimize this code, it will cause compiling warning */ + table[tableIndex] = (unsigned char)(table[tableIndex] | tableValue); +} + +/* + * Determine whether the expression can be satisfied + */ +SECUREC_INLINE int SecCanInputForBracket(int convChr, SecInt ch, const SecBracketTable *bracketTable) +{ + unsigned int tableIndex = SECUREC_BRACKET_INDEX(((unsigned int)(int)(ch) & SECUREC_CHAR_MASK)); + unsigned int tableValue = SECUREC_BRACKET_VALUE(((unsigned int)(int)(ch) & SECUREC_CHAR_MASK)); +#ifdef SECUREC_FOR_WCHAR + return (convChr == SECUREC_BRACE && bracketTable->table != NULL && + ((bracketTable->table[tableIndex] ^ bracketTable->mask) & tableValue)); +#else + return (convChr == SECUREC_BRACE && ((bracketTable->table[tableIndex] ^ bracketTable->mask) & tableValue)); +#endif +} + +/* + * String input ends when blank character is encountered + */ +SECUREC_INLINE int SecCanInputString(int convChr, SecInt ch) +{ + return ((convChr) == SECUREC_CHAR('s') && + (!((ch) >= SECUREC_CHAR('\t') && (ch) <= SECUREC_CHAR('\r')) && (ch) != SECUREC_CHAR(' '))); +} + +/* + * Can input a character when format is %c + */ +SECUREC_INLINE int SecCanInputCharacter(int convChr) +{ + return (convChr == SECUREC_CHAR('c')); +} + +/* + * Determine if it is a 64-bit pointer function + * Return 0 is not ,1 is 64bit pointer + */ +SECUREC_INLINE int SecIs64BitPtr(size_t sizeOfVoidStar) +{ + /* Point size is 4 or 8 , Under the 64 bit system, the value not 0 */ + /* To clear e778 */ + if ((sizeOfVoidStar & sizeof(SecInt64)) != 0) { + return 1; + } + return 0; +} +SECUREC_INLINE int SecIsDigit(SecInt ch); +SECUREC_INLINE int SecIsXdigit(SecInt ch); +SECUREC_INLINE int SecIsSpace(SecInt ch); +SECUREC_INLINE SecInt SecSkipSpaceChar(SecFileStream *stream, int *counter); +SECUREC_INLINE SecInt SecGetChar(SecFileStream *stream, int *counter); +SECUREC_INLINE void SecUnGetChar(SecInt ch, SecFileStream *stream, int *counter); + +#if SECUREC_ENABLE_SCANF_FLOAT + +/* + * Convert a floating point string to a floating point number + */ +SECUREC_INLINE void SecAssignFloat(const char *floatStr, int numberWidth, void *argPtr) +{ + char *endPtr = NULL; + double d; +#if SECUREC_SUPPORT_STRTOLD + if (numberWidth == SECUREC_NUM_WIDTH_LONG_LONG) { + long double d2 = strtold(floatStr, &endPtr); + *(long double UNALIGNED *)(argPtr) = d2; + return; + } +#endif + d = strtod(floatStr, &endPtr); + if (numberWidth > SECUREC_NUM_WIDTH_INT) { + *(double UNALIGNED *)(argPtr) = (double)d; + } else { + *(float UNALIGNED *)(argPtr) = (float)d; + } +} + +#ifdef SECUREC_FOR_WCHAR +/* + * Convert a floating point wchar string to a floating point number + * Success ret 0 + */ +SECUREC_INLINE int SecAssignFloatW(const SecFloatSpec *floatSpec, const SecScanSpec *spec) +{ + /* Convert float string */ + size_t mbsLen; + size_t tempFloatStrLen = (size_t)(floatSpec->floatStrTotalLen + 1) * sizeof(wchar_t); + char *tempFloatStr = (char *)SECUREC_MALLOC(tempFloatStrLen); + + if (tempFloatStr == NULL) { + return -1; + } + tempFloatStr[0] = '\0'; + SECUREC_MASK_MSVC_CRT_WARNING + mbsLen = wcstombs(tempFloatStr, floatSpec->floatStr, tempFloatStrLen - 1); + SECUREC_END_MASK_MSVC_CRT_WARNING + /* This condition must satisfy mbsLen is not -1 */ + if (mbsLen < tempFloatStrLen) { + tempFloatStr[mbsLen] = '\0'; + SecAssignFloat(tempFloatStr, spec->numberWidth, spec->argPtr); + } else { + SECUREC_FREE(tempFloatStr); + return -1; + } + SECUREC_FREE(tempFloatStr); + return 0; +} +#endif + +/* + * Init SecFloatSpec befor parse format + */ +SECUREC_INLINE void SecInitFloatSpec(SecFloatSpec *floatSpec) +{ + floatSpec->floatStr = floatSpec->buffer; + floatSpec->allocatedFloatStr = NULL; + floatSpec->floatStrTotalLen = sizeof(floatSpec->buffer) / sizeof(floatSpec->buffer[0]); + floatSpec->floatStr = floatSpec->buffer; + floatSpec->floatStrUsedLen = 0; +} + +SECUREC_INLINE void SecFreeFloatSpec(SecFloatSpec *floatSpec, int *doneCount) +{ + /* LSD 2014.3.6 add, clear the stack data */ + if (memset_s(floatSpec->buffer, sizeof(floatSpec->buffer), 0, sizeof(floatSpec->buffer)) != EOK) { + *doneCount = 0; /* This code just to meet the coding requirements */ + } + /* The pFloatStr can be alloced in SecUpdateFloatString function, clear and free it */ + if (floatSpec->allocatedFloatStr != NULL) { + size_t bufferSize = floatSpec->floatStrTotalLen * sizeof(SecChar); + if (memset_s(floatSpec->allocatedFloatStr, bufferSize, 0, bufferSize) != EOK) { + *doneCount = 0; /* This code just to meet the coding requirements */ + } + SECUREC_FREE(floatSpec->allocatedFloatStr); + floatSpec->allocatedFloatStr = NULL; + floatSpec->floatStr = NULL; + } +} + +/* + * Splice floating point string + * Return 0 OK + */ +SECUREC_INLINE int SecUpdateFloatString(SecChar ch, SecFloatSpec *floatSpec) +{ + floatSpec->floatStr[floatSpec->floatStrUsedLen++] = ch; + if (floatSpec->floatStrUsedLen >= floatSpec->floatStrTotalLen) { + /* Buffer size is len x sizeof(SecChar) */ + size_t oriSize = floatSpec->floatStrTotalLen * sizeof(SecChar); + /* Add one character to clear tool warning */ + size_t nextSize = (oriSize * 2) + sizeof(SecChar); /* Multiply 2 to extend buffer size */ + + /* Prevents integer overflow, the maximum length of SECUREC_MAX_WIDTH_LEN is enough */ + if (nextSize <= SECUREC_MAX_WIDTH_LEN) { + void *nextBuffer = (void *)SECUREC_MALLOC(nextSize); + if (nextBuffer == NULL) { + return -1; + } + if (memcpy_s(nextBuffer, nextSize, floatSpec->floatStr, oriSize) != EOK) { + SECUREC_FREE(nextBuffer); /* This is a dead code, just to meet the coding requirements */ + return -1; + } + /* Clear old buffer memory */ + if (memset_s(floatSpec->floatStr, oriSize, 0, oriSize) != EOK) { + SECUREC_FREE(nextBuffer); /* This is a dead code, just to meet the coding requirements */ + return -1; + } + /* Free old allocated buffer */ + if (floatSpec->allocatedFloatStr != NULL) { + SECUREC_FREE(floatSpec->allocatedFloatStr); + } + floatSpec->allocatedFloatStr = (SecChar *)(nextBuffer); /* Use to clear free on stack warning */ + floatSpec->floatStr = (SecChar *)(nextBuffer); + floatSpec->floatStrTotalLen = nextSize / sizeof(SecChar); /* Get buffer total len in character */ + return 0; + } + return -1; /* Next size is beyond max */ + } + return 0; +} + + +/* Do not use localeconv()->decimal_pointif onlay support '.' */ +SECUREC_INLINE int SecIsFloatDecimal(SecChar ch) +{ + return ((ch) == SECUREC_CHAR('.')); +} + +/* + * Scan value of exponent. + * Return 0 OK + */ +SECUREC_INLINE int SecInputFloatE(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec) +{ + spec->ch = SecGetChar(stream, &(spec->charCount)); + if (spec->ch == SECUREC_CHAR('+') || spec->ch == SECUREC_CHAR('-')) { + if (spec->ch == SECUREC_CHAR('-') && SecUpdateFloatString((SecChar)'-', floatSpec) != 0) { + return -1; + } + if (spec->width != 0) { + spec->ch = SecGetChar(stream, &(spec->charCount)); + --spec->width; + } + } + + while (SecIsDigit(spec->ch) && spec->width-- != 0) { + if (SecUpdateFloatString((SecChar)spec->ch, floatSpec) != 0) { + return -1; + } + spec->ch = SecGetChar(stream, &(spec->charCount)); + } + return 0; +} + +/* + * Scan %f. + * Return 0 OK + */ +SECUREC_INLINE int SecInputFloat(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec) +{ + int started = -1; + spec->ch = SecGetChar(stream, &(spec->charCount)); + + floatSpec->floatStrUsedLen = 0; + if (spec->ch == SECUREC_CHAR('-')) { + floatSpec->floatStr[floatSpec->floatStrUsedLen++] = SECUREC_CHAR('-'); + --spec->width; + spec->ch = SecGetChar(stream, &(spec->charCount)); + } else if (spec->ch == SECUREC_CHAR('+')) { + --spec->width; + spec->ch = SecGetChar(stream, &(spec->charCount)); + } + + if (spec->widthSet == 0) { /* Must care width */ + spec->width = -1; /* -1 is unlimited */ + } + + /* Now get integral part */ + while (SecIsDigit(spec->ch) && spec->width-- != 0) { + started = 0; + /* The ch must be '0' - '9' */ + if (SecUpdateFloatString((SecChar)spec->ch, floatSpec) != 0) { + return -1; + } + spec->ch = SecGetChar(stream, &(spec->charCount)); + } + + /* Now get fractional part */ + if (SecIsFloatDecimal((SecChar)spec->ch) && spec->width-- != 0) { + /* Now check for decimal */ + if (SecUpdateFloatString((SecChar)spec->ch, floatSpec) != 0) { + return -1; + } + spec->ch = SecGetChar(stream, &(spec->charCount)); + while (SecIsDigit(spec->ch) && spec->width-- != 0) { + started = 0; + if (SecUpdateFloatString((SecChar)spec->ch, floatSpec) != 0) { + return -1; + } + spec->ch = SecGetChar(stream, &(spec->charCount)); + } + } + + /* Now get exponent part */ + if (started == 0 && (spec->ch == SECUREC_CHAR('e') || spec->ch == SECUREC_CHAR('E')) && spec->width-- != 0) { + if (SecUpdateFloatString((SecChar)'e', floatSpec) != 0) { + return -1; + } + if (SecInputFloatE(stream, spec, floatSpec) != 0) { + return -1; + } + } + /* Un set the last character that is not a floating point number */ + SecUnGetChar(spec->ch, stream, &(spec->charCount)); + /* Make sure have a string terminator, buffer is large enough */ + floatSpec->floatStr[floatSpec->floatStrUsedLen] = SECUREC_CHAR('\0'); + return started; +} +#endif + +#if (!defined(SECUREC_FOR_WCHAR) && SECUREC_HAVE_WCHART && SECUREC_HAVE_MBTOWC) || \ + (!defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_VERSION)) +/* LSD only multi-bytes string need isleadbyte() function */ +SECUREC_INLINE int SecIsLeadByte(SecInt ch) +{ + unsigned int c = (unsigned int)ch; +#if !(defined(_MSC_VER) || defined(_INC_WCTYPE)) + return (int)(c & 0x80); +#else + return (int)isleadbyte((int)(c & 0xff)); +#endif +} +#endif + +/* + * Parsing whether it is a wide character + */ +SECUREC_INLINE void SecUpdateWcharFlagByType(SecUnsignedChar ch, SecScanSpec *spec) +{ + if (spec->isWCharOrLong != 0) { + /* Wide character identifiers have been explicitly set by l or h flag */ + return; + } + + /* Set default flag */ +#if defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_WIN_FORMAT) + spec->isWCharOrLong = 1; /* On windows wide char version %c %s %[ is wide char */ +#else + spec->isWCharOrLong = -1; /* On linux all version %c %s %[ is multi char */ +#endif + + if (ch == SECUREC_CHAR('C') || ch == SECUREC_CHAR('S')) { +#if defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_WIN_FORMAT) + spec->isWCharOrLong = -1; /* On windows wide char version %C %S is multi char */ +#else + spec->isWCharOrLong = 1; /* On linux all version %C %S is wide char */ +#endif + } + + return; +} +/* + * Decode %l %ll + */ +SECUREC_INLINE void SecDecodeScanQualifierL(const SecUnsignedChar **format, SecScanSpec *spec) +{ + const SecUnsignedChar *fmt = *format; + if (*(fmt + 1) == SECUREC_CHAR('l')) { + spec->isInt64Arg = 1; + spec->numberWidth = SECUREC_NUM_WIDTH_LONG_LONG; + ++fmt; + } else { + spec->numberWidth = SECUREC_NUM_WIDTH_LONG; +#if defined(SECUREC_ON_64BITS) && !(defined(SECUREC_COMPATIBLE_WIN_FORMAT)) + /* On window 64 system sizeof long is 32bit */ + spec->isInt64Arg = 1; +#endif + spec->isWCharOrLong = 1; + } + *format = fmt; +} + +/* + * Decode %I %I43 %I64 %Id %Ii %Io ... + * Set finishFlag to 1 finish Flag + */ +SECUREC_INLINE void SecDecodeScanQualifierI(const SecUnsignedChar **format, SecScanSpec *spec, int *finishFlag) +{ + const SecUnsignedChar *fmt = *format; + if ((*(fmt + 1) == SECUREC_CHAR('6')) && + (*(fmt + 2) == SECUREC_CHAR('4'))) { /* Offset 2 for I64 */ + spec->isInt64Arg = 1; + *format = *format + 2; /* Add 2 to skip I64 point to '4' next loop will inc */ + } else if ((*(fmt + 1) == SECUREC_CHAR('3')) && + (*(fmt + 2) == SECUREC_CHAR('2'))) { /* Offset 2 for I32 */ + *format = *format + 2; /* Add 2 to skip I32 point to '2' next loop will inc */ + } else if ((*(fmt + 1) == SECUREC_CHAR('d')) || + (*(fmt + 1) == SECUREC_CHAR('i')) || + (*(fmt + 1) == SECUREC_CHAR('o')) || + (*(fmt + 1) == SECUREC_CHAR('x')) || + (*(fmt + 1) == SECUREC_CHAR('X'))) { + spec->isInt64Arg = SecIs64BitPtr(sizeof(void *)); + } else { + /* For %I */ + spec->isInt64Arg = SecIs64BitPtr(sizeof(void *)); + *finishFlag = 1; + } +} + +SECUREC_INLINE int SecDecodeScanWidth(const SecUnsignedChar **format, SecScanSpec *spec) +{ + const SecUnsignedChar *fmt = *format; + while (SecIsDigit((SecInt)(int)(*fmt))) { + spec->widthSet = 1; + if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(spec->width)) { + return -1; + } + spec->width = (int)SECUREC_MUL_TEN((unsigned int)spec->width) + (unsigned char)(*fmt - SECUREC_CHAR('0')); + ++fmt; + } + *format = fmt; + return 0; +} + +/* + * Init default flags for each format. do not init ch this variable is context-dependent + */ +SECUREC_INLINE void SecSetDefaultScanSpec(SecScanSpec *spec) +{ + /* The ch and charCount member variables cannot be initialized here */ + spec->number64 = 0; + spec->number = 0; + spec->numberWidth = SECUREC_NUM_WIDTH_INT; /* 0 = SHORT, 1 = int, > 1 long or L_DOUBLE */ + spec->isInt64Arg = 0; /* 1 for 64-bit integer, 0 otherwise */ + spec->negative = 0; +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + spec->beyondMax = 0; +#endif + spec->argPtr = NULL; + spec->arrayWidth = 0; + spec->width = 0; + spec->widthSet = 0; + spec->convChr = 0; + spec->oriConvChr = 0; + spec->isWCharOrLong = 0; + spec->suppress = 0; +} + +/* + * Decode qualifier %I %L %h ... + * Set finishFlag to 1 finish Flag + */ +SECUREC_INLINE void SecDecodeScanQualifier(const SecUnsignedChar **format, SecScanSpec *spec, int *finishFlag) +{ + switch ((int)(unsigned char)(**(format))) { + case SECUREC_CHAR('F'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('N'): + break; + case SECUREC_CHAR('h'): + --spec->numberWidth; /* The h for SHORT , hh for CHAR */ + spec->isWCharOrLong = -1; + break; +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + case SECUREC_CHAR('j'): + spec->numberWidth = SECUREC_NUM_WIDTH_LONG_LONG; /* For intmax_t or uintmax_t */ + spec->isInt64Arg = 1; + break; + case SECUREC_CHAR('t'): /* fall-through */ /* FALLTHRU */ +#endif +#if SECUREC_IN_KERNEL + case SECUREC_CHAR('Z'): /* fall-through */ /* FALLTHRU */ +#endif + case SECUREC_CHAR('z'): +#ifdef SECUREC_ON_64BITS + spec->numberWidth = SECUREC_NUM_WIDTH_LONG_LONG; + spec->isInt64Arg = 1; +#else + spec->numberWidth = SECUREC_NUM_WIDTH_LONG; +#endif + break; + case SECUREC_CHAR('L'): /* For long double */ /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('q'): + spec->numberWidth = SECUREC_NUM_WIDTH_LONG_LONG; + spec->isInt64Arg = 1; + break; + case SECUREC_CHAR('l'): + SecDecodeScanQualifierL(format, spec); + break; + case SECUREC_CHAR('w'): + spec->isWCharOrLong = 1; + break; + case SECUREC_CHAR('*'): + spec->suppress = 1; + break; + case SECUREC_CHAR('I'): + SecDecodeScanQualifierI(format, spec, finishFlag); + break; + default: + *finishFlag = 1; + break; + } + +} +/* + * Decode width and qualifier in format + */ +SECUREC_INLINE int SecDecodeScanFlag(const SecUnsignedChar **format, SecScanSpec *spec) +{ + const SecUnsignedChar *fmt = *format; + int finishFlag = 0; + + do { + ++fmt; /* First skip % , next seek fmt */ + /* May %*6d , so put it inside the loop */ + if (SecDecodeScanWidth(&fmt, spec) != 0) { + return -1; + } + SecDecodeScanQualifier(&fmt, spec, &finishFlag); + } while (finishFlag == 0); + *format = fmt; + return 0; +} + +/* + * Judging whether a zeroing buffer is needed according to different formats + */ +SECUREC_INLINE int SecDecodeClearFormat(const SecUnsignedChar *format, int *convChr) +{ + const SecUnsignedChar *fmt = format; + /* To lowercase */ + int ch = (unsigned char)(*fmt) | (SECUREC_CHAR('a') - SECUREC_CHAR('A')); + if (!(ch == SECUREC_CHAR('c') || ch == SECUREC_CHAR('s') || ch == SECUREC_BRACE)) { + return -1; /* First argument is not a string type */ + } + if (ch == SECUREC_BRACE) { +#if !(defined(SECUREC_COMPATIBLE_WIN_FORMAT)) + if (*fmt == SECUREC_CHAR('{')) { + return -1; + } +#endif + ++fmt; + if (*fmt == SECUREC_CHAR('^')) { + ++fmt; + } + if (*fmt == SECUREC_CHAR(']')) { + ++fmt; + } + while (*fmt != SECUREC_CHAR('\0') && *fmt != SECUREC_CHAR(']')) { + ++fmt; + } + if (*fmt == SECUREC_CHAR('\0')) { + return -1; /* Trunc'd format string */ + } + } + *convChr = ch; + return 0; +} + +/* + * Add L'\0' for wchar string , add '\0' for char string + */ +SECUREC_INLINE void SecAddEndingZero(void *ptr, const SecScanSpec *spec) +{ + if (spec->suppress == 0) { + *(char *)ptr = '\0'; +#if SECUREC_HAVE_WCHART + if (spec->isWCharOrLong > 0) { + *(wchar_t UNALIGNED *)ptr = L'\0'; + } +#endif + } +} + +#ifdef SECUREC_FOR_WCHAR +/* + * Clean up the first %s %c buffer to zero for wchar version + */ +void SecClearDestBufW(const wchar_t *buffer, const wchar_t *format, va_list argList) +#else +/* + * Clean up the first %s %c buffer to zero for char version + */ +void SecClearDestBuf(const char *buffer, const char *format, va_list argList) +#endif +{ + + va_list argListSave; /* Backup for argList value, this variable don't need initialized */ + SecScanSpec spec; + int convChr = 0; + const SecUnsignedChar *fmt = (const SecUnsignedChar *)format; + if (fmt == NULL) { + return; + } + + /* Find first % */ + while (*fmt != SECUREC_CHAR('\0') && *fmt != SECUREC_CHAR('%')) { + ++fmt; + } + if (*fmt == SECUREC_CHAR('\0')) { + return; + } + + SecSetDefaultScanSpec(&spec); + if (SecDecodeScanFlag(&fmt, &spec) != 0) { + return; + } + + /* Update wchar flag for %S %C */ + SecUpdateWcharFlagByType(*fmt, &spec); + + if (spec.suppress != 0 || SecDecodeClearFormat(fmt, &convChr) != 0) { + return; + } + + if (buffer != NULL && *buffer != SECUREC_CHAR('\0') && convChr != SECUREC_CHAR('s')) { + /* + * When buffer not empty just clear %s. + * Example call sscanf by argment of (" \n", "%s", s, sizeof(s)) + */ + return; + } + (void)memset(&argListSave, 0, sizeof(va_list)); /* To clear e530 argListSave not initialized */ +#if defined(va_copy) + va_copy(argListSave, argList); +#elif defined(__va_copy) /* For vxworks */ + __va_copy(argListSave, argList); +#else + argListSave = argList; +#endif + do { + void *argPtr = (void *)va_arg(argListSave, void *); + /* Get the next argument - size of the array in characters */ + size_t arrayWidth = ((size_t)(va_arg(argListSave, size_t))) & 0xFFFFFFFFUL; + va_end(argListSave); + /* To clear e438 last value assigned not used , the compiler will optimize this code */ + (void)argListSave; + /* There is no need to judge the upper limit */ + if (arrayWidth == 0 || argPtr == NULL) { + return; + } + + /* Clear one char */ + SecAddEndingZero(argPtr, &spec); + } SECUREC_WHILE_ZERO; + return; + +} + +/* + * Assign number to output buffer + */ +SECUREC_INLINE void SecAssignNumber(const SecScanSpec *spec) +{ + void *argPtr = spec->argPtr; + if (spec->isInt64Arg != 0) { +#if defined(SECUREC_VXWORKS_PLATFORM) +#if defined(SECUREC_VXWORKS_PLATFORM_COMP) + *(SecInt64 UNALIGNED *)argPtr = (SecInt64)(spec->number64); +#else + /* Take number64 as unsigned number unsigned to int clear Compile warning */ + *(SecInt64 UNALIGNED *)argPtr = *(SecUnsignedInt64 *)(&(spec->number64)); +#endif +#else + /* Take number64 as unsigned number */ + *(SecInt64 UNALIGNED *)argPtr = (SecInt64)(spec->number64); +#endif + return; + } + if (spec->numberWidth > SECUREC_NUM_WIDTH_INT) { + /* Take number as unsigned number */ + *(long UNALIGNED *)argPtr = (long)(spec->number); + } else if (spec->numberWidth == SECUREC_NUM_WIDTH_INT) { + *(int UNALIGNED *)argPtr = (int)(spec->number); + } else if (spec->numberWidth == SECUREC_NUM_WIDTH_SHORT) { + /* Take number as unsigned number */ + *(short UNALIGNED *)argPtr = (short)(spec->number); + } else { /* < 0 for hh format modifier */ + /* Take number as unsigned number */ + *(char UNALIGNED *)argPtr = (char)(spec->number); + } +} + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) +/* + * Judge the long bit width + */ +SECUREC_INLINE int SecIsLongBitEqual(int bitNum) +{ + return (unsigned int)bitNum == SECUREC_LONG_BIT_NUM; +} +#endif + +/* + * Convert hexadecimal characters to decimal value + */ +SECUREC_INLINE int SecHexValueOfChar(SecInt ch) +{ + /* Use isdigt Causing tool false alarms */ + return (int)((ch >= '0' && ch <= '9') ? ((unsigned char)ch - '0') : + ((((unsigned char)ch | (unsigned char)('a' - 'A')) - ('a')) + 10)); /* Adding 10 is to hex value */ +} + +/* + * Parse decimal character to integer for 32bit . + */ +static void SecDecodeNumberDecimal(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + unsigned long decimalEdge = SECUREC_MAX_32BITS_VALUE_DIV_TEN; +#ifdef SECUREC_ON_64BITS + if (SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH)) { + decimalEdge = (unsigned long)SECUREC_MAX_64BITS_VALUE_DIV_TEN; + } +#endif + if (spec->number > decimalEdge) { + spec->beyondMax = 1; + } +#endif + spec->number = SECUREC_MUL_TEN(spec->number); +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (spec->number == SECUREC_MUL_TEN(decimalEdge)) { + SecUnsignedInt64 number64As = (unsigned long)SECUREC_MAX_64BITS_VALUE - spec->number; + if (number64As < (SecUnsignedInt64)((SecUnsignedInt)spec->ch - SECUREC_CHAR('0'))) { + spec->beyondMax = 1; + } + } +#endif + spec->number += (unsigned long)((SecUnsignedInt)spec->ch - SECUREC_CHAR('0')); + +} + + +/* + * Parse Hex character to integer for 32bit . + */ +static void SecDecodeNumberHex(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (SECUREC_LONG_HEX_BEYOND_MAX(spec->number)) { + spec->beyondMax = 1; + } +#endif + spec->number = SECUREC_MUL_SIXTEEN(spec->number); + spec->number += (unsigned long)(unsigned int)SecHexValueOfChar(spec->ch); +} + + +/* + * Parse Octal character to integer for 32bit . + */ +static void SecDecodeNumberOctal(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (SECUREC_LONG_OCTAL_BEYOND_MAX(spec->number)) { + spec->beyondMax = 1; + } +#endif + spec->number = SECUREC_MUL_EIGHT(spec->number); + spec->number += (unsigned long)((SecUnsignedInt)spec->ch - SECUREC_CHAR('0')); +} + + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) +/* Compatible with integer negative values other than int */ +SECUREC_INLINE void SecFinishNumberNegativeOther(SecScanSpec *spec) +{ + if (spec->oriConvChr == SECUREC_CHAR('d') || spec->oriConvChr == SECUREC_CHAR('i')) { + if (spec->number > SECUREC_MIN_LONG_NEG_VALUE) { + spec->number = SECUREC_MIN_LONG_NEG_VALUE; + } else { + spec->number = (unsigned long)(-(long)spec->number); + } + if (spec->beyondMax != 0) { + if (spec->numberWidth < SECUREC_NUM_WIDTH_INT) { + spec->number = 0; + } else if (spec->numberWidth == SECUREC_NUM_WIDTH_LONG) { + spec->number = SECUREC_MIN_LONG_NEG_VALUE; + } + } + } else { /* For o, u, x, X, p */ + spec->number = (unsigned long)(-(long)spec->number); + if (spec->beyondMax != 0) { + spec->number |= (unsigned long)SECUREC_MAX_64BITS_VALUE; + } + } +} +/* Compatible processing of integer negative numbers */ +SECUREC_INLINE void SecFinishNumberNegativeInt(SecScanSpec *spec) +{ + if (spec->oriConvChr == SECUREC_CHAR('d') || spec->oriConvChr == SECUREC_CHAR('i')) { +#ifdef SECUREC_ON_64BITS + if (SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH)) { + if ((spec->number > SECUREC_MIN_64BITS_NEG_VALUE)) { + spec->number = 0; + } else { + spec->number = (unsigned int)(-(int)spec->number); + } + } +#else + if (SecIsLongBitEqual(SECUREC_LP32_BIT_WIDTH)) { + if ((spec->number > SECUREC_MIN_32BITS_NEG_VALUE)) { + spec->number = SECUREC_MIN_32BITS_NEG_VALUE; + } else { + spec->number = (unsigned int)(-(int)spec->number); + } + } +#endif + if (spec->beyondMax != 0) { +#ifdef SECUREC_ON_64BITS + if (SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH)) { + spec->number = 0; + } +#else + if (SecIsLongBitEqual(SECUREC_LP32_BIT_WIDTH)) { + spec->number = SECUREC_MIN_32BITS_NEG_VALUE; + } +#endif + } + } else { /* For o, u, x, X ,p */ +#ifdef SECUREC_ON_64BITS + if (spec->number > SECUREC_MAX_32BITS_VALUE_INC) { + spec->number = SECUREC_MAX_32BITS_VALUE; + } else { + spec->number = (unsigned int)(-(int)spec->number); + } +#else + spec->number = (unsigned int)(-(int)spec->number); +#endif + if (spec->beyondMax != 0) { + spec->number |= (unsigned long)SECUREC_MAX_64BITS_VALUE; + } + } +} + +/* Compatible with integer positive values other than int */ +SECUREC_INLINE void SecFinishNumberPositiveOther(SecScanSpec *spec) +{ + if (spec->oriConvChr == SECUREC_CHAR('d') || spec->oriConvChr == SECUREC_CHAR('i')) { + if (spec->number > SECUREC_MAX_LONG_POS_VALUE) { + spec->number = SECUREC_MAX_LONG_POS_VALUE; + } + if ((spec->beyondMax != 0 && spec->numberWidth < SECUREC_NUM_WIDTH_INT)) { + spec->number |= (unsigned long)SECUREC_MAX_64BITS_VALUE; + } + if (spec->beyondMax != 0 && spec->numberWidth == SECUREC_NUM_WIDTH_LONG) { + spec->number = SECUREC_MAX_LONG_POS_VALUE; + } + } else { + if (spec->beyondMax != 0) { + spec->number |= (unsigned long)SECUREC_MAX_64BITS_VALUE; + } + } +} + +/* Compatible processing of integer positive numbers */ +SECUREC_INLINE void SecFinishNumberPositiveInt(SecScanSpec *spec) +{ + if (spec->oriConvChr == SECUREC_CHAR('d') || spec->oriConvChr == SECUREC_CHAR('i')) { +#ifdef SECUREC_ON_64BITS + if (SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH)) { + if (spec->number > SECUREC_MAX_64BITS_POS_VALUE) { + spec->number |= (unsigned long)SECUREC_MAX_64BITS_VALUE; + } + } + if (spec->beyondMax != 0 && SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH)) { + spec->number |= (unsigned long)SECUREC_MAX_64BITS_VALUE; + } +#else + if (SecIsLongBitEqual(SECUREC_LP32_BIT_WIDTH)) { + if (spec->number > SECUREC_MAX_32BITS_POS_VALUE) { + spec->number = SECUREC_MAX_32BITS_POS_VALUE; + } + } + if (spec->beyondMax != 0 && SecIsLongBitEqual(SECUREC_LP32_BIT_WIDTH)) { + spec->number = SECUREC_MAX_32BITS_POS_VALUE; + } +#endif + } else { /* For o,u,x,X,p */ + if (spec->beyondMax != 0) { + spec->number = SECUREC_MAX_32BITS_VALUE; + } + } +} + +#endif + +/* + * Parse decimal character to integer for 64bit . + */ +static void SecDecodeNumber64Decimal(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (spec->number64 > SECUREC_MAX_64BITS_VALUE_DIV_TEN) { + spec->beyondMax = 1; + } +#endif + spec->number64 = SECUREC_MUL_TEN(spec->number64); +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (spec->number64 == SECUREC_MAX_64BITS_VALUE_CUT_LAST_DIGIT) { + SecUnsignedInt64 number64As = (SecUnsignedInt64)SECUREC_MAX_64BITS_VALUE - spec->number64; + if (number64As < (SecUnsignedInt64)((SecUnsignedInt)spec->ch - SECUREC_CHAR('0'))) { + spec->beyondMax = 1; + } + } +#endif + spec->number64 += (SecUnsignedInt64)((SecUnsignedInt)spec->ch - SECUREC_CHAR('0')); +} + +/* + * Parse Hex character to integer for 64bit . + */ +static void SecDecodeNumber64Hex(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (SECUREC_QWORD_HEX_BEYOND_MAX(spec->number64)) { + spec->beyondMax = 1; + } +#endif + spec->number64 = SECUREC_MUL_SIXTEEN(spec->number64); + spec->number64 += (SecUnsignedInt64)(unsigned int)SecHexValueOfChar(spec->ch); + +} + +/* + * Parse Octal character to integer for 64bit . + */ +static void SecDecodeNumber64Octal(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (SECUREC_QWORD_OCTAL_BEYOND_MAX(spec->number64)) { + spec->beyondMax = 1; + } +#endif + spec->number64 = SECUREC_MUL_EIGHT(spec->number64); + spec->number64 += (SecUnsignedInt64)((SecUnsignedInt)spec->ch - SECUREC_CHAR('0')); +} + +#define SECUREC_DECODE_NUMBER_FUNC_NUM 2 +/* Function name cannot add address symbol, causing 546 alarm */ +static void (*g_secDecodeNumberHex[SECUREC_DECODE_NUMBER_FUNC_NUM])(SecScanSpec *spec) = \ + { SecDecodeNumberHex, SecDecodeNumber64Hex }; +static void (*g_secDecodeNumberOctal[SECUREC_DECODE_NUMBER_FUNC_NUM])(SecScanSpec *spec) = \ + { SecDecodeNumberOctal, SecDecodeNumber64Octal }; +static void (*g_secDecodeNumberDecimal[SECUREC_DECODE_NUMBER_FUNC_NUM])(SecScanSpec *spec) = \ + { SecDecodeNumberDecimal, SecDecodeNumber64Decimal }; + +/* + * Parse 64-bit integer formatted input, return 0 when ch is a number. + */ +SECUREC_INLINE int SecDecodeNumber(SecScanSpec *spec) +{ + if (spec->convChr == SECUREC_CHAR('x') || spec->convChr == SECUREC_CHAR('p')) { + if (SecIsXdigit(spec->ch)) { + (*g_secDecodeNumberHex[spec->isInt64Arg])(spec); + } else { + return -1; + } + return 0; + } + if (!(SecIsDigit(spec->ch))) { + return -1; + } + if (spec->convChr == SECUREC_CHAR('o')) { + if (spec->ch < SECUREC_CHAR('8')) { + (*g_secDecodeNumberOctal[spec->isInt64Arg])(spec); + } else { + return -1; + } + } else { /* The convChr is 'd' */ + (*g_secDecodeNumberDecimal[spec->isInt64Arg])(spec); + } + return 0; +} + + +/* + * Complete the final 32-bit integer formatted input + */ +static void SecFinishNumber(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (spec->negative != 0) { + if (spec->numberWidth == SECUREC_NUM_WIDTH_INT) { + SecFinishNumberNegativeInt(spec); + } else { + SecFinishNumberNegativeOther(spec); + } + } else { + if (spec->numberWidth == SECUREC_NUM_WIDTH_INT) { + SecFinishNumberPositiveInt(spec); + } else { + SecFinishNumberPositiveOther(spec); + } + } +#else + if (spec->negative != 0) { +#if defined(__hpux) + if (spec->oriConvChr != SECUREC_CHAR('p')) { + spec->number = (unsigned long)(-(long)spec->number); + } +#else + spec->number = (unsigned long)(-(long)spec->number); +#endif + } +#endif + return; +} + +/* + * Complete the final 64-bit integer formatted input + */ +static void SecFinishNumber64(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (spec->negative != 0) { + if (spec->oriConvChr == SECUREC_CHAR('d') || spec->oriConvChr == SECUREC_CHAR('i')) { + if (spec->number64 > SECUREC_MIN_64BITS_NEG_VALUE) { + spec->number64 = SECUREC_MIN_64BITS_NEG_VALUE; + } else { + spec->number64 = (SecUnsignedInt64)(-(SecInt64)spec->number64); + } + if (spec->beyondMax != 0) { + spec->number64 = SECUREC_MIN_64BITS_NEG_VALUE; + } + } else { /* For o, u, x, X, p */ + spec->number64 = (SecUnsignedInt64)(-(SecInt64)spec->number64); + if (spec->beyondMax != 0) { + spec->number64 = SECUREC_MAX_64BITS_VALUE; + } + } + } else { + if (spec->oriConvChr == SECUREC_CHAR('d') || spec->oriConvChr == SECUREC_CHAR('i')) { + if (spec->number64 > SECUREC_MAX_64BITS_POS_VALUE) { + spec->number64 = SECUREC_MAX_64BITS_POS_VALUE; + } + if (spec->beyondMax != 0) { + spec->number64 = SECUREC_MAX_64BITS_POS_VALUE; + } + } else { + if (spec->beyondMax != 0) { + spec->number64 = SECUREC_MAX_64BITS_VALUE; + } + } + } +#else + if (spec->negative != 0) { +#if defined(__hpux) + if (spec->oriConvChr != SECUREC_CHAR('p')) { + spec->number64 = (SecUnsignedInt64)(-(SecInt64)spec->number64); + } +#else + spec->number64 = (SecUnsignedInt64)(-(SecInt64)spec->number64); +#endif + } +#endif + return; +} +static void (*g_secFinishNumber[SECUREC_DECODE_NUMBER_FUNC_NUM])(SecScanSpec *spec) = \ + { SecFinishNumber, SecFinishNumber64 }; + +#if SECUREC_ENABLE_SCANF_FILE + +/* + * Adjust the pointer position of the file stream + */ +SECUREC_INLINE void SecSeekStream(SecFileStream *stream) +{ + if ((stream->count <= 0) && feof(stream->pf)) { + /* File pointer at the end of file, don't need to seek back */ + stream->base[0] = '\0'; + return; + } + /* LSD seek to original position, bug fix 2014 1 21 */ + if (fseek(stream->pf, stream->oriFilePos, SEEK_SET)) { + /* Seek failed, ignore it */ + stream->oriFilePos = 0; + return; + } + + if (stream->fileRealRead > 0) { /* LSD bug fix. when file reach to EOF, don't seek back */ +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + int loops; + for (loops = 0; loops < (stream->fileRealRead / SECUREC_BUFFERED_BLOK_SIZE); ++loops) { + if (fread(stream->base, (size_t)1, (size_t)SECUREC_BUFFERED_BLOK_SIZE, + stream->pf) != SECUREC_BUFFERED_BLOK_SIZE) { + break; + } + } + if ((stream->fileRealRead % SECUREC_BUFFERED_BLOK_SIZE) != 0) { + size_t len = fread(stream->base, (size_t)((unsigned int)stream->fileRealRead % SECUREC_BUFFERED_BLOK_SIZE), + (size_t)1, stream->pf); + if ((len == 1 || len == 0) && (ftell(stream->pf) < stream->oriFilePos + stream->fileRealRead)) { + (void)fseek(stream->pf, stream->oriFilePos + stream->fileRealRead, SEEK_SET); + } + } + +#else + /* On linux like system */ + if (fseek(stream->pf, stream->oriFilePos + stream->fileRealRead, SEEK_SET)) { + /* Seek failed, ignore it */ + stream->oriFilePos = 0; + } +#endif + } + + return; +} + +/* + * Adjust the pointer position of the file stream and free memory + */ +SECUREC_INLINE void SecAdjustStream(SecFileStream *stream) +{ + if (stream != NULL && (stream->flag & SECUREC_FILE_STREAM_FLAG) && stream->base != NULL) { + SecSeekStream(stream); + SECUREC_FREE(stream->base); + stream->base = NULL; + } + return; +} +#endif + +SECUREC_INLINE void SecSkipSpaceFormat(const SecUnsignedChar **format) +{ + const SecUnsignedChar *fmt = *format; + while (SecIsSpace((SecInt)(int)(*fmt))) { + ++fmt; + } + *format = fmt; +} + +#if !defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_VERSION) +/* + * Handling multi-character characters + */ +SECUREC_INLINE int SecDecodeLeadByte(SecScanSpec *spec, + const SecUnsignedChar **format, SecFileStream *stream, int *counter) +{ +#if SECUREC_HAVE_MBTOWC + const SecUnsignedChar *fmt = *format; + int ch1 = (int)spec->ch; + int ch2 = SecGetChar(stream, counter); + spec->ch = (SecInt)ch2; + if (*fmt == SECUREC_CHAR('\0') || (int)(*fmt) != ch2) { + /* LSD in console mode, ungetc twice may cause problem */ + SecUnGetChar(ch2, stream, counter); + SecUnGetChar(ch1, stream, counter); + return -1; + } + ++fmt; + if (MB_CUR_MAX >= SECUREC_UTF8_BOM_HEADER_SIZE && + (((unsigned char)ch1 & SECUREC_UTF8_LEAD_1ST) == SECUREC_UTF8_LEAD_1ST) && + (((unsigned char)ch2 & SECUREC_UTF8_LEAD_2ND) == SECUREC_UTF8_LEAD_2ND)) { + /* This char is very likely to be a UTF-8 char */ + wchar_t tempWChar; + char temp[SECUREC_MULTI_BYTE_MAX_LEN]; + int ch3 = (int)SecGetChar(stream, counter); + spec->ch = (SecInt)ch3; + temp[0] = (char)ch1; + temp[1] = (char)ch2; /* 1 index of second character */ + temp[2] = (char)ch3; /* 2 index of third character */ + temp[3] = '\0'; /* 3 of string terminator position */ + + if (mbtowc(&tempWChar, temp, sizeof(temp)) > 0) { + /* Succeed */ + if (*fmt == SECUREC_CHAR('\0') || (int)(*fmt) != ch3) { + SecUnGetChar(ch3, stream, counter); + return -1; + } + ++fmt; + *counter = *counter - 1; + } else { + SecUnGetChar(ch3, stream, counter); + } + } + *counter = *counter - 1; /* Only count as one character read */ + *format = fmt; + return 0; +#else + SecUnGetChar(spec->ch, stream, counter); + (void)format; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + return -1; +#endif +} +#endif + +/* + * Resolving sequence of characters from %[ format, format wile point to ']' + */ +SECUREC_INLINE int SecSetupBracketTable(const SecUnsignedChar **format, SecBracketTable *bracketTable) +{ + const SecUnsignedChar *fmt = *format; + SecUnsignedChar prevChar = 0; + SecUnsignedChar last = 0; +#if !(defined(SECUREC_COMPATIBLE_WIN_FORMAT)) + if (*fmt == SECUREC_CHAR('{')) { + return -1; + } +#endif + /* For building "table" data */ + ++fmt; /* Skip [ */ + bracketTable->mask = 0; + if (*fmt == SECUREC_CHAR('^')) { + ++fmt; + bracketTable->mask = (unsigned char)0xff; + } + if (*fmt == SECUREC_CHAR(']')) { + prevChar = SECUREC_CHAR(']'); + ++fmt; + SecBracketSetBit(bracketTable->table, SECUREC_CHAR(']')); + } + while (*fmt != SECUREC_CHAR('\0') && *fmt != SECUREC_CHAR(']')) { + SecUnsignedChar expCh = *(fmt++); + if (expCh != SECUREC_CHAR('-') || prevChar == 0 || *fmt == SECUREC_CHAR(']')) { + /* Normal character */ + prevChar = expCh; + SecBracketSetBit(bracketTable->table, expCh); + } else { + /* For %[a-z] */ + expCh = *(fmt++); /* Get end of range */ + if (prevChar < expCh) { /* %[a-z] */ + last = expCh; + } else { + prevChar = expCh; +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + /* For %[z-a] */ + last = prevChar; +#else + SecBracketSetBit(bracketTable->table, SECUREC_CHAR('-')); + SecBracketSetBit(bracketTable->table, expCh); + continue; +#endif + } + /* Format %[a-\xff] last is 0xFF, condition (rnch <= last) cause dead loop */ + for (expCh = prevChar; expCh < last; ++expCh) { + SecBracketSetBit(bracketTable->table, expCh); + } + SecBracketSetBit(bracketTable->table, last); + prevChar = 0; + } + } + *format = fmt; + return 0; +} + +#ifdef SECUREC_FOR_WCHAR +SECUREC_INLINE int SecInputForWchar(SecScanSpec *spec) +{ + void *endPtr = spec->argPtr; + if (spec->isWCharOrLong > 0) { + *(wchar_t UNALIGNED *)endPtr = (wchar_t)spec->ch; + endPtr = (wchar_t *)endPtr + 1; + --spec->arrayWidth; + } else { +#if SECUREC_HAVE_WCTOMB + int temp; + char tmpBuf[SECUREC_MB_LEN + 1]; + SECUREC_MASK_MSVC_CRT_WARNING temp = wctomb(tmpBuf, (wchar_t)spec->ch); + SECUREC_END_MASK_MSVC_CRT_WARNING + if (temp <= 0 || (size_t)(unsigned int)temp > sizeof(tmpBuf)) { + /* If wctomb error, then ignore character */ + return 0; + } + if (((size_t)(unsigned int)temp) > spec->arrayWidth) { + return -1; + } + if (memcpy_s(endPtr, spec->arrayWidth, tmpBuf, (size_t)(unsigned int)temp) != EOK) { + return -1; + } + endPtr = (char *)endPtr + temp; + spec->arrayWidth -= (size_t)(unsigned int)temp; +#else + return -1; +#endif + } + spec->argPtr = endPtr; + return 0; +} +#endif + +#ifndef SECUREC_FOR_WCHAR +#if SECUREC_HAVE_WCHART +SECUREC_INLINE wchar_t SecConvertInputCharToWchar(SecScanSpec *spec, SecFileStream *stream) +{ + wchar_t tempWChar = L'?'; /* Set default char is ? */ +#if SECUREC_HAVE_MBTOWC + char temp[SECUREC_MULTI_BYTE_MAX_LEN + 1]; + temp[0] = (char)spec->ch; + temp[1] = '\0'; +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + if (SecIsLeadByte(spec->ch)) { + spec->ch = SecGetChar(stream, &(spec->charCount)); + temp[1] = (char)spec->ch; + temp[2] = '\0'; /* 2 of string terminator position */ + } + if (mbtowc(&tempWChar, temp, sizeof(temp)) <= 0) { + /* No string termination error for tool */ + tempWChar = L'?'; + } +#else + if (SecIsLeadByte(spec->ch)) { + int convRes = 0; + int di = 1; + /* On Linux like system, the string is encoded in UTF-8 */ + while (convRes <= 0 && di < (int)MB_CUR_MAX && di < SECUREC_MULTI_BYTE_MAX_LEN) { + spec->ch = SecGetChar(stream, &(spec->charCount)); + temp[di++] = (char)spec->ch; + temp[di] = '\0'; + convRes = mbtowc(&tempWChar, temp, sizeof(temp)); + } + if (convRes <= 0) { + tempWChar = L'?'; + } + } else { + if (mbtowc(&tempWChar, temp, sizeof(temp)) <= 0) { + tempWChar = L'?'; + } + } +#endif +#else + (void)spec; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + (void)stream; /* To clear e438 last value assigned not used , the compiler will optimize this code */ +#endif /* SECUREC_HAVE_MBTOWC */ + + return tempWChar; +} +#endif /* SECUREC_HAVE_WCHART */ + + +SECUREC_INLINE int SecInputForChar(SecScanSpec *spec, SecFileStream *stream) +{ + void *endPtr = spec->argPtr; + if (spec->isWCharOrLong > 0) { +#if SECUREC_HAVE_WCHART + *(wchar_t UNALIGNED *)endPtr = SecConvertInputCharToWchar(spec, stream); + endPtr = (wchar_t *)endPtr + 1; + --spec->arrayWidth; +#else + (void)stream; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + return -1; +#endif + } else { + *(char *)endPtr = (char)spec->ch; + endPtr = (char *)endPtr + 1; + --spec->arrayWidth; + } + spec->argPtr = endPtr; + return 0; +} +#endif + +/* + * Scan digital part of %d %i %o %u %x %p. + * Return 0 OK + */ +SECUREC_INLINE int SecInputNumberDigital(SecFileStream *stream, SecScanSpec *spec) +{ + int loopFlag = 0; + int started = -1; + while (loopFlag == 0) { + /* Decode ch to number */ + loopFlag = SecDecodeNumber(spec); + if (loopFlag == 0) { + started = 0; + if (spec->widthSet != 0 && --spec->width == 0) { + loopFlag = 1; + } else { + spec->ch = SecGetChar(stream, &(spec->charCount)); + } + } else { + SecUnGetChar(spec->ch, stream, &(spec->charCount)); + } + } + /* Handling integer negative numbers and beyond max */ + (*g_secFinishNumber[spec->isInt64Arg])(spec); + return started; + +} + +/* + * Scan %d %i %o %u %x %p. + * Return 0 OK + */ +SECUREC_INLINE int SecInputNumber(SecFileStream *stream, SecScanSpec *spec) +{ + spec->ch = SecGetChar(stream, &(spec->charCount)); + + if (spec->ch == SECUREC_CHAR('+') || spec->ch == SECUREC_CHAR('-')) { + if (spec->ch == SECUREC_CHAR('-')) { + spec->negative = 1; +#if SECUREC_IN_KERNEL + if (spec->convChr == SECUREC_CHAR('x') || + spec->convChr == SECUREC_CHAR('o') || + spec->convChr == SECUREC_CHAR('u')) { + /* In kernel Refuse to enter negative number */ + return -1; + } +#endif + } + if (spec->widthSet != 0 && --spec->width == 0) { + return -1; + } else { + spec->ch = SecGetChar(stream, &(spec->charCount)); + } + } + + if (spec->oriConvChr == SECUREC_CHAR('i')) { + /* The i could be d, o, or x, use d as default */ + spec->convChr = SECUREC_CHAR('d'); + } + + if (spec->oriConvChr == SECUREC_CHAR('x') || spec->oriConvChr == SECUREC_CHAR('i')) { + if (spec->ch != SECUREC_CHAR('0')) { + /* Scan number */ + return SecInputNumberDigital(stream, spec); + } + /* Now input string may be 0x123 or 0X123 or just 0 */ + /* Get next char */ + spec->ch = SecGetChar(stream, &(spec->charCount)); + if ((SecChar)spec->ch == SECUREC_CHAR('x') || (SecChar)spec->ch == SECUREC_CHAR('X')) { + spec->convChr = SECUREC_CHAR('x'); + spec->ch = SecGetChar(stream, &(spec->charCount)); + /* Length of 0x is 2 */ + if (spec->widthSet != 0 && spec->width <= (1 + 1)) { + /* Length not enough for "0x" */ + return -1; + } + spec->width -= 2; /* Subtract 2 for the length of "0x" */ + } else { + if (spec->oriConvChr != SECUREC_CHAR('x')) { + spec->convChr = SECUREC_CHAR('o'); + } + /* Unset the character after 0 back to stream, input only '0' result is OK */ + SecUnGetChar(spec->ch, stream, &(spec->charCount)); + spec->ch = SECUREC_CHAR('0'); + } + } + /* Scan number */ + return SecInputNumberDigital(stream, spec); +} + +/* + * Scan %c %s %[ + * Return 0 OK + */ +SECUREC_INLINE int SecInputString(SecFileStream *stream, SecScanSpec *spec, + const SecBracketTable *bracketTable, int *doneCount) +{ + void *startPtr = spec->argPtr; + int suppressed = 0; + int errNoMem = 0; + + while (spec->widthSet == 0 || spec->width-- != 0) { + spec->ch = SecGetChar(stream, &(spec->charCount)); + /* + * The char condition or string condition and bracket condition. + * Only supports wide characters with a maximum length of two bytes + */ + if (spec->ch != SECUREC_EOF && (SecCanInputCharacter(spec->convChr) || + SecCanInputString(spec->convChr, spec->ch) || + SecCanInputForBracket(spec->convChr, spec->ch, bracketTable))) { + if (spec->suppress != 0) { + /* Used to identify processed data for %*, use argPtr to identify will cause 613, so use suppressed */ + suppressed = 1; + continue; + } + /* Now suppress is not set */ + if (spec->arrayWidth == 0) { + errNoMem = 1; /* We have exhausted the user's buffer */ + break; + } +#ifdef SECUREC_FOR_WCHAR + errNoMem = SecInputForWchar(spec); +#else + errNoMem = SecInputForChar(spec, stream); +#endif + if (errNoMem != 0) { + break; + } + } else { + SecUnGetChar(spec->ch, stream, &(spec->charCount)); + break; + } + } + + if (errNoMem != 0) { + /* In case of error, blank out the input buffer */ + SecAddEndingZero(startPtr, spec); + return -1; + } + + /* No input was scanned */ + if ((spec->suppress != 0 && suppressed == 0) || + (spec->suppress == 0 && startPtr == spec->argPtr)) { + return -1; + } + + if (spec->convChr != 'c') { + /* Add null-terminate for strings */ + SecAddEndingZero(spec->argPtr, spec); + } + if (spec->suppress == 0) { + *doneCount = *doneCount + 1; + } + return 0; +} + +#ifdef SECUREC_FOR_WCHAR +/* + * Alloce buffer for wchar version of %[. + * Return 0 OK + */ +SECUREC_INLINE int SecAllocBracketTable(SecBracketTable *bracketTable) +{ + if (bracketTable->table == NULL) { + /* Table should be freed after use */ + bracketTable->table = (unsigned char *)SECUREC_MALLOC(SECUREC_BRACKET_TABLE_SIZE); + if (bracketTable->table == NULL) { + return -1; + } + } + return 0; +} + +/* + * Free buffer for wchar version of %[ + */ +SECUREC_INLINE void SecFreeBracketTable(SecBracketTable *bracketTable) +{ + if (bracketTable->table != NULL) { + SECUREC_FREE(bracketTable->table); + bracketTable->table = NULL; + } +} +#endif + +#ifdef SECUREC_FOR_WCHAR +/* + * Formatting input core functions for wchar version.Called by a function such as vswscanf_s + */ +int SecInputSW(SecFileStream *stream, const wchar_t *cFormat, va_list argList) +#else +/* + * Formatting input core functions for char version.Called by a function such as vsscanf_s + */ +int SecInputS(SecFileStream *stream, const char *cFormat, va_list argList) +#endif +{ + const SecUnsignedChar *format = (const SecUnsignedChar *)cFormat; + SecBracketTable bracketTable = SECUREC_INIT_BRACKET_TABLE; + SecScanSpec spec; + int doneCount = 0; + int formatError = 0; + int paraIsNull = 0; + int match = 0; /* When % is found , inc this value */ + int errRet = 0; +#if SECUREC_ENABLE_SCANF_FLOAT + SecFloatSpec floatSpec; + SecInitFloatSpec(&floatSpec); +#endif + spec.ch = 0; + spec.charCount = 0; + + /* Format must not NULL, use err < 1 to claer 845 */ + while (errRet < 1 && *format != SECUREC_CHAR('\0')) { + /* Skip space in format and space in input */ + if (SecIsSpace((SecInt)(int)(*format))) { + /* Read first no space char */ + spec.ch = SecSkipSpaceChar(stream, &(spec.charCount)); + if (spec.ch == SECUREC_EOF) { + break; + } + /* Put fist no space char backup */ + SecUnGetChar(spec.ch, stream, &(spec.charCount)); + SecSkipSpaceFormat(&format); + continue; + } + + if (*format != SECUREC_CHAR('%')) { + spec.ch = SecGetChar(stream, &(spec.charCount)); + if ((int)(*(format++)) != (int)(spec.ch)) { + SecUnGetChar(spec.ch, stream, &(spec.charCount)); + break; + } +#if !defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_VERSION) + if (SecIsLeadByte(spec.ch) && SecDecodeLeadByte(&spec, &format, stream) != 0) { + break; + } +#endif + + if (SECUREC_MEET_EOF_BEFORE_NEXT_N(spec.ch, format)) { + break; + } + continue; + } + + /* Now *format is % */ + /* Set default value for each % */ + SecSetDefaultScanSpec(&spec); + if (SecDecodeScanFlag(&format, &spec) != 0) { + formatError = 1; + ++errRet; + continue; + } + /* Update wchar flag for %S %C */ + SecUpdateWcharFlagByType(*format, &spec); + + if (spec.widthSet != 0 && spec.width == 0) { + /* 0 width in format */ + ++errRet; + continue; + } + + spec.convChr = (unsigned char)(*format) | (SECUREC_CHAR('a') - SECUREC_CHAR('A')); /* To lowercase */ + spec.oriConvChr = spec.convChr; + + if (spec.convChr != SECUREC_CHAR('n')) { + if (spec.convChr != SECUREC_CHAR('c') && spec.convChr != SECUREC_BRACE) { + spec.ch = SecSkipSpaceChar(stream, &(spec.charCount)); + } else { + spec.ch = SecGetChar(stream, &(spec.charCount)); + } + if (spec.ch == SECUREC_EOF) { + ++errRet; + continue; + } + } + + /* Now no 0 width in format and get one char from input */ + switch (spec.convChr) { + case SECUREC_CHAR('c'): /* Also 'C' */ + /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('s'): /* Also 'S': */ + /* fall-through */ /* FALLTHRU */ + case SECUREC_BRACE: + /* Check dest buffer and size */ + if (spec.suppress == 0) { + spec.argPtr = (void *)va_arg(argList, void *); + if (spec.argPtr == NULL) { + paraIsNull = 1; + ++errRet; + continue; + } + /* Get the next argument - size of the array in characters */ +#ifdef SECUREC_ON_64BITS + spec.arrayWidth = ((size_t)(va_arg(argList, size_t))) & 0xFFFFFFFFUL; +#else /* !SECUREC_ON_64BITS */ + spec.arrayWidth = (size_t)va_arg(argList, size_t); +#endif + if (SECUREC_ARRAY_WIDTH_IS_WRONG(spec)) { + /* Do not clear buffer just go error */ + ++errRet; + continue; + } + /* One element is needed for '\0' for %s and %[ */ + if (spec.convChr != SECUREC_CHAR('c')) { + --spec.arrayWidth; + } + } else { + /* Set argPtr to NULL is necessary, in supress mode we don't use argPtr to store data */ + spec.argPtr = NULL; + } + + if (spec.convChr == 'c') { + if (spec.widthSet == 0) { + spec.widthSet = 1; + spec.width = 1; + } + } else if (spec.convChr == SECUREC_BRACE) { + /* Malloc when first %[ is meet for wchar version */ +#ifdef SECUREC_FOR_WCHAR + if (SecAllocBracketTable(&bracketTable) != 0) { + ++errRet; + continue; + } +#endif + (void)memset(bracketTable.table, 0, (size_t)SECUREC_BRACKET_TABLE_SIZE); + if (SecSetupBracketTable(&format, &bracketTable) != 0) { + ++errRet; + continue; + } + + if (*format == SECUREC_CHAR('\0')) { + /* Default add string terminator */ + SecAddEndingZero(spec.argPtr, &spec); + ++errRet; + /* Truncated format */ + continue; + } + } + /* Unset last char to stream */ + SecUnGetChar(spec.ch, stream, &(spec.charCount)); + /* Set completed. Now read string */ + if (SecInputString(stream, &spec, &bracketTable, &doneCount) != 0) { + ++errRet; + continue; + } + break; + case SECUREC_CHAR('p'): + /* Make %hp same as %p */ + spec.numberWidth = SECUREC_NUM_WIDTH_INT; +#ifdef SECUREC_ON_64BITS + spec.isInt64Arg = 1; +#endif + /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('o'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('u'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('d'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('i'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('x'): + /* Unset last char to stream */ + SecUnGetChar(spec.ch, stream, &(spec.charCount)); + if (SecInputNumber(stream, &spec) != 0) { + ++errRet; + continue; + } + if (spec.suppress == 0) { + spec.argPtr = (void *)va_arg(argList, void *); + if (spec.argPtr == NULL) { + paraIsNull = 1; + ++errRet; + continue; + } + SecAssignNumber(&spec); + ++doneCount; + } + break; + case SECUREC_CHAR('n'): /* Char count */ + if (spec.suppress == 0) { + spec.argPtr = (void *)va_arg(argList, void *); + if (spec.argPtr == NULL) { + paraIsNull = 1; + ++errRet; + continue; + } + spec.number = (unsigned long)(unsigned int)(spec.charCount); + spec.isInt64Arg = 0; + SecAssignNumber(&spec); + } + break; + case SECUREC_CHAR('e'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('f'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('g'): /* Scan a float */ +#if SECUREC_ENABLE_SCANF_FLOAT + /* Unset last char to stream */ + SecUnGetChar(spec.ch, stream, &(spec.charCount)); + if (SecInputFloat(stream, &spec, &floatSpec) != 0) { + ++errRet; + continue; + } + if (spec.suppress == 0) { + spec.argPtr = (void *)va_arg(argList, void *); + if (spec.argPtr == NULL) { + ++errRet; + paraIsNull = 1; + continue; + } +#ifdef SECUREC_FOR_WCHAR + if (SecAssignFloatW(&floatSpec, &spec) != 0) { + ++errRet; + continue; + } +#else + SecAssignFloat(floatSpec.floatStr, spec.numberWidth, spec.argPtr); +#endif + ++doneCount; + } + + break; +#else /* SECUREC_ENABLE_SCANF_FLOAT */ + ++errRet; + continue; +#endif + default: + if ((int)(*format) != (int)spec.ch) { + SecUnGetChar(spec.ch, stream, &(spec.charCount)); + formatError = 1; + ++errRet; + continue; + } else { + --match; /* Compensate for the self-increment of the following code */ + } + } + + ++match; + ++format; + + if (SECUREC_MEET_EOF_BEFORE_NEXT_N(spec.ch, format)) { + break; + } + } + +#ifdef SECUREC_FOR_WCHAR + SecFreeBracketTable(&bracketTable); +#endif + +#if SECUREC_ENABLE_SCANF_FLOAT + SecFreeFloatSpec(&floatSpec, &doneCount); +#endif + +#if SECUREC_ENABLE_SCANF_FILE + SecAdjustStream(stream); +#endif + + if (spec.ch == SECUREC_EOF) { + return ((doneCount || match) ? doneCount : SECUREC_SCANF_EINVAL); + } else if (formatError != 0 || paraIsNull != 0) { + /* Invalid Input Format or parameter */ + return SECUREC_SCANF_ERROR_PARA; + } + + return doneCount; +} + +#if SECUREC_ENABLE_SCANF_FILE + +#if defined(SECUREC_NO_STD_UNGETC) +/* + * Get char from stream or buffer + */ +SECUREC_INLINE SecInt SecGetCharFromStream(SecFileStream *stream) +{ + SecInt ch; + if (stream->fUnGet == 1) { + ch = (SecInt) stream->lastChar; + stream->fUnGet = 0; + } else { + ch = SECUREC_GETC(stream->pf); + stream->lastChar = (unsigned int)ch; + } + return ch; +} +#else +/* + * Get char from stream use std function + */ +SECUREC_INLINE SecInt SecGetCharFromStream(const SecFileStream *stream) +{ + SecInt ch; + ch = SECUREC_GETC(stream->pf); + return ch; +} +#endif + +/* + * Make data is aligned to SecChar size + */ +SECUREC_INLINE void SecMakeDataIsAligned(SecFileStream *stream) +{ + int remainder = stream->count % (int)sizeof(SecChar); + if (remainder != 0) { + int needLen = (int)sizeof(SecChar) - remainder; + int len = (int)fread(stream->base + stream->count, (size_t)1, (size_t)(unsigned int)needLen, stream->pf); + if (len > 0 && len <= needLen) { + /* When encountering the end of a file, the read length is less than needLen */ + stream->count += len; + } + } +} + +/* + * Try to read the BOM header, when meet a BOM head, discard it + */ +SECUREC_INLINE void SecReadAndSkipBomHeader(SecFileStream *stream) +{ + int bomHeadSize; +#ifdef SECUREC_FOR_WCHAR + bomHeadSize = SECUREC_BOM_HEADER_SIZE; +#else + bomHeadSize = SECUREC_UTF8_BOM_HEADER_SIZE; +#endif + stream->count = (int)fread(stream->base, (size_t)1, (size_t)(unsigned int)bomHeadSize, stream->pf); + if (stream->count < 0 || stream->count > bomHeadSize) { + stream->count = 0; + } +#ifdef SECUREC_FOR_WCHAR + if (stream->count >= SECUREC_BOM_HEADER_SIZE && + (((unsigned char)(stream->base[0]) == SECUREC_BOM_HEADER_LE_1ST && + (unsigned char)(stream->base[1]) == SECUREC_BOM_HEADER_LE_2ST) || + ((unsigned char)(stream->base[0]) == SECUREC_BOM_HEADER_BE_1ST && + (unsigned char)(stream->base[1]) == SECUREC_BOM_HEADER_BE_2ST))) { + /* It's BOM header, discard it */ + stream->count = 0; + } +#else + if (stream->count >= SECUREC_UTF8_BOM_HEADER_SIZE && + (unsigned char)(stream->base[0]) == SECUREC_UTF8_BOM_HEADER_1ST && + (unsigned char)(stream->base[1]) == SECUREC_UTF8_BOM_HEADER_2ND && + (unsigned char)(stream->base[2]) == SECUREC_UTF8_BOM_HEADER_3RD) { /* 2 offset of third head character */ + /* It's BOM header, discard it */ + stream->count = 0; + } +#endif + SecMakeDataIsAligned(stream); +} + +/* + * Get char from file stream or buffer + */ +SECUREC_INLINE SecInt SecGetCharFromFile(SecFileStream *stream) +{ + SecInt ch; + if (stream->count == 0) { + int len; + /* Load file to buffer */ + if (stream->base == NULL) { + stream->oriFilePos = ftell(stream->pf); /* Save original file read position */ + if (stream->oriFilePos == -1) { + /* It may be a pipe stream */ + stream->flag = SECUREC_PIPE_STREAM_FLAG; + return SecGetCharFromStream(stream); + } + /* Reserve the length of BOM head */ + stream->base = (char *)SECUREC_MALLOC(SECUREC_BUFFERED_BLOK_SIZE + + SECUREC_BOM_HEADER_SIZE + SECUREC_UTF8_BOM_HEADER_SIZE); + if (stream->base == NULL) { + return SECUREC_EOF; + } + /* First read file */ + if (stream->oriFilePos == 0) { + SecReadAndSkipBomHeader(stream); + } + } + /* SecReadAndSkipBomHeader has read part of the data, so add offset */ + len = (int)fread(stream->base + stream->count, + (size_t)1, (size_t)SECUREC_BUFFERED_BLOK_SIZE, stream->pf); + if (len < 0 || len > SECUREC_BUFFERED_BLOK_SIZE) { + len = 0; + } + stream->count += len; + stream->cur = stream->base; + stream->flag |= SECUREC_LOAD_FILE_TO_MEM_FLAG; + stream->base[stream->count] = '\0'; /* For tool Warning string null */ + } + /* According wchar_t has two bytes */ + stream->count -= (int)sizeof(SecChar); + ch = (SecInt)((stream->count) >= 0 ? \ + (SecInt)(SECUREC_CHAR_MASK & \ + (unsigned int)(int)(*((const SecChar *)(const void *)stream->cur))) : SECUREC_EOF); + stream->cur += sizeof(SecChar); /* Pointer may be out of bounds, but overread does not occur */ + + if (ch != SECUREC_EOF && stream->base != NULL) { + stream->fileRealRead += (int)sizeof(SecChar); + } + return ch; +} +#endif + +/* + * Get char for wchar version + */ +SECUREC_INLINE SecInt SecGetChar(SecFileStream *stream, int *counter) +{ + SecInt ch = SECUREC_EOF; +#if SECUREC_ENABLE_SCANF_FILE + if ((stream->flag & SECUREC_PIPE_STREAM_FLAG) > 0) { + ch = SecGetCharFromStream(stream); + } else if ((stream->flag & SECUREC_FILE_STREAM_FLAG) > 0) { + ch = SecGetCharFromFile(stream); + } +#endif + if ((stream->flag & SECUREC_MEM_STR_FLAG) > 0) { + /* According wchar_t has two bytes */ + stream->count -= (int)sizeof(SecChar); + ch = (SecInt)((stream->count >= 0) ? \ + (SecInt)(SECUREC_CHAR_MASK & \ + (unsigned int)(int)(*((const SecChar *)(const void *)stream->cur))) : SECUREC_EOF); + stream->cur += sizeof(SecChar); + } + *counter = *counter + 1; + return ch; +} + +/* + * Unget Public realizatio char for wchar and char version + */ +SECUREC_INLINE void SecUnGetCharImpl(SecInt ch, SecFileStream *stream) +{ + if ((stream->flag & SECUREC_PIPE_STREAM_FLAG) > 0) { +#if SECUREC_ENABLE_SCANF_FILE +#if defined(SECUREC_NO_STD_UNGETC) + stream->lastChar = (unsigned int)ch; + stream->fUnGet = 1; +#else + (void)SECUREC_UN_GETC(ch, stream->pf); +#endif +#else + (void)ch; /* To clear e438 last value assigned not used , the compiler will optimize this code */ +#endif + } else if ((stream->flag & SECUREC_MEM_STR_FLAG) || (stream->flag & SECUREC_LOAD_FILE_TO_MEM_FLAG) > 0) { + if (stream->cur > stream->base) { + stream->cur -= sizeof(SecChar); + stream->count += (int)sizeof(SecChar); + } + } +#if SECUREC_ENABLE_SCANF_FILE + if ((stream->flag & SECUREC_FILE_STREAM_FLAG) > 0 && stream->base) { + stream->fileRealRead -= (int)sizeof(SecChar); + } +#endif +} + +/* + * Unget char for char version + */ +SECUREC_INLINE void SecUnGetChar(SecInt ch, SecFileStream *stream, int *counter) +{ + if (ch != SECUREC_EOF) { + SecUnGetCharImpl(ch, stream); + } + *counter = *counter - 1; +} + +/* + * Skip space char by isspace + */ +SECUREC_INLINE SecInt SecSkipSpaceChar(SecFileStream *stream, int *counter) +{ + SecInt ch; + do { + ch = SecGetChar(stream, counter); + } while (ch != SECUREC_EOF && SecIsSpace(ch)); + return ch; +} +#endif /* __INPUT_INL__5D13A042_DC3F_4ED9_A8D1_882811274C27 */ + diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/memcpy_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/memcpy_s.c new file mode 100644 index 000000000..f444b0c92 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/memcpy_s.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +/* + * [Standardize-exceptions] Use unsafe function: Portability + * [reason] Use unsafe function to implement security function to maintain platform compatibility. + * And sufficient input validation is performed before calling + */ + +#include "securecutil.h" + +#ifndef SECUREC_MEMCOPY_WITH_PERFORMANCE +#define SECUREC_MEMCOPY_WITH_PERFORMANCE 0 +#endif + +#if SECUREC_WITH_PERFORMANCE_ADDONS || SECUREC_MEMCOPY_WITH_PERFORMANCE +#ifndef SECUREC_MEMCOPY_THRESHOLD_SIZE +#define SECUREC_MEMCOPY_THRESHOLD_SIZE 64UL +#endif + +#define SECUREC_SMALL_MEM_COPY(dest, src, count) \ + do { \ + if (SECUREC_ADDR_ALIGNED_8(dest) && SECUREC_ADDR_ALIGNED_8(src)) { \ + /* Use struct assignment */ \ + switch (count) { \ + case 1: \ + *(SecStrBuf1 *)(dest) = *(const SecStrBuf1 *)(src); \ + break; \ + case 2: \ + *(SecStrBuf2 *)(dest) = *(const SecStrBuf2 *)(src); \ + break; \ + case 3: \ + *(SecStrBuf3 *)(dest) = *(const SecStrBuf3 *)(src); \ + break; \ + case 4: \ + *(SecStrBuf4 *)(dest) = *(const SecStrBuf4 *)(src); \ + break; \ + case 5: \ + *(SecStrBuf5 *)(dest) = *(const SecStrBuf5 *)(src); \ + break; \ + case 6: \ + *(SecStrBuf6 *)(dest) = *(const SecStrBuf6 *)(src); \ + break; \ + case 7: \ + *(SecStrBuf7 *)(dest) = *(const SecStrBuf7 *)(src); \ + break; \ + case 8: \ + *(SecStrBuf8 *)(dest) = *(const SecStrBuf8 *)(src); \ + break; \ + case 9: \ + *(SecStrBuf9 *)(dest) = *(const SecStrBuf9 *)(src); \ + break; \ + case 10: \ + *(SecStrBuf10 *)(dest) = *(const SecStrBuf10 *)(src); \ + break; \ + case 11: \ + *(SecStrBuf11 *)(dest) = *(const SecStrBuf11 *)(src); \ + break; \ + case 12: \ + *(SecStrBuf12 *)(dest) = *(const SecStrBuf12 *)(src); \ + break; \ + case 13: \ + *(SecStrBuf13 *)(dest) = *(const SecStrBuf13 *)(src); \ + break; \ + case 14: \ + *(SecStrBuf14 *)(dest) = *(const SecStrBuf14 *)(src); \ + break; \ + case 15: \ + *(SecStrBuf15 *)(dest) = *(const SecStrBuf15 *)(src); \ + break; \ + case 16: \ + *(SecStrBuf16 *)(dest) = *(const SecStrBuf16 *)(src); \ + break; \ + case 17: \ + *(SecStrBuf17 *)(dest) = *(const SecStrBuf17 *)(src); \ + break; \ + case 18: \ + *(SecStrBuf18 *)(dest) = *(const SecStrBuf18 *)(src); \ + break; \ + case 19: \ + *(SecStrBuf19 *)(dest) = *(const SecStrBuf19 *)(src); \ + break; \ + case 20: \ + *(SecStrBuf20 *)(dest) = *(const SecStrBuf20 *)(src); \ + break; \ + case 21: \ + *(SecStrBuf21 *)(dest) = *(const SecStrBuf21 *)(src); \ + break; \ + case 22: \ + *(SecStrBuf22 *)(dest) = *(const SecStrBuf22 *)(src); \ + break; \ + case 23: \ + *(SecStrBuf23 *)(dest) = *(const SecStrBuf23 *)(src); \ + break; \ + case 24: \ + *(SecStrBuf24 *)(dest) = *(const SecStrBuf24 *)(src); \ + break; \ + case 25: \ + *(SecStrBuf25 *)(dest) = *(const SecStrBuf25 *)(src); \ + break; \ + case 26: \ + *(SecStrBuf26 *)(dest) = *(const SecStrBuf26 *)(src); \ + break; \ + case 27: \ + *(SecStrBuf27 *)(dest) = *(const SecStrBuf27 *)(src); \ + break; \ + case 28: \ + *(SecStrBuf28 *)(dest) = *(const SecStrBuf28 *)(src); \ + break; \ + case 29: \ + *(SecStrBuf29 *)(dest) = *(const SecStrBuf29 *)(src); \ + break; \ + case 30: \ + *(SecStrBuf30 *)(dest) = *(const SecStrBuf30 *)(src); \ + break; \ + case 31: \ + *(SecStrBuf31 *)(dest) = *(const SecStrBuf31 *)(src); \ + break; \ + case 32: \ + *(SecStrBuf32 *)(dest) = *(const SecStrBuf32 *)(src); \ + break; \ + case 33: \ + *(SecStrBuf33 *)(dest) = *(const SecStrBuf33 *)(src); \ + break; \ + case 34: \ + *(SecStrBuf34 *)(dest) = *(const SecStrBuf34 *)(src); \ + break; \ + case 35: \ + *(SecStrBuf35 *)(dest) = *(const SecStrBuf35 *)(src); \ + break; \ + case 36: \ + *(SecStrBuf36 *)(dest) = *(const SecStrBuf36 *)(src); \ + break; \ + case 37: \ + *(SecStrBuf37 *)(dest) = *(const SecStrBuf37 *)(src); \ + break; \ + case 38: \ + *(SecStrBuf38 *)(dest) = *(const SecStrBuf38 *)(src); \ + break; \ + case 39: \ + *(SecStrBuf39 *)(dest) = *(const SecStrBuf39 *)(src); \ + break; \ + case 40: \ + *(SecStrBuf40 *)(dest) = *(const SecStrBuf40 *)(src); \ + break; \ + case 41: \ + *(SecStrBuf41 *)(dest) = *(const SecStrBuf41 *)(src); \ + break; \ + case 42: \ + *(SecStrBuf42 *)(dest) = *(const SecStrBuf42 *)(src); \ + break; \ + case 43: \ + *(SecStrBuf43 *)(dest) = *(const SecStrBuf43 *)(src); \ + break; \ + case 44: \ + *(SecStrBuf44 *)(dest) = *(const SecStrBuf44 *)(src); \ + break; \ + case 45: \ + *(SecStrBuf45 *)(dest) = *(const SecStrBuf45 *)(src); \ + break; \ + case 46: \ + *(SecStrBuf46 *)(dest) = *(const SecStrBuf46 *)(src); \ + break; \ + case 47: \ + *(SecStrBuf47 *)(dest) = *(const SecStrBuf47 *)(src); \ + break; \ + case 48: \ + *(SecStrBuf48 *)(dest) = *(const SecStrBuf48 *)(src); \ + break; \ + case 49: \ + *(SecStrBuf49 *)(dest) = *(const SecStrBuf49 *)(src); \ + break; \ + case 50: \ + *(SecStrBuf50 *)(dest) = *(const SecStrBuf50 *)(src); \ + break; \ + case 51: \ + *(SecStrBuf51 *)(dest) = *(const SecStrBuf51 *)(src); \ + break; \ + case 52: \ + *(SecStrBuf52 *)(dest) = *(const SecStrBuf52 *)(src); \ + break; \ + case 53: \ + *(SecStrBuf53 *)(dest) = *(const SecStrBuf53 *)(src); \ + break; \ + case 54: \ + *(SecStrBuf54 *)(dest) = *(const SecStrBuf54 *)(src); \ + break; \ + case 55: \ + *(SecStrBuf55 *)(dest) = *(const SecStrBuf55 *)(src); \ + break; \ + case 56: \ + *(SecStrBuf56 *)(dest) = *(const SecStrBuf56 *)(src); \ + break; \ + case 57: \ + *(SecStrBuf57 *)(dest) = *(const SecStrBuf57 *)(src); \ + break; \ + case 58: \ + *(SecStrBuf58 *)(dest) = *(const SecStrBuf58 *)(src); \ + break; \ + case 59: \ + *(SecStrBuf59 *)(dest) = *(const SecStrBuf59 *)(src); \ + break; \ + case 60: \ + *(SecStrBuf60 *)(dest) = *(const SecStrBuf60 *)(src); \ + break; \ + case 61: \ + *(SecStrBuf61 *)(dest) = *(const SecStrBuf61 *)(src); \ + break; \ + case 62: \ + *(SecStrBuf62 *)(dest) = *(const SecStrBuf62 *)(src); \ + break; \ + case 63: \ + *(SecStrBuf63 *)(dest) = *(const SecStrBuf63 *)(src); \ + break; \ + case 64: \ + *(SecStrBuf64 *)(dest) = *(const SecStrBuf64 *)(src); \ + break; \ + default: \ + break; \ + } /* END switch */ \ + } else { \ + char *tmpDest = (char *)(dest); \ + const char *tmpSrc = (const char *)(src); \ + switch (count) { \ + case 64: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 63: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 62: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 61: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 60: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 59: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 58: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 57: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 56: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 55: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 54: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 53: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 52: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 51: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 50: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 49: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 48: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 47: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 46: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 45: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 44: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 43: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 42: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 41: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 40: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 39: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 38: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 37: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 36: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 35: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 34: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 33: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 32: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 31: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 30: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 29: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 28: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 27: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 26: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 25: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 24: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 23: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 22: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 21: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 20: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 19: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 18: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 17: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 16: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 15: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 14: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 13: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 12: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 11: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 10: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 9: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 8: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 7: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 6: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 5: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 4: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 3: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 2: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 1: \ + *(tmpDest++) = *(tmpSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + default: \ + break; \ + } \ + } \ + } \ + SECUREC_WHILE_ZERO + +/* + * Performance optimization + */ +#define SECUREC_MEMCPY_OPT(dest, src, count) \ + do { \ + if ((count) > SECUREC_MEMCOPY_THRESHOLD_SIZE) { \ + SECUREC_MEMCPY_WARP_OPT((dest), (src), (count)); \ + } else { \ + SECUREC_SMALL_MEM_COPY((dest), (src), (count)); \ + } \ + } \ + SECUREC_WHILE_ZERO +#endif + +/* + * Handling errors + */ +SECUREC_INLINE errno_t SecMemcpyError(void *dest, size_t destMax, const void *src, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("memcpy_s"); + return ERANGE; + } + if (dest == NULL || src == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("memcpy_s"); + if (dest != NULL) { + (void)memset(dest, 0, destMax); + return EINVAL_AND_RESET; + } + return EINVAL; + } + if (count > destMax) { + (void)memset(dest, 0, destMax); + SECUREC_ERROR_INVALID_RANGE("memcpy_s"); + return ERANGE_AND_RESET; + } + if (SECUREC_MEMORY_IS_OVERLAP(dest, src, count)) { + (void)memset(dest, 0, destMax); + SECUREC_ERROR_BUFFER_OVERLAP("memcpy_s"); + return EOVERLAP_AND_RESET; + } + /* Count is 0 or dest equal src also ret EOK */ + return EOK; +} + +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) +/* + * The fread API in windows will call memcpy_s and pass 0xffffffff to destMax. + * To avoid the failure of fread, we don't check desMax limit. + */ +#define SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count) \ + (SECUREC_LIKELY((count) <= (destMax) && (dest) != NULL && (src) != NULL && (count) > 0 && \ + SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count)))) +#else +#define SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count) \ + (SECUREC_LIKELY((count) <= (destMax) && (dest) != NULL && (src) != NULL && \ + (destMax) <= SECUREC_MEM_MAX_LEN && (count) > 0 && SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count)))) +#endif + +/* + * + * The memcpy_s function copies n characters from the object pointed to by src into the object pointed to by dest + * + * + * dest Destination buffer. + * destMax Size of the destination buffer. + * src Buffer to copy from. + * count Number of characters to copy + * + * + * dest buffer is updated. + * + * + * EOK Success + * EINVAL dest is NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN + * EINVAL_AND_RESET dest != NULL and src is NULLL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN + * ERANGE destMax > SECUREC_MEM_MAX_LEN or destMax is 0 + * ERANGE_AND_RESET count > destMax and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN + * and dest != NULL and src != NULL + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and + * count <= destMax destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN and dest != NULL + * and src != NULL and dest != src + * + * if an error occured, dest will be filled with 0. + * If the source and destination overlap, the behavior of memcpy_s is undefined. + * Use memmove_s to handle overlapping regions. + */ +errno_t memcpy_s(void *dest, size_t destMax, const void *src, size_t count) +{ + if (SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count)) { +#if SECUREC_MEMCOPY_WITH_PERFORMANCE + SECUREC_MEMCPY_OPT(dest, src, count); +#else + SECUREC_MEMCPY_WARP_OPT(dest, src, count); +#endif + return EOK; + } + /* Meet some runtime violation, return error code */ + return SecMemcpyError(dest, destMax, src, count); +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(memcpy_s); +#endif + +#if SECUREC_WITH_PERFORMANCE_ADDONS +/* + * Performance optimization + */ +errno_t memcpy_sOptAsm(void *dest, size_t destMax, const void *src, size_t count) +{ + if (SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count)) { + SECUREC_MEMCPY_OPT(dest, src, count); + return EOK; + } + /* Meet some runtime violation, return error code */ + return SecMemcpyError(dest, destMax, src, count); +} + +/* Trim judgement on "destMax <= SECUREC_MEM_MAX_LEN" */ +errno_t memcpy_sOptTc(void *dest, size_t destMax, const void *src, size_t count) +{ + if (SECUREC_LIKELY(count <= destMax && dest != NULL && src != NULL && count > 0 && + SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count)))) { + SECUREC_MEMCPY_OPT(dest, src, count); + return EOK; + } + /* Meet some runtime violation, return error code */ + return SecMemcpyError(dest, destMax, src, count); +} +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/memmove_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/memmove_s.c new file mode 100644 index 000000000..2c34f792f --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/memmove_s.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +/* + * [Standardize-exceptions] Use unsafe function: Portability + * [reason] Use unsafe function to implement security function to maintain platform compatibility. + * And sufficient input validation is performed before calling + */ + +#include "securecutil.h" + +#ifdef SECUREC_NOT_CALL_LIBC_CORE_API +/* + * Implementing memory data movement + */ +SECUREC_INLINE void SecUtilMemmove(void *dst, const void *src, size_t count) +{ + unsigned char *pDest = (unsigned char *)dst; + const unsigned char *pSrc = (const unsigned char *)src; + size_t maxCount = count; + + if (dst <= src || pDest >= (pSrc + maxCount)) { + /* + * Non-Overlapping Buffers + * Copy from lower addresses to higher addresses + */ + while (maxCount--) { + *pDest = *pSrc; + ++pDest; + ++pSrc; + } + } else { + /* + * Overlapping Buffers + * Copy from higher addresses to lower addresses + */ + pDest = pDest + maxCount - 1; + pSrc = pSrc + maxCount - 1; + while (maxCount--) { + *pDest = *pSrc; + --pDest; + --pSrc; + } + } +} +#endif + +/* + * + * The memmove_s function copies count bytes of characters from src to dest. + * This function can be assigned correctly when memory overlaps. + * + * dest Destination object. + * destMax Size of the destination buffer. + * src Source object. + * count Number of characters to copy. + * + * + * dest buffer is uptdated. + * + * + * EOK Success + * EINVAL dest is NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN + * EINVAL_AND_RESET dest != NULL and src is NULLL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN + * ERANGE destMax > SECUREC_MEM_MAX_LEN or destMax is 0 + * ERANGE_AND_RESET count > destMax and dest != NULL and src != NULL and destMax != 0 + * and destMax <= SECUREC_MEM_MAX_LEN + * + * If an error occured, dest will be filled with 0 when dest and destMax valid. + * If some regions of the source area and the destination overlap, memmove_s + * ensures that the original source bytes in the overlapping region are copied + * before being overwritten. + */ +errno_t memmove_s(void *dest, size_t destMax, const void *src, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("memmove_s"); + return ERANGE; + } + if (dest == NULL || src == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("memmove_s"); + if (dest != NULL) { + (void)memset(dest, 0, destMax); + return EINVAL_AND_RESET; + } + return EINVAL; + } + if (count > destMax) { + (void)memset(dest, 0, destMax); + SECUREC_ERROR_INVALID_RANGE("memmove_s"); + return ERANGE_AND_RESET; + } + if (dest == src) { + return EOK; + } + + if (count > 0) { +#ifdef SECUREC_NOT_CALL_LIBC_CORE_API + SecUtilMemmove(dest, src, count); +#else + /* Use underlying memmove for performance consideration */ + (void)memmove(dest, src, count); +#endif + } + return EOK; +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(memmove_s); +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/memset_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/memset_s.c new file mode 100644 index 000000000..3bc5a126a --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/memset_s.c @@ -0,0 +1,572 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +/* + * [Standardize-exceptions] Use unsafe function: Portability + * [reason] Use unsafe function to implement security function to maintain platform compatibility. + * And sufficient input validation is performed before calling + */ + +#include "securecutil.h" + +#ifndef SECUREC_MEMSET_WITH_PERFORMANCE +#define SECUREC_MEMSET_WITH_PERFORMANCE 0 +#endif + +#define SECUREC_MEMSET_PARAM_OK(dest, destMax, count) \ + (SECUREC_LIKELY((destMax) <= SECUREC_MEM_MAX_LEN && (dest) != NULL && (count) <= (destMax))) + +#if SECUREC_WITH_PERFORMANCE_ADDONS || SECUREC_MEMSET_WITH_PERFORMANCE + +/* Use union to clear strict-aliasing warning */ +typedef union { + SecStrBuf32 buf32; + SecStrBuf31 buf31; + SecStrBuf30 buf30; + SecStrBuf29 buf29; + SecStrBuf28 buf28; + SecStrBuf27 buf27; + SecStrBuf26 buf26; + SecStrBuf25 buf25; + SecStrBuf24 buf24; + SecStrBuf23 buf23; + SecStrBuf22 buf22; + SecStrBuf21 buf21; + SecStrBuf20 buf20; + SecStrBuf19 buf19; + SecStrBuf18 buf18; + SecStrBuf17 buf17; + SecStrBuf16 buf16; + SecStrBuf15 buf15; + SecStrBuf14 buf14; + SecStrBuf13 buf13; + SecStrBuf12 buf12; + SecStrBuf11 buf11; + SecStrBuf10 buf10; + SecStrBuf9 buf9; + SecStrBuf8 buf8; + SecStrBuf7 buf7; + SecStrBuf6 buf6; + SecStrBuf5 buf5; + SecStrBuf4 buf4; + SecStrBuf3 buf3; + SecStrBuf2 buf2; + SecStrBuf1 buf1; +} SecStrBuf32Union; +/* C standard initializes the first member of the consortium. */ +static const SecStrBuf32 g_allZero = { + {'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'}}; +static const SecStrBuf32 g_allFF = { + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; + +/* Clear coversion warning strict aliasing" */ +SECUREC_INLINE const SecStrBuf32Union *SecStrictAliasingCast(const SecStrBuf32 *buf) +{ + return (const SecStrBuf32Union *)buf; +} + +#ifndef SECUREC_MEMSET_THRESHOLD_SIZE +#define SECUREC_MEMSET_THRESHOLD_SIZE 32UL +#endif + +#define SECUREC_UNALIGNED_SET(dest, c, count) \ + do { \ + char *pcDest = (char *)(dest); \ + switch (count) { \ + case 32: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 31: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 30: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 29: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 28: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 27: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 26: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 25: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 24: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 23: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 22: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 21: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 20: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 19: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 18: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 17: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 16: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 15: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 14: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 13: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 12: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 11: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 10: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 9: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 8: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 7: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 6: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 5: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 4: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 3: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 2: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 1: \ + *(pcDest++) = (char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + default: \ + break; \ + } \ + } \ + SECUREC_WHILE_ZERO + +#define SECUREC_ALIGNED_SET_OPT_ZERO_FF(dest, c, count) \ + do { \ + switch (c) { \ + case 0: \ + switch (count) { \ + case 1: \ + *(SecStrBuf1 *)(dest) = \ + *(const SecStrBuf1 *)(&((SecStrictAliasingCast(&g_allZero))->buf1)); \ + break; \ + case 2: \ + *(SecStrBuf2 *)(dest) = \ + *(const SecStrBuf2 *)(&((SecStrictAliasingCast(&g_allZero))->buf2)); \ + break; \ + case 3: \ + *(SecStrBuf3 *)(dest) = \ + *(const SecStrBuf3 *)(&((SecStrictAliasingCast(&g_allZero))->buf3)); \ + break; \ + case 4: \ + *(SecStrBuf4 *)(dest) = \ + *(const SecStrBuf4 *)(&((SecStrictAliasingCast(&g_allZero))->buf4)); \ + break; \ + case 5: \ + *(SecStrBuf5 *)(dest) = \ + *(const SecStrBuf5 *)(&((SecStrictAliasingCast(&g_allZero))->buf5)); \ + break; \ + case 6: \ + *(SecStrBuf6 *)(dest) = \ + *(const SecStrBuf6 *)(&((SecStrictAliasingCast(&g_allZero))->buf6)); \ + break; \ + case 7: \ + *(SecStrBuf7 *)(dest) = \ + *(const SecStrBuf7 *)(&((SecStrictAliasingCast(&g_allZero))->buf7)); \ + break; \ + case 8: \ + *(SecStrBuf8 *)(dest) = \ + *(const SecStrBuf8 *)(&((SecStrictAliasingCast(&g_allZero))->buf8)); \ + break; \ + case 9: \ + *(SecStrBuf9 *)(dest) = \ + *(const SecStrBuf9 *)(&((SecStrictAliasingCast(&g_allZero))->buf9)); \ + break; \ + case 10: \ + *(SecStrBuf10 *)(dest) = \ + *(const SecStrBuf10 *)(&((SecStrictAliasingCast(&g_allZero))->buf10)); \ + break; \ + case 11: \ + *(SecStrBuf11 *)(dest) = \ + *(const SecStrBuf11 *)(&((SecStrictAliasingCast(&g_allZero))->buf11)); \ + break; \ + case 12: \ + *(SecStrBuf12 *)(dest) = \ + *(const SecStrBuf12 *)(&((SecStrictAliasingCast(&g_allZero))->buf12)); \ + break; \ + case 13: \ + *(SecStrBuf13 *)(dest) = \ + *(const SecStrBuf13 *)(&((SecStrictAliasingCast(&g_allZero))->buf13)); \ + break; \ + case 14: \ + *(SecStrBuf14 *)(dest) = \ + *(const SecStrBuf14 *)(&((SecStrictAliasingCast(&g_allZero))->buf14)); \ + break; \ + case 15: \ + *(SecStrBuf15 *)(dest) = \ + *(const SecStrBuf15 *)(&((SecStrictAliasingCast(&g_allZero))->buf15)); \ + break; \ + case 16: \ + *(SecStrBuf16 *)(dest) = \ + *(const SecStrBuf16 *)(&((SecStrictAliasingCast(&g_allZero))->buf16)); \ + break; \ + case 17: \ + *(SecStrBuf17 *)(dest) = \ + *(const SecStrBuf17 *)(&((SecStrictAliasingCast(&g_allZero))->buf17)); \ + break; \ + case 18: \ + *(SecStrBuf18 *)(dest) = \ + *(const SecStrBuf18 *)(&((SecStrictAliasingCast(&g_allZero))->buf18)); \ + break; \ + case 19: \ + *(SecStrBuf19 *)(dest) = \ + *(const SecStrBuf19 *)(&((SecStrictAliasingCast(&g_allZero))->buf19)); \ + break; \ + case 20: \ + *(SecStrBuf20 *)(dest) = \ + *(const SecStrBuf20 *)(&((SecStrictAliasingCast(&g_allZero))->buf20)); \ + break; \ + case 21: \ + *(SecStrBuf21 *)(dest) = \ + *(const SecStrBuf21 *)(&((SecStrictAliasingCast(&g_allZero))->buf21)); \ + break; \ + case 22: \ + *(SecStrBuf22 *)(dest) = \ + *(const SecStrBuf22 *)(&((SecStrictAliasingCast(&g_allZero))->buf22)); \ + break; \ + case 23: \ + *(SecStrBuf23 *)(dest) = \ + *(const SecStrBuf23 *)(&((SecStrictAliasingCast(&g_allZero))->buf23)); \ + break; \ + case 24: \ + *(SecStrBuf24 *)(dest) = \ + *(const SecStrBuf24 *)(&((SecStrictAliasingCast(&g_allZero))->buf24)); \ + break; \ + case 25: \ + *(SecStrBuf25 *)(dest) = \ + *(const SecStrBuf25 *)(&((SecStrictAliasingCast(&g_allZero))->buf25)); \ + break; \ + case 26: \ + *(SecStrBuf26 *)(dest) = \ + *(const SecStrBuf26 *)(&((SecStrictAliasingCast(&g_allZero))->buf26)); \ + break; \ + case 27: \ + *(SecStrBuf27 *)(dest) = \ + *(const SecStrBuf27 *)(&((SecStrictAliasingCast(&g_allZero))->buf27)); \ + break; \ + case 28: \ + *(SecStrBuf28 *)(dest) = \ + *(const SecStrBuf28 *)(&((SecStrictAliasingCast(&g_allZero))->buf28)); \ + break; \ + case 29: \ + *(SecStrBuf29 *)(dest) = \ + *(const SecStrBuf29 *)(&((SecStrictAliasingCast(&g_allZero))->buf29)); \ + break; \ + case 30: \ + *(SecStrBuf30 *)(dest) = \ + *(const SecStrBuf30 *)(&((SecStrictAliasingCast(&g_allZero))->buf30)); \ + break; \ + case 31: \ + *(SecStrBuf31 *)(dest) = \ + *(const SecStrBuf31 *)(&((SecStrictAliasingCast(&g_allZero))->buf31)); \ + break; \ + case 32: \ + *(SecStrBuf32 *)(dest) = \ + *(const SecStrBuf32 *)(&((SecStrictAliasingCast(&g_allZero))->buf32)); \ + break; \ + default: \ + break; \ + } \ + break; \ + case 0xFF: \ + switch (count) { \ + case 1: \ + *(SecStrBuf1 *)(dest) = *(const SecStrBuf1 *)(&((SecStrictAliasingCast(&g_allFF))->buf1)); \ + break; \ + case 2: \ + *(SecStrBuf2 *)(dest) = *(const SecStrBuf2 *)(&((SecStrictAliasingCast(&g_allFF))->buf2)); \ + break; \ + case 3: \ + *(SecStrBuf3 *)(dest) = *(const SecStrBuf3 *)(&((SecStrictAliasingCast(&g_allFF))->buf3)); \ + break; \ + case 4: \ + *(SecStrBuf4 *)(dest) = *(const SecStrBuf4 *)(&((SecStrictAliasingCast(&g_allFF))->buf4)); \ + break; \ + case 5: \ + *(SecStrBuf5 *)(dest) = *(const SecStrBuf5 *)(&((SecStrictAliasingCast(&g_allFF))->buf5)); \ + break; \ + case 6: \ + *(SecStrBuf6 *)(dest) = *(const SecStrBuf6 *)(&((SecStrictAliasingCast(&g_allFF))->buf6)); \ + break; \ + case 7: \ + *(SecStrBuf7 *)(dest) = *(const SecStrBuf7 *)(&((SecStrictAliasingCast(&g_allFF))->buf7)); \ + break; \ + case 8: \ + *(SecStrBuf8 *)(dest) = *(const SecStrBuf8 *)(&((SecStrictAliasingCast(&g_allFF))->buf8)); \ + break; \ + case 9: \ + *(SecStrBuf9 *)(dest) = *(const SecStrBuf9 *)(&((SecStrictAliasingCast(&g_allFF))->buf9)); \ + break; \ + case 10: \ + *(SecStrBuf10 *)(dest) = \ + *(const SecStrBuf10 *)(&((SecStrictAliasingCast(&g_allFF))->buf10)); \ + break; \ + case 11: \ + *(SecStrBuf11 *)(dest) = \ + *(const SecStrBuf11 *)(&((SecStrictAliasingCast(&g_allFF))->buf11)); \ + break; \ + case 12: \ + *(SecStrBuf12 *)(dest) = \ + *(const SecStrBuf12 *)(&((SecStrictAliasingCast(&g_allFF))->buf12)); \ + break; \ + case 13: \ + *(SecStrBuf13 *)(dest) = \ + *(const SecStrBuf13 *)(&((SecStrictAliasingCast(&g_allFF))->buf13)); \ + break; \ + case 14: \ + *(SecStrBuf14 *)(dest) = \ + *(const SecStrBuf14 *)(&((SecStrictAliasingCast(&g_allFF))->buf14)); \ + break; \ + case 15: \ + *(SecStrBuf15 *)(dest) = \ + *(const SecStrBuf15 *)(&((SecStrictAliasingCast(&g_allFF))->buf15)); \ + break; \ + case 16: \ + *(SecStrBuf16 *)(dest) = \ + *(const SecStrBuf16 *)(&((SecStrictAliasingCast(&g_allFF))->buf16)); \ + break; \ + case 17: \ + *(SecStrBuf17 *)(dest) = \ + *(const SecStrBuf17 *)(&((SecStrictAliasingCast(&g_allFF))->buf17)); \ + break; \ + case 18: \ + *(SecStrBuf18 *)(dest) = \ + *(const SecStrBuf18 *)(&((SecStrictAliasingCast(&g_allFF))->buf18)); \ + break; \ + case 19: \ + *(SecStrBuf19 *)(dest) = \ + *(const SecStrBuf19 *)(&((SecStrictAliasingCast(&g_allFF))->buf19)); \ + break; \ + case 20: \ + *(SecStrBuf20 *)(dest) = \ + *(const SecStrBuf20 *)(&((SecStrictAliasingCast(&g_allFF))->buf20)); \ + break; \ + case 21: \ + *(SecStrBuf21 *)(dest) = \ + *(const SecStrBuf21 *)(&((SecStrictAliasingCast(&g_allFF))->buf21)); \ + break; \ + case 22: \ + *(SecStrBuf22 *)(dest) = \ + *(const SecStrBuf22 *)(&((SecStrictAliasingCast(&g_allFF))->buf22)); \ + break; \ + case 23: \ + *(SecStrBuf23 *)(dest) = \ + *(const SecStrBuf23 *)(&((SecStrictAliasingCast(&g_allFF))->buf23)); \ + break; \ + case 24: \ + *(SecStrBuf24 *)(dest) = \ + *(const SecStrBuf24 *)(&((SecStrictAliasingCast(&g_allFF))->buf24)); \ + break; \ + case 25: \ + *(SecStrBuf25 *)(dest) = \ + *(const SecStrBuf25 *)(&((SecStrictAliasingCast(&g_allFF))->buf25)); \ + break; \ + case 26: \ + *(SecStrBuf26 *)(dest) = \ + *(const SecStrBuf26 *)(&((SecStrictAliasingCast(&g_allFF))->buf26)); \ + break; \ + case 27: \ + *(SecStrBuf27 *)(dest) = \ + *(const SecStrBuf27 *)(&((SecStrictAliasingCast(&g_allFF))->buf27)); \ + break; \ + case 28: \ + *(SecStrBuf28 *)(dest) = \ + *(const SecStrBuf28 *)(&((SecStrictAliasingCast(&g_allFF))->buf28)); \ + break; \ + case 29: \ + *(SecStrBuf29 *)(dest) = \ + *(const SecStrBuf29 *)(&((SecStrictAliasingCast(&g_allFF))->buf29)); \ + break; \ + case 30: \ + *(SecStrBuf30 *)(dest) = \ + *(const SecStrBuf30 *)(&((SecStrictAliasingCast(&g_allFF))->buf30)); \ + break; \ + case 31: \ + *(SecStrBuf31 *)(dest) = \ + *(const SecStrBuf31 *)(&((SecStrictAliasingCast(&g_allFF))->buf31)); \ + break; \ + case 32: \ + *(SecStrBuf32 *)(dest) = \ + *(const SecStrBuf32 *)(&((SecStrictAliasingCast(&g_allFF))->buf32)); \ + break; \ + default: \ + break; \ + } \ + break; \ + default: \ + SECUREC_UNALIGNED_SET((dest), (c), (count)); \ + } /* END switch */ \ + } \ + SECUREC_WHILE_ZERO + +#define SECUREC_SMALL_MEM_SET(dest, c, count) \ + ; \ + do { \ + if (SECUREC_ADDR_ALIGNED_8((dest))) { \ + SECUREC_ALIGNED_SET_OPT_ZERO_FF((dest), (c), (count)); \ + } else { \ + SECUREC_UNALIGNED_SET((dest), (c), (count)); \ + } \ + } \ + SECUREC_WHILE_ZERO + +/* + * Performance optimization + */ +#define SECUREC_MEMSET_OPT(dest, c, count) \ + do { \ + if ((count) > SECUREC_MEMSET_THRESHOLD_SIZE) { \ + SECUREC_MEMSET_WARP_OPT((dest), (c), (count)); \ + } else { \ + SECUREC_SMALL_MEM_SET((dest), (c), (count)); \ + } \ + } \ + SECUREC_WHILE_ZERO +#endif + +/* + * Handling errors + */ +SECUREC_INLINE errno_t SecMemsetError(void *dest, size_t destMax, int c, size_t count) +{ + /* Check destMax is 0 compatible with _sp macro */ + if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("memset_s"); + return ERANGE; + } + if (dest == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("memset_s"); + return EINVAL; + } + if (count > destMax) { + (void)memset(dest, c, destMax); /* Set entire buffer to value c */ + SECUREC_ERROR_INVALID_RANGE("memset_s"); + return ERANGE_AND_RESET; + } + return EOK; +} + +/* + * + * The memset_s function copies the value of c (converted to an unsigned char) + * into each of the first count characters of the object pointed to by dest. + * + * + * dest Pointer to destination. + * destMax The size of the buffer. + * c Character to set. + * count Number of characters. + * + * + * dest buffer is uptdated. + * + * + * EOK Success + * EINVAL dest == NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN + * ERANGE destMax > SECUREC_MEM_MAX_LEN or (destMax is 0 and count > destMax) + * ERANGE_AND_RESET count > destMax and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN and dest != NULL + * + * if return ERANGE_AND_RESET then fill dest to c ,fill length is destMax + */ +errno_t memset_s(void *dest, size_t destMax, int c, size_t count) +{ + if (SECUREC_MEMSET_PARAM_OK(dest, destMax, count)) { +#if SECUREC_MEMSET_WITH_PERFORMANCE + SECUREC_MEMSET_OPT(dest, c, count); +#else + SECUREC_MEMSET_WARP_OPT(dest, c, count); +#endif + return EOK; + } + /* Meet some runtime violation, return error code */ + return SecMemsetError(dest, destMax, c, count); +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(memset_s); +#endif + +#if SECUREC_WITH_PERFORMANCE_ADDONS +/* + * Performance optimization + */ +errno_t memset_sOptAsm(void *dest, size_t destMax, int c, size_t count) +{ + if (SECUREC_MEMSET_PARAM_OK(dest, destMax, count)) { + SECUREC_MEMSET_OPT(dest, c, count); + return EOK; + } + /* Meet some runtime violation, return error code */ + return SecMemsetError(dest, destMax, c, count); +} + +/* + * Performance optimization, trim judgement on "destMax <= SECUREC_MEM_MAX_LEN" + */ +errno_t memset_sOptTc(void *dest, size_t destMax, int c, size_t count) +{ + if (SECUREC_LIKELY(count <= destMax && dest != NULL)) { + SECUREC_MEMSET_OPT(dest, c, count); + return EOK; + } + /* Meet some runtime violation, return error code */ + return SecMemsetError(dest, destMax, c, count); +} +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/output.inl b/http/services/netmanagernative/common/huawei_secure_c/src/output.inl new file mode 100644 index 000000000..1c6029de1 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/output.inl @@ -0,0 +1,1636 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +/* + * [Standardize-exceptions] Use unsafe function: Portability + * [reason] Use unsafe function to implement security function to maintain platform compatibility. + * And sufficient input validation is performed before calling + */ + +#ifndef OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 +#define OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 + +#define SECUREC_NULL_STRING_SIZE 8 +#define SECUREC_STATE_TABLE_SIZE 337 +#define SECUREC_OFFSET_BITS_WORD 16 +#define SECUREC_OFFSET_BITS_DWORD 32 + +#define SECUREC_OFFSET_DIV_OCTAL 3 +#define SECUREC_OFFSET_DIV_HEX 4 +#define SECUREC_RADIX_OCTAL 8 +#define SECUREC_RADIX_DECIMAL 10 +#define SECUREC_RADIX_HEX 16 +#define SECUREC_PREFIX_LEN 2 +/* Size include '+' and '\0' */ +#define SECUREC_FLOAT_BUF_EXT 2 + +typedef union { + /* Integer formatting refers to the end of the buffer, plus 1 to prevent tool alarms */ + char str[SECUREC_BUFFER_SIZE + 1]; +#if SECUREC_HAVE_WCHART + wchar_t wStr[SECUREC_WCHAR_BUFFER_SIZE]; /* Just for %lc */ +#endif +} SecBuffer; + +typedef union { + char *str; /* Not a null terminated string */ +#if SECUREC_HAVE_WCHART + wchar_t *wStr; +#endif +} SecFormatBuf; + +typedef struct { + const char *digits; /* Point to the hexadecimal subset */ + SecFormatBuf text; /* Point to formated string */ + int textLen; /* Length of the text */ + int textIsWide; /* Flag for text is wide chars ; 0 is not wide char */ + unsigned int radix; /* Use for output number , default set to 10 */ + unsigned int flags; + int fldWidth; + int precision; + int dynWidth; /* %* 1 width from variable parameter ;0 not */ + int dynPrecision; /* %.* 1 precision from variable parameter ;0 not */ + int padding; /* Padding len */ + int prefixLen; /* Length of prefix, 0 or 1 or 2 */ + SecChar prefix[SECUREC_PREFIX_LEN]; /* Prefix is 0 or 0x */ + SecBuffer buffer; +} SecFormatAttr; + +#if SECUREC_ENABLE_SPRINTF_FLOAT +#ifdef SECUREC_STACK_SIZE_LESS_THAN_1K +#define SECUREC_FMT_STR_LEN 8 +#else +#define SECUREC_FMT_STR_LEN 16 +#endif +typedef struct { + char buffer[SECUREC_FMT_STR_LEN]; + char *fmtStr; /* Initialization must point to buffer */ + char *allocatedFmtStr; /* Initialization must be NULL to store alloced point */ + char *floatBuffer; /* Use heap memory if the SecFormatAttr.buffer is not enough */ + int bufferSize; /* The size of floatBuffer */ +} SecFloatAdapt; +#endif + + + + +static const char *g_itoaUpperDigits = "0123456789ABCDEFX"; +static const char *g_itoaLowerDigits = "0123456789abcdefx"; +static const unsigned char g_stateTable[SECUREC_STATE_TABLE_SIZE] = { + /* + * Type + * 0: nospecial meanin; + * 1: '%' + * 2: '.' + * 3: '*' + * 4: '0' + * 5: '1' ... '9' + * 6: ' ', '+', '-', '#' + * 7: 'h', 'l', 'L', 'w' , 'N', 'z', 'q', 't', 'j' + * 8: 'd', 'o', 'u', 'i', 'x', 'X', 'e', 'f', 'g', 'E', 'F', 'G', 's', 'c', '[', 'p' + */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x00, + 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x07, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x08, 0x07, 0x00, 0x07, 0x00, 0x00, 0x08, + 0x08, 0x07, 0x00, 0x08, 0x07, 0x08, 0x00, 0x07, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Fill zero for normal char 128 byte for 0x80 - 0xff */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* + * State + * 0: normal + * 1: percent + * 2: flag + * 3: width + * 4: dot + * 5: precis + * 6: size + * 7: type + * 8: invalid + */ + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x01, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x01, 0x00, 0x00, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03, 0x08, 0x05, + 0x08, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03, + 0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00, + 0x00 +}; + +#if SECUREC_ENABLE_SPRINTF_FLOAT +/* Call system sprintf to format float value */ +SECUREC_INLINE int SecFormatFloat(char *strDest, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + SECUREC_MASK_MSVC_CRT_WARNING + ret = vsprintf(strDest, format, argList); + SECUREC_END_MASK_MSVC_CRT_WARNING + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} + +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT +/* Out put long double value to dest */ +SECUREC_INLINE void SecFormatLongDboule(SecFormatAttr *attr, const SecFloatAdapt *floatAdapt, long double ldValue) +{ + int fldWidth = ((attr->flags & SECUREC_FLAG_LEFT) ? (-attr->fldWidth) : attr->fldWidth); + if (attr->dynWidth && attr->dynPrecision) { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, attr->precision, ldValue); + } else if (attr->dynWidth) { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, ldValue); + } else if (attr->dynPrecision) { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, attr->precision, ldValue); + } else { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, ldValue); + } + if (attr->textLen < 0 || attr->textLen >= floatAdapt->bufferSize) { + attr->textLen = 0; + } +} +#endif + +/* Out put double value to dest */ +SECUREC_INLINE void SecFormatDboule(SecFormatAttr *attr, const SecFloatAdapt *floatAdapt, double dValue) +{ + int fldWidth = ((attr->flags & SECUREC_FLAG_LEFT) ? (-attr->fldWidth) : attr->fldWidth); + if (attr->dynWidth && attr->dynPrecision) { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, attr->precision, dValue); + } else if (attr->dynWidth) { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, dValue); + } else if (attr->dynPrecision) { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, attr->precision, dValue); + } else { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, dValue); + } + if (attr->textLen < 0 || attr->textLen >= floatAdapt->bufferSize) { + attr->textLen = 0; + } +} +#endif + +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT +/* To clear e506 warning */ +SECUREC_INLINE int SecIsSameSize(size_t sizeA, size_t sizeB) +{ + return sizeA == sizeB; +} +#endif + + +#ifndef SECUREC_ON_64BITS +/* + * Compiler Optimized Division 8. + * The text.str point to buffer end, must be Large enough + */ +SECUREC_INLINE void SecNumber32ToOctalString(SecUnsignedInt32 number, SecFormatAttr *attr) +{ + SecUnsignedInt32 val32 = number; + do { + --attr->text.str; + /* Just use lowerDigits for 0 - 9 */ + *(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_OCTAL]; + } while ((val32 /= SECUREC_RADIX_OCTAL) != 0); +} + +#ifdef _AIX +/* + * Compiler Optimized Division 10. + * The text.str point to buffer end, must be Large enough + */ +SECUREC_INLINE void SecNumber32ToDecString(SecUnsignedInt32 number, SecFormatAttr *attr) +{ + SecUnsignedInt32 val32 = number; + do { + --attr->text.str; + /* Just use lowerDigits for 0 - 9 */ + *(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_DECIMAL]; + } while ((val32 /= SECUREC_RADIX_DECIMAL) != 0); +} +#endif +/* + * Compiler Optimized Division 16. + * The text.str point to buffer end, must be Large enough + */ +SECUREC_INLINE void SecNumber32ToHexString(SecUnsignedInt32 number, SecFormatAttr *attr) +{ + SecUnsignedInt32 val32 = number; + do { + --attr->text.str; + *(attr->text.str) = attr->digits[val32 % SECUREC_RADIX_HEX]; + } while ((val32 /= SECUREC_RADIX_HEX) != 0); +} + +#ifndef _AIX +/* Use fast div 10 */ +SECUREC_INLINE void SecNumber32ToDecStringFast(SecUnsignedInt32 number, SecFormatAttr *attr) +{ + SecUnsignedInt32 val32 = number; + do { + SecUnsignedInt32 quotient; + SecUnsignedInt32 remain; + --attr->text.str; + *(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_DECIMAL]; + quotient = (val32 >> 1) + (val32 >> 2); /* Fast div magic 2 */ + quotient = quotient + (quotient >> 4); /* Fast div magic 4 */ + quotient = quotient + (quotient >> 8); /* Fast div magic 8 */ + quotient = quotient + (quotient >> 16); /* Fast div magic 16 */ + quotient = quotient >> 3; /* Fast div magic 3 */ + remain = val32 - SECUREC_MUL_TEN(quotient); + val32 = (remain > 9) ? (quotient + 1) : quotient; /* Fast div magic 9 */ + } while (val32 != 0); +} +#endif + +SECUREC_INLINE void SecNumber32ToString(SecUnsignedInt32 number, SecFormatAttr *attr) +{ + switch (attr->radix) { + case SECUREC_RADIX_HEX: + SecNumber32ToHexString(number, attr); + break; + case SECUREC_RADIX_OCTAL: + SecNumber32ToOctalString(number, attr); + break; + case SECUREC_RADIX_DECIMAL: +#ifdef _AIX + /* The compiler will optimize div 10 */ + SecNumber32ToDecString(number, attr); +#else + SecNumber32ToDecStringFast(number, attr); +#endif + break; + default: + break; + } +} +#endif + +#if defined(SECUREC_USE_SPECIAL_DIV64) || (defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS)) +/* + * This function just to clear warning, on sume vxworks compiler shift 32 bit make warnigs + */ +SECUREC_INLINE SecUnsignedInt64 SecU64Shr32(SecUnsignedInt64 number) +{ + return (((number) >> 16) >> 16); /* Two shifts of 16 bits to realize shifts of 32 bits */ +} +/* + * Fast divide by 10 algorithm. + * Calculation divisor multiply 0xcccccccccccccccdULL, resultHi64 >> 3 as quotient + */ +SECUREC_INLINE void SecU64Div10(SecUnsignedInt64 divisor, SecUnsignedInt64 *quotient, SecUnsignedInt32 *remainder) +{ + SecUnsignedInt64 mask = 0xffffffffULL; /* Use 0xffffffffULL as 32 bit mask */ + SecUnsignedInt64 magicHi = 0xccccccccULL; /* Fast divide 10 magic numbers high 32bit 0xccccccccULL */ + SecUnsignedInt64 magicLow = 0xcccccccdULL; /* Fast divide 10 magic numbers low 32bit 0xcccccccdULL */ + SecUnsignedInt64 divisorHi = (SecUnsignedInt64)(SecU64Shr32(divisor)); /* High 32 bit use */ + SecUnsignedInt64 divisorLow = (SecUnsignedInt64)(divisor & mask); /* Low 32 bit mask */ + SecUnsignedInt64 factorHi = divisorHi * magicHi; + SecUnsignedInt64 factorLow1 = divisorHi * magicLow; + SecUnsignedInt64 factorLow2 = divisorLow * magicHi; + SecUnsignedInt64 factorLow3 = divisorLow * magicLow; + SecUnsignedInt64 carry = (factorLow1 & mask) + (factorLow2 & mask) + SecU64Shr32(factorLow3); + SecUnsignedInt64 resultHi64 = factorHi + SecU64Shr32(factorLow1) + SecU64Shr32(factorLow2) + SecU64Shr32(carry); + + *quotient = resultHi64 >> 3; /* Fast divide 10 magic numbers 3 */ + *remainder = (SecUnsignedInt32)(divisor - ((*quotient) * 10)); /* Quotient mul 10 */ + return; +} +#if defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS) +/* + * Divide function for VXWORKS + */ +SECUREC_INLINE int SecU64Div32(SecUnsignedInt64 divisor, SecUnsignedInt32 radix, + SecUnsignedInt64 *quotient, SecUnsignedInt32 *remainder) +{ + switch (radix) { + case SECUREC_RADIX_DECIMAL: + SecU64Div10(divisor, quotient, remainder); + break; + case SECUREC_RADIX_HEX: + *quotient = (divisor >> SECUREC_OFFSET_DIV_HEX); + *remainder = (SecUnsignedInt32)(divisor & 0xfULL); /* Mask one hex number by 0xfULL */ + break; + case SECUREC_RADIX_OCTAL: + *quotient = (divisor >> SECUREC_OFFSET_DIV_OCTAL); + *remainder = (SecUnsignedInt32)(divisor & 0x7ULL); /* Mask one hex number by 0x7ULL */ + break; + default: + return -1; /* This does not happen in the current file */ + } + return 0; +} +SECUREC_INLINE void SecNumber64ToStringSpecial(SecUnsignedInt64 number, SecFormatAttr *attr) +{ + SecUnsignedInt64 val64 = number; + do { + SecUnsignedInt32 digit = 0; /* Ascii value of digit */ + SecUnsignedInt64 quotient = 0; + if (SecU64Div32(val64, (SecUnsignedInt32)attr->radix, "ient, &digit) != 0) { + /* Just break, when enter this function, no error is returned */ + break; + } + --attr->text.str; + *(attr->text.str) = attr->digits[digit]; + val64 = quotient; + } while (val64 != 0); +} +#endif +#endif + +#if defined(SECUREC_ON_64BITS) || !defined(SECUREC_VXWORKS_VERSION_5_4) +#if defined(SECUREC_USE_SPECIAL_DIV64) +/* The compiler does not provide 64 bit division problems */ +SECUREC_INLINE void SecNumber64ToDecString(SecUnsignedInt64 number, SecFormatAttr *attr) +{ + SecUnsignedInt64 val64 = number; + do { + SecUnsignedInt64 quotient = 0; + SecUnsignedInt32 digit = 0; + SecU64Div10(val64, "ient, &digit); + --attr->text.str; + /* Just use lowerDigits for 0 - 9 */ + *(attr->text.str) = g_itoaLowerDigits[digit]; + val64 = quotient; + } while (val64 != 0); +} +#else +/* + * Compiler Optimized Division 10. + * The text.str point to buffer end, must be Large enough + */ +SECUREC_INLINE void SecNumber64ToDecString(SecUnsignedInt64 number, SecFormatAttr *attr) +{ + SecUnsignedInt64 val64 = number; + do { + --attr->text.str; + /* Just use lowerDigits for 0 - 9 */ + *(attr->text.str) = g_itoaLowerDigits[val64 % SECUREC_RADIX_DECIMAL]; + } while ((val64 /= SECUREC_RADIX_DECIMAL) != 0); +} +#endif + +/* + * Compiler Optimized Division 8. + * The text.str point to buffer end, must be Large enough + */ +SECUREC_INLINE void SecNumber64ToOctalString(SecUnsignedInt64 number, SecFormatAttr *attr) +{ + SecUnsignedInt64 val64 = number; + do { + --attr->text.str; + /* Just use lowerDigits for 0 - 9 */ + *(attr->text.str) = g_itoaLowerDigits[val64 % SECUREC_RADIX_OCTAL]; + } while ((val64 /= SECUREC_RADIX_OCTAL) != 0); +} +/* + * Compiler Optimized Division 16. + * The text.str point to buffer end, must be Large enough + */ +SECUREC_INLINE void SecNumber64ToHexString(SecUnsignedInt64 number, SecFormatAttr *attr) +{ + SecUnsignedInt64 val64 = number; + do { + --attr->text.str; + *(attr->text.str) = attr->digits[val64 % SECUREC_RADIX_HEX]; + } while ((val64 /= SECUREC_RADIX_HEX) != 0); +} + + +SECUREC_INLINE void SecNumber64ToString(SecUnsignedInt64 number, SecFormatAttr *attr) +{ + switch (attr->radix) { + /* The compiler will optimize div 10 */ + case SECUREC_RADIX_DECIMAL: + SecNumber64ToDecString(number, attr); + break; + case SECUREC_RADIX_OCTAL: + SecNumber64ToOctalString(number, attr); + break; + case SECUREC_RADIX_HEX: + SecNumber64ToHexString(number, attr); + break; + default: + break; + } +} +#endif + +/* + * Converting integers to string + */ +SECUREC_INLINE void SecNumberToString(SecUnsignedInt64 number, SecFormatAttr *attr) +{ +#ifdef SECUREC_ON_64BITS + SecNumber64ToString(number, attr); +#else /* For 32 bits system */ + if (number <= 0xFFFFFFFFUL) { + /* In most case, the value to be converted is small value */ + SecUnsignedInt32 n32Tmp = (SecUnsignedInt32)number; + SecNumber32ToString(n32Tmp, attr); + } else { + /* The value to be converted is greater than 4G */ +#if defined(SECUREC_VXWORKS_VERSION_5_4) + SecNumber64ToStringSpecial(number, attr); +#else + SecNumber64ToString(number, attr); +#endif + } +#endif + +} + +SECUREC_INLINE int SecIsNumberNeedTo32Bit(const SecFormatAttr *attr) +{ + return (((attr->flags & SECUREC_FLAG_I64) == 0) && +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + ((attr->flags & SECUREC_FLAG_INTMAX) == 0) && +#endif +#ifdef SECUREC_ON_64BITS + ((attr->flags & SECUREC_FLAG_PTRDIFF) == 0) && + ((attr->flags & SECUREC_FLAG_SIZE) == 0) && +#if !defined(SECUREC_COMPATIBLE_WIN_FORMAT) /* on window 64 system sizeof long is 32bit */ + ((attr->flags & SECUREC_FLAG_LONG) == 0) && +#endif +#endif + ((attr->flags & SECUREC_FLAG_LONGLONG) == 0)); +} + +SECUREC_INLINE void SecNumberToBuffer(SecFormatAttr *attr, SecInt64 num64) +{ + SecUnsignedInt64 number; + /* Check for negative; copy into number */ + if ((attr->flags & SECUREC_FLAG_SIGNED) && num64 < 0) { + number = (SecUnsignedInt64)(-num64); + attr->flags |= SECUREC_FLAG_NEGATIVE; + } else { + number = (SecUnsignedInt64)num64; + } + if (SecIsNumberNeedTo32Bit(attr)) { + number = (number & (SecUnsignedInt64)0xffffffffUL); /* Use 0xffffffff as 32 bit mask */ + } + + /* The text.str must be point to buffer.str, this pointer is used outside the function */ + attr->text.str = &attr->buffer.str[SECUREC_BUFFER_SIZE]; + + if (number == 0) { + /* Turn off hex prefix default, and textLen is zero */ + attr->prefixLen = 0; + attr->textLen = 0; + return; + } + + /* Convert integer to string. It must be invoked when number > 0, otherwise the following logic is incorrect */ + SecNumberToString(number, attr); + /* Compute length of number, text.str must be in buffer.str */ + attr->textLen = (int)(size_t)((char *)&attr->buffer.str[SECUREC_BUFFER_SIZE] - attr->text.str); +} + +/* Use loop copy char or wchar_t string */ +SECUREC_INLINE void SecWriteStringToStreamOpt(SecPrintfStream *stream, const SecChar *str, int len) +{ + int i; + const SecChar *tmp = str; + for (i = 0; i < len; ++i) { + *((SecChar *)(void *)(stream->cur)) = *(const SecChar *)(tmp); + stream->cur += sizeof(SecChar); + tmp = tmp + 1; + } + stream->count -= len * (int)(sizeof(SecChar)); +} + +SECUREC_INLINE void SecWriteStringToStream(SecPrintfStream *stream, const SecChar *str, int len) +{ + if (len < 12) { /* Performance optimization for mobile number length 12 */ + SecWriteStringToStreamOpt(stream, str, len); + } else { + size_t count = (size_t)(unsigned int)len * (sizeof(SecChar)); + SECUREC_MEMCPY_WARP_OPT(stream->cur, str, count); + stream->cur += (size_t)((size_t)(unsigned int)len * (sizeof(SecChar))); + stream->count -= len * (int)(sizeof(SecChar)); + } +} + +/* + * Return if buffer length is enough + * The count variable can be reduced to 0, and the external function complements the \0 terminator. + */ +SECUREC_INLINE int SecIsStreamBufEnough(const SecPrintfStream *stream, int needLen) +{ + return ((int)(stream->count - (needLen * (int)(sizeof(SecChar)))) >= 0); +} + +/* Write left padding */ +SECUREC_INLINE void SecWriteLeftPadding(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ + if (!(attr->flags & (SECUREC_FLAG_LEFT | SECUREC_FLAG_LEADZERO)) && attr->padding > 0) { + /* Pad on left with blanks */ + SECUREC_WRITE_MULTI_CHAR(SECUREC_CHAR(' '), attr->padding, stream, charsOut); + } +} + +/* Write prefix */ +SECUREC_INLINE void SecWritePrefix(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ + if (attr->prefixLen > 0) { + if (SecIsStreamBufEnough(stream, attr->prefixLen)) { + /* Max prefix len is 2, use loop copy */ + SecWriteStringToStreamOpt(stream, attr->prefix, attr->prefixLen); + *charsOut += attr->prefixLen; + } else { + SECUREC_WRITE_STRING(attr->prefix, attr->prefixLen, stream, charsOut); + } + } +} + +/* Write leading zeros */ +SECUREC_INLINE void SecWriteLeadingZero(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ + if ((attr->flags & SECUREC_FLAG_LEADZERO) && !(attr->flags & SECUREC_FLAG_LEFT) && + attr->padding > 0) { + SECUREC_WRITE_MULTI_CHAR(SECUREC_CHAR('0'), attr->padding, stream, charsOut); + } +} + +/* Write right padding */ +SECUREC_INLINE void SecWriteRightPadding(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ + if (*charsOut >= 0 && (attr->flags & SECUREC_FLAG_LEFT) && attr->padding > 0) { + /* Pad on right with blanks */ + SECUREC_WRITE_MULTI_CHAR(SECUREC_CHAR(' '), attr->padding, stream, charsOut); + } +} + +/* Write text string */ +SECUREC_INLINE void SecWriteStringChk(SecPrintfStream *stream, const SecChar *str, int len, int *charsOut) +{ + if (SecIsStreamBufEnough(stream, len)) { + SecWriteStringToStream(stream, str, len); + *charsOut += len; + } else { + SECUREC_WRITE_STRING(str, len, stream, charsOut); + } +} + +#ifdef SECUREC_FOR_WCHAR +#if SECUREC_HAVE_MBTOWC +SECUREC_INLINE void SecWriteTextAfterMbtowc(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ + char *p = attr->text.str; + int count = attr->textLen; + while (count > 0) { + wchar_t wChar = L'\0'; + int retVal = mbtowc(&wChar, p, (size_t)MB_CUR_MAX); + if (retVal <= 0) { + *charsOut = -1; + break; + } + SecWriteCharW(wChar, stream, charsOut); + if (*charsOut == -1) { + break; + } + p += retVal; + count -= retVal; + } +} +#endif +#else /* Not SECUREC_FOR_WCHAR */ +#if SECUREC_HAVE_WCTOMB +SECUREC_INLINE void SecWriteTextAfterWctomb(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ + wchar_t *p = attr->text.wStr; + int count = attr->textLen; + while (count > 0) { + char tmpBuf[SECUREC_MB_LEN + 1]; + SECUREC_MASK_MSVC_CRT_WARNING + int retVal = wctomb(tmpBuf, *p); + SECUREC_END_MASK_MSVC_CRT_WARNING + if (retVal <= 0) { + *charsOut = -1; + break; + } + SecWriteString(tmpBuf, retVal, stream, charsOut); + if (*charsOut == -1) { + break; + } + --count; + ++p; + } +} +#endif +#endif + +#if SECUREC_ENABLE_SPRINTF_FLOAT +/* + * Write text of float + * Using independent functions to optimize the expansion of inline functions by the compiler + */ +SECUREC_INLINE void SecWriteFloatText(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ +#ifdef SECUREC_FOR_WCHAR +#if SECUREC_HAVE_MBTOWC + SecWriteTextAfterMbtowc(stream, attr, charsOut); +#else + *charsOut = -1; + (void)stream; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + (void)attr; /* To clear e438 last value assigned not used , the compiler will optimize this code */ +#endif +#else /* Not SECUREC_FOR_WCHAR */ + SecWriteString(attr->text.str, attr->textLen, stream, charsOut); +#endif +} +#endif + +/* Write text of integer or string ... */ +SECUREC_INLINE void SecWriteText(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ +#ifdef SECUREC_FOR_WCHAR + if (attr->textIsWide != 0) { + SecWriteStringChk(stream, attr->text.wStr, attr->textLen, charsOut); + } else { +#if SECUREC_HAVE_MBTOWC + SecWriteTextAfterMbtowc(stream, attr, charsOut); +#else + *charsOut = -1; +#endif + } + +#else /* Not SECUREC_FOR_WCHAR */ + if (attr->textIsWide != 0) { +#if SECUREC_HAVE_WCTOMB + SecWriteTextAfterWctomb(stream, attr, charsOut); +#else + *charsOut = -1; +#endif + } else { + SecWriteStringChk(stream, attr->text.str, attr->textLen, charsOut); + } +#endif +} + +#define SECUREC_FMT_STATE_OFFSET 256 +SECUREC_INLINE SecFmtState SecDecodeState(SecChar ch, SecFmtState lastState) +{ +#ifdef SECUREC_FOR_WCHAR + /* Convert to unsigned char to clear gcc 4.3.4 warning */ + unsigned char fmtType = (unsigned char)((((unsigned int)(int)(ch)) <= (unsigned int)(int)(L'~')) ? \ + (g_stateTable[(unsigned char)(ch)]) : 0); + return (SecFmtState)(g_stateTable[fmtType * ((unsigned char)STAT_INVALID + 1) + + (unsigned char)(lastState) + SECUREC_FMT_STATE_OFFSET]); +#else + unsigned char fmtType = g_stateTable[(unsigned char)(ch)]; + return (SecFmtState)(g_stateTable[fmtType * ((unsigned char)STAT_INVALID + 1) + + (unsigned char)(lastState) + SECUREC_FMT_STATE_OFFSET]); +#endif +} + +SECUREC_INLINE void SecDecodeFlags(SecChar ch, SecFormatAttr *attr) +{ + switch (ch) { + case SECUREC_CHAR(' '): + attr->flags |= SECUREC_FLAG_SIGN_SPACE; + break; + case SECUREC_CHAR('+'): + attr->flags |= SECUREC_FLAG_SIGN; + break; + case SECUREC_CHAR('-'): + attr->flags |= SECUREC_FLAG_LEFT; + break; + case SECUREC_CHAR('0'): + attr->flags |= SECUREC_FLAG_LEADZERO; /* Add zero th the front */ + break; + case SECUREC_CHAR('#'): + attr->flags |= SECUREC_FLAG_ALTERNATE; /* Output %x with 0x */ + break; + default: + break; + } + return; +} + + +/* + * Decoded size identifier in format string to Reduce the number of lines of function code + */ +SECUREC_INLINE int SecDecodeSizeI(SecFormatAttr *attr, const SecChar **format) +{ +#ifdef SECUREC_ON_64BITS + attr->flags |= SECUREC_FLAG_I64; /* %I to INT64 */ +#endif + if ((**format == SECUREC_CHAR('6')) && (*((*format) + 1) == SECUREC_CHAR('4'))) { + (*format) += 2; /* Add 2 to skip I64 */ + attr->flags |= SECUREC_FLAG_I64; /* %I64 to INT64 */ + } else if ((**format == SECUREC_CHAR('3')) && (*((*format) + 1) == SECUREC_CHAR('2'))) { + (*format) += 2; /* Add 2 to skip I32 */ + attr->flags &= ~SECUREC_FLAG_I64; /* %I64 to INT32 */ + } else if ((**format == SECUREC_CHAR('d')) || (**format == SECUREC_CHAR('i')) || + (**format == SECUREC_CHAR('o')) || (**format == SECUREC_CHAR('u')) || + (**format == SECUREC_CHAR('x')) || (**format == SECUREC_CHAR('X'))) { + /* Do nothing */ + } else { + /* Compatibility code for "%I" just print I */ + return -1; + } + return 0; +} +/* + * Decoded size identifier in format string, and skip format to next charater + */ +SECUREC_INLINE int SecDecodeSize(SecChar ch, SecFormatAttr *attr, const SecChar **format) +{ + switch (ch) { + case SECUREC_CHAR('l'): + if (**format == SECUREC_CHAR('l')) { + *format = *format + 1; + attr->flags |= SECUREC_FLAG_LONGLONG; /* For long long */ + } else { + attr->flags |= SECUREC_FLAG_LONG; /* For long int or wchar_t */ + } + break; +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + case SECUREC_CHAR('z'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('Z'): + attr->flags |= SECUREC_FLAG_SIZE; + break; + case SECUREC_CHAR('j'): + attr->flags |= SECUREC_FLAG_INTMAX; + break; +#endif + case SECUREC_CHAR('t'): + attr->flags |= SECUREC_FLAG_PTRDIFF; + break; + case SECUREC_CHAR('q'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('L'): + attr->flags |= (SECUREC_FLAG_LONGLONG | SECUREC_FLAG_LONG_DOUBLE); + break; + case SECUREC_CHAR('I'): + if (SecDecodeSizeI(attr, format) != 0) { + /* Compatibility code for "%I" just print I */ + return -1; + } + break; + case SECUREC_CHAR('h'): + if (**format == SECUREC_CHAR('h')) { + *format = *format + 1; + attr->flags |= SECUREC_FLAG_CHAR; /* For char */ + } else { + attr->flags |= SECUREC_FLAG_SHORT; /* For short int */ + } + break; + case SECUREC_CHAR('w'): + attr->flags |= SECUREC_FLAG_WIDECHAR; /* For wide char */ + break; + default: + break; + } + return 0; +} + + +/* + * Decoded char type identifier + */ +SECUREC_INLINE void SecDecodeTypeC(SecFormatAttr *attr, unsigned int c) +{ + attr->textLen = 1; /* Only 1 wide character */ + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) && !(defined(__hpux)) && !(defined(SECUREC_ON_SOLARIS)) + attr->flags &= ~SECUREC_FLAG_LEADZERO; +#endif + +#ifdef SECUREC_FOR_WCHAR + if (attr->flags & SECUREC_FLAG_SHORT) { + /* Get multibyte character from argument */ + attr->buffer.str[0] = (char)c; + attr->text.str = attr->buffer.str; + attr->textIsWide = 0; + } else { + attr->buffer.wStr[0] = (wchar_t)c; + attr->text.wStr = attr->buffer.wStr; + attr->textIsWide = 1; + } +#else /* Not SECUREC_FOR_WCHAR */ + if (attr->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) { +#if SECUREC_HAVE_WCHART + attr->buffer.wStr[0] = (wchar_t)c; + attr->text.wStr = attr->buffer.wStr; + attr->textIsWide = 1; +#else + attr->textLen = 0; /* Ignore unsupported characters */ + attr->fldWidth = 0; /* No paddings */ +#endif + } else { + /* Get multibyte character from argument */ + attr->buffer.str[0] = (char)c; + attr->text.str = attr->buffer.str; + attr->textIsWide = 0; + } +#endif +} + +SECUREC_INLINE void SecDecodeTypeSchar(SecFormatAttr *attr) +{ + if (attr->text.str == NULL) { + /* + * Literal string to print null ptr, define it as array rather than const text area + * To avoid gcc warning with pointing const text with variable + */ + static char strNullString[SECUREC_NULL_STRING_SIZE] = "(null)"; + attr->text.str = strNullString; + } + if (attr->precision == -1) { + /* Precision NOT assigned */ + /* The strlen performance is high when the string length is greater than 32 */ + attr->textLen = (int)strlen(attr->text.str); + } else { + /* Precision assigned */ + size_t textLen; + SECUREC_CALC_STR_LEN(attr->text.str, (size_t)(unsigned int)attr->precision, &textLen); + attr->textLen = (int)textLen; + } +} + +SECUREC_INLINE void SecDecodeTypeSwchar(SecFormatAttr *attr) +{ +#if SECUREC_HAVE_WCHART + size_t textLen; + attr->textIsWide = 1; + if (attr->text.wStr == NULL) { + /* + * Literal string to print null ptr, define it as array rather than const text area + * To avoid gcc warning with pointing const text with variable + */ + static wchar_t wStrNullString[SECUREC_NULL_STRING_SIZE] = { L'(', L'n', L'u', L'l', L'l', L')', L'\0', L'\0' }; + attr->text.wStr = wStrNullString; + } + /* The textLen in wchar_t,when precision is -1, it is unlimited */ + SECUREC_CALC_WSTR_LEN(attr->text.wStr, (size_t)(unsigned int)attr->precision, &textLen); + attr->textLen = (int)textLen; +#else + attr->textLen = 0; +#endif +} + + +/* + * Decoded string identifier + */ +SECUREC_INLINE void SecDecodeTypeS(SecFormatAttr *attr, char *argPtr) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) && (!defined(SECUREC_ON_UNIX)) + attr->flags &= ~SECUREC_FLAG_LEADZERO; +#endif + attr->text.str = argPtr; +#ifdef SECUREC_FOR_WCHAR +#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) + if (!(attr->flags & SECUREC_FLAG_LONG)) { + attr->flags |= SECUREC_FLAG_SHORT; + } +#endif + if (attr->flags & SECUREC_FLAG_SHORT) { + /* The textLen now contains length in multibyte chars */ + SecDecodeTypeSchar(attr); + } else { + /* The textLen now contains length in wide chars */ + SecDecodeTypeSwchar(attr); + } +#else /* SECUREC_FOR_WCHAR */ + if (attr->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) { + /* The textLen now contains length in wide chars */ + SecDecodeTypeSwchar(attr); + } else { + /* The textLen now contains length in multibyte chars */ + SecDecodeTypeSchar(attr); + } +#endif /* SECUREC_FOR_WCHAR */ + if (attr->textLen < 0) { + attr->textLen = 0; + } +} + +/* + * Write one character to dest buffer + */ +SECUREC_INLINE void SecOutputOneChar(SecChar ch, SecPrintfStream *stream, int *counter) +{ + /* Count must be reduced first, In order to identify insufficient length */ + if ((stream->count -= (int)(sizeof(SecChar))) >= 0) { + *((SecChar *)(void *)(stream->cur)) = (SecChar)ch; + stream->cur += sizeof(SecChar); + *counter = *(counter) + 1; + return; + } + /* No enough length */ + *counter = -1; +} + +/* + * Check precison in format + */ +SECUREC_INLINE int SecDecodePrecision(SecChar ch, SecFormatAttr *attr) +{ + if (attr->dynPrecision == 0) { + /* Add digit to current precision */ + if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(attr->precision)) { + return -1; + } + attr->precision = (int)SECUREC_MUL_TEN((unsigned int)attr->precision) + + (unsigned char)(ch - SECUREC_CHAR('0')); + } else { + if (attr->precision < 0) { + attr->precision = -1; + } + if (attr->precision > SECUREC_MAX_WIDTH_LEN) { + return -1; + } + } + return 0; +} + + +/* + * Check width in format + */ +SECUREC_INLINE int SecDecodeWidth(SecChar ch, SecFormatAttr *attr, SecFmtState lastState) +{ + if (attr->dynWidth == 0) { + if (lastState != STAT_WIDTH) { + attr->fldWidth = 0; + } + if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(attr->fldWidth)) { + return -1; + } + attr->fldWidth = (int)SECUREC_MUL_TEN((unsigned int)attr->fldWidth) + + (unsigned char)(ch - SECUREC_CHAR('0')); + } else { + if (attr->fldWidth < 0) { + attr->flags |= SECUREC_FLAG_LEFT; + attr->fldWidth = (-attr->fldWidth); + if (attr->fldWidth > SECUREC_MAX_WIDTH_LEN) { + return -1; + } + } + } + return 0; +} + + +/* + * The sprintf_s function processes the wide character as a parameter for %C + * The swprintf_s function processes the multiple character as a parameter for %C + */ +SECUREC_INLINE void SecUpdateWcharFlags(SecFormatAttr *attr) +{ + if (!(attr->flags & (SECUREC_FLAG_SHORT | SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR))) { +#ifdef SECUREC_FOR_WCHAR + attr->flags |= SECUREC_FLAG_SHORT; +#else + attr->flags |= SECUREC_FLAG_WIDECHAR; +#endif + } +} +/* + * When encountering %S, current just same as %C + */ +SECUREC_INLINE void SecUpdateWstringFlags(SecFormatAttr *attr) +{ + SecUpdateWcharFlags(attr); +} + +#if SECUREC_IN_KERNEL +SECUREC_INLINE void SecUpdatePointFlagsForKernel(SecFormatAttr *attr) +{ + /* Width is not set */ + if (attr->fldWidth <= 0) { + attr->flags |= SECUREC_FLAG_LEADZERO; + attr->fldWidth = 2 * sizeof(void *); /* 2 x byte number is the length of hex */ + } + if (attr->flags & SECUREC_FLAG_ALTERNATE) { + /* Alternate form means '0x' prefix */ + attr->prefix[0] = SECUREC_CHAR('0'); + attr->prefix[1] = SECUREC_CHAR('x'); + attr->prefixLen = SECUREC_PREFIX_LEN; + } + attr->flags |= SECUREC_FLAG_LONG; /* Converting a long */ +} +#endif + +SECUREC_INLINE void SecUpdatePointFlags(SecFormatAttr *attr) +{ + attr->flags |= SECUREC_FLAG_POINTER; +#if SECUREC_IN_KERNEL + SecUpdatePointFlagsForKernel(attr); +#else +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM)) && (!defined(SECUREC_ON_UNIX)) +#if defined(SECUREC_VXWORKS_PLATFORM) + attr->precision = 1; +#else + attr->precision = 0; +#endif + attr->flags |= SECUREC_FLAG_ALTERNATE; /* "0x" is not default prefix in UNIX */ + attr->digits = g_itoaLowerDigits; +#else /* On unix or win */ +#if defined(_AIX) || defined(SECUREC_ON_SOLARIS) + attr->precision = 1; +#else + attr->precision = 2 * sizeof(void *); /* 2 x byte number is the length of hex */ +#endif +#if defined(SECUREC_ON_UNIX) + attr->digits = g_itoaLowerDigits; +#else + attr->digits = g_itoaUpperDigits; +#endif +#endif + +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + attr->flags &= ~SECUREC_FLAG_LEADZERO; +#endif + +#ifdef SECUREC_ON_64BITS + attr->flags |= SECUREC_FLAG_I64; /* Converting an int64 */ +#else + attr->flags |= SECUREC_FLAG_LONG; /* Converting a long */ +#endif + /* Set up for %#p on different system */ + if (attr->flags & SECUREC_FLAG_ALTERNATE) { + /* Alternate form means '0x' prefix */ + attr->prefix[0] = SECUREC_CHAR('0'); +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM)) + attr->prefix[1] = SECUREC_CHAR('x'); +#else + attr->prefix[1] = (SecChar)(attr->digits[16]); /* 16 for 'x' or 'X' */ +#endif +#if defined(_AIX) || defined(SECUREC_ON_SOLARIS) + attr->prefixLen = 0; +#else + attr->prefixLen = SECUREC_PREFIX_LEN; +#endif + } +#endif +} + +SECUREC_INLINE void SecUpdateXpxFlags(SecFormatAttr *attr, SecChar ch) +{ + /* Use unsigned lower hex output for 'x' */ + attr->digits = g_itoaLowerDigits; + attr->radix = SECUREC_RADIX_HEX; + switch (ch) { + case SECUREC_CHAR('p'): + /* Print a pointer */ + SecUpdatePointFlags(attr); + break; + case SECUREC_CHAR('X'): /* fall-through */ /* FALLTHRU */ + /* Unsigned upper hex output */ + attr->digits = g_itoaUpperDigits; + /* fall-through */ /* FALLTHRU */ + default: + /* For %#x or %#X */ + if (attr->flags & SECUREC_FLAG_ALTERNATE) { + /* Alternate form means '0x' prefix */ + attr->prefix[0] = SECUREC_CHAR('0'); + attr->prefix[1] = (SecChar)(attr->digits[16]); /* 16 for 'x' or 'X' */ + attr->prefixLen = SECUREC_PREFIX_LEN; + } + break; + } +} +SECUREC_INLINE void SecUpdateOudiFlags(SecFormatAttr *attr, SecChar ch) +{ + /* Do not set digits here */ + switch (ch) { + case SECUREC_CHAR('i'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('d'): /* fall-through */ /* FALLTHRU */ + /* For signed decimal output */ + attr->flags |= SECUREC_FLAG_SIGNED; + /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('u'): + attr->radix = SECUREC_RADIX_DECIMAL; + attr->digits = g_itoaLowerDigits; + break; + case SECUREC_CHAR('o'): + /* For unsigned octal output */ + attr->radix = SECUREC_RADIX_OCTAL; + attr->digits = g_itoaLowerDigits; + if (attr->flags & SECUREC_FLAG_ALTERNATE) { + /* Alternate form means force a leading 0 */ + attr->flags |= SECUREC_FLAG_FORCE_OCTAL; + } + break; + default: + break; + } +} + +#if SECUREC_ENABLE_SPRINTF_FLOAT +SECUREC_INLINE void SecFreeFloatBuffer(SecFloatAdapt *floatAdapt) +{ + if (floatAdapt->floatBuffer != NULL) { + SECUREC_FREE(floatAdapt->floatBuffer); + } + if (floatAdapt->allocatedFmtStr != NULL) { + SECUREC_FREE(floatAdapt->allocatedFmtStr); + } + floatAdapt->floatBuffer = NULL; + floatAdapt->allocatedFmtStr = NULL; + floatAdapt->fmtStr = NULL; + floatAdapt->bufferSize = 0; +} + +SECUREC_INLINE void SecSeekToFrontPercent(const SecChar **format) +{ + const SecChar *fmt = *format; + while (*fmt != SECUREC_CHAR('%')) { /* Must meet '%' */ + --fmt; + } + *format = fmt; +} + +/* Init float format, return 0 is OK */ +SECUREC_INLINE int SecInitFloatFmt(SecFloatAdapt *floatFmt, const SecChar *format) +{ + const SecChar *fmt = format - 2; /* Sub 2 to the position before 'f' or 'g' */ + int fmtStrLen; + int i; + + SecSeekToFrontPercent(&fmt); + /* Now fmt point to '%' */ + fmtStrLen = (int)(size_t)(format - fmt) + 1; /* With ending terminator */ + + if (fmtStrLen > (int)sizeof(floatFmt->buffer)) { + /* When buffer is NOT enough, alloc a new buffer */ + floatFmt->allocatedFmtStr = (char *)SECUREC_MALLOC((size_t)((unsigned int)fmtStrLen)); + if (floatFmt->allocatedFmtStr == NULL) { + return -1; + } + floatFmt->fmtStr = floatFmt->allocatedFmtStr; + } else { + floatFmt->fmtStr = floatFmt->buffer; + floatFmt->allocatedFmtStr = NULL; /* Must set to NULL, later code free memory based on this identity */ + } + + for (i = 0; i < fmtStrLen - 1; ++i) { + /* Convert wchar to char */ + floatFmt->fmtStr[i] = (char)(fmt[i]); /* Copy the format string */ + } + floatFmt->fmtStr[fmtStrLen - 1] = '\0'; + + return 0; + +} + +/* Init float buffer and format, return 0 is OK */ +SECUREC_INLINE int SecInitFloatBuffer(SecFloatAdapt *floatAdapt, const SecChar *format, SecFormatAttr *attr) +{ + floatAdapt->allocatedFmtStr = NULL; + floatAdapt->fmtStr = NULL; + floatAdapt->floatBuffer = NULL; + /* Compute the precision value */ + if (attr->precision < 0) { + attr->precision = SECUREC_FLOAT_DEFAULT_PRECISION; + } + /* + * Calc buffer size to store double value + * The maximum length of SECUREC_MAX_WIDTH_LEN is enough + */ + if (attr->flags & SECUREC_FLAG_LONG_DOUBLE) { + if (attr->precision > (SECUREC_MAX_WIDTH_LEN - SECUREC_FLOAT_BUFSIZE_LB)) { + return -1; + } + /* Long double needs to meet the basic print length */ + floatAdapt->bufferSize = SECUREC_FLOAT_BUFSIZE_LB + attr->precision + SECUREC_FLOAT_BUF_EXT; + } else { + if (attr->precision > (SECUREC_MAX_WIDTH_LEN - SECUREC_FLOAT_BUFSIZE)) { + return -1; + } + /* Double needs to meet the basic print length */ + floatAdapt->bufferSize = SECUREC_FLOAT_BUFSIZE + attr->precision + SECUREC_FLOAT_BUF_EXT; + } + if (attr->fldWidth > floatAdapt->bufferSize) { + floatAdapt->bufferSize = attr->fldWidth + SECUREC_FLOAT_BUF_EXT; + } + + if (floatAdapt->bufferSize > SECUREC_BUFFER_SIZE) { + /* The current vlaue of SECUREC_BUFFER_SIZE could NOT store the formatted float string */ + floatAdapt->floatBuffer = (char *)SECUREC_MALLOC(((size_t)(unsigned int)floatAdapt->bufferSize)); + if (floatAdapt->floatBuffer == NULL) { + return -1; + } + attr->text.str = floatAdapt->floatBuffer; + } else { + attr->text.str = attr->buffer.str; /* Output buffer for float string with default size */ + } + + if (SecInitFloatFmt(floatAdapt, format) != 0) { + if (floatAdapt->floatBuffer != NULL) { + SECUREC_FREE(floatAdapt->floatBuffer); + floatAdapt->floatBuffer = NULL; + } + return -1; + } + return 0; +} +#endif + +SECUREC_INLINE SecInt64 SecUpdateNegativeChar(SecFormatAttr *attr, char ch) +{ + SecInt64 num64 = ch; /* Sign extend */ + if (num64 >= 128) { /* 128 on some platform, char is always unsigned */ + unsigned char tmp = (unsigned char)(~((unsigned char)ch)); + num64 = tmp + 1; + attr->flags |= SECUREC_FLAG_NEGATIVE; + } + return num64; +} + +/* + * If the precision is not satisfied, zero is added before the string + */ +SECUREC_INLINE void SecNumberSatisfyPrecision(SecFormatAttr *attr) +{ + int precision; + if (attr->precision < 0) { + precision = 1; /* Default precision 1 */ + } else { +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + attr->flags &= ~SECUREC_FLAG_LEADZERO; +#else + if (!(attr->flags & SECUREC_FLAG_POINTER)) { + attr->flags &= ~SECUREC_FLAG_LEADZERO; + } +#endif + if (attr->precision > SECUREC_MAX_PRECISION) { + attr->precision = SECUREC_MAX_PRECISION; + } + precision = attr->precision; + } + while (attr->textLen < precision) { + ++attr->textLen; + *(--attr->text.str) = '0'; + } +} + +/* + * Add leading zero for %#o + */ +SECUREC_INLINE void SecNumberForceOctal(SecFormatAttr *attr) +{ + /* Force a leading zero if FORCEOCTAL flag set */ + if ((attr->flags & SECUREC_FLAG_FORCE_OCTAL) && + (attr->textLen == 0 || attr->text.str[0] != '0')) { + *(--attr->text.str) = '0'; + ++attr->textLen; + } +} + +SECUREC_INLINE void SecUpdateSignedNumberPrefix(SecFormatAttr *attr) +{ + if (attr->flags & SECUREC_FLAG_SIGNED) { + if (attr->flags & SECUREC_FLAG_NEGATIVE) { + /* Prefix is '-' */ + attr->prefix[0] = SECUREC_CHAR('-'); + attr->prefixLen = 1; + } else if (attr->flags & SECUREC_FLAG_SIGN) { + /* Prefix is '+' */ + attr->prefix[0] = SECUREC_CHAR('+'); + attr->prefixLen = 1; + } else if (attr->flags & SECUREC_FLAG_SIGN_SPACE) { + /* Prefix is ' ' */ + attr->prefix[0] = SECUREC_CHAR(' '); + attr->prefixLen = 1; + } + } +} + +SECUREC_INLINE void SecNumberCompatZero(SecFormatAttr *attr) +{ +#if SECUREC_IN_KERNEL + if (attr->flags & SECUREC_FLAG_POINTER) { + static char strNullPointer[SECUREC_NULL_STRING_SIZE] = "(null)"; + attr->text.str = strNullPointer; + attr->textLen = 6; /* Length of (null) is 6 */ + attr->flags &= ~SECUREC_FLAG_LEADZERO; + attr->prefixLen = 0; + if (attr->precision >= 0 && attr->precision < attr->textLen) { + attr->textLen = attr->precision; + } + } + if (!(attr->flags & SECUREC_FLAG_POINTER) && attr->radix == SECUREC_RADIX_HEX && + (attr->flags & SECUREC_FLAG_ALTERNATE)) { + /* Add 0x prefix for %x or %X, the prefix string has been set before */ + attr->prefixLen = SECUREC_PREFIX_LEN; + } +#elif defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && (!defined(SECUREC_ON_UNIX)) + if (attr->flags & SECUREC_FLAG_POINTER) { + static char strNullPointer[SECUREC_NULL_STRING_SIZE] = "(nil)"; + attr->text.str = strNullPointer; + attr->textLen = 5; /* Length of (nil) is 5 */ + attr->flags &= ~SECUREC_FLAG_LEADZERO; + } +#elif defined(SECUREC_VXWORKS_PLATFORM) || defined(__hpux) + if ((attr->flags & SECUREC_FLAG_POINTER) && (attr->flags & SECUREC_FLAG_ALTERNATE)) { + /* Add 0x prefix for %p, the prefix string has been set before */ + attr->prefixLen = SECUREC_PREFIX_LEN; + } +#endif + (void)attr; /* To clear e438 last value assigned not used , the compiler will optimize this code */ +} + +#ifdef SECUREC_FOR_WCHAR +/* + * Formatting output core functions for wchar version.Called by a function such as vswprintf_s + * The argList must not be declare as const + */ +SECUREC_INLINE int SecOutputSW(SecPrintfStream *stream, const wchar_t *cFormat, va_list argList) +#else +/* + * Formatting output core functions for char version.Called by a function such as vsnprintf_s + */ +SECUREC_INLINE int SecOutputS(SecPrintfStream *stream, const char *cFormat, va_list argList) +#endif +{ + const SecChar *format = cFormat; + int charsOut; /* Characters written */ + int noOutput = 0; /* Must be initialized or compiler alerts */ + SecFmtState state; + SecChar ch; /* Currently read character */ + SecFormatAttr formatAttr; + + formatAttr.flags = 0; + formatAttr.textIsWide = 0; /* Flag for buffer contains wide chars */ + formatAttr.fldWidth = 0; + formatAttr.precision = 0; + formatAttr.dynWidth = 0; + formatAttr.dynPrecision = 0; + formatAttr.digits = g_itoaUpperDigits; + formatAttr.radix = SECUREC_RADIX_DECIMAL; + formatAttr.padding = 0; + formatAttr.textLen = 0; + formatAttr.text.str = NULL; + formatAttr.prefixLen = 0; + formatAttr.prefix[0] = SECUREC_CHAR('\0'); + formatAttr.prefix[1] = SECUREC_CHAR('\0'); + charsOut = 0; + state = STAT_NORMAL; /* Starting state */ + + /* Loop each format character */ + while (*format != SECUREC_CHAR('\0') && charsOut >= 0) { + SecFmtState lastState = state; + ch = *(format++); + state = SecDecodeState(ch, lastState); + switch (state) { + case STAT_NORMAL: + SecOutputOneChar(ch, stream, &charsOut); + continue; + case STAT_PERCENT: + /* Set default values */ + noOutput = 0; + formatAttr.prefixLen = 0; + formatAttr.textLen = 0; + formatAttr.flags = 0; + formatAttr.fldWidth = 0; + formatAttr.precision = -1; + formatAttr.textIsWide = 0; + formatAttr.dynWidth = 0; + formatAttr.dynPrecision = 0; + break; + case STAT_FLAG: + /* Set flag based on which flag character */ + SecDecodeFlags(ch, &formatAttr); + break; + case STAT_WIDTH: + /* Update width value */ + formatAttr.dynWidth = 0; + if (ch == SECUREC_CHAR('*')) { + /* get width from arg list */ + formatAttr.fldWidth = (int)va_arg(argList, int); + formatAttr.dynWidth = 1; + } + if (SecDecodeWidth(ch, &formatAttr, lastState) != 0) { + return -1; + } + break; + case STAT_DOT: + formatAttr.precision = 0; + break; + case STAT_PRECIS: + /* Update precison value */ + formatAttr.dynPrecision = 0; + if (ch == SECUREC_CHAR('*')) { + /* Get precision from arg list */ + formatAttr.precision = (int)va_arg(argList, int); + formatAttr.dynPrecision = 1; + } + if (SecDecodePrecision(ch, &formatAttr) != 0) { + return -1; + } + break; + case STAT_SIZE: + /* Read a size specifier, set the formatAttr.flags based on it, and skip format to next charater */ + if (SecDecodeSize(ch, &formatAttr, &format) != 0) { + /* Compatibility code for "%I" just print I */ + SecOutputOneChar(ch, stream, &charsOut); + state = STAT_NORMAL; + continue; + } + break; + case STAT_TYPE: + switch (ch) { + case SECUREC_CHAR('C'): /* Wide char */ + SecUpdateWcharFlags(&formatAttr); + /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('c'): { + unsigned int cValue = (unsigned int)va_arg(argList, int); + SecDecodeTypeC(&formatAttr, cValue); + break; + } + case SECUREC_CHAR('S'): /* Wide char string */ + SecUpdateWstringFlags(&formatAttr); + /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('s'): { + char *argPtr = (char *)va_arg(argList, char *); + SecDecodeTypeS(&formatAttr, argPtr); + break; + } + case SECUREC_CHAR('G'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('g'): /* fall-through */ /* FALLTHRU */ + /* Default precision is 1 for g or G */ + if (formatAttr.precision == 0) { + formatAttr.precision = 1; + } + /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('E'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('F'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('e'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('f'): { +#if SECUREC_ENABLE_SPRINTF_FLOAT + /* Add following code to call system sprintf API for float number */ + SecFloatAdapt floatAdapt; + noOutput = 1; /* It's no more data needs to be written */ + + /* Now format is pointer to the next character of 'f' */ + if (SecInitFloatBuffer(&floatAdapt, format, &formatAttr) != 0) { + break; + } + + if (formatAttr.flags & SECUREC_FLAG_LONG_DOUBLE) { +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + long double tmp = (long double)va_arg(argList, long double); + SecFormatLongDboule(&formatAttr, &floatAdapt, tmp); +#else + double tmp = (double)va_arg(argList, double); + SecFormatDboule(&formatAttr, &floatAdapt, tmp); +#endif + } else { + double tmp = (double)va_arg(argList, double); + SecFormatDboule(&formatAttr, &floatAdapt, tmp); + } + + /* Only need write formated float string */ + SecWriteFloatText(stream, &formatAttr, &charsOut); + SecFreeFloatBuffer(&floatAdapt); + break; +#else + return -1; +#endif + } + + case SECUREC_CHAR('X'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('p'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('x'): /* fall-through */ /* FALLTHRU */ + SecUpdateXpxFlags(&formatAttr, ch); + /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('i'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('d'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('u'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('o'): { + SecInt64 num64; + SecUpdateOudiFlags(&formatAttr, ch); + /* Read argument into variable num64 */ + if ((formatAttr.flags & SECUREC_FLAG_I64) || (formatAttr.flags & SECUREC_FLAG_LONGLONG)) { + num64 = (SecInt64)va_arg(argList, SecInt64); /* Maximum Bit Width sign bit unchanged */ + } else if (formatAttr.flags & SECUREC_FLAG_LONG) { + if (formatAttr.flags & SECUREC_FLAG_SIGNED) { + num64 = (long)va_arg(argList, long); /* Sign extend */ + } else { + num64 = (SecInt64)(unsigned long)va_arg(argList, long); /* Zero-extend */ + } + } else if (formatAttr.flags & SECUREC_FLAG_CHAR) { + if (formatAttr.flags & SECUREC_FLAG_SIGNED) { + char tmp = (char)va_arg(argList, int); /* Sign extend */ + num64 = SecUpdateNegativeChar(&formatAttr, tmp); + } else { + num64 = (SecInt64)(unsigned char)va_arg(argList, int); /* Zero-extend */ + } + } else if (formatAttr.flags & SECUREC_FLAG_SHORT) { + if (formatAttr.flags & SECUREC_FLAG_SIGNED) { + num64 = (short)va_arg(argList, int); /* Sign extend */ + } else { + num64 = (SecInt64)(unsigned short)va_arg(argList, int); /* Zero-extend */ + } + } +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + else if (formatAttr.flags & SECUREC_FLAG_PTRDIFF) { + num64 = (ptrdiff_t)va_arg(argList, ptrdiff_t); /* Sign extend */ + } else if (formatAttr.flags & SECUREC_FLAG_SIZE) { + if (formatAttr.flags & SECUREC_FLAG_SIGNED) { + /* No suitable macros were found to handle the branch */ + if (SecIsSameSize(sizeof(size_t), sizeof(long))) { + num64 = va_arg(argList, long); /* Sign extend */ + } else if (SecIsSameSize(sizeof(size_t), sizeof(long long))) { + num64 = va_arg(argList, long long); /* Sign extend */ + } else { + num64 = va_arg(argList, int); /* Sign extend */ + } + } else { + num64 = (SecInt64)(size_t)va_arg(argList, size_t); /* Zero-extend */ + } + } else if (formatAttr.flags & SECUREC_FLAG_INTMAX) { + num64 = (SecInt64)va_arg(argList, SecInt64); + } +#endif + else { + if (formatAttr.flags & SECUREC_FLAG_SIGNED) { + num64 = va_arg(argList, int); /* Sign extend */ + } else { + num64 = (SecInt64)(unsigned int)va_arg(argList, int); /* Zero-extend */ + } + } + + /* The order of the following calls must be correct */ + SecNumberToBuffer(&formatAttr, num64); + SecNumberSatisfyPrecision(&formatAttr); + SecNumberForceOctal(&formatAttr); + SecUpdateSignedNumberPrefix(&formatAttr); + if (num64 == 0) { + SecNumberCompatZero(&formatAttr); + } + break; + } + default: + break; + } + + if (noOutput == 0) { + /* Calculate amount of padding */ + formatAttr.padding = (formatAttr.fldWidth - formatAttr.textLen) - formatAttr.prefixLen; + + /* Put out the padding, prefix, and text, in the correct order */ + SecWriteLeftPadding(stream, &formatAttr, &charsOut); + SecWritePrefix(stream, &formatAttr, &charsOut); + SecWriteLeadingZero(stream, &formatAttr, &charsOut); + SecWriteText(stream, &formatAttr, &charsOut); + SecWriteRightPadding(stream, &formatAttr, &charsOut); + } + break; + case STAT_INVALID: /* fall-through */ /* FALLTHRU */ + default: + return -1; /* Input format is wrong(STAT_INVALID), directly return */ + } + } + + if (state != STAT_NORMAL && state != STAT_TYPE) { + return -1; + } + + return charsOut; /* The number of characters written */ +} + +/* + * Output one zero character zero into the SecPrintfStream structure + * If there is not enough space, make sure f->count is less than 0 + */ +SECUREC_INLINE int SecPutZeroChar(SecPrintfStream *str) +{ + if (--(str->count) >= 0) { + *(str->cur) = '\0'; + str->cur = str->cur + 1; + return 0; + } + return -1; +} + +#endif /* OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 */ + diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/scanf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/scanf_s.c new file mode 100644 index 000000000..ceea71b12 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/scanf_s.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securec.h" + +/* + * + * The scanf_s function is equivalent to fscanf_s with the argument stdin interposed before the arguments to + * scanf_s The scanf_s function reads data from the standard input stream stdin and writes the data into the + * location that's given by argument. Each argument must be a pointer to a variable of a type that corresponds to a + * type specifier in format. If copying occurs between strings that overlap, the behavior is undefined. + * + * + * format Format control string. + * ... Optional arguments. + * + * + * ... The converted value stored in user assigned address + * + * + * Returns the number of fields successfully converted and assigned; + * the return value does not include fields that were read but not assigned. + * A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int scanf_s(const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vscanf_s(format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/secinput.h b/http/services/netmanagernative/common/huawei_secure_c/src/secinput.h new file mode 100644 index 000000000..6dc11ec3d --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/secinput.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef SEC_INPUT_H_E950DA2C_902F_4B15_BECD_948E99090D9C +#define SEC_INPUT_H_E950DA2C_902F_4B15_BECD_948E99090D9C +#include "securecutil.h" + +#define SECUREC_SCANF_EINVAL (-1) +#define SECUREC_SCANF_ERROR_PARA (-2) + +/* For internal stream flag */ +#define SECUREC_MEM_STR_FLAG 0X01 +#define SECUREC_FILE_STREAM_FLAG 0X02 +#define SECUREC_PIPE_STREAM_FLAG 0X04 +#define SECUREC_LOAD_FILE_TO_MEM_FLAG 0X08 + +#define SECUREC_BOM_HEADER_SIZE 2 +#define SECUREC_BOM_HEADER_BE_1ST 0xFEU +#define SECUREC_BOM_HEADER_BE_2ST 0xFFU +#define SECUREC_BOM_HEADER_LE_1ST 0xFFU +#define SECUREC_BOM_HEADER_LE_2ST 0xFEU +#define SECUREC_UTF8_BOM_HEADER_SIZE 3 +#define SECUREC_UTF8_BOM_HEADER_1ST 0xEFU +#define SECUREC_UTF8_BOM_HEADER_2ND 0xBBU +#define SECUREC_UTF8_BOM_HEADER_3RD 0xBFU +#define SECUREC_UTF8_LEAD_1ST 0xE0 +#define SECUREC_UTF8_LEAD_2ND 0x80 + +typedef struct { + unsigned int flag; /* Mark the properties of input stream */ + int count; /* The size of buffered string in bytes */ + const char *cur; /* The pointer to next read position */ + char *base; /* The pointer to the header of buffered string */ +#if SECUREC_ENABLE_SCANF_FILE + FILE *pf; /* The file pointer */ + long oriFilePos; /* The original position of file offset when fscanf is called */ + int fileRealRead; +#ifdef SECUREC_NO_STD_UNGETC + unsigned int lastChar; /* The char code of last input */ + int fUnGet; /* The boolean flag of pushing a char back to read stream */ +#endif +#endif +} SecFileStream; + +#ifdef SECUREC_INLINE_INIT_FILE_STREAM_STR +/* + * This initialization for eliminating redundant initialization. + */ +SECUREC_INLINE void SecInitFileStreamFromString(SecFileStream *stream, const char *cur, int count) +{ + stream->flag = SECUREC_MEM_STR_FLAG; + stream->count = count; + stream->cur = cur; + stream->base = NULL; +#if SECUREC_ENABLE_SCANF_FILE + stream->pf = NULL; + stream->oriFilePos = 0; + stream->fileRealRead = 0; +#ifdef SECUREC_NO_STD_UNGETC + stream->lastChar = 0; + stream->fUnGet = 0; +#endif +#endif +} +#endif + +#ifdef SECUREC_INLINE_INIT_FILE_STREAM_STDIN +/* + * This initialization for eliminating redundant initialization. + */ +SECUREC_INLINE void SecInitFileStreamFromStdin(SecFileStream *stream) +{ + stream->flag = SECUREC_PIPE_STREAM_FLAG; + stream->count = 0; + stream->cur = NULL; + stream->base = NULL; +#if SECUREC_ENABLE_SCANF_FILE + stream->pf = SECUREC_STREAM_STDIN; + stream->oriFilePos = 0; + stream->fileRealRead = 0; +#ifdef SECUREC_NO_STD_UNGETC + stream->lastChar = 0; + stream->fUnGet = 0; +#endif +#endif +} +#endif + +#ifdef SECUREC_INLINE_INIT_FILE_STREAM_FILE +/* + * This initialization for eliminating redundant initialization. + * Compared with the previous version initialization 0, + * the current code causes the binary size to increase by some bytes + */ +SECUREC_INLINE void SecInitFileStreamFromFile(SecFileStream *stream, FILE *file) +{ + stream->flag = SECUREC_FILE_STREAM_FLAG; + stream->count = 0; + stream->cur = NULL; + stream->base = NULL; +#if SECUREC_ENABLE_SCANF_FILE + stream->pf = file; + stream->oriFilePos = 0; + stream->fileRealRead = 0; +#ifdef SECUREC_NO_STD_UNGETC + stream->lastChar = 0; + stream->fUnGet = 0; +#endif +#endif +} +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +extern int SecInputS(SecFileStream *stream, const char *cFormat, va_list argList); +extern void SecClearDestBuf(const char *buffer, const char *format, va_list argList); +#if SECUREC_IN_KERNEL == 0 +extern int SecInputSW(SecFileStream *stream, const wchar_t *cFormat, va_list argList); +extern void SecClearDestBufW(const wchar_t *buffer, const wchar_t *format, va_list argList); +#endif +/* 20150105 For software and hardware decoupling,such as UMG */ +#if defined(SECUREC_SYSAPI4VXWORKS) +#ifdef feof +#undef feof +#endif +extern int feof(FILE *stream); +#endif + +#if defined(SECUREC_SYSAPI4VXWORKS) || defined(SECUREC_CTYPE_MACRO_ADAPT) +#ifndef isspace +#define isspace(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n')) +#endif +#ifndef iswspace +#define iswspace(c) (((c) == L' ') || ((c) == L'\t') || ((c) == L'\r') || ((c) == L'\n')) +#endif +#ifndef isascii +#define isascii(c) (((unsigned char)(c)) <= 0x7f) +#endif +#ifndef isupper +#define isupper(c) ((c) >= 'A' && (c) <= 'Z') +#endif +#ifndef islower +#define islower(c) ((c) >= 'a' && (c) <= 'z') +#endif +#ifndef isalpha +#define isalpha(c) (isupper(c) || (islower(c))) +#endif +#ifndef isdigit +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#endif +#ifndef isxupper +#define isxupper(c) ((c) >= 'A' && (c) <= 'F') +#endif +#ifndef isxlower +#define isxlower(c) ((c) >= 'a' && (c) <= 'f') +#endif +#ifndef isxdigit +#define isxdigit(c) (isdigit(c) || isxupper(c) || isxlower(c)) +#endif +#endif + +#ifdef __cplusplus +} +#endif +/* Reserved file operation macro interface */ +#define SECUREC_LOCK_FILE(s) +#define SECUREC_UNLOCK_FILE(s) +#define SECUREC_LOCK_STDIN(i, s) +#define SECUREC_UNLOCK_STDIN(i, s) +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/securecutil.c b/http/services/netmanagernative/common/huawei_secure_c/src/securecutil.c new file mode 100644 index 000000000..c06c45aae --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/securecutil.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/* Avoid duplicate header files,not include securecutil.h */ +#include "securecutil.h" + +#if defined(ANDROID) && (SECUREC_HAVE_WCTOMB || SECUREC_HAVE_MBTOWC) +#include +#if SECUREC_HAVE_WCTOMB +/* + * Convert wide characters to narrow multi-bytes + */ +int wctomb(char *s, wchar_t wc) +{ + return wcrtomb(s, wc, NULL); +} +#endif + +#if SECUREC_HAVE_MBTOWC +/* + * Converting narrow multi-byte characters to wide characters + */ +int mbtowc(wchar_t *pwc, const char *s, size_t n) +{ + return mbrtowc(pwc, s, n, NULL); +} +#endif +#endif + +/* The V100R001C01 version num is 0x5 */ +#define SECUREC_C_VERSION (0x5 << 8) +#define SECUREC_SPC_VERSION 9 +#define SECUREC_VERSION_STR "Huawei Secure C V100R001C01SPC009B003" + +/* + * SPC verNumber<->verStr like: + * 0X201<->C01 + * 0X202<->SPC001 Redefine numbers after this version + * 0X502<->SPC002 + * 0X503<->SPC003 + * ... + * 0X50a<->SPC010 + * 0X50b<->SPC011 + * ... + */ +/* + * CP verNumber<->verStr like: + * 0X601<->CP0001 + * 0X602<->CP0002 + * ... + */ +const char *GetHwSecureCVersion(unsigned short *verNumber) +{ + if (verNumber != NULL) { + *verNumber = (unsigned short)(SECUREC_C_VERSION | SECUREC_SPC_VERSION); + } + return SECUREC_VERSION_STR; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(GetHwSecureCVersion); +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/securecutil.h b/http/services/netmanagernative/common/huawei_secure_c/src/securecutil.h new file mode 100644 index 000000000..79e93cf25 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/securecutil.h @@ -0,0 +1,537 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef SECURECUTIL_H_46C86578_F8FF_4E49_8E64_9B175241761F +#define SECURECUTIL_H_46C86578_F8FF_4E49_8E64_9B175241761F +#include "securec.h" + +#if (defined(_MSC_VER)) && (_MSC_VER >= 1400) +/* Shield compilation alerts using discarded functions and Constant expression to maximize code compatibility */ +#define SECUREC_MASK_MSVC_CRT_WARNING __pragma(warning(push)) __pragma(warning(disable : 4996 4127)) +#define SECUREC_END_MASK_MSVC_CRT_WARNING __pragma(warning(pop)) +#else +#define SECUREC_MASK_MSVC_CRT_WARNING +#define SECUREC_END_MASK_MSVC_CRT_WARNING +#endif +#define SECUREC_WHILE_ZERO SECUREC_MASK_MSVC_CRT_WARNING while (0) SECUREC_END_MASK_MSVC_CRT_WARNING + +/* Automatically identify the platform that supports strnlen function, and use this function to improve performance */ +#ifndef SECUREC_HAVE_STRNLEN +#if (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200809L) +#if SECUREC_IN_KERNEL +#define SECUREC_HAVE_STRNLEN 0 +#else +#if defined(__GLIBC__) && __GLIBC__ >= 2 && defined(__GLIBC_MINOR__) && __GLIBC_MINOR__ >= 10 +#define SECUREC_HAVE_STRNLEN 1 +#else +#define SECUREC_HAVE_STRNLEN 0 +#endif +#endif +#else +#define SECUREC_HAVE_STRNLEN 0 +#endif +#endif + +#if SECUREC_IN_KERNEL +/* In kernel disbale functions */ +#ifndef SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_SCANF_FILE 0 +#endif +#ifndef SECUREC_ENABLE_SCANF_FLOAT +#define SECUREC_ENABLE_SCANF_FLOAT 0 +#endif +#ifndef SECUREC_ENABLE_SPRINTF_FLOAT +#define SECUREC_ENABLE_SPRINTF_FLOAT 0 +#endif +#ifndef SECUREC_HAVE_MBTOWC +#define SECUREC_HAVE_MBTOWC 0 +#endif +#ifndef SECUREC_HAVE_WCTOMB +#define SECUREC_HAVE_WCTOMB 0 +#endif +#ifndef SECUREC_HAVE_WCHART +#define SECUREC_HAVE_WCHART 0 +#endif +#else /* Not in kernel */ +/* Systems that do not support file, can define this macro to 0. */ +#ifndef SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_SCANF_FILE 1 +#endif +#ifndef SECUREC_ENABLE_SCANF_FLOAT +#define SECUREC_ENABLE_SCANF_FLOAT 1 +#endif +/* Systems that do not support float, can define this macro to 0. */ +#ifndef SECUREC_ENABLE_SPRINTF_FLOAT +#define SECUREC_ENABLE_SPRINTF_FLOAT 1 +#endif +#ifndef SECUREC_HAVE_MBTOWC +#define SECUREC_HAVE_MBTOWC 1 +#endif +#ifndef SECUREC_HAVE_WCTOMB +#define SECUREC_HAVE_WCTOMB 1 +#endif +#ifndef SECUREC_HAVE_WCHART +#define SECUREC_HAVE_WCHART 1 +#endif +#endif + +#ifndef SECUREC_ENABLE_INLINE +#define SECUREC_ENABLE_INLINE 0 +#endif + +#ifndef SECUREC_INLINE +#if SECUREC_ENABLE_INLINE +#define SECUREC_INLINE inline static +#else +#define SECUREC_INLINE static +#endif +#endif + +#ifndef SECUREC_WARP_OUTPUT +#if SECUREC_IN_KERNEL +#define SECUREC_WARP_OUTPUT 1 +#else +#define SECUREC_WARP_OUTPUT 0 +#endif +#endif + +#ifndef SECUREC_STREAM_STDIN +#define SECUREC_STREAM_STDIN stdin +#endif + +#define SECUREC_INT_MAX 2147483647 +#define SECUREC_MUL_SIXTEEN(x) ((x) << 4) +#define SECUREC_MUL_EIGHT(x) ((x) << 3) +#define SECUREC_MUL_TEN(x) ((((x) << 2) + (x)) << 1) +/* Limited format input and output width */ +#define SECUREC_MAX_WIDTH_LEN_DIV_TEN 21474836 +#define SECUREC_MAX_WIDTH_LEN SECUREC_MUL_TEN(SECUREC_MAX_WIDTH_LEN_DIV_TEN) +/* Is the x multiplied by 10 greater than */ +#define SECUREC_MUL_TEN_ADD_BEYOND_MAX(x) (((x) > SECUREC_MAX_WIDTH_LEN_DIV_TEN)) + +#define SECUREC_FLOAT_BUFSIZE (309 + 40) /* Max length of double value */ +#define SECUREC_FLOAT_BUFSIZE_LB (4932 + 40) /* Max length of long double value */ +#define SECUREC_FLOAT_DEFAULT_PRECISION 6 + +/* This macro does not handle pointer equality or integer overflow */ +#define SECUREC_MEMORY_NO_OVERLAP(dest, src, count) \ + (((src) < (dest) && ((const char *)(src) + (count)) <= (char *)(dest)) || \ + ((dest) < (src) && ((char *)(dest) + (count)) <= (const char *)(src))) + +#define SECUREC_MEMORY_IS_OVERLAP(dest, src, count) \ + (((src) < (dest) && ((const char *)(src) + (count)) > (char *)(dest)) || \ + ((dest) < (src) && ((char *)(dest) + (count)) > (const char *)(src))) + +/* + * Check whether the strings overlap, len is the length of the string not include terminator + * Length is related to data type char or wchar , do not force conversion of types + */ +#define SECUREC_STRING_NO_OVERLAP(dest, src, len) \ + (((src) < (dest) && ((src) + (len)) < (dest)) || ((dest) < (src) && ((dest) + (len)) < (src))) + +/* + * Check whether the strings overlap for strcpy wcscpy function, dest len and src Len are not include terminator + * Length is related to data type char or wchar , do not force conversion of types + */ +#define SECUREC_STRING_IS_OVERLAP(dest, src, len) \ + (((src) < (dest) && ((src) + (len)) >= (dest)) || ((dest) < (src) && ((dest) + (len)) >= (src))) + +/* + * Check whether the strings overlap for strcat wcscat function, dest len and src Len are not include terminator + * Length is related to data type char or wchar , do not force conversion of types + */ +#define SECUREC_CAT_STRING_IS_OVERLAP(dest, destLen, src, srcLen) \ + (((dest) < (src) && ((dest) + (destLen) + (srcLen)) >= (src)) || \ + ((src) < (dest) && ((src) + (srcLen)) >= (dest))) + +#if SECUREC_HAVE_STRNLEN +#define SECUREC_CALC_STR_LEN(str, maxLen, outLen) \ + do { \ + *(outLen) = strnlen((str), (maxLen)); \ + } \ + SECUREC_WHILE_ZERO +#define SECUREC_CALC_STR_LEN_OPT(str, maxLen, outLen) \ + do { \ + if ((maxLen) > 8) { \ + /* Optimization or len less then 8 */ \ + if (*((str) + 0) == '\0') { \ + *(outLen) = 0; \ + } else if (*((str) + 1) == '\0') { \ + *(outLen) = 1; \ + } else if (*((str) + 2) == '\0') { \ + *(outLen) = 2; \ + } else if (*((str) + 3) == '\0') { \ + *(outLen) = 3; \ + } else if (*((str) + 4) == '\0') { \ + *(outLen) = 4; \ + } else if (*((str) + 5) == '\0') { \ + *(outLen) = 5; \ + } else if (*((str) + 6) == '\0') { \ + *(outLen) = 6; \ + } else if (*((str) + 7) == '\0') { \ + *(outLen) = 7; \ + } else if (*((str) + 8) == '\0') { \ + /* Optimization with a length of 8 */ \ + *(outLen) = 8; \ + } else { \ + /* The offset is 8 because the performance of 8 byte alignment is high */ \ + *(outLen) = 8 + strnlen((str) + 8, (maxLen)-8); \ + } \ + } else { \ + SECUREC_CALC_STR_LEN((str), (maxLen), (outLen)); \ + } \ + } \ + SECUREC_WHILE_ZERO +#else +#define SECUREC_CALC_STR_LEN(str, maxLen, outLen) \ + do { \ + const char *strEnd = (const char *)(str); \ + size_t availableSize = (size_t)(maxLen); \ + while (availableSize > 0 && *strEnd != '\0') { \ + --availableSize; \ + ++strEnd; \ + } \ + *(outLen) = (size_t)(strEnd - (str)); \ + } \ + SECUREC_WHILE_ZERO +#define SECUREC_CALC_STR_LEN_OPT SECUREC_CALC_STR_LEN +#endif + +#define SECUREC_CALC_WSTR_LEN(str, maxLen, outLen) \ + do { \ + const wchar_t *strEnd = (const wchar_t *)(str); \ + size_t len = 0; \ + while (len < (maxLen) && *strEnd != L'\0') { \ + ++len; \ + ++strEnd; \ + } \ + *(outLen) = len; \ + } \ + SECUREC_WHILE_ZERO + +/* Performance optimization, product may disable inline function */ +#ifdef SECUREC_USE_ASM +#define SECUREC_MEMCPY_WARP_OPT(dest, src, count) (void)memcpy_opt((dest), (src), (count)) +#define SECUREC_MEMSET_WARP_OPT(dest, c, count) (void)memset_opt((dest), (c), (count)) +#else +#define SECUREC_MEMCPY_WARP_OPT(dest, src, count) (void)memcpy((dest), (src), (count)) +#define SECUREC_MEMSET_WARP_OPT(dest, c, count) (void)memset((dest), (c), (count)) +#endif + +#ifdef SECUREC_FORMAT_OUTPUT_INPUT +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) || defined(__ARMCC_VERSION) +typedef __int64 SecInt64; +typedef unsigned __int64 SecUnsignedInt64; +#if defined(__ARMCC_VERSION) +typedef unsigned int SecUnsignedInt32; +#else +typedef unsigned __int32 SecUnsignedInt32; +#endif +#else +typedef unsigned int SecUnsignedInt32; +typedef long long SecInt64; +typedef unsigned long long SecUnsignedInt64; +#endif + +#ifdef SECUREC_FOR_WCHAR +#if defined(SECUREC_VXWORKS_PLATFORM) && !defined(__WINT_TYPE__) +typedef wchar_t wint_t; +#endif +#ifndef WEOF +#define WEOF ((wchar_t)(-1)) +#endif +typedef wchar_t SecChar; +typedef wchar_t SecUnsignedChar; +typedef wint_t SecInt; +typedef wint_t SecUnsignedInt; +#else /* no SECUREC_FOR_WCHAR */ +typedef char SecChar; +typedef unsigned char SecUnsignedChar; +typedef int SecInt; +typedef unsigned int SecUnsignedInt; +#endif +#endif + +/* + * Determine whether the address is 8-byte aligned + * Some systems do not have uintptr_t type, so use NULL to clear tool alarm 507 + */ +#define SECUREC_ADDR_ALIGNED_8(addr) ((((size_t)(addr)) & 7) == 0) /* Use 7 to check aligned 8 */ + +/* + * If you define the memory allocation function, you need to define the function prototype. + * You can define this macro as a header file. + */ +#if defined(SECUREC_MALLOC_PROTOTYPE) +SECUREC_MALLOC_PROTOTYPE +#endif + +#ifndef SECUREC_MALLOC +#define SECUREC_MALLOC(x) malloc((size_t)(x)) +#endif + +#ifndef SECUREC_FREE +#define SECUREC_FREE(x) free((void *)(x)) +#endif + +/* Struct for performance */ +typedef struct { + unsigned char buf[1]; /* Performance optimization code structure assignment length 1 bytes */ +} SecStrBuf1; +typedef struct { + unsigned char buf[2]; /* Performance optimization code structure assignment length 2 bytes */ +} SecStrBuf2; +typedef struct { + unsigned char buf[3]; /* Performance optimization code structure assignment length 3 bytes */ +} SecStrBuf3; +typedef struct { + unsigned char buf[4]; /* Performance optimization code structure assignment length 4 bytes */ +} SecStrBuf4; +typedef struct { + unsigned char buf[5]; /* Performance optimization code structure assignment length 5 bytes */ +} SecStrBuf5; +typedef struct { + unsigned char buf[6]; /* Performance optimization code structure assignment length 6 bytes */ +} SecStrBuf6; +typedef struct { + unsigned char buf[7]; /* Performance optimization code structure assignment length 7 bytes */ +} SecStrBuf7; +typedef struct { + unsigned char buf[8]; /* Performance optimization code structure assignment length 8 bytes */ +} SecStrBuf8; +typedef struct { + unsigned char buf[9]; /* Performance optimization code structure assignment length 9 bytes */ +} SecStrBuf9; +typedef struct { + unsigned char buf[10]; /* Performance optimization code structure assignment length 10 bytes */ +} SecStrBuf10; +typedef struct { + unsigned char buf[11]; /* Performance optimization code structure assignment length 11 bytes */ +} SecStrBuf11; +typedef struct { + unsigned char buf[12]; /* Performance optimization code structure assignment length 12 bytes */ +} SecStrBuf12; +typedef struct { + unsigned char buf[13]; /* Performance optimization code structure assignment length 13 bytes */ +} SecStrBuf13; +typedef struct { + unsigned char buf[14]; /* Performance optimization code structure assignment length 14 bytes */ +} SecStrBuf14; +typedef struct { + unsigned char buf[15]; /* Performance optimization code structure assignment length 15 bytes */ +} SecStrBuf15; +typedef struct { + unsigned char buf[16]; /* Performance optimization code structure assignment length 16 bytes */ +} SecStrBuf16; +typedef struct { + unsigned char buf[17]; /* Performance optimization code structure assignment length 17 bytes */ +} SecStrBuf17; +typedef struct { + unsigned char buf[18]; /* Performance optimization code structure assignment length 18 bytes */ +} SecStrBuf18; +typedef struct { + unsigned char buf[19]; /* Performance optimization code structure assignment length 19 bytes */ +} SecStrBuf19; +typedef struct { + unsigned char buf[20]; /* Performance optimization code structure assignment length 20 bytes */ +} SecStrBuf20; +typedef struct { + unsigned char buf[21]; /* Performance optimization code structure assignment length 21 bytes */ +} SecStrBuf21; +typedef struct { + unsigned char buf[22]; /* Performance optimization code structure assignment length 22 bytes */ +} SecStrBuf22; +typedef struct { + unsigned char buf[23]; /* Performance optimization code structure assignment length 23 bytes */ +} SecStrBuf23; +typedef struct { + unsigned char buf[24]; /* Performance optimization code structure assignment length 24 bytes */ +} SecStrBuf24; +typedef struct { + unsigned char buf[25]; /* Performance optimization code structure assignment length 25 bytes */ +} SecStrBuf25; +typedef struct { + unsigned char buf[26]; /* Performance optimization code structure assignment length 26 bytes */ +} SecStrBuf26; +typedef struct { + unsigned char buf[27]; /* Performance optimization code structure assignment length 27 bytes */ +} SecStrBuf27; +typedef struct { + unsigned char buf[28]; /* Performance optimization code structure assignment length 28 bytes */ +} SecStrBuf28; +typedef struct { + unsigned char buf[29]; /* Performance optimization code structure assignment length 29 bytes */ +} SecStrBuf29; +typedef struct { + unsigned char buf[30]; /* Performance optimization code structure assignment length 30 bytes */ +} SecStrBuf30; +typedef struct { + unsigned char buf[31]; /* Performance optimization code structure assignment length 31 bytes */ +} SecStrBuf31; +typedef struct { + unsigned char buf[32]; /* Performance optimization code structure assignment length 32 bytes */ +} SecStrBuf32; +typedef struct { + unsigned char buf[33]; /* Performance optimization code structure assignment length 33 bytes */ +} SecStrBuf33; +typedef struct { + unsigned char buf[34]; /* Performance optimization code structure assignment length 34 bytes */ +} SecStrBuf34; +typedef struct { + unsigned char buf[35]; /* Performance optimization code structure assignment length 35 bytes */ +} SecStrBuf35; +typedef struct { + unsigned char buf[36]; /* Performance optimization code structure assignment length 36 bytes */ +} SecStrBuf36; +typedef struct { + unsigned char buf[37]; /* Performance optimization code structure assignment length 37 bytes */ +} SecStrBuf37; +typedef struct { + unsigned char buf[38]; /* Performance optimization code structure assignment length 38 bytes */ +} SecStrBuf38; +typedef struct { + unsigned char buf[39]; /* Performance optimization code structure assignment length 39 bytes */ +} SecStrBuf39; +typedef struct { + unsigned char buf[40]; /* Performance optimization code structure assignment length 40 bytes */ +} SecStrBuf40; +typedef struct { + unsigned char buf[41]; /* Performance optimization code structure assignment length 41 bytes */ +} SecStrBuf41; +typedef struct { + unsigned char buf[42]; /* Performance optimization code structure assignment length 42 bytes */ +} SecStrBuf42; +typedef struct { + unsigned char buf[43]; /* Performance optimization code structure assignment length 43 bytes */ +} SecStrBuf43; +typedef struct { + unsigned char buf[44]; /* Performance optimization code structure assignment length 44 bytes */ +} SecStrBuf44; +typedef struct { + unsigned char buf[45]; /* Performance optimization code structure assignment length 45 bytes */ +} SecStrBuf45; +typedef struct { + unsigned char buf[46]; /* Performance optimization code structure assignment length 46 bytes */ +} SecStrBuf46; +typedef struct { + unsigned char buf[47]; /* Performance optimization code structure assignment length 47 bytes */ +} SecStrBuf47; +typedef struct { + unsigned char buf[48]; /* Performance optimization code structure assignment length 48 bytes */ +} SecStrBuf48; +typedef struct { + unsigned char buf[49]; /* Performance optimization code structure assignment length 49 bytes */ +} SecStrBuf49; +typedef struct { + unsigned char buf[50]; /* Performance optimization code structure assignment length 50 bytes */ +} SecStrBuf50; +typedef struct { + unsigned char buf[51]; /* Performance optimization code structure assignment length 51 bytes */ +} SecStrBuf51; +typedef struct { + unsigned char buf[52]; /* Performance optimization code structure assignment length 52 bytes */ +} SecStrBuf52; +typedef struct { + unsigned char buf[53]; /* Performance optimization code structure assignment length 53 bytes */ +} SecStrBuf53; +typedef struct { + unsigned char buf[54]; /* Performance optimization code structure assignment length 54 bytes */ +} SecStrBuf54; +typedef struct { + unsigned char buf[55]; /* Performance optimization code structure assignment length 55 bytes */ +} SecStrBuf55; +typedef struct { + unsigned char buf[56]; /* Performance optimization code structure assignment length 56 bytes */ +} SecStrBuf56; +typedef struct { + unsigned char buf[57]; /* Performance optimization code structure assignment length 57 bytes */ +} SecStrBuf57; +typedef struct { + unsigned char buf[58]; /* Performance optimization code structure assignment length 58 bytes */ +} SecStrBuf58; +typedef struct { + unsigned char buf[59]; /* Performance optimization code structure assignment length 59 bytes */ +} SecStrBuf59; +typedef struct { + unsigned char buf[60]; /* Performance optimization code structure assignment length 60 bytes */ +} SecStrBuf60; +typedef struct { + unsigned char buf[61]; /* Performance optimization code structure assignment length 61 bytes */ +} SecStrBuf61; +typedef struct { + unsigned char buf[62]; /* Performance optimization code structure assignment length 62 bytes */ +} SecStrBuf62; +typedef struct { + unsigned char buf[63]; /* Performance optimization code structure assignment length 63 bytes */ +} SecStrBuf63; +typedef struct { + unsigned char buf[64]; /* Performance optimization code structure assignment length 64 bytes */ +} SecStrBuf64; + +/* + * User can change the error handler by modify the following definition, + * such as logging the detail error in file. + */ +#if defined(_DEBUG) || defined(DEBUG) +#if defined(SECUREC_ERROR_HANDLER_BY_ASSERT) +#define SECUREC_ERROR_INVALID_PARAMTER(msg) assert(msg "invalid argument" == NULL) +#define SECUREC_ERROR_INVALID_RANGE(msg) assert(msg "invalid dest buffer size" == NULL) +#define SECUREC_ERROR_BUFFER_OVERLAP(msg) assert(msg "buffer overlap" == NULL) +#elif defined(SECUREC_ERROR_HANDLER_BY_PRINTF) +#if SECUREC_IN_KERNEL +#define SECUREC_ERROR_INVALID_PARAMTER(msg) printk("%s invalid argument\n", msg) +#define SECUREC_ERROR_INVALID_RANGE(msg) printk("%s invalid dest buffer size\n", msg) +#define SECUREC_ERROR_BUFFER_OVERLAP(msg) printk("%s buffer overlap\n", msg) +#else +#define SECUREC_ERROR_INVALID_PARAMTER(msg) printf("%s invalid argument\n", msg) +#define SECUREC_ERROR_INVALID_RANGE(msg) printf("%s invalid dest buffer size\n", msg) +#define SECUREC_ERROR_BUFFER_OVERLAP(msg) printf("%s buffer overlap\n", msg) +#endif +#elif defined(SECUREC_ERROR_HANDLER_BY_FILE_LOG) +#define SECUREC_ERROR_INVALID_PARAMTER(msg) LogSecureCRuntimeError(msg " EINVAL\n") +#define SECUREC_ERROR_INVALID_RANGE(msg) LogSecureCRuntimeError(msg " ERANGE\n") +#define SECUREC_ERROR_BUFFER_OVERLAP(msg) LogSecureCRuntimeError(msg " EOVERLAP\n") +#endif +#endif + +/* Default handler is none */ +#ifndef SECUREC_ERROR_INVALID_PARAMTER +#define SECUREC_ERROR_INVALID_PARAMTER(msg) ((void)0) +#endif +#ifndef SECUREC_ERROR_INVALID_RANGE +#define SECUREC_ERROR_INVALID_RANGE(msg) ((void)0) +#endif +#ifndef SECUREC_ERROR_BUFFER_OVERLAP +#define SECUREC_ERROR_BUFFER_OVERLAP(msg) ((void)0) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Assembly language memory copy and memory set for X86 or MIPS ... */ +#ifdef SECUREC_USE_ASM +extern void *memcpy_opt(void *, const void *, size_t); +extern void *memset_opt(void *, int, size_t); +#endif + +#if defined(SECUREC_ERROR_HANDLER_BY_FILE_LOG) +extern void LogSecureCRuntimeError(const char *errDetail); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/secureinput_a.c b/http/services/netmanagernative/common/huawei_secure_c/src/secureinput_a.c new file mode 100644 index 000000000..d2acd5b4e --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/secureinput_a.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#define SECUREC_FORMAT_OUTPUT_INPUT 1 +#ifdef SECUREC_FOR_WCHAR +#undef SECUREC_FOR_WCHAR +#endif + +#include "secinput.h" + +#include "input.inl" + +SECUREC_INLINE int SecIsDigit(SecInt ch) +{ + /* SecInt to unsigned char clear 571 */ + return isdigit((unsigned char)(ch)&0x00ff); +} +SECUREC_INLINE int SecIsXdigit(SecInt ch) +{ + return isxdigit((unsigned char)(ch)&0x00ff); +} +SECUREC_INLINE int SecIsSpace(SecInt ch) +{ + return isspace((unsigned char)(ch)&0x00ff); +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/secureinput_w.c b/http/services/netmanagernative/common/huawei_secure_c/src/secureinput_w.c new file mode 100644 index 000000000..95985b62a --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/secureinput_w.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/* If some platforms don't have wchar.h, dont't include it */ +#if !(defined(SECUREC_VXWORKS_PLATFORM)) +/* If there is no macro below, it will cause vs2010 compiling alarm */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#ifndef __STDC_WANT_SECURE_LIB__ +/* The order of adjustment is to eliminate alarm of Duplicate Block */ +#define __STDC_WANT_SECURE_LIB__ 0 +#endif +#ifndef _CRTIMP_ALTERNATIVE +#define _CRTIMP_ALTERNATIVE /* Comment microsoft *_s function */ +#endif +#endif +#include +#endif + +/* Disable wchar func to clear vs warning */ +#define SECUREC_ENABLE_WCHAR_FUNC 0 +#define SECUREC_FORMAT_OUTPUT_INPUT 1 + +#ifndef SECUREC_FOR_WCHAR +#define SECUREC_FOR_WCHAR +#endif + +#include "secinput.h" + +#include "input.inl" + +SECUREC_INLINE int SecIsDigit(SecInt ch) +{ + /* Convert int to unsigned int clear 571 */ + return (!((unsigned int)(int)(ch)&0xff00) && isdigit(((unsigned int)(int)(ch)&0x00ff))); +} +SECUREC_INLINE int SecIsXdigit(SecInt ch) +{ + return (!((unsigned int)(int)(ch)&0xff00) && isxdigit(((unsigned int)(int)(ch)&0x00ff))); +} +SECUREC_INLINE int SecIsSpace(SecInt ch) +{ + return iswspace((wint_t)(int)(ch)); +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/secureprintoutput.h b/http/services/netmanagernative/common/huawei_secure_c/src/secureprintoutput.h new file mode 100644 index 000000000..f8a15974c --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/secureprintoutput.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef SECUREPRINTOUTPUT_H_E950DA2C_902F_4B15_BECD_948E99090D9C +#define SECUREPRINTOUTPUT_H_E950DA2C_902F_4B15_BECD_948E99090D9C +#include "securecutil.h" + +/* + * Flag definitions. + * Using macros instead of enumerations is because some of the enumerated types under the compiler are 16bit. + */ +#define SECUREC_FLAG_SIGN 0x00001U +#define SECUREC_FLAG_SIGN_SPACE 0x00002U +#define SECUREC_FLAG_LEFT 0x00004U +#define SECUREC_FLAG_LEADZERO 0x00008U +#define SECUREC_FLAG_LONG 0x00010U +#define SECUREC_FLAG_SHORT 0x00020U +#define SECUREC_FLAG_SIGNED 0x00040U +#define SECUREC_FLAG_ALTERNATE 0x00080U +#define SECUREC_FLAG_NEGATIVE 0x00100U +#define SECUREC_FLAG_FORCE_OCTAL 0x00200U +#define SECUREC_FLAG_LONG_DOUBLE 0x00400U +#define SECUREC_FLAG_WIDECHAR 0x00800U +#define SECUREC_FLAG_LONGLONG 0x01000U +#define SECUREC_FLAG_CHAR 0x02000U +#define SECUREC_FLAG_POINTER 0x04000U +#define SECUREC_FLAG_I64 0x08000U +#define SECUREC_FLAG_PTRDIFF 0x10000U +#define SECUREC_FLAG_SIZE 0x20000U +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT +#define SECUREC_FLAG_INTMAX 0x40000U +#endif + +/* State definitions. Identify the status of the current format */ +typedef enum { + STAT_NORMAL, + STAT_PERCENT, + STAT_FLAG, + STAT_WIDTH, + STAT_DOT, + STAT_PRECIS, + STAT_SIZE, + STAT_TYPE, + STAT_INVALID +} SecFmtState; + +/* Format output buffer pointer and available size */ +typedef struct { + int count; + char *cur; +} SecPrintfStream; + +#ifndef SECUREC_BUFFER_SIZE +#if SECUREC_IN_KERNEL +#define SECUREC_BUFFER_SIZE 32 +#elif defined(SECUREC_STACK_SIZE_LESS_THAN_1K) +/* + * SECUREC BUFFER SIZE Can not be less than 23 + * The length of the octal representation of 64-bit integers with zero lead + */ +#define SECUREC_BUFFER_SIZE 256 +#else +#define SECUREC_BUFFER_SIZE 512 +#endif +#endif +#if SECUREC_BUFFER_SIZE < 23 +#error SECUREC_BUFFER_SIZE Can not be less than 23 +#endif +/* Buffer size for wchar, use 4 to make the compiler aligns as 8 bytes as possible */ +#define SECUREC_WCHAR_BUFFER_SIZE 4 + +#define SECUREC_MAX_PRECISION SECUREC_BUFFER_SIZE +/* Max. # bytes in multibyte char ,see MB_LEN_MAX */ +#define SECUREC_MB_LEN 16 +/* The return value of the internal function, which is returned when truncated */ +#define SECUREC_PRINTF_TRUNCATE (-2) + +#define SECUREC_VSPRINTF_PARAM_ERROR(format, strDest, destMax, maxLimit) \ + ((format) == NULL || (strDest) == NULL || (destMax) == 0 || (destMax) > (maxLimit)) + +#define SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, maxLimit) \ + do { \ + if ((strDest) != NULL && (destMax) > 0 && (destMax) <= (maxLimit)) { \ + *(strDest) = '\0'; \ + } \ + } \ + SECUREC_WHILE_ZERO + +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT +#define SECUREC_VSNPRINTF_PARAM_ERROR(format, strDest, destMax, count, maxLimit) \ + (((format) == NULL || (strDest) == NULL || (destMax) == 0 || (destMax) > (maxLimit)) || \ + ((count) > (SECUREC_STRING_MAX_LEN - 1) && (count) != (size_t)(-1))) + +#else +#define SECUREC_VSNPRINTF_PARAM_ERROR(format, strDest, destMax, count, maxLimit) \ + (((format) == NULL || (strDest) == NULL || (destMax) == 0 || (destMax) > (maxLimit)) || \ + ((count) > (SECUREC_STRING_MAX_LEN - 1))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif +extern int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList); +#if SECUREC_IN_KERNEL == 0 +extern int SecVswprintfImpl(wchar_t *string, size_t sizeInWchar, const wchar_t *format, va_list argList); +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/secureprintoutput_a.c b/http/services/netmanagernative/common/huawei_secure_c/src/secureprintoutput_a.c new file mode 100644 index 000000000..69861d7f1 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/secureprintoutput_a.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#define SECUREC_FORMAT_OUTPUT_INPUT 1 + +#ifdef SECUREC_FOR_WCHAR +#undef SECUREC_FOR_WCHAR +#endif + +#include "secureprintoutput.h" +#if SECUREC_WARP_OUTPUT +#define SECUREC_FORMAT_FLAG_TABLE_SIZE 128 +static const unsigned char g_flagTable[SECUREC_FORMAT_FLAG_TABLE_SIZE] = { + /* + * Known flag is "0123456789 +-#hlLwZzjqt*I" + */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00}; + +SECUREC_INLINE const char *SecSkipKnownFlags(const char *format) +{ + const char *fmt = format; + while (*fmt != '\0') { + char fmtChar = *fmt; + if ((unsigned char)fmtChar > 0x7f) { /* 0x7f is upper limit of format char value */ + break; + } + if (g_flagTable[(unsigned char)fmtChar] == 0) { + break; + } + ++fmt; + } + return fmt; +} + +SECUREC_INLINE int SecFormatContainN(const char *format) +{ + const char *fmt = format; + while (*fmt != '\0') { + ++fmt; + /* Skip normal char */ + if (*(fmt - 1) != '%') { + continue; + } + /* Meet %% */ + if (*fmt == '%') { + ++fmt; /* Point to the character after the %. Correct handling %%xx */ + continue; + } + /* Now parse %..., fmt point to the character after the % */ + fmt = SecSkipKnownFlags(fmt); + if (*fmt == 'n') { + return 1; + } + } + return 0; +} +/* + * Multi character formatted output implementation, the count include \0 character, must be greater than zero + */ +int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList) +{ + int retVal; + if (SecFormatContainN(format)) { + string[0] = '\0'; + return -1; + } + retVal = vsnprintf(string, count, format, argList); + if (retVal >= (int)count) { /* The size_t to int is ok, count max is SECUREC_STRING_MAX_LEN */ + /* The buffer was too small; we return truncation */ + string[count - 1] = '\0'; + return SECUREC_PRINTF_TRUNCATE; + } else if (retVal < 0) { + string[0] = '\0'; /* Empty the dest strDest */ + return -1; + } + return retVal; +} +#else +#if SECUREC_IN_KERNEL +#include +#endif + +#define SECUREC_CHAR(x) x +#define SECUREC_WRITE_MULTI_CHAR SecWriteMultiChar +#define SECUREC_WRITE_STRING SecWriteString + +#ifndef EOF +#define EOF (-1) +#endif + +SECUREC_INLINE void SecWriteMultiChar(char ch, int num, SecPrintfStream *f, int *pnumwritten); +SECUREC_INLINE void SecWriteString(const char *string, int len, SecPrintfStream *f, int *pnumwritten); + +#include "output.inl" + +/* + * Multi character formatted output implementation + */ +int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList) +{ + SecPrintfStream str; + int retVal; + + str.count = (int)count; /* The count include \0 character, must be greater than zero */ + str.cur = string; + + retVal = SecOutputS(&str, format, argList); + if (retVal >= 0 && SecPutZeroChar(&str) == 0) { + return retVal; + } else if (str.count < 0) { + /* The buffer was too small; we return truncation */ + string[count - 1] = '\0'; + return SECUREC_PRINTF_TRUNCATE; + } + string[0] = '\0'; /* Empty the dest strDest */ + return -1; +} + +/* + * Write a wide character + */ +SECUREC_INLINE void SecWriteMultiChar(char ch, int num, SecPrintfStream *f, int *pnumwritten) +{ + int count = num; + while (count-- > 0 && --(f->count) >= 0) { + *(f->cur) = ch; + ++(f->cur); + *pnumwritten = *pnumwritten + 1; + } + if (f->count < 0) { + *pnumwritten = -1; + } +} + +/* + * Write string function, where this function is called, make sure that len is greater than 0 + */ +SECUREC_INLINE void SecWriteString(const char *string, int len, SecPrintfStream *f, int *pnumwritten) +{ + const char *str = string; + int count = len; + while (count-- > 0 && --(f->count) >= 0) { + *(f->cur) = *str; + ++(f->cur); + ++str; + } + *pnumwritten = *pnumwritten + (int)(size_t)(str - string); + if (f->count < 0) { + *pnumwritten = -1; + } +} +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/secureprintoutput_w.c b/http/services/netmanagernative/common/huawei_secure_c/src/secureprintoutput_w.c new file mode 100644 index 000000000..ef1086142 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/secureprintoutput_w.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/* If some platforms don't have wchar.h, dont't include it */ +#if !(defined(SECUREC_VXWORKS_PLATFORM)) +/* If there is no macro above, it will cause compiling alarm */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#ifndef _CRTIMP_ALTERNATIVE +#define _CRTIMP_ALTERNATIVE /* Comment microsoft *_s function */ +#endif +#ifndef __STDC_WANT_SECURE_LIB__ +#define __STDC_WANT_SECURE_LIB__ 0 +#endif +#endif +#include +#endif + +/* Disable wchar func to clear vs warning */ +#define SECUREC_ENABLE_WCHAR_FUNC 0 +#define SECUREC_FORMAT_OUTPUT_INPUT 1 + +#ifndef SECUREC_FOR_WCHAR +#define SECUREC_FOR_WCHAR +#endif + +#if defined(SECUREC_WARP_OUTPUT) && SECUREC_WARP_OUTPUT +#undef SECUREC_WARP_OUTPUT +#define SECUREC_WARP_OUTPUT 0 +#endif + +#include "secureprintoutput.h" + +#define SECUREC_CHAR(x) L##x +#define SECUREC_WRITE_MULTI_CHAR SecWriteMultiCharW +#define SECUREC_WRITE_STRING SecWriteStringW + +SECUREC_INLINE void SecWriteCharW(wchar_t ch, SecPrintfStream *f, int *pnumwritten); +SECUREC_INLINE void SecWriteMultiCharW(wchar_t ch, int num, SecPrintfStream *f, int *pnumwritten); +SECUREC_INLINE void SecWriteStringW(const wchar_t *string, int len, SecPrintfStream *f, int *pnumwritten); +SECUREC_INLINE int SecPutWcharStrEndingZero(SecPrintfStream *str, int zeroCount); + +#include "output.inl" + +/* + * Wide character formatted output implementation + */ +int SecVswprintfImpl(wchar_t *string, size_t sizeInWchar, const wchar_t *format, va_list argList) +{ + SecPrintfStream str; + int retVal; /* If initialization causes e838 */ + + str.cur = (char *)string; + /* This count include \0 character, Must be greater than zero */ + str.count = (int)(sizeInWchar * sizeof(wchar_t)); + + retVal = SecOutputSW(&str, format, argList); + if (retVal >= 0 && SecPutWcharStrEndingZero(&str, (int)sizeof(wchar_t)) == 0) { + return (retVal); + } else if (str.count < 0) { + /* The buffer was too small; we return truncation */ + string[sizeInWchar - 1] = L'\0'; + return SECUREC_PRINTF_TRUNCATE; + } + string[0] = L'\0'; + return -1; +} + +/* + * Output a wide character zero end into the SecPrintfStream structure + */ +SECUREC_INLINE int SecPutWcharStrEndingZero(SecPrintfStream *str, int zeroCount) +{ + int i = 0; + while (i < zeroCount && SecPutZeroChar(str) == 0) { + ++i; + } + if (i == zeroCount) { + return 0; + } + return -1; +} + +/* + * Output a wide character into the SecPrintfStream structure + */ +SECUREC_INLINE int SecPutCharW(wchar_t ch, SecPrintfStream *f) +{ + if (((f)->count -= (int)sizeof(wchar_t)) >= 0) { + *(wchar_t *)(void *)(f->cur) = ch; + f->cur += sizeof(wchar_t); + return 0; + } + return -1; +} + +/* + * Output a wide character into the SecPrintfStream structure, returns the number of characters written + */ +SECUREC_INLINE void SecWriteCharW(wchar_t ch, SecPrintfStream *f, int *pnumwritten) +{ + if (SecPutCharW(ch, f) == 0) { + *pnumwritten = *pnumwritten + 1; + } else { + *pnumwritten = -1; + } +} + +/* + * Output multiple wide character into the SecPrintfStream structure, returns the number of characters written + */ +SECUREC_INLINE void SecWriteMultiCharW(wchar_t ch, int num, SecPrintfStream *f, int *pnumwritten) +{ + int count = num; + while (count-- > 0) { + SecWriteCharW(ch, f, pnumwritten); + if (*pnumwritten == -1) { + break; + } + } +} + +/* + * Output a wide string into the SecPrintfStream structure, returns the number of characters written + */ +SECUREC_INLINE void SecWriteStringW(const wchar_t *string, int len, SecPrintfStream *f, int *pnumwritten) +{ + const wchar_t *str = string; + int count = len; + while (count-- > 0) { + SecWriteCharW(*str, f, pnumwritten); + ++str; + if (*pnumwritten == -1) { + break; + } + } +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/snprintf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/snprintf_s.c new file mode 100644 index 000000000..d37995af0 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/snprintf_s.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securec.h" + +#if SECUREC_ENABLE_SNPRINTF +/* + * + * The snprintf_s function is equivalent to the snprintf function + * except for the parameter destMax/count and the explicit runtime-constraints violation + * The snprintf_s function formats and stores count or fewer characters in + * strDest and appends a terminating null. Each argument (if any) is converted + * and output according to the corresponding format specification in format. + * The formatting is consistent with the printf family of functions; If copying + * occurs between strings that overlap, the behavior is undefined. + * + * + * strDest Storage location for the output. + * destMax The size of the storage location for output. Size + * in bytes for snprintf_s or size in words for snwprintf_s. + * count Maximum number of character to store. + * format Format-control string. + * ... Optional arguments. + * + * + * strDest is updated + * + * + * return the number of characters written, not including the terminating null + * return -1 if an error occurs. + * return -1 if count < destMax and the output string has been truncated + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + * + */ +int snprintf_s(char *strDest, size_t destMax, size_t count, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vsnprintf_s(strDest, destMax, count, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(snprintf_s); +#endif +#endif + +#if SECUREC_SNPRINTF_TRUNCATED +/* + * + * The snprintf_truncated_s function is equivalent to the snprintf function + * except for the parameter destMax/count and the explicit runtime-constraints violation + * The snprintf_truncated_s function formats and stores count or fewer characters in + * strDest and appends a terminating null. Each argument (if any) is converted + * and output according to the corresponding format specification in format. + * The formatting is consistent with the printf family of functions; If copying + * occurs between strings that overlap, the behavior is undefined. + * + * + * strDest Storage location for the output. + * destMax The size of the storage location for output. Size + * in bytes for snprintf_truncated_s or size in words for snwprintf_s. + * format Format-control string. + * ... Optional arguments. + * + * + * strDest is updated + * + * + * return the number of characters written, not including the terminating null + * return -1 if an error occurs. + * return destMax-1 if output string has been truncated + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + * + */ +int snprintf_truncated_s(char *strDest, size_t destMax, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vsnprintf_truncated_s(strDest, destMax, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(snprintf_truncated_s); +#endif + +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/sprintf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/sprintf_s.c new file mode 100644 index 000000000..bcbd8c7a0 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/sprintf_s.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securec.h" + +/* + * + * The sprintf_s function is equivalent to the sprintf function + * except for the parameter destMax and the explicit runtime-constraints violation + * The sprintf_s function formats and stores a series of characters and values + * in strDest. Each argument (if any) is converted and output according to + * the corresponding format specification in format. The format consists of + * ordinary characters and has the same form and function as the format argument + * for printf. A null character is appended after the last character written. + * If copying occurs between strings that overlap, the behavior is undefined. + * + * + * strDest Storage location for output. + * destMax Maximum number of characters to store. + * format Format-control string. + * ... Optional arguments + * + * + * strDest is updated + * + * + * return the number of bytes stored in strDest, not counting the terminating null character. + * return -1 if an error occurred. + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +int sprintf_s(char *strDest, size_t destMax, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vsprintf_s(strDest, destMax, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(sprintf_s); +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/sscanf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/sscanf_s.c new file mode 100644 index 000000000..f3fcc0257 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/sscanf_s.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securec.h" + +/* + * + * The sscanf_s function is equivalent to fscanf_s, + * except that input is obtained from a string (specified by the argument buffer) rather than from a stream + * The sscanf function reads data from buffer into the location given by each + * argument. Every argument must be a pointer to a variable with a type that + * corresponds to a type specifier in format. The format argument controls the + * interpretation of the input fields and has the same form and function as + * the format argument for the scanf function. + * If copying takes place between strings that overlap, the behavior is undefined. + * + * + * buffer Stored data. + * format Format control string, see Format Specifications. + * ... Optional arguments. + * + * + * ... The converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. + * A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int sscanf_s(const char *buffer, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vsscanf_s(buffer, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(sscanf_s); +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/strcat_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/strcat_s.c new file mode 100644 index 000000000..8b6344ebd --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/strcat_s.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securecutil.h" + +/* + * Befor this function, the basic parameter checking has been done + */ +SECUREC_INLINE errno_t SecDoCat(char *strDest, size_t destMax, const char *strSrc) +{ + size_t destLen; + size_t srcLen; + size_t maxSrcLen; + SECUREC_CALC_STR_LEN(strDest, destMax, &destLen); + /* Only optimize strSrc, do not apply this function to strDest */ + maxSrcLen = destMax - destLen; + SECUREC_CALC_STR_LEN_OPT(strSrc, maxSrcLen, &srcLen); + + if (SECUREC_CAT_STRING_IS_OVERLAP(strDest, destLen, strSrc, srcLen)) { + strDest[0] = '\0'; + if (strDest + destLen <= strSrc && destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("strcat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_BUFFER_OVERLAP("strcat_s"); + return EOVERLAP_AND_RESET; + } + if (srcLen + destLen >= destMax || strDest == strSrc) { + strDest[0] = '\0'; + if (destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("strcat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_INVALID_RANGE("strcat_s"); + return ERANGE_AND_RESET; + } + SECUREC_MEMCPY_WARP_OPT(strDest + destLen, strSrc, srcLen + 1); /* Single character length include \0 */ + return EOK; +} + +/* + * + * The strcat_s function appends a copy of the string pointed to by strSrc (including the terminating null + * character) to the end of the string pointed to by strDest. The initial character of strSrc overwrites the + * terminating null character of strDest. strcat_s will return EOVERLAP_AND_RESET if the source and destination + * strings overlap. + * + * Note that the second parameter is the total size of the buffer, not the + * remaining size. + * + * + * strDest Null-terminated destination string buffer. + * destMax Size of the destination string buffer. + * strSrc Null-terminated source string buffer. + * + * + * strDest is updated + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN + * EINVAL_AND_RESET (strDest unterminated and all other parameters are valid)or + * (strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= + * SECUREC_STRING_MAX_LEN) ERANGE destMax is 0 and destMax > SECUREC_STRING_MAX_LEN ERANGE_AND_RESET + * strDest have not enough space and all other parameters are valid and not overlap EOVERLAP_AND_RESET dest + * buffer and source buffer are overlapped and all parameters are valid + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t strcat_s(char *strDest, size_t destMax, const char *strSrc) +{ + if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("strcat_s"); + return ERANGE; + } + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("strcat_s"); + if (strDest != NULL) { + strDest[0] = '\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + return SecDoCat(strDest, destMax, strSrc); +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(strcat_s); +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/strcpy_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/strcpy_s.c new file mode 100644 index 000000000..f3074f727 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/strcpy_s.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +/* + * [Standardize-exceptions] Use unsafe function: Performance-sensitive + * [reason] Always used in the performance critical path, + * and sufficient input validation is performed before calling + */ + +#include "securecutil.h" + +#ifndef SECUREC_STRCPY_WITH_PERFORMANCE +#define SECUREC_STRCPY_WITH_PERFORMANCE 1 +#endif + +#if (SECUREC_IN_KERNEL == 0) && SECUREC_STRCPY_WITH_PERFORMANCE +#ifndef SECUREC_STRCOPY_THRESHOLD_SIZE +#define SECUREC_STRCOPY_THRESHOLD_SIZE 32UL +#endif + +/* The purpose of converting to void is to clean up the alarm */ +#define SECUREC_SMALL_STR_COPY(strDest, strSrc, srcStrLen) \ + do { \ + if (SECUREC_ADDR_ALIGNED_8(strDest) && SECUREC_ADDR_ALIGNED_8(strSrc)) { \ + /* Use struct assignment */ \ + switch (srcStrLen) { \ + case 1: \ + *(SecStrBuf1 *)(void *)(strDest) = *(const SecStrBuf1 *)(const void *)(strSrc); \ + break; \ + case 2: \ + *(SecStrBuf2 *)(void *)(strDest) = *(const SecStrBuf2 *)(const void *)(strSrc); \ + break; \ + case 3: \ + *(SecStrBuf3 *)(void *)(strDest) = *(const SecStrBuf3 *)(const void *)(strSrc); \ + break; \ + case 4: \ + *(SecStrBuf4 *)(void *)(strDest) = *(const SecStrBuf4 *)(const void *)(strSrc); \ + break; \ + case 5: \ + *(SecStrBuf5 *)(void *)(strDest) = *(const SecStrBuf5 *)(const void *)(strSrc); \ + break; \ + case 6: \ + *(SecStrBuf6 *)(void *)(strDest) = *(const SecStrBuf6 *)(const void *)(strSrc); \ + break; \ + case 7: \ + *(SecStrBuf7 *)(void *)(strDest) = *(const SecStrBuf7 *)(const void *)(strSrc); \ + break; \ + case 8: \ + *(SecStrBuf8 *)(void *)(strDest) = *(const SecStrBuf8 *)(const void *)(strSrc); \ + break; \ + case 9: \ + *(SecStrBuf9 *)(void *)(strDest) = *(const SecStrBuf9 *)(const void *)(strSrc); \ + break; \ + case 10: \ + *(SecStrBuf10 *)(void *)(strDest) = *(const SecStrBuf10 *)(const void *)(strSrc); \ + break; \ + case 11: \ + *(SecStrBuf11 *)(void *)(strDest) = *(const SecStrBuf11 *)(const void *)(strSrc); \ + break; \ + case 12: \ + *(SecStrBuf12 *)(void *)(strDest) = *(const SecStrBuf12 *)(const void *)(strSrc); \ + break; \ + case 13: \ + *(SecStrBuf13 *)(void *)(strDest) = *(const SecStrBuf13 *)(const void *)(strSrc); \ + break; \ + case 14: \ + *(SecStrBuf14 *)(void *)(strDest) = *(const SecStrBuf14 *)(const void *)(strSrc); \ + break; \ + case 15: \ + *(SecStrBuf15 *)(void *)(strDest) = *(const SecStrBuf15 *)(const void *)(strSrc); \ + break; \ + case 16: \ + *(SecStrBuf16 *)(void *)(strDest) = *(const SecStrBuf16 *)(const void *)(strSrc); \ + break; \ + case 17: \ + *(SecStrBuf17 *)(void *)(strDest) = *(const SecStrBuf17 *)(const void *)(strSrc); \ + break; \ + case 18: \ + *(SecStrBuf18 *)(void *)(strDest) = *(const SecStrBuf18 *)(const void *)(strSrc); \ + break; \ + case 19: \ + *(SecStrBuf19 *)(void *)(strDest) = *(const SecStrBuf19 *)(const void *)(strSrc); \ + break; \ + case 20: \ + *(SecStrBuf20 *)(void *)(strDest) = *(const SecStrBuf20 *)(const void *)(strSrc); \ + break; \ + case 21: \ + *(SecStrBuf21 *)(void *)(strDest) = *(const SecStrBuf21 *)(const void *)(strSrc); \ + break; \ + case 22: \ + *(SecStrBuf22 *)(void *)(strDest) = *(const SecStrBuf22 *)(const void *)(strSrc); \ + break; \ + case 23: \ + *(SecStrBuf23 *)(void *)(strDest) = *(const SecStrBuf23 *)(const void *)(strSrc); \ + break; \ + case 24: \ + *(SecStrBuf24 *)(void *)(strDest) = *(const SecStrBuf24 *)(const void *)(strSrc); \ + break; \ + case 25: \ + *(SecStrBuf25 *)(void *)(strDest) = *(const SecStrBuf25 *)(const void *)(strSrc); \ + break; \ + case 26: \ + *(SecStrBuf26 *)(void *)(strDest) = *(const SecStrBuf26 *)(const void *)(strSrc); \ + break; \ + case 27: \ + *(SecStrBuf27 *)(void *)(strDest) = *(const SecStrBuf27 *)(const void *)(strSrc); \ + break; \ + case 28: \ + *(SecStrBuf28 *)(void *)(strDest) = *(const SecStrBuf28 *)(const void *)(strSrc); \ + break; \ + case 29: \ + *(SecStrBuf29 *)(void *)(strDest) = *(const SecStrBuf29 *)(const void *)(strSrc); \ + break; \ + case 30: \ + *(SecStrBuf30 *)(void *)(strDest) = *(const SecStrBuf30 *)(const void *)(strSrc); \ + break; \ + case 31: \ + *(SecStrBuf31 *)(void *)(strDest) = *(const SecStrBuf31 *)(const void *)(strSrc); \ + break; \ + case 32: \ + *(SecStrBuf32 *)(void *)(strDest) = *(const SecStrBuf32 *)(const void *)(strSrc); \ + break; \ + default: \ + break; \ + } /* END switch */ \ + } else { \ + char *tmpStrDest = (char *)(strDest); \ + const char *tmpStrSrc = (const char *)(strSrc); \ + switch (srcStrLen) { \ + case 32: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 31: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 30: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 29: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 28: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 27: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 26: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 25: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 24: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 23: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 22: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 21: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 20: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 19: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 18: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 17: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 16: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 15: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 14: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 13: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 12: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 11: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 10: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 9: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 8: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 7: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 6: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 5: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 4: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 3: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 2: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + case 1: \ + *(tmpStrDest++) = *(tmpStrSrc++); \ + /* fall-through */ /* FALLTHRU */ \ + default: \ + break; \ + } \ + } \ + } \ + SECUREC_WHILE_ZERO +#endif + +#if SECUREC_IN_KERNEL || (SECUREC_STRCPY_WITH_PERFORMANCE == 0) +#define SECUREC_STRCPY_OPT(dest, src, lenWithTerm) SECUREC_MEMCPY_WARP_OPT((dest), (src), (lenWithTerm)) +#else +/* + * Performance optimization. lenWithTerm include '\0' + */ +#define SECUREC_STRCPY_OPT(dest, src, lenWithTerm) \ + do { \ + if ((lenWithTerm) > SECUREC_STRCOPY_THRESHOLD_SIZE) { \ + SECUREC_MEMCPY_WARP_OPT((dest), (src), (lenWithTerm)); \ + } else { \ + SECUREC_SMALL_STR_COPY((dest), (src), (lenWithTerm)); \ + } \ + } \ + SECUREC_WHILE_ZERO +#endif + +/* + * Check Src Range + */ +SECUREC_INLINE errno_t CheckSrcRange(char *strDest, size_t destMax, const char *strSrc) +{ + size_t tmpDestMax = destMax; + const char *tmpSrc = strSrc; + /* Use destMax as boundary checker and destMax must be greater than zero */ + while (*(tmpSrc) != '\0' && tmpDestMax > 0) { + ++tmpSrc; + --tmpDestMax; + } + if (tmpDestMax == 0) { + strDest[0] = '\0'; + SECUREC_ERROR_INVALID_RANGE("strcpy_s"); + return ERANGE_AND_RESET; + } + return EOK; +} + +/* + * Handling errors + */ +errno_t strcpy_error(char *strDest, size_t destMax, const char *strSrc) +{ + if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("strcpy_s"); + return ERANGE; + } else if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("strcpy_s"); + if (strDest != NULL) { + strDest[0] = '\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + return CheckSrcRange(strDest, destMax, strSrc); +} + +/* + * + * The strcpy_s function copies the string pointed to strSrc + * (including the terminating null character) into the array pointed to by strDest + * The destination string must be large enough to hold the source string, + * including the terminating null character. strcpy_s will return EOVERLAP_AND_RESET + * if the source and destination strings overlap. + * + * + * strDest Location of destination string buffer + * destMax Size of the destination string buffer. + * strSrc Null-terminated source string buffer. + * + * + * strDest is updated. + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN + * EINVAL_AND_RESET strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= + * SECUREC_STRING_MAX_LEN ERANGE destMax is 0 and destMax > SECUREC_STRING_MAX_LEN + * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t strcpy_s(char *strDest, size_t destMax, const char *strSrc) +{ + if ((destMax > 0 && destMax <= SECUREC_STRING_MAX_LEN && strDest != NULL && strSrc != NULL && + strDest != strSrc)) { + size_t srcStrLen; + SECUREC_CALC_STR_LEN(strSrc, destMax, &srcStrLen); + ++srcStrLen; /* The length include '\0' */ + + if (srcStrLen <= destMax) { + /* Use mem overlap check include '\0' */ + if (SECUREC_MEMORY_NO_OVERLAP(strDest, strSrc, srcStrLen)) { + /* Performance optimization srcStrLen include '\0' */ + SECUREC_STRCPY_OPT(strDest, strSrc, srcStrLen); + return EOK; + } else { + strDest[0] = '\0'; + SECUREC_ERROR_BUFFER_OVERLAP("strcpy_s"); + return EOVERLAP_AND_RESET; + } + } + } + return strcpy_error(strDest, destMax, strSrc); +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(strcpy_s); +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/strncat_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/strncat_s.c new file mode 100644 index 000000000..de00c50fd --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/strncat_s.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securecutil.h" + +/* + * Befor this function, the basic parameter checking has been done + */ +SECUREC_INLINE errno_t SecDoCatLimit(char *strDest, size_t destMax, const char *strSrc, size_t count) +{ + size_t destLen; + size_t srcLen; + SECUREC_CALC_STR_LEN(strDest, destMax, &destLen); + /* + * The strSrc is no longer optimized. The reason is that when count is small, + * the efficiency of strnlen is higher than that of self realization. + */ + SECUREC_CALC_STR_LEN(strSrc, count, &srcLen); + + if (SECUREC_CAT_STRING_IS_OVERLAP(strDest, destLen, strSrc, srcLen)) { + strDest[0] = '\0'; + if (strDest + destLen <= strSrc && destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("strncat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_BUFFER_OVERLAP("strncat_s"); + return EOVERLAP_AND_RESET; + } + if (srcLen + destLen >= destMax || strDest == strSrc) { + strDest[0] = '\0'; + if (destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("strncat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_INVALID_RANGE("strncat_s"); + return ERANGE_AND_RESET; + } + SECUREC_MEMCPY_WARP_OPT(strDest + destLen, strSrc, srcLen); /* No terminator */ + *(strDest + destLen + srcLen) = '\0'; + return EOK; +} + +/* + * + * The strncat_s function appends not more than n successive characters + * (not including the terminating null character) + * from the array pointed to by strSrc to the end of the string pointed to by strDest + * The strncat_s function try to append the first D characters of strSrc to + * the end of strDest, where D is the lesser of count and the length of strSrc. + * If appending those D characters will fit within strDest (whose size is given + * as destMax) and still leave room for a null terminator, then those characters + * are appended, starting at the original terminating null of strDest, and a + * new terminating null is appended; otherwise, strDest[0] is set to the null + * character. + * + * + * strDest Null-terminated destination string. + * destMax Size of the destination buffer. + * strSrc Null-terminated source string. + * count Number of character to append, or truncate. + * + * + * strDest is updated + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN + * EINVAL_AND_RESET (strDest unterminated and all other parameters are valid)or + * (strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= + * SECUREC_STRING_MAX_LEN) ERANGE destMax is 0 and destMax > SECUREC_STRING_MAX_LEN + * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("strncat_s"); + return ERANGE; + } + + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("strncat_s"); + if (strDest != NULL) { + strDest[0] = '\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + if (count > SECUREC_STRING_MAX_LEN) { +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT + if (count == (size_t)(-1)) { + /* Windows internal functions may pass in -1 when calling this function */ + return SecDoCatLimit(strDest, destMax, strSrc, destMax); + } +#endif + strDest[0] = '\0'; + SECUREC_ERROR_INVALID_RANGE("strncat_s"); + return ERANGE_AND_RESET; + } + return SecDoCatLimit(strDest, destMax, strSrc, count); +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(strncat_s); +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/strncpy_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/strncpy_s.c new file mode 100644 index 000000000..558be3d69 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/strncpy_s.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +/* + * [Standardize-exceptions] Use unsafe function: Performance-sensitive + * [reason] Always used in the performance critical path, + * and sufficient input validation is performed before calling + */ + +#include "securecutil.h" + +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) +#define SECUREC_STRNCPY_PARAM_OK(strDest, destMax, strSrc, count) \ + (((destMax) > 0 && (destMax) <= SECUREC_STRING_MAX_LEN && (strDest) != NULL && (strSrc) != NULL && \ + ((count) <= SECUREC_STRING_MAX_LEN || (count) == ((size_t)(-1))) && (count) > 0)) +#else +#define SECUREC_STRNCPY_PARAM_OK(strDest, destMax, strSrc, count) \ + (((destMax) > 0 && (destMax) <= SECUREC_STRING_MAX_LEN && (strDest) != NULL && (strSrc) != NULL && \ + (count) <= SECUREC_STRING_MAX_LEN && (count) > 0)) +#endif + +/* + * Check Src Count Range + */ +SECUREC_INLINE errno_t CheckSrcCountRange(char *strDest, size_t destMax, const char *strSrc, size_t count) +{ + size_t tmpDestMax = destMax; + size_t tmpCount = count; + const char *endPos = strSrc; + + /* Use destMax and count as boundary checker and destMax must be greater than zero */ + while (*(endPos) != '\0' && tmpDestMax > 0 && tmpCount > 0) { + ++endPos; + --tmpCount; + --tmpDestMax; + } + if (tmpDestMax == 0) { + strDest[0] = '\0'; + SECUREC_ERROR_INVALID_RANGE("strncpy_s"); + return ERANGE_AND_RESET; + } + return EOK; +} + +/* + * Handling errors, when dest euqal src return EOK + */ +errno_t strncpy_error(char *strDest, size_t destMax, const char *strSrc, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("strncpy_s"); + return ERANGE; + } else if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("strncpy_s"); + if (strDest != NULL) { + strDest[0] = '\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } else if (count > SECUREC_STRING_MAX_LEN) { + strDest[0] = '\0'; /* Clear dest string */ + SECUREC_ERROR_INVALID_RANGE("strncpy_s"); + return ERANGE_AND_RESET; + } else if (count == 0) { + strDest[0] = '\0'; + return EOK; + } + + return CheckSrcCountRange(strDest, destMax, strSrc, count); +} + +/* + * + * The strncpy_s function copies not more than n successive characters (not including the terminating null + * character) from the array pointed to by strSrc to the array pointed to by strDest. + * + * + * strDest Destination string. + * destMax The size of the destination string, in characters. + * strSrc Source string. + * count Number of characters to be copied. + * + * + * strDest is updated + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN + * EINVAL_AND_RESET strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= + * SECUREC_STRING_MAX_LEN ERANGE destMax is 0 and destMax > SECUREC_STRING_MAX_LEN + * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t strncpy_s(char *strDest, size_t destMax, const char *strSrc, size_t count) +{ + if (SECUREC_STRNCPY_PARAM_OK(strDest, destMax, strSrc, count)) { + size_t minCpLen; /* Use it to store the maxi length limit */ + if (count < destMax) { + SECUREC_CALC_STR_LEN(strSrc, count, &minCpLen); /* No ending terminator */ + } else { + size_t tmpCount = destMax; +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT + if (count == ((size_t)(-1))) { + tmpCount = destMax - 1; + } +#endif + SECUREC_CALC_STR_LEN(strSrc, tmpCount, &minCpLen); /* No ending terminator */ + if (minCpLen == destMax) { + strDest[0] = '\0'; + SECUREC_ERROR_INVALID_RANGE("strncpy_s"); + return ERANGE_AND_RESET; + } + } + if (SECUREC_STRING_NO_OVERLAP(strDest, strSrc, minCpLen) || strDest == strSrc) { + /* Not overlap */ + SECUREC_MEMCPY_WARP_OPT(strDest, strSrc, minCpLen); /* Copy string without terminator */ + strDest[minCpLen] = '\0'; + return EOK; + } else { + strDest[0] = '\0'; + SECUREC_ERROR_BUFFER_OVERLAP("strncpy_s"); + return EOVERLAP_AND_RESET; + } + } + return strncpy_error(strDest, destMax, strSrc, count); +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(strncpy_s); +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/strtok_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/strtok_s.c new file mode 100644 index 000000000..87fa52336 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/strtok_s.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securecutil.h" + +SECUREC_INLINE int SecIsInDelimit(char ch, const char *strDelimit) +{ + const char *ctl = strDelimit; + while (*ctl != '\0' && *ctl != ch) { + ++ctl; + } + return (int)(*ctl != '\0'); +} + +/* + * Find beginning of token (skip over leading delimiters). + * Note that there is no token if this loop sets string to point to the terminal null. + */ +SECUREC_INLINE char *SecFindBegin(char *strToken, const char *strDelimit) +{ + char *token = strToken; + while (*token != '\0') { + if (SecIsInDelimit(*token, strDelimit)) { + ++token; + continue; + } + /* Don't find any delimiter in string header, break the loop */ + break; + } + return token; +} + +/* + * Find rest of token + */ +SECUREC_INLINE char *SecFindRest(char *strToken, const char *strDelimit) +{ + /* Find the rest of the token. If it is not the end of the string, put a null there */ + char *token = strToken; + while (*token != '\0') { + if (SecIsInDelimit(*token, strDelimit)) { + /* Find a delimiter, set string termintor */ + *token = '\0'; + ++token; + break; + } + ++token; + } + return token; +} + +/* + * Find the final position pointer + */ +SECUREC_INLINE char *SecUpdateToken(char *strToken, const char *strDelimit, char **context) +{ + /* Point to updated position */ + char *token = SecFindRest(strToken, strDelimit); + /* Record string position for next search in the context */ + *context = token; + /* Determine if a token has been found. */ + if (token == strToken) { + return NULL; + } + return strToken; +} + +/* + * + * The strtok_s function parses a string into a sequence of strToken, + * replace all characters in strToken string that match to strDelimit set with 0. + * On the first call to strtok_s the string to be parsed should be specified in strToken. + * In each subsequent call that should parse the same string, strToken should be NULL + * + * strToken String containing token or tokens. + * strDelimit Set of delimiter characters. + * context Used to store position information between calls + * to strtok_s + * + * context is updated + * + * On the first call returns the address of the first non \0 character, otherwise NULL is returned. + * In subsequent calls, the strtoken is set to NULL, and the context set is the same as the previous call, + * return NULL if the *context string length is equal 0, otherwise return *context. + */ +char *strtok_s(char *strToken, const char *strDelimit, char **context) +{ + char *orgToken = strToken; + /* Validate delimiter and string context */ + if (context == NULL || strDelimit == NULL) { + return NULL; + } + /* Valid input string and string pointer from where to search */ + if (orgToken == NULL && *context == NULL) { + return NULL; + } + /* If string is null, continue searching from previous string position stored in context */ + if (orgToken == NULL) { + orgToken = *context; + } + orgToken = SecFindBegin(orgToken, strDelimit); + return SecUpdateToken(orgToken, strDelimit, context); +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(strtok_s); +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/swprintf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/swprintf_s.c new file mode 100644 index 000000000..646b9430f --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/swprintf_s.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securec.h" + +/* + * + * The swprintf_s function is the wide-character equivalent of the sprintf_s function + * + * + * strDest Storage location for the output. + * destMax Maximum number of characters to store. + * format Format-control string. + * ... Optional arguments + * + * + * strDest is updated + * + * + * return the number of wide characters stored in strDest, not counting the terminating null wide character. + * return -1 if an error occurred. + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +int swprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vswprintf_s(strDest, destMax, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/swscanf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/swscanf_s.c new file mode 100644 index 000000000..7fc11fa0a --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/swscanf_s.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securec.h" + +/* + * + * The swscanf_s function is the wide-character equivalent of the sscanf_s function + * The swscanf_s function reads data from buffer into the location given by + * each argument. Every argument must be a pointer to a variable with a type + * that corresponds to a type specifier in format. The format argument controls + * the interpretation of the input fields and has the same form and function + * as the format argument for the scanf function. If copying takes place between + * strings that overlap, the behavior is undefined. + * + * + * buffer Stored data. + * format Format control string, see Format Specifications. + * ... Optional arguments. + * + * + * ... the converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; The return value does not include fields that were read but not + * assigned. + * A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int swscanf_s(const wchar_t *buffer, const wchar_t *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vswscanf_s(buffer, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/vfscanf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/vfscanf_s.c new file mode 100644 index 000000000..21429cdec --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/vfscanf_s.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#define SECUREC_INLINE_INIT_FILE_STREAM_FILE 1 +#include "secinput.h" + +/* + * + * The vfscanf_s function is equivalent to fscanf_s, with the variable argument list replaced by argList + * The vfscanf_s function reads data from the current position of stream into + * the locations given by argument (if any). Each argument must be a pointer + * to a variable of a type that corresponds to a type specifier in format. + * format controls the interpretation of the input fields and has the same + * form and function as the format argument for scanf. + * + * + * stream Pointer to FILE structure. + * format Format control string, see Format Specifications. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int vfscanf_s(FILE *stream, const char *format, va_list argList) +{ + int retVal; /* If initialization causes e838 */ + SecFileStream fStr; + + if (stream == NULL || format == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("vfscanf_s"); + return SECUREC_SCANF_EINVAL; + } + if (stream == SECUREC_STREAM_STDIN) { + return vscanf_s(format, argList); + } + + SECUREC_LOCK_FILE(stream); + SecInitFileStreamFromFile(&fStr, stream); + retVal = SecInputS(&fStr, format, argList); + SECUREC_UNLOCK_FILE(stream); + if (retVal < 0) { + SECUREC_ERROR_INVALID_PARAMTER("vfscanf_s"); + return SECUREC_SCANF_EINVAL; + } + + return retVal; +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/vfwscanf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/vfwscanf_s.c new file mode 100644 index 000000000..5ed15d234 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/vfwscanf_s.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#define SECUREC_INLINE_INIT_FILE_STREAM_FILE 1 +#include "secinput.h" + +/* + * + * The vfwscanf_s function is the wide-character equivalent of the vfscanf_s function + * The vfwscanf_s function reads data from the current position of stream into + * the locations given by argument (if any). Each argument must be a pointer + * to a variable of a type that corresponds to a type specifier in format. + * format controls the interpretation of the input fields and has the same form + * and function as the format argument for scanf. + * + * + * stream Pointer to FILE structure. + * format Format control string, see Format Specifications. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int vfwscanf_s(FILE *stream, const wchar_t *format, va_list argList) +{ + int retVal; /* If initialization causes e838 */ + SecFileStream fStr; + + if (stream == NULL || format == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("vfwscanf_s"); + return SECUREC_SCANF_EINVAL; + } + if (stream == SECUREC_STREAM_STDIN) { + return vwscanf_s(format, argList); + } + + SECUREC_LOCK_FILE(stream); + SecInitFileStreamFromFile(&fStr, stream); + retVal = SecInputSW(&fStr, format, argList); + SECUREC_UNLOCK_FILE(stream); + if (retVal < 0) { + SECUREC_ERROR_INVALID_PARAMTER("vfwscanf_s"); + return SECUREC_SCANF_EINVAL; + } + return retVal; +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/vscanf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/vscanf_s.c new file mode 100644 index 000000000..c28f01759 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/vscanf_s.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#define SECUREC_INLINE_INIT_FILE_STREAM_STDIN 1 +#include "secinput.h" + +/* + * + * The vscanf_s function is equivalent to scanf_s, with the variable argument list replaced by argList, + * The vscanf_s function reads data from the standard input stream stdin and + * writes the data into the location that's given by argument. Each argument + * must be a pointer to a variable of a type that corresponds to a type specifier + * in format. If copying occurs between strings that overlap, the behavior is + * undefined. + * + * + * format Format control string. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * Returns the number of fields successfully converted and assigned; + * the return value does not include fields that were read but not assigned. + * A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int vscanf_s(const char *format, va_list argList) +{ + int retVal; /* If initialization causes e838 */ + SecFileStream fStr; + SecInitFileStreamFromStdin(&fStr); + /* + * The "va_list" has different definition on different platform, so we can't use argList == NULL + * To determine it's invalid. If you has fixed platform, you can check some fields to validate it, + * such as "argList == NULL" or argList.xxx != NULL or *(size_t *)&argList != 0. + */ + if (format == NULL || fStr.pf == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("vscanf_s"); + return SECUREC_SCANF_EINVAL; + } + + SECUREC_LOCK_STDIN(0, fStr.pf); + + retVal = SecInputS(&fStr, format, argList); + + SECUREC_UNLOCK_STDIN(0, fStr.pf); + if (retVal < 0) { + SECUREC_ERROR_INVALID_PARAMTER("vscanf_s"); + return SECUREC_SCANF_EINVAL; + } + return retVal; +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/vsnprintf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/vsnprintf_s.c new file mode 100644 index 000000000..8b4082f74 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/vsnprintf_s.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "secureprintoutput.h" + +#if SECUREC_ENABLE_VSNPRINTF +/* + * + * The vsnprintf_s function is equivalent to the vsnprintf function + * except for the parameter destMax/count and the explicit runtime-constraints violation + * The vsnprintf_s function takes a pointer to an argument list, then formats + * and writes up to count characters of the given data to the memory pointed + * to by strDest and appends a terminating null. + * + * + * strDest Storage location for the output. + * destMax The size of the strDest for output. + * count Maximum number of character to write(not including + * the terminating NULL) + * format Format-control string. + * argList pointer to list of arguments. + * + * + * strDest is updated + * + * + * return the number of characters written, not including the terminating null + * return -1 if an error occurs. + * return -1 if count < destMax and the output string has been truncated + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +int vsnprintf_s(char *strDest, size_t destMax, size_t count, const char *format, va_list argList) +{ + int retVal; + + if (SECUREC_VSNPRINTF_PARAM_ERROR(format, strDest, destMax, count, SECUREC_STRING_MAX_LEN)) { + SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, SECUREC_STRING_MAX_LEN); + SECUREC_ERROR_INVALID_PARAMTER("vsnprintf_s"); + return -1; + } + + if (destMax > count) { + retVal = SecVsnprintfImpl(strDest, count + 1, format, argList); + if (retVal == SECUREC_PRINTF_TRUNCATE) { /* To keep dest buffer not destroyed 2014.2.18 */ + /* The string has been truncated, return -1 */ + return -1; /* To skip error handler, return strlen(strDest) or -1 */ + } + } else { + retVal = SecVsnprintfImpl(strDest, destMax, format, argList); +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT + if (retVal == SECUREC_PRINTF_TRUNCATE && count == (size_t)(-1)) { + return -1; + } +#endif + } + + if (retVal < 0) { + strDest[0] = '\0'; /* Empty the dest strDest */ + + if (retVal == SECUREC_PRINTF_TRUNCATE) { + /* Buffer too small */ + SECUREC_ERROR_INVALID_RANGE("vsnprintf_s"); + } + + SECUREC_ERROR_INVALID_PARAMTER("vsnprintf_s"); + return -1; + } + + return retVal; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(vsnprintf_s); +#endif +#endif + +#if SECUREC_SNPRINTF_TRUNCATED +/* + * + * The vsnprintf_truncated_s function is equivalent to the vsnprintf function + * except for the parameter destMax/count and the explicit runtime-constraints violation + * The vsnprintf_truncated_s function takes a pointer to an argument list, then formats + * and writes up to count characters of the given data to the memory pointed + * to by strDest and appends a terminating null. + * + * + * strDest Storage location for the output. + * destMax The size of the strDest for output. + * the terminating NULL) + * format Format-control string. + * argList pointer to list of arguments. + * + * + * strDest is updated + * + * + * return the number of characters written, not including the terminating null + * return -1 if an error occurs. + * return destMax-1 if output string has been truncated + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +int vsnprintf_truncated_s(char *strDest, size_t destMax, const char *format, va_list argList) +{ + int retVal; + + if (SECUREC_VSPRINTF_PARAM_ERROR(format, strDest, destMax, SECUREC_STRING_MAX_LEN)) { + SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, SECUREC_STRING_MAX_LEN); + SECUREC_ERROR_INVALID_PARAMTER("vsnprintf_truncated_s"); + return -1; + } + + retVal = SecVsnprintfImpl(strDest, destMax, format, argList); + + if (retVal < 0) { + if (retVal == SECUREC_PRINTF_TRUNCATE) { + return (int)(destMax - 1); /* To skip error handler, return strlen(strDest) */ + } + strDest[0] = '\0'; /* Empty the dest strDest */ + SECUREC_ERROR_INVALID_PARAMTER("vsnprintf_truncated_s"); + return -1; + } + + return retVal; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(vsnprintf_truncated_s); +#endif +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/vsprintf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/vsprintf_s.c new file mode 100644 index 000000000..3dff65a02 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/vsprintf_s.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "secureprintoutput.h" + +/* + * + * The vsprintf_s function is equivalent to the vsprintf function + * except for the parameter destMax and the explicit runtime-constraints violation + * The vsprintf_s function takes a pointer to an argument list, and then formats + * and writes the given data to the memory pointed to by strDest. + * The function differ from the non-secure versions only in that the secure + * versions support positional parameters. + * + * + * strDest Storage location for the output. + * destMax Size of strDest + * format Format specification. + * argList pointer to list of arguments + * + * + * strDest is updated + * + * + * return the number of characters written, not including the terminating null character, + * return -1 if an error occurs. + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +int vsprintf_s(char *strDest, size_t destMax, const char *format, va_list argList) +{ + int retVal; /* If initialization causes e838 */ + + if (SECUREC_VSPRINTF_PARAM_ERROR(format, strDest, destMax, SECUREC_STRING_MAX_LEN)) { + SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, SECUREC_STRING_MAX_LEN); + SECUREC_ERROR_INVALID_PARAMTER("vsprintf_s"); + return -1; + } + + retVal = SecVsnprintfImpl(strDest, destMax, format, argList); + + if (retVal < 0) { + strDest[0] = '\0'; + if (retVal == SECUREC_PRINTF_TRUNCATE) { + /* Buffer is too small */ + SECUREC_ERROR_INVALID_RANGE("vsprintf_s"); + } + SECUREC_ERROR_INVALID_PARAMTER("vsprintf_s"); + return -1; + } + + return retVal; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(vsprintf_s); +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/vsscanf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/vsscanf_s.c new file mode 100644 index 000000000..f6e811968 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/vsscanf_s.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#define SECUREC_INLINE_INIT_FILE_STREAM_STR 1 +#include "secinput.h" +#if defined(SECUREC_VXWORKS_PLATFORM) && !SECUREC_IN_KERNEL && \ + (!defined(SECUREC_SYSAPI4VXWORKS) && !defined(SECUREC_CTYPE_MACRO_ADAPT)) +#include +#endif + +/* + * + * vsscanf_s + * + * + * + * The vsscanf_s function is equivalent to sscanf_s, with the variable argument list replaced by argList + * The vsscanf_s function reads data from buffer into the location given by + * each argument. Every argument must be a pointer to a variable with a type + * that corresponds to a type specifier in format. The format argument controls + * the interpretation of the input fields and has the same form and function + * as the format argument for the scanf function. + * If copying takes place between strings that overlap, the behavior is undefined. + * + * + * buffer Stored data + * format Format control string, see Format Specifications. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int vsscanf_s(const char *buffer, const char *format, va_list argList) +{ + size_t count; /* If initialization causes e838 */ + int retVal; + SecFileStream fStr; + + /* Validation section */ + if (buffer == NULL || format == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("vsscanf_s"); + return SECUREC_SCANF_EINVAL; + } + count = strlen(buffer); + if (count == 0 || count > SECUREC_STRING_MAX_LEN) { + SecClearDestBuf(buffer, format, argList); + SECUREC_ERROR_INVALID_PARAMTER("vsscanf_s"); + return SECUREC_SCANF_EINVAL; + } +#if defined(SECUREC_VXWORKS_PLATFORM) && !SECUREC_IN_KERNEL + /* + * On vxworks platform when buffer is white string, will set first %s argument tu zero.like following useage: + * " \v\f\t\r\n", "%s", str, strSize + * Do not check all character, just first and last character then consider it is white string + */ + if (isspace((int)buffer[0]) && isspace((int)buffer[count - 1])) { + SecClearDestBuf(buffer, format, argList); + } +#endif + SecInitFileStreamFromString(&fStr, buffer, (int)count); + retVal = SecInputS(&fStr, format, argList); + if (retVal < 0) { + SECUREC_ERROR_INVALID_PARAMTER("vsscanf_s"); + return SECUREC_SCANF_EINVAL; + } + return retVal; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(vsscanf_s); +#endif diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/vswprintf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/vswprintf_s.c new file mode 100644 index 000000000..02b86ea73 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/vswprintf_s.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "secureprintoutput.h" + +/* + * + * The vswprintf_s function is the wide-character equivalent of the vsprintf_s function + * + * + * strDest Storage location for the output. + * destMax Maximum number of characters to store + * format Format specification. + * argList pointer to list of arguments + * + * + * strDest is updated + * + * + * return the number of wide characters stored in strDest, not counting the terminating null wide character. + * return -1 if an error occurred. + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +int vswprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, va_list argList) +{ + int retVal; /* If initialization causes e838 */ + if (SECUREC_VSPRINTF_PARAM_ERROR(format, strDest, destMax, SECUREC_WCHAR_STRING_MAX_LEN)) { + SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, SECUREC_WCHAR_STRING_MAX_LEN); + SECUREC_ERROR_INVALID_PARAMTER("vswprintf_s"); + return -1; + } + + retVal = SecVswprintfImpl(strDest, destMax, format, argList); + + if (retVal < 0) { + strDest[0] = '\0'; + if (retVal == SECUREC_PRINTF_TRUNCATE) { + /* Buffer too small */ + SECUREC_ERROR_INVALID_RANGE("vswprintf_s"); + } + SECUREC_ERROR_INVALID_PARAMTER("vswprintf_s"); + return -1; + } + + return retVal; +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/vswscanf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/vswscanf_s.c new file mode 100644 index 000000000..ba296a0b8 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/vswscanf_s.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#define SECUREC_INLINE_INIT_FILE_STREAM_STR 1 +#include "secinput.h" + +SECUREC_INLINE size_t SecWcslen(const wchar_t *s) +{ + const wchar_t *end = s; + while (*end != L'\0') { + ++end; + } + return ((size_t)((end - s))); +} + +/* + * + * The vswscanf_s function is the wide-character equivalent of the vsscanf_s function + * The vsscanf_s function reads data from buffer into the location given by + * each argument. Every argument must be a pointer to a variable with a type + * that corresponds to a type specifier in format. + * The format argument controls the interpretation of the input fields and + * has the same form and function as the format argument for the scanf function. + * If copying takes place between strings that overlap, the behavior is undefined. + * + * + * buffer Stored data + * format Format control string, see Format Specifications. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int vswscanf_s(const wchar_t *buffer, const wchar_t *format, va_list argList) +{ + size_t count; /* If initialization causes e838 */ + SecFileStream fStr; + int retVal; + + /* Validation section */ + if (buffer == NULL || format == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("vswscanf_s"); + return SECUREC_SCANF_EINVAL; + } + count = SecWcslen(buffer); + if (count == 0 || count > SECUREC_WCHAR_STRING_MAX_LEN) { + SecClearDestBufW(buffer, format, argList); + SECUREC_ERROR_INVALID_PARAMTER("vswscanf_s"); + return SECUREC_SCANF_EINVAL; + } + SecInitFileStreamFromString(&fStr, (const char *)buffer, (int)count * ((int)sizeof(wchar_t))); + retVal = SecInputSW(&fStr, format, argList); + if (retVal < 0) { + SECUREC_ERROR_INVALID_PARAMTER("vswscanf_s"); + return SECUREC_SCANF_EINVAL; + } + return retVal; +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/vwscanf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/vwscanf_s.c new file mode 100644 index 000000000..5adb01da9 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/vwscanf_s.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#define SECUREC_INLINE_INIT_FILE_STREAM_STDIN 1 +#include "secinput.h" + +/* + * + * The vwscanf_s function is the wide-character equivalent of the vscanf_s function + * The vwscanf_s function is the wide-character version of vscanf_s. The + * function reads data from the standard input stream stdin and writes the + * data into the location that's given by argument. Each argument must be a + * pointer to a variable of a type that corresponds to a type specifier in + * format. If copying occurs between strings that overlap, the behavior is + * undefined. + * + * + * format Format control string. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * Returns the number of fields successfully converted and assigned; + * the return value does not include fields that were read but not assigned. + * A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int vwscanf_s(const wchar_t *format, va_list argList) +{ + int retVal; /* If initialization causes e838 */ + SecFileStream fStr; + + SecInitFileStreamFromStdin(&fStr); + if (format == NULL || fStr.pf == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("vwscanf_s"); + return SECUREC_SCANF_EINVAL; + } + + SECUREC_LOCK_STDIN(0, fStr.pf); + + retVal = SecInputSW(&fStr, format, argList); + + SECUREC_UNLOCK_STDIN(0, fStr.pf); + + if (retVal < 0) { + SECUREC_ERROR_INVALID_PARAMTER("vwscanf_s"); + return SECUREC_SCANF_EINVAL; + } + + return retVal; +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/wcscat_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/wcscat_s.c new file mode 100644 index 000000000..075c16bac --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/wcscat_s.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securecutil.h" + +/* + * Befor this function, the basic parameter checking has been done + */ +SECUREC_INLINE errno_t SecDoCatW(wchar_t *strDest, size_t destMax, const wchar_t *strSrc) +{ + size_t destLen; + size_t srcLen; + size_t maxCount; /* Store the maximum available count */ + + /* To calculate the length of a wide character, the parameter must be a wide character */ + SECUREC_CALC_WSTR_LEN(strDest, destMax, &destLen); + maxCount = destMax - destLen; + SECUREC_CALC_WSTR_LEN(strSrc, maxCount, &srcLen); + + if (SECUREC_CAT_STRING_IS_OVERLAP(strDest, destLen, strSrc, srcLen)) { + strDest[0] = L'\0'; + if (strDest + destLen <= strSrc && destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("wcscat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_BUFFER_OVERLAP("wcscat_s"); + return EOVERLAP_AND_RESET; + } + if (srcLen + destLen >= destMax || strDest == strSrc) { + strDest[0] = L'\0'; + if (destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("wcscat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_INVALID_RANGE("wcscat_s"); + return ERANGE_AND_RESET; + } + /* Copy single character length include \0 */ + SECUREC_MEMCPY_WARP_OPT(strDest + destLen, strSrc, (srcLen + 1) * sizeof(wchar_t)); + return EOK; +} + +/* + * + * The wcscat_s function appends a copy of the wide string pointed to by strSrc + * (including the terminating null wide character) + * to the end of the wide string pointed to by strDest. + * The arguments and return value of wcscat_s are wide-character strings. + * + * The wcscat_s function appends strSrc to strDest and terminates the resulting + * string with a null character. The initial character of strSrc overwrites the + * terminating null character of strDest. wcscat_s will return EOVERLAP_AND_RESET if the + * source and destination strings overlap. + * + * Note that the second parameter is the total size of the buffer, not the + * remaining size. + * + * + * strDest Null-terminated destination string buffer. + * destMax Size of the destination string buffer. + * strSrc Null-terminated source string buffer. + * + * + * strDest is updated + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * EINVAL_AND_RESET (strDest unterminated and all other parameters are valid) or + * (strDest != NULL and strSrc is NULLL and destMax != 0 + * and destMax <= SECUREC_WCHAR_STRING_MAX_LEN) + * ERANGE destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0 + * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t wcscat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc) +{ + if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("wcscat_s"); + return ERANGE; + } + + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("wcscat_s"); + if (strDest != NULL) { + strDest[0] = L'\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + + return SecDoCatW(strDest, destMax, strSrc); +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/wcscpy_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/wcscpy_s.c new file mode 100644 index 000000000..d1f5bce46 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/wcscpy_s.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securecutil.h" + +SECUREC_INLINE errno_t SecDoCpyW(wchar_t *strDest, size_t destMax, const wchar_t *strSrc) +{ + size_t srcStrLen; + SECUREC_CALC_WSTR_LEN(strSrc, destMax, &srcStrLen); + + if (srcStrLen == destMax) { + strDest[0] = '\0'; + SECUREC_ERROR_INVALID_RANGE("wcscpy_s"); + return ERANGE_AND_RESET; + } + if (strDest == strSrc) { + return EOK; + } + + if (SECUREC_STRING_NO_OVERLAP(strDest, strSrc, srcStrLen)) { + /* Performance optimization, srcStrLen is single character length include '\0' */ + SECUREC_MEMCPY_WARP_OPT(strDest, strSrc, (srcStrLen + 1) * sizeof(wchar_t)); + return EOK; + } else { + strDest[0] = L'\0'; + SECUREC_ERROR_BUFFER_OVERLAP("wcscpy_s"); + return EOVERLAP_AND_RESET; + } +} + +/* + * + * The wcscpy_s function copies the wide string pointed to by strSrc + * (including theterminating null wide character) into the array pointed to by strDest + + * + * strDest Destination string buffer + * destMax Size of the destination string buffer. + * strSrc Null-terminated source string buffer. + * + * + * strDest is updated. + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * EINVAL_AND_RESET strDest != NULL and strSrc is NULLL and destMax != 0 + * and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * ERANGE destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0 + * ERANGE_AND_RESET destMax <= length of strSrc and strDest != strSrc + * and strDest != NULL and strSrc != NULL and destMax != 0 + * and destMax <= SECUREC_WCHAR_STRING_MAX_LEN and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and destMax != 0 + * and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * and strDest != NULL and strSrc !=NULL and strDest != strSrc + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t wcscpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc) +{ + if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("wcscpy_s"); + return ERANGE; + } + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("wcscpy_s"); + if (strDest != NULL) { + strDest[0] = L'\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + return SecDoCpyW(strDest, destMax, strSrc); +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/wcsncat_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/wcsncat_s.c new file mode 100644 index 000000000..5a3ad1c78 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/wcsncat_s.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securecutil.h" + +/* + * Befor this function, the basic parameter checking has been done + */ +SECUREC_INLINE errno_t SecDoCatLimitW(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count) +{ + /* To calculate the length of a wide character, the parameter must be a wide character */ + size_t destLen; + size_t srcLen; + SECUREC_CALC_WSTR_LEN(strDest, destMax, &destLen); + SECUREC_CALC_WSTR_LEN(strSrc, count, &srcLen); + + if (SECUREC_CAT_STRING_IS_OVERLAP(strDest, destLen, strSrc, srcLen)) { + strDest[0] = L'\0'; + if (strDest + destLen <= strSrc && destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("wcsncat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_BUFFER_OVERLAP("wcsncat_s"); + return EOVERLAP_AND_RESET; + } + if (srcLen + destLen >= destMax || strDest == strSrc) { + strDest[0] = L'\0'; + if (destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("wcsncat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_INVALID_RANGE("wcsncat_s"); + return ERANGE_AND_RESET; + } + SECUREC_MEMCPY_WARP_OPT(strDest + destLen, strSrc, srcLen * sizeof(wchar_t)); /* no terminator */ + *(strDest + destLen + srcLen) = L'\0'; + return EOK; +} + +/* + * + * The wcsncat_s function appends not more than n successive wide characters + * (not including the terminating null wide character) + * from the array pointed to by strSrc to the end of the wide string pointed to by strDest. + * + * The wcsncat_s function try to append the first D characters of strSrc to + * the end of strDest, where D is the lesser of count and the length of strSrc. + * If appending those D characters will fit within strDest (whose size is + * given as destMax) and still leave room for a null terminator, then those + * characters are appended, starting at the original terminating null of + * strDest, and a new terminating null is appended; otherwise, strDest[0] is + * set to the null character. + * + * + * strDest Null-terminated destination string. + * destMax Size of the destination buffer. + * strSrc Null-terminated source string. + * count Number of character to append, or truncate. + * + * + * strDest is updated + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * EINVAL_AND_RESET (strDest unterminated and all other parameters are valid) or + * (strDest != NULL and strSrc is NULLL and destMax != 0 and destMax <= + * SECUREC_WCHAR_STRING_MAX_LEN) ERANGE destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0 + * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t wcsncat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("wcsncat_s"); + return ERANGE; + } + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("wcsncat_s"); + if (strDest != NULL) { + strDest[0] = L'\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + if (count > SECUREC_WCHAR_STRING_MAX_LEN) { +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT + if (count == ((size_t)-1)) { + /* Windows internal functions may pass in -1 when calling this function */ + return SecDoCatLimitW(strDest, destMax, strSrc, destMax); + } +#endif + strDest[0] = L'\0'; + SECUREC_ERROR_INVALID_RANGE("wcsncat_s"); + return ERANGE_AND_RESET; + } + return SecDoCatLimitW(strDest, destMax, strSrc, count); +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/wcsncpy_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/wcsncpy_s.c new file mode 100644 index 000000000..14e7b5501 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/wcsncpy_s.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securecutil.h" + +SECUREC_INLINE errno_t SecDoCpyLimitW(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count) +{ + size_t srcStrLen; + if (count < destMax) { + SECUREC_CALC_WSTR_LEN(strSrc, count, &srcStrLen); + } else { + SECUREC_CALC_WSTR_LEN(strSrc, destMax, &srcStrLen); + } + if (srcStrLen == destMax) { + strDest[0] = '\0'; + SECUREC_ERROR_INVALID_RANGE("wcsncpy_s"); + return ERANGE_AND_RESET; + } + if (strDest == strSrc) { + return EOK; + } + if (SECUREC_STRING_NO_OVERLAP(strDest, strSrc, srcStrLen)) { + /* Performance optimization srcStrLen not include '\0' */ + SECUREC_MEMCPY_WARP_OPT(strDest, strSrc, srcStrLen * sizeof(wchar_t)); + *(strDest + srcStrLen) = L'\0'; + return EOK; + } else { + strDest[0] = L'\0'; + SECUREC_ERROR_BUFFER_OVERLAP("wcsncpy_s"); + return EOVERLAP_AND_RESET; + } +} + +/* + * + * The wcsncpy_s function copies not more than n successive wide characters + * (not including the terminating null wide character) + * from the array pointed to by strSrc to the array pointed to by strDest + * + * + * strDest Destination string. + * destMax The size of the destination string, in characters. + * strSrc Source string. + * count Number of characters to be copied. + * + * + * strDest is updated + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * EINVAL_AND_RESET strDest != NULL and strSrc is NULLL and destMax != 0 + * and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * ERANGE destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0 + * ERANGE_AND_RESET count > SECUREC_WCHAR_STRING_MAX_LEN or + * (destMax <= length of strSrc and destMax <= count and strDest != strSrc + * and strDest != NULL and strSrc != NULL and destMax != 0 and + * destMax <= SECUREC_WCHAR_STRING_MAX_LEN and not overlap) + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t wcsncpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("wcsncpy_s"); + return ERANGE; + } + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("wcsncpy_s"); + if (strDest != NULL) { + strDest[0] = '\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + if (count > SECUREC_WCHAR_STRING_MAX_LEN) { +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT + if (count == (size_t)(-1)) { + return SecDoCpyLimitW(strDest, destMax, strSrc, destMax - 1); + } +#endif + strDest[0] = '\0'; /* Clear dest string */ + SECUREC_ERROR_INVALID_RANGE("wcsncpy_s"); + return ERANGE_AND_RESET; + } + + if (count == 0) { + strDest[0] = '\0'; + return EOK; + } + + return SecDoCpyLimitW(strDest, destMax, strSrc, count); +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/wcstok_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/wcstok_s.c new file mode 100644 index 000000000..454d3b61d --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/wcstok_s.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securecutil.h" + +SECUREC_INLINE int SecIsInDelimitW(wchar_t ch, const wchar_t *strDelimit) +{ + const wchar_t *ctl = strDelimit; + while (*ctl != L'\0' && *ctl != ch) { + ++ctl; + } + return (int)(*ctl != L'\0'); +} + +/* + * Find beginning of token (skip over leading delimiters). + * Note that there is no token if this loop sets string to point to the terminal null. + */ +SECUREC_INLINE wchar_t *SecFindBeginW(wchar_t *strToken, const wchar_t *strDelimit) +{ + wchar_t *token = strToken; + while (*token != L'\0') { + if (SecIsInDelimitW(*token, strDelimit)) { + ++token; + continue; + } + /* Don't find any delimiter in string header, break the loop */ + break; + } + return token; +} + +/* + * Find the end of the token. If it is not the end of the string, put a null there. + */ +SECUREC_INLINE wchar_t *SecFindRestW(wchar_t *strToken, const wchar_t *strDelimit) +{ + wchar_t *token = strToken; + while (*token != L'\0') { + if (SecIsInDelimitW(*token, strDelimit)) { + /* Find a delimiter, set string termintor */ + *token = L'\0'; + ++token; + break; + } + ++token; + } + return token; +} + +/* + * Update Token wide character function + */ +SECUREC_INLINE wchar_t *SecUpdateTokenW(wchar_t *strToken, const wchar_t *strDelimit, wchar_t **context) +{ + /* Point to updated position */ + wchar_t *token = SecFindRestW(strToken, strDelimit); + /* Update the context */ + *context = token; + /* Determine if a token has been found. */ + if (token == strToken) { + return NULL; + } + return strToken; +} + +/* + * + * wcstok_s + * + * + * + * The wcstok_s function is the wide-character equivalent of the strtok_s function + * + * + * strToken String containing token or tokens. + * strDelimit Set of delimiter characters. + * context Used to store position information between calls to + * wcstok_s. + * + * + * context is updated + * + * The wcstok_s function is the wide-character equivalent of the strtok_s function + */ +wchar_t *wcstok_s(wchar_t *strToken, const wchar_t *strDelimit, wchar_t **context) +{ + wchar_t *orgToken = strToken; + /* Validation section */ + if (context == NULL || strDelimit == NULL) { + return NULL; + } + if (orgToken == NULL && *context == NULL) { + return NULL; + } + /* If string==NULL, continue with previous string */ + if (orgToken == NULL) { + orgToken = *context; + } + orgToken = SecFindBeginW(orgToken, strDelimit); + return SecUpdateTokenW(orgToken, strDelimit, context); +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/wmemcpy_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/wmemcpy_s.c new file mode 100644 index 000000000..743afdbe8 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/wmemcpy_s.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +/* + * [Standardize-exceptions] Use unsafe function: Portability + * [reason] Use unsafe function to implement security function to maintain platform compatibility. + * And sufficient input validation is performed before calling + */ + +#include "securecutil.h" + +/* + * + * The wmemcpy_s function copies n successive wide characters + * from the object pointed to by src into the object pointed to by dest.t. + * + * + * dest Destination buffer. + * destMax Size of the destination buffer. + * src Buffer to copy from. + * count Number of characters to copy. + * + * + * dest buffer is uptdated. + * + * + * EOK Success + * EINVAL dest is NULL and destMax != 0 and count <= destMax + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN + * EINVAL_AND_RESET dest != NULL and src is NULLL and destMax != 0 + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN and count <= destMax + * ERANGE destMax > SECUREC_WCHAR_MEM_MAX_LEN or destMax is 0 or + * (count > destMax and dest is NULL and destMax != 0 + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN) + * ERANGE_AND_RESET count > destMax and dest != NULL and destMax != 0 + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and + * count <= destMax destMax != 0 and destMax <= SECUREC_WCHAR_MEM_MAX_LEN + * and dest != NULL and src != NULL and dest != src + * + * if an error occured, dest will be filled with 0 when dest and destMax valid . + * If the source and destination overlap, the behavior of wmemcpy_s is undefined. + * Use wmemmove_s to handle overlapping regions. + */ +errno_t wmemcpy_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_WCHAR_MEM_MAX_LEN) { + SECUREC_ERROR_INVALID_PARAMTER("wmemcpy_s"); + return ERANGE; + } + if (count > destMax) { + SECUREC_ERROR_INVALID_PARAMTER("wmemcpy_s"); + if (dest != NULL) { + (void)memset(dest, 0, destMax * sizeof(wchar_t)); + return ERANGE_AND_RESET; + } + return ERANGE; + } + return memcpy_s(dest, destMax * sizeof(wchar_t), src, count * sizeof(wchar_t)); +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/wmemmove_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/wmemmove_s.c new file mode 100644 index 000000000..311379f2d --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/wmemmove_s.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +/* + * [Standardize-exceptions] Use unsafe function: Portability + * [reason] Use unsafe function to implement security function to maintain platform compatibility. + * And sufficient input validation is performed before calling + */ + +#include "securecutil.h" + +/* + * + * The wmemmove_s function copies n successive wide characters from the object pointed + * to by src into the object pointed to by dest. + * + * + * dest Destination buffer. + * destMax Size of the destination buffer. + * src Source object. + * count Number of bytes or character to copy. + * + * + * dest is updated. + * + * + * EOK Success + * EINVAL dest is NULL and destMax != 0 and count <= destMax + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN + * EINVAL_AND_RESET dest != NULL and src is NULLL and destMax != 0 + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN and count <= destMax + * ERANGE destMax > SECUREC_WCHAR_MEM_MAX_LEN or destMax is 0 or + * (count > destMax and dest is NULL and destMax != 0 + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN) + * ERANGE_AND_RESET count > destMax and dest != NULL and destMax != 0 + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN + * + * + * If an error occured, dest will be filled with 0 when dest and destMax valid. + * If some regions of the source area and the destination overlap, wmemmove_s + * ensures that the original source bytes in the overlapping region are copied + * before being overwritten + */ +errno_t wmemmove_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_WCHAR_MEM_MAX_LEN) { + SECUREC_ERROR_INVALID_PARAMTER("wmemmove_s"); + return ERANGE; + } + if (count > destMax) { + SECUREC_ERROR_INVALID_PARAMTER("wmemmove_s"); + if (dest != NULL) { + (void)memset(dest, 0, destMax * sizeof(wchar_t)); + return ERANGE_AND_RESET; + } + return ERANGE; + } + return memmove_s(dest, destMax * sizeof(wchar_t), src, count * sizeof(wchar_t)); +} diff --git a/http/services/netmanagernative/common/huawei_secure_c/src/wscanf_s.c b/http/services/netmanagernative/common/huawei_secure_c/src/wscanf_s.c new file mode 100644 index 000000000..e8660a0f8 --- /dev/null +++ b/http/services/netmanagernative/common/huawei_secure_c/src/wscanf_s.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "securec.h" + +/* + * + * + * The wscanf_s function is the wide-character equivalent of the scanf_s function + * The wscanf_s function reads data from the standard input stream stdin and + * writes the data into the location that's given by argument. Each argument + * must be a pointer to a variable of a type that corresponds to a type specifier + * in format. If copying occurs between strings that overlap, the behavior is + * undefined. + * + * + * format Format control string. + * ... Optional arguments. + * + * + * ... the converted value stored in user assigned address + * + * + * Returns the number of fields successfully converted and assigned; + * the return value does not include fields that were read but not assigned. + * A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int wscanf_s(const wchar_t *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vwscanf_s(format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} diff --git a/http/services/netmanagernative/common/include/bitcast.h b/http/services/netmanagernative/common/include/bitcast.h new file mode 100644 index 000000000..0911d7275 --- /dev/null +++ b/http/services/netmanagernative/common/include/bitcast.h @@ -0,0 +1,36 @@ +#ifndef __INCLUDE_BITCAST_H__ +#define __INCLUDE_BITCAST_H__ + +#include +#include +#include + +namespace OHOS { +namespace nmd { +namespace common { +namespace internal_casts { + +template +struct is_bitcastable + : std::integral_constant::value && + std::is_trivially_copyable::value && std::is_default_constructible::value> {}; + +} // namespace internal_casts + +template::value, int>::type = 0> +inline Dest bit_cast(const Source &source) noexcept +{ + Dest dest; + std::memcpy(static_cast(std::addressof(dest)), static_cast(std::addressof(source)), + sizeof(dest)); + return dest; +} + +} // namespace common + +} // namespace nmd +} // namespace OHOS + +#endif //!__INCLUDE_BITCAST_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/common/include/blocking_queue.h b/http/services/netmanagernative/common/include/blocking_queue.h new file mode 100644 index 000000000..944d2c03e --- /dev/null +++ b/http/services/netmanagernative/common/include/blocking_queue.h @@ -0,0 +1,62 @@ +#ifndef __INCLUDE_BLOCKING_QUEUE_H__ +#define __INCLUDE_BLOCKING_QUEUE_H__ + +#include +#include +#include +namespace OHOS { +namespace nmd { +template +class blocking_queue { +private: + std::mutex mutex_; + std::condition_variable notFull_; + std::condition_variable notEmpty_; + unsigned int start_; + unsigned int end_; + unsigned int capacity_; + std::vector vt_; + +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; + } +}; + +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_BLOCKING_QUEUE_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/common/include/error_code.h b/http/services/netmanagernative/common/include/error_code.h new file mode 100644 index 000000000..387c44845 --- /dev/null +++ b/http/services/netmanagernative/common/include/error_code.h @@ -0,0 +1,30 @@ +#ifndef __INCLUDE_ERROR_CODE_H__ +#define __INCLUDE_ERROR_CODE_H__ + +#include + +namespace OHOS { +namespace nmd { +namespace common { +enum class error_code { errNoInfName = 1, errIpverAndWhich = 2 }; +class error_code_category : public std::error_category { +public: + error_code_category(); + const char *name() const noexcept override; + std::string message(int ev) const override; + const static error_category &get(); +}; +std::error_code make_error_code(error_code e); + +enum class dnsresolv_error_code { + errBadHints = 1, +}; +} // namespace common +} // namespace nmd +} // namespace OHOS +namespace std { +template<> +struct is_error_code_enum : std::true_type {}; +} // namespace std + +#endif //!__INCLUDE_ERROR_CODE_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/common/include/interface_utils.h b/http/services/netmanagernative/common/include/interface_utils.h new file mode 100644 index 000000000..dec148be1 --- /dev/null +++ b/http/services/netmanagernative/common/include/interface_utils.h @@ -0,0 +1,22 @@ +#ifndef __INCLUDE_INTERFACE_UTILS_H__ +#define __INCLUDE_INTERFACE_UTILS_H__ +#include + +namespace OHOS { +namespace nmd { +namespace common { +namespace interface_utils { +int ifcGetAddr(const char *name, in_addr_t *addr); +int ifcSetAddr(const char *name, in_addr_t addr); +void ifcClearAddresses(const char *name); +int ifcInit(void); +int getInterfaceIndex(const char *interfaceName); +int ifcAddAddr(const char *ifName, const char *addr, const int prefixLen); +int ifcActOnAddr(uint16_t action, const char *name, const char *address, const int prefixlen, const bool nodad); +int ifcDelAddr(const char *ifName, const char *addr, const int prefixLen); + +} // namespace interface_utils +} // namespace common +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_INTERFACE_UTILS_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/common/include/job.h b/http/services/netmanagernative/common/include/job.h new file mode 100644 index 000000000..61101c870 --- /dev/null +++ b/http/services/netmanagernative/common/include/job.h @@ -0,0 +1,24 @@ +#ifndef __INCLUDE_JOB_H__ +#define __INCLUDE_JOB_H__ + +#include "server_socket.h" +#include +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/http/services/netmanagernative/common/include/logger.h b/http/services/netmanagernative/common/include/logger.h new file mode 100644 index 000000000..d89369070 --- /dev/null +++ b/http/services/netmanagernative/common/include/logger.h @@ -0,0 +1,112 @@ +#ifndef __COMMON_LOG_H__ +#define __COMMON_LOG_H__ + +#include +#include +#include +#include +#include +#include +#include + +static const std::string endl = "\n"; + +#define LogError nmd::common::logger::error() << "[File:'" << __FILE__ << "',Line:'" << __LINE__ << "']: " + +namespace nmd { +namespace common { + +typedef enum log_level { INFO = 0, DEBUG, ERROR, WARN, FATAL } log_level; + +typedef struct log_config { + std::string path; +} log_config; + +class logger { +private: + std::string getLogFileName(); + std::ofstream *osWrite_; + + log_level level_; + + static logger *logger_; + static log_config config_; + +public: + std::mutex mu_; + + logger(); + ~logger(); + + void writeTime(); + void write(std::string log); + + static void config(log_config &config) + { + config_ = config; + } + + static logger *instance(log_level level) + { + if (!logger_) { + logger_ = new logger(); + logger_->level_ = level; + return logger_; + } else { + logger_->level_ = level; + return logger_; + } + } + + static logger &info() + { + logger &log = *instance(INFO); + log.writeTime(); + return log; + } + + static logger &debug() + { + logger &log = *instance(DEBUG); + log.writeTime(); + return log; + } + + static logger &error() + { + logger &log = *instance(ERROR); + log.writeTime(); + return log; + } + + static logger &warn() + { + logger &log = *instance(WARN); + log.writeTime(); + return log; + } + + static logger &fatal() + { + logger &log = *instance(FATAL); + log.writeTime(); + return log; + } + + std::ostringstream os; +}; + +template +logger &operator<<(nmd::common::logger &log, T const &value) +{ + std::lock_guard lo(log.mu_); + log.os.str(std::string()); + log.os << value; + log.write(log.os.str()); + return log; +} + +} // namespace common +} // namespace nmd + +#endif //!__COMMON_LOG_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/common/include/net_utils.h b/http/services/netmanagernative/common/include/net_utils.h new file mode 100644 index 000000000..16f9a7945 --- /dev/null +++ b/http/services/netmanagernative/common/include/net_utils.h @@ -0,0 +1,528 @@ +#ifndef __INCLUDE_NET_ADDR_H__ +#define __INCLUDE_NET_ADDR_H__ + +#include "warning_disable.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +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); + } + } + 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; + } + } + 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) : mData({AF_INET, IPV4_ADDR_BITS, 0U, 0U, {.v4 = ipv4}}) {} + explicit ip_address(const in6_addr &ipv6) : mData({AF_INET6, IPV6_ADDR_BITS, 0U, 0U, {.v6 = ipv6}}) {} + ip_address(const in6_addr &ipv6, uint32_t scope_id) + : mData({AF_INET6, IPV6_ADDR_BITS, 0U, + // Sanity check: scoped_ids only for link-local addresses. + usesScopedIds(ipv6) ? scope_id : 0U, {.v6 = ipv6}}) + {} + + 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: + // TODO: static forString + + 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; + } + 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(/* args */) = default; + ~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_ADDR_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/common/include/raii.h b/http/services/netmanagernative/common/include/raii.h new file mode 100644 index 000000000..1cb25becf --- /dev/null +++ b/http/services/netmanagernative/common/include/raii.h @@ -0,0 +1,125 @@ +#ifndef __INCLUDE_RAII_H__ +#define __INCLUDE_RAII_H__ +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT +#endif + +#include +#include +#include +namespace OHOS { +namespace nmd { +namespace common { + +template +struct no_const { + using type = typename std::conditional::value, typename std::remove_const::type, T>::type; +}; + +class raii final { +public: + using fun_type = std::function; + + explicit raii( + fun_type release, fun_type acquire = [] {}, bool default_com = true) noexcept + : _commit(default_com), _release(release) + { + acquire(); + } + ~raii() noexcept + { + if (_commit) + _release(); + } + raii(raii &&rv) noexcept : _commit(rv._commit), _release(rv._release) + { + rv._commit = false; + }; + raii(const raii &) = delete; + raii &operator=(const raii &) = delete; + + raii &commit(bool c = true) noexcept + { + _commit = c; + return *this; + }; + +private: + bool _commit; + +protected: + std::function _release; +}; + +template +class raii_var { +public: + using _Self = raii_var; + using acq_type = std::function; + using rel_type = std::function; + explicit raii_var(acq_type acquire, rel_type release) noexcept : _resource(acquire()), _release(release) {} + raii_var(raii_var &&rv) : _resource(std::move(rv._resource)), _release(std::move(rv._release)) + { + rv._commit = false; + } + ~raii_var() noexcept + { + if (_commit) + _release(_resource); + } + _Self &commit(bool c = true) noexcept + { + _commit = c; + return *this; + }; + T &get() noexcept + { + return _resource; + } + T &operator*() noexcept + { + return get(); + } + + template + typename std::enable_if::value, _T>::type operator->() const noexcept + { + return _resource; + } + template + typename std::enable_if::value, _T *>::type operator->() const noexcept + { + return std::addressof(_resource); + } + +private: + bool _commit = true; + T _resource; + rel_type _release; +}; + +template +raii make_raii(RES &res, M_REL rel, M_ACQ acq, bool default_com = true) noexcept +{ + static_assert(std::is_class::value, "RES is not a class or struct type."); + static_assert(std::is_member_function_pointer::value, "M_REL is not a member function."); + static_assert(std::is_member_function_pointer::value, "M_ACQ is not a member function."); + auto p_res = std::addressof(const_cast::type &>(res)); + return raii(std::bind(rel, p_res), std::bind(acq, p_res), default_com); +} +template +raii make_raii(RES &res, M_REL rel, bool default_com = true) noexcept +{ + static_assert(std::is_class::value, "RES is not a class or struct type."); + static_assert(std::is_member_function_pointer::value, "M_REL is not a member function."); + assert(nullptr != rel); + auto p_res = std::addressof(const_cast::type &>(res)); + return raii( + std::bind(rel, p_res), [] {}, default_com); +} +} // namespace common +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_RAII_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/common/include/rwlock.h b/http/services/netmanagernative/common/include/rwlock.h new file mode 100644 index 000000000..69d8b8bb5 --- /dev/null +++ b/http/services/netmanagernative/common/include/rwlock.h @@ -0,0 +1,52 @@ +#ifndef __INCLUDE_RWLOCK_H__ +#define __INCLUDE_RWLOCK_H__ + +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT +#endif + +#include "raii.h" +#include +#include +#include +#include + +namespace OHOS { +namespace nmd { +namespace common { + +class rwlock { +#define WRITE_LOCK_STATUS -1 +#define FREE_STATUS 0 +private: + static const std::thread::id NULL_THEAD; + const bool WRITE_FIRST; + std::thread::id m_write_thread_id; + std::atomic_int m_lockCount; + std::atomic_uint m_writeWaitCount; + +public: + rwlock(const rwlock &) = delete; + rwlock &operator=(const rwlock &) = delete; + explicit rwlock(bool writeFirst = false); + virtual ~rwlock() = default; + int readLock(); + int readUnlock(); + int writeLock(); + int writeUnlock(); + raii read_guard() const noexcept + { + return make_raii(*this, &rwlock::readUnlock, &rwlock::readLock); + } + raii write_guard() noexcept + { + return make_raii(*this, &rwlock::writeUnlock, &rwlock::writeLock); + } +}; + +} // namespace common +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_RWLOCK_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/common/include/server_socket.h b/http/services/netmanagernative/common/include/server_socket.h new file mode 100644 index 000000000..987798380 --- /dev/null +++ b/http/services/netmanagernative/common/include/server_socket.h @@ -0,0 +1,24 @@ +#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 { +private: + struct sockaddr addr_ {}; + +public: + server_socket(); + ~server_socket(); + + int bindPort(uint16_t port); + int bindFile(const char *filePath, const char *name); +}; + +} // namespace common + +} // namespace nmd +} // namespace OHOS +#endif // __NETD_COMMON_SERVER_SOCKET_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/common/include/server_template.h b/http/services/netmanagernative/common/include/server_template.h new file mode 100644 index 000000000..3164f9044 --- /dev/null +++ b/http/services/netmanagernative/common/include/server_template.h @@ -0,0 +1,41 @@ +#ifndef __INCLUDE_SERVER_TEMPLATE_H__ +#define __INCLUDE_SERVER_TEMPLATE_H__ + +#include "server_socket.h" +#include "thread_pool.h" +#include +#include +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/http/services/netmanagernative/common/include/socket_base.h b/http/services/netmanagernative/common/include/socket_base.h new file mode 100644 index 000000000..741cbac1f --- /dev/null +++ b/http/services/netmanagernative/common/include/socket_base.h @@ -0,0 +1,66 @@ +#ifndef __NETD_SOCKET_BASE_H__ +#define __NETD_SOCKET_BASE_H__ + +#include "logger.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 { +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); + +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) + { + NETNATIVE_LOGD("setRecevedHandler bind begin"); + this->handler_ = + std::bind(func, instance, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + NETNATIVE_LOGD("setRecevedHandler bind end"); + } + + int getSocketFileDescriptor() + { + return this->socketFd_; + } +}; + +} // namespace common +} // namespace nmd +} // namespace OHOS +#endif // !__NETD_SOCKET_BASE_H__ diff --git a/http/services/netmanagernative/common/include/thread_pool.h b/http/services/netmanagernative/common/include/thread_pool.h new file mode 100644 index 000000000..5bff858e7 --- /dev/null +++ b/http/services/netmanagernative/common/include/thread_pool.h @@ -0,0 +1,40 @@ +#ifndef __INCLUDE_THREAD_POOL_H__ +#define __INCLUDE_THREAD_POOL_H__ + +#include "blocking_queue.h" +#include "job.h" +#include +#include +#include +#include +#include +namespace OHOS { +namespace nmd { +class 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(); + +public: + thread_pool(unsigned int threadNums, unsigned int queueSize); + + void execute(nmd::job *job); + + ~thread_pool(); +}; + +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_THREAD_POOL_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/common/include/utils.h b/http/services/netmanagernative/common/include/utils.h new file mode 100644 index 000000000..280815611 --- /dev/null +++ b/http/services/netmanagernative/common/include/utils.h @@ -0,0 +1,35 @@ +#ifndef __INCLUDE_UTILS_H__ +#define __INCLUDE_UTILS_H__ + +#include + +namespace OHOS { +namespace nmd { +namespace common { +namespace utils { +std::time_t getCurrentTime(); +int removeDirectory(const char *path); + +template +class auto_destroyer { + typedef void (*Action)(T); + +public: + auto_destroyer(T res, Action action) : res_(res), action_(action) {} + ~auto_destroyer() + { + if (nullptr != action_) { + action_(res_); + } + } + +private: + T res_; + Action action_; +}; +} // namespace utils +} // namespace common +} // namespace nmd +} // namespace OHOS + +#endif //!__INCLUDE_UTILS_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/common/include/warning_disable.h b/http/services/netmanagernative/common/include/warning_disable.h new file mode 100644 index 000000000..635c39f9b --- /dev/null +++ b/http/services/netmanagernative/common/include/warning_disable.h @@ -0,0 +1,31 @@ +#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/http/services/netmanagernative/common/src/error_code.cpp b/http/services/netmanagernative/common/src/error_code.cpp new file mode 100644 index 000000000..4a368a621 --- /dev/null +++ b/http/services/netmanagernative/common/src/error_code.cpp @@ -0,0 +1,39 @@ +#include "error_code.h" + +namespace OHOS { +namespace nmd { +namespace common { +nmd::common::error_code_category::error_code_category() {} + +const char *error_code_category::name() const noexcept +{ + return "netd error code"; +} + +std::string error_code_category::message(int ev) const +{ + switch (static_cast(ev)) { + case nmd::common::error_code::errNoInfName: + return "no such interface name"; + break; + case nmd::common::error_code::errIpverAndWhich: + return "bad ip version or bad which for setProcSysNet"; + break; + default: + return "this is unknow error_code"; + break; + } +} +const std::error_category &error_code_category::get() +{ + const static nmd::common::error_code_category category_const; + return category_const; +} + +std::error_code make_error_code(nmd::common::error_code e) +{ + return std::error_code(static_cast(e), nmd::common::error_code_category::get()); +} +} // namespace common +} // namespace nmd +} // namespace OHOS diff --git a/http/services/netmanagernative/common/src/interface_utils.cpp b/http/services/netmanagernative/common/src/interface_utils.cpp new file mode 100644 index 000000000..2a506d66c --- /dev/null +++ b/http/services/netmanagernative/common/src/interface_utils.cpp @@ -0,0 +1,294 @@ +#include "interface_utils.h" +#include "bitcast.h" +#include "warning_disable.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { +namespace common { + +int ifc_ctl_sock = -1; +// pthread_mutex_t ifc_sock_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +pthread_mutex_t ifc_sock_mutex = PTHREAD_MUTEX_INITIALIZER; +const uint32_t INET_ADDRLEN = 4; +const uint32_t INET6_ADDRLEN = 16; + +void ifcInitIfr(const char *name, struct ifreq *ifr) +{ + memset(ifr, 0, sizeof(struct ifreq)); + strncpy(ifr->ifr_name, name, IFNAMSIZ); + ifr->ifr_name[IFNAMSIZ - 1] = 0; +} + +void initSockaddrin(struct sockaddr *sa, in_addr_t addr) +{ + struct sockaddr_in *sin = reinterpret_cast(sa); + sin->sin_family = AF_INET; + sin->sin_port = 0; + sin->sin_addr.s_addr = addr; +} + +void ifcClose(void) +{ + if (ifc_ctl_sock != -1) { + (void)close(ifc_ctl_sock); + ifc_ctl_sock = -1; + } + pthread_mutex_unlock(&ifc_sock_mutex); +} + +void ifcClearIpv4Addresses(const char *name) +{ + unsigned count, addr; + nmd::common::interface_utils::ifcInit(); + for (count = 0, addr = 1; ((addr != 0) && (count < 255)); count++) { + if (OHOS::nmd::common::interface_utils::ifcGetAddr(name, &addr) < 0) { + break; + } + if (addr) { + OHOS::nmd::common::interface_utils::ifcSetAddr(name, 0); + } + } + ifcClose(); +} + +int stringToIp(const char *string, struct sockaddr_storage *ss) +{ + struct addrinfo *ai(nullptr); + + if (ss == NULL) { + return -EFAULT; + } + + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + hints.ai_socktype = SOCK_DGRAM; + + int ret = getaddrinfo(string, NULL, &hints, &ai); + if (ret == 0) { + memcpy(ss, ai->ai_addr, ai->ai_addrlen); + freeaddrinfo(ai); + } else { + // Getaddrinfo has its own error codes. Convert to negative errno. + // There, the only thing that can reasonably happen is that the passed-in string is invalid. + ret = (ret == EAI_SYSTEM) ? -errno : -EINVAL; + } + + return ret; +} + +namespace interface_utils { + +int ifcInit(void) +{ + int ret; + pthread_mutex_lock(&ifc_sock_mutex); + if (ifc_ctl_sock == -1) { + ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (ifc_ctl_sock < 0) { + std::error_code err = std::error_code(errno, std::system_category()); + // LogError << err.message() << "[socket error in ifcInit()]" << endl; + NETNATIVE_LOGE("interface_utils::ifcInit socket fail %{public}s [socket error in ifcInit()]", + err.message().c_str()); + } + } + + ret = ifc_ctl_sock < 0 ? -1 : 0; + + return ret; +} + +int ifcGetAddr(const char *name, in_addr_t *addr) +{ + struct ifreq ifr; + int ret = 0; + + ifcInitIfr(name, &ifr); + ifcInit(); + if (addr != NULL) { + ret = ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr); + if (ret == -1) { + *addr = 0; + } else { + *addr = OHOS::nmd::common::bit_cast(ifr.ifr_addr).sin_addr.s_addr; + } + } + ifcClose(); + return ret; +} + +int ifcSetAddr(const char *name, in_addr_t addr) +{ + struct ifreq ifr; + int ret; + + ifcInitIfr(name, &ifr); + ifcInit(); + initSockaddrin(&ifr.ifr_addr, addr); + + ret = ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr); + ifcClose(); + return ret; +} + +void ifcClearAddresses(const char *name) +{ + return ifcClearIpv4Addresses(name); +} + +int getInterfaceIndex(const char *interfaceName) +{ + int fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (fd == -1) { + return 0; + } + + // get inierface index for ioctl + struct ifreq req; + + strncpy(req.ifr_ifrn.ifrn_name, interfaceName, sizeof(req.ifr_ifrn.ifrn_name)); + + int iod = ioctl(fd, SIOCGIFINDEX, &req); + if (iod == -1) { + return 0; + } + return req.ifr_ifru.ifru_ivalue; +} + +int ifcAddAddr(const char *ifName, const char *addr, const int prefixLen) +{ + return ifcActOnAddr(RTM_NEWADDR, ifName, addr, prefixLen, false); +} + +int ifcActOnAddr( + unsigned short action, const char *name, const char *address, const int prefixlen, const bool nodad) +{ + DISABLE_WARNING_PUSH + DISABLE_WARNING_OLD_STYLE_CAST + + struct sockaddr_storage ss = {}; + int saved_errno = 0; + void *addr = nullptr; + uint16_t addrlen = 0; + struct { + struct nlmsghdr n; + struct ifaddrmsg r; + // Allow for IPv4 or IPv6 address, headers, IPv4 broadcast address and padding. + char attrbuf[NLMSG_ALIGN(sizeof(struct rtattr)) + NLMSG_ALIGN(INET6_ADDRLEN) + + NLMSG_ALIGN(sizeof(struct rtattr)) + NLMSG_ALIGN(INET_ADDRLEN)]; + } req; + struct rtattr *rta(nullptr); + struct nlmsghdr *nh(nullptr); + struct nlmsgerr *err(nullptr); + + // Get interface ID. + uint32_t ifindex = if_nametoindex(name); + if (ifindex == 0) { + return -errno; + } + + // Convert string representation to sockaddr_storage. + int ret = stringToIp(address, &ss); + if (ret) { + return ret; + } + + // Determine address type and length. + if (ss.ss_family == AF_INET) { + struct sockaddr_in *sin = reinterpret_cast(&ss); + addr = &sin->sin_addr; + addrlen = INET_ADDRLEN; + } else if (ss.ss_family == AF_INET6) { + struct sockaddr_in6 *sin6 = reinterpret_cast(&ss); + addr = &sin6->sin6_addr; + addrlen = INET6_ADDRLEN; + } else { + return -EAFNOSUPPORT; + } + + // Fill in netlink structures. + memset(&req, 0, sizeof(req)); + + // Netlink message header. + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r)); + req.n.nlmsg_type = action; + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.n.nlmsg_pid = static_cast(getpid()); + + // Interface address message header. + req.r.ifa_family = static_cast(ss.ss_family); + req.r.ifa_flags = nodad ? IFA_F_NODAD : 0; + req.r.ifa_prefixlen = static_cast(prefixlen); + req.r.ifa_index = ifindex; + + // Routing attribute. Contains the actual IP address. + rta = reinterpret_cast((reinterpret_cast(&req)) + NLMSG_ALIGN(req.n.nlmsg_len)); + rta->rta_type = IFA_LOCAL; + rta->rta_len = RTA_LENGTH(addrlen); + req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_LENGTH(addrlen); + memcpy(RTA_DATA(rta), addr, addrlen); + + // Add an explicit IFA_BROADCAST for IPv4 RTM_NEWADDRs. + if (ss.ss_family == AF_INET && action == RTM_NEWADDR) { + rta = reinterpret_cast((reinterpret_cast(&req)) + NLMSG_ALIGN(req.n.nlmsg_len)); + rta->rta_type = IFA_BROADCAST; + rta->rta_len = RTA_LENGTH(addrlen); + req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_LENGTH(addrlen); + (reinterpret_cast(addr))->s_addr |= htonl((unsigned int)(1 << (32 - prefixlen)) - 1); + memcpy(RTA_DATA(rta), addr, addrlen); + } + + int s = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); + if (s < 0) { + return -errno; + } + + if (send(s, &req, req.n.nlmsg_len, 0) < 0) { + saved_errno = errno; + close(s); + return -saved_errno; + } + + char buf[NLMSG_ALIGN(sizeof(struct nlmsgerr)) + sizeof(req)]; + ssize_t len = recv(s, buf, sizeof(buf), 0); + saved_errno = errno; + close(s); + if (len < 0) { + return -saved_errno; + } + + // Parse the acknowledgement to find the return code. + nh = reinterpret_cast(buf); + if (!NLMSG_OK(nh, static_cast(len)) || nh->nlmsg_type != NLMSG_ERROR) { + return -EINVAL; + } + + err = (nlmsgerr *)NLMSG_DATA(nh); + + DISABLE_WARNING_POP + + return err->error; +} + +int ifcDelAddr(const char *ifName, const char *addr, const int prefixLen) +{ + return ifcActOnAddr(RTM_DELADDR, ifName, addr, prefixLen, false); +} + +} // namespace interface_utils +} // namespace common +} // namespace nmd +} // namespace OHOS diff --git a/http/services/netmanagernative/common/src/job.cpp b/http/services/netmanagernative/common/src/job.cpp new file mode 100644 index 000000000..b2c3f273e --- /dev/null +++ b/http/services/netmanagernative/common/src/job.cpp @@ -0,0 +1 @@ +#include "job.h" diff --git a/http/services/netmanagernative/common/src/logger.cpp b/http/services/netmanagernative/common/src/logger.cpp new file mode 100644 index 000000000..a7b2b33a4 --- /dev/null +++ b/http/services/netmanagernative/common/src/logger.cpp @@ -0,0 +1,47 @@ +#include "logger.h" +#include +#include +#include + +nmd::common::logger *nmd::common::logger::logger_ = nullptr; +nmd::common::log_config nmd::common::logger::config_; + +const char *g_log_level_name[8] = {"Info", "Debug", "Error", "Warn", "Fatal"}; +nmd::common::logger::logger() +{ + std::string logFileName = this->getLogFileName(); + this->osWrite_ = new std::ofstream(logFileName, std::ofstream::app); +} + +nmd::common::logger::~logger() +{ + this->osWrite_->close(); +} + +void nmd::common::logger::writeTime() +{ + char logStr[2048] = {'\0'}; + time_t t = time(0); + char date[32] = {'\0'}; + strftime(date, sizeof(date), "[%Y-%m-%d %H:%M:%S]", localtime(&t)); + sprintf(logStr, "%s[%s]", date, g_log_level_name[this->level_]); + *(this->osWrite_) << logStr; + std::cout << logStr; +} + +void nmd::common::logger::write(std::string log) +{ + *(this->osWrite_) << log; + std::cout << log; +} + +std::string nmd::common::logger::getLogFileName() +{ + time_t t = time(0); + char tmp[32] = {'\0'}; + strftime(tmp, sizeof(tmp), "%Y-%m-%d", localtime(&t)); + std::string path(config_.path); + path.append(tmp); + path.append(".log"); + return path; +} \ No newline at end of file diff --git a/http/services/netmanagernative/common/src/net_utils.cpp b/http/services/netmanagernative/common/src/net_utils.cpp new file mode 100644 index 000000000..7e698505b --- /dev/null +++ b/http/services/netmanagernative/common/src/net_utils.cpp @@ -0,0 +1,178 @@ +#include "net_utils.h" +#include +#include +#include +#include +#include + +#define BUFF_MAX_LEN 100 +namespace OHOS { +namespace nmd { +namespace common { +namespace net_utils { +std::string ip_address::toString() const noexcept +{ + char repr[INET6_ADDRSTRLEN] = "\0"; + + switch (mData.family) { + case AF_UNSPEC: + return ""; + case AF_INET: { + const in_addr v4 = mData.ip.v4; + inet_ntop(AF_INET, &v4, repr, sizeof(repr)); + break; + } + case AF_INET6: { + const in6_addr v6 = mData.ip.v6; + inet_ntop(AF_INET6, &v6, repr, sizeof(repr)); + break; + } + default: + return ""; + } + + if (mData.family == AF_INET6 && mData.scope_id > 0) { + // return StringPrintf("%s%%%u", repr, mData.scope_id); + char repr6[BUFF_MAX_LEN] = {}; + snprintf(repr6, sizeof(repr6), "%s%%%u", repr, mData.scope_id); + return repr6; + } + + return repr; +} + +bool ip_address::forString(const std::string &repr, ip_address *ip) +{ + addrinfo hints = {}; + hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; + + addrinfo *res(nullptr); + const int ret = getaddrinfo(repr.c_str(), nullptr, &hints, &res); + ScopedAddrinfo res_cleanup(res); + if (ret != 0) { + return false; + } + + bool rval = true; + switch (res[0].ai_family) { + case AF_INET: { + sockaddr_in *sin = reinterpret_cast(res[0].ai_addr); + if (ip) + *ip = ip_address(sin->sin_addr); + break; + } + case AF_INET6: { + sockaddr_in6 *sin6 = reinterpret_cast(res[0].ai_addr); + if (ip) + *ip = ip_address(sin6->sin6_addr, sin6->sin6_scope_id); + break; + } + default: + rval = false; + break; + } + + return rval; +} + +ip_prefix::ip_prefix(const ip_address &ip, size_t length) : ip_prefix(ip) +{ + // Silently treat CIDR lengths like "-1" as meaning the full bit length + // appropriate to the address family. + if (length < 0) + return; + if (length >= mData.cidrlen) + return; + + switch (mData.family) { + case AF_UNSPEC: + break; + case AF_INET: { + const in_addr_t mask = (length > 0) ? (~0U) << (IPV4_ADDR_BITS - length) : 0U; + mData.ip.v4.s_addr &= htonl(mask); + mData.cidrlen = static_cast(length); + break; + } + case AF_INET6: { + // The byte in which this CIDR length falls. + const size_t which = length / 8; + const int mask = (length % 8 == 0) ? 0 : 0xff << (8 - length % 8); + mData.ip.v6.s6_addr[which] &= mask; + for (size_t i = which + 1; i < IPV6_ADDR_LEN; i++) { + mData.ip.v6.s6_addr[i] = 0U; + } + mData.cidrlen = static_cast(length); + break; + } + default: + // TODO: Complain bitterly about possible data corruption? + return; + } +} + +bool ip_prefix::isUninitialized() const noexcept +{ + static const compact_ipdata empty {}; + return mData == empty; +} + +bool ip_prefix::forString(const std::string &repr, ip_prefix *prefix) +{ + size_t index = repr.find('/'); + if (index == std::string::npos) + return false; + + // Parse the IP address. + ip_address ip; + if (!ip_address::forString(repr.substr(0, index), &ip)) + return false; + + // Parse the prefix length. Can't use base::ParseUint because it accepts non-base 10 input. + const char *prefixString = repr.c_str() + index + 1; + if (!isdigit(*prefixString)) + return false; + char *endptr; + unsigned long prefixlen = strtoul(prefixString, &endptr, 10); + if (*endptr != '\0') + return false; + + uint8_t maxlen = (ip.family() == AF_INET) ? 32 : 128; + if (prefixlen > maxlen) + return false; + + *prefix = ip_prefix(ip, prefixlen); + return true; +} + +std::string ip_prefix::toString() const noexcept +{ + // return StringPrintf("%s/%d", ip().toString().c_str(), mData.cidrlen); + char result[BUFF_MAX_LEN] = {}; + snprintf(result, sizeof(result), "%s/%d", ip().toString().c_str(), mData.cidrlen); + return result; +} + +std::string ip_sock_addr::toString() const noexcept +{ + switch (mData.family) { + case AF_INET6: + // return StringPrintf("[%s]:%u", ip().toString().c_str(), mData.port); + { + char result[BUFF_MAX_LEN] = {}; + snprintf(result, sizeof(result), "[%s]:%u", ip().toString().c_str(), mData.port); + return result; + } + default: + // return StringPrintf("%s:%u", ip().toString().c_str(), mData.port); + { + char result[BUFF_MAX_LEN] = {}; + snprintf(result, sizeof(result), "%s:%u", ip().toString().c_str(), mData.port); + return result; + } + } +} + +} // namespace net_utils +} // namespace common +} // namespace nmd +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netmanagernative/common/src/rwlock.cpp b/http/services/netmanagernative/common/src/rwlock.cpp new file mode 100644 index 000000000..64a80eefb --- /dev/null +++ b/http/services/netmanagernative/common/src/rwlock.cpp @@ -0,0 +1,58 @@ +#include "rwlock.h" +#include + +namespace OHOS { +namespace nmd { +nmd::common::rwlock::rwlock(bool writeFirst) + : WRITE_FIRST(writeFirst), m_write_thread_id(), m_lockCount(0), m_writeWaitCount(0) +{} +int nmd::common::rwlock::readLock() +{ + if (std::this_thread::get_id() != this->m_write_thread_id) { + int count; + if (WRITE_FIRST) + do { + while ((count = m_lockCount) == WRITE_LOCK_STATUS || m_writeWaitCount > 0) + ; + } while (!m_lockCount.compare_exchange_weak(count, count + 1)); + else + do { + while ((count = m_lockCount) == WRITE_LOCK_STATUS) + ; + } while (!m_lockCount.compare_exchange_weak(count, count + 1)); + } + return m_lockCount; +} +int nmd::common::rwlock::readUnlock() +{ + if (std::this_thread::get_id() != this->m_write_thread_id) { + --m_lockCount; + } + return m_lockCount; +} +int nmd::common::rwlock::writeLock() +{ + if (std::this_thread::get_id() != this->m_write_thread_id) { + ++m_writeWaitCount; + for (int zero = FREE_STATUS; !this->m_lockCount.compare_exchange_weak(zero, WRITE_LOCK_STATUS); + zero = FREE_STATUS) + ; + --m_writeWaitCount; + m_write_thread_id = std::this_thread::get_id(); + } + return m_lockCount; +} +int nmd::common::rwlock::writeUnlock() +{ + if (std::this_thread::get_id() != this->m_write_thread_id) { + return -1; + } + assert(WRITE_LOCK_STATUS == m_lockCount); + m_write_thread_id = NULL_THEAD; + m_lockCount.store(FREE_STATUS); + return m_lockCount; +} + +const std::thread::id nmd::common::rwlock::NULL_THEAD; +} // namespace nmd +} // namespace OHOS diff --git a/http/services/netmanagernative/common/src/server_socket.cpp b/http/services/netmanagernative/common/src/server_socket.cpp new file mode 100644 index 000000000..57c280e02 --- /dev/null +++ b/http/services/netmanagernative/common/src/server_socket.cpp @@ -0,0 +1,69 @@ +#include "server_socket.h" +#include +#include +#include +#include +#include +#include +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { +common::server_socket::server_socket() {} + +common::server_socket::~server_socket() {} + +int common::server_socket::bindPort(uint16_t port) +{ + struct sockaddr_in addr {}; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + struct sockaddr *ad = reinterpret_cast(&addr); + memcpy(&(this->addr_), ad, sizeof(*ad)); + + int bindFd = 0; + if ((bindFd = bind(this->socketFd_, &this->addr_, sizeof(this->addr_))) != 0) { + // logger::error() << "[Socket] Unable to bind the Socket: " << strerror(errno) << endl; + NETNATIVE_LOGE("[Socket] Unable to bind the Socket: %{public}s", strerror(errno)); + exit(0); + } + return bindFd; +} + +int common::server_socket::bindFile(const char *filePath, const char *name) +{ + NETNATIVE_LOGI("server_socket::bindFile start:"); + int openSock = open(std::string(filePath).append("/").append(name).c_str(), O_CREAT | O_WRONLY, 0643); + if (openSock == -1) { + // logger::error() << "[Socket] Unable to create file: '" << name << "'," << strerror(errno) << endl; + NETNATIVE_LOGE("[Socket] Unable to create file: '%{public}s', %{public}s", name, strerror(errno)); + exit(0); + } + fsync(openSock); + close(openSock); + + // logger::info() << "[Socket]: will bind at:" << std::string(filePath).append("/").append(name).c_str() << endl; + NETNATIVE_LOGI("[Socket]: will bind at: %{public}s", std::string(filePath).append("/").append(name).c_str()); + struct sockaddr_un addr {}; + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, std::string(filePath).append("/").append(name).c_str()); + + struct sockaddr *ad = reinterpret_cast(&addr); + memcpy(&(this->addr_), ad, sizeof(*ad)); + int bindFd = 0; + if ((bindFd = bind(this->socketFd_, &this->addr_, sizeof(this->addr_))) != 0) { + // logger::error() << "[Socket] Unable to bind the unix Socket:'" + // << std::string(filePath).append("/").append(name).c_str() << "'," << strerror(errno) + // << endl; + NETNATIVE_LOGE("[Socket] Unable to bind the unix Socket:'%{public}s',', %{public}s", + std::string(filePath).append("/").append(name).c_str(), strerror(errno)); + exit(-1); + } + return bindFd; +} + +} // namespace nmd +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netmanagernative/common/src/server_template.cpp b/http/services/netmanagernative/common/src/server_template.cpp new file mode 100644 index 000000000..6e9a14dce --- /dev/null +++ b/http/services/netmanagernative/common/src/server_template.cpp @@ -0,0 +1,38 @@ +#include "server_template.h" +#include "logger.h" +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { +void common::server_template::start() +{ + // common::logger::info() << serverName_ << " start ." << endl; + NETNATIVE_LOGD("%{public}s start .", serverName_.c_str()); + this->server_->createUnix(); + NETNATIVE_LOGI("setRecevedHandler start:"); + this->server_->setRecevedHandler( + &common::server_template::handler, this); + NETNATIVE_LOGI("setRecevedHandler end:"); + this->server_->bindFile(SOCKET_FILE_PATH, socketName_.c_str()); + this->server_->listenSocket(); + + this->mRunning = true; + while (this->mRunning) { + this->server_->acceptSocket(); + } +} + +void common::server_template::stop() +{ + this->mRunning = false; +} + +void common::server_template::handler(int socketFd, const uint8_t *msg, const size_t msgLen) +{ + // common::logger::info() << "socket:" << socketFd << ",msg:" << msg << endl; + NETNATIVE_LOGD("socket: %{public}d ,msg: %{public}s", socketFd, msg); + initJob(socketFd, msg, msgLen); + this->pool_->execute(job_); +} +} // namespace nmd +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netmanagernative/common/src/socket_base.cpp b/http/services/netmanagernative/common/src/socket_base.cpp new file mode 100644 index 000000000..170924036 --- /dev/null +++ b/http/services/netmanagernative/common/src/socket_base.cpp @@ -0,0 +1,154 @@ +#include "socket_base.h" +#include +#include +#include +#include +#include +#include +#include "netnative_log_wrapper.h" +static const int EPOLL_SIZE = 50; + +namespace OHOS { +namespace nmd { +nmd::common::socket_base::socket_base(/* args */) {} + +nmd::common::socket_base::~socket_base() {} + +int nmd::common::socket_base::create(int domain, int protocol) +{ + this->socketFd_ = -1; + if ((this->socketFd_ = socket(domain, SOCK_STREAM, protocol)) == -1) { + // logger::info() << "[Socket] Unable to Open the Socket: " << strerror(errno) << endl; + NETNATIVE_LOGE("[Socket] Unable to Open the Socket: %{public}s", strerror(errno)); + exit(0); + } + this->epollFd_ = epoll_create(EPOLL_SIZE); + this->epollEvents_ = new epoll_event[EPOLL_SIZE]; + + event_.events = EPOLLIN; + event_.data.fd = this->socketFd_; + epoll_ctl(this->epollFd_, EPOLL_CTL_ADD, this->socketFd_, &this->event_); + + return this->socketFd_; +} + +int nmd::common::socket_base::createInet() +{ + return this->create(AF_INET, 0); +} + +int nmd::common::socket_base::createUnix() +{ + return this->create(AF_UNIX, 0); +} + +int nmd::common::socket_base::listenSocket() +{ + int listenFd = -1; + if ((listenFd = listen(this->socketFd_, 50)) == -1) { + // logger::error() << "[Socket] Unable to listen the Socket: " << strerror(errno) << endl; + NETNATIVE_LOGE("[Socket] Unable to listen the Socket: %{public}s", strerror(errno)); + exit(0); + } + return listenFd; +} + +static const int BUF_SIZE = 4096; +int nmd::common::socket_base::acceptSocket() +{ + int clientFd = 0; + this->eventCnt_ = epoll_wait(this->epollFd_, this->epollEvents_, EPOLL_SIZE, -1); + if (this->eventCnt_ == -1) { + // logger::error() << "[Socket] epoll_wait() error: " << strerror(errno) << endl; + NETNATIVE_LOGE("[Socket] epoll_wait() error: %{public}s", strerror(errno)); + return this->eventCnt_; + } + + for (int i = 0; i < this->eventCnt_; i++) { + if (this->epollEvents_[i].data.fd == this->socketFd_) { + struct sockaddr_in clientAddr; + socklen_t adr_sz = sizeof(clientAddr); + clientFd = accept(this->socketFd_, reinterpret_cast(&clientAddr), &adr_sz); + char clientStr[20] = {'\0'}; + const char *clientAddrStr = + inet_ntop(clientAddr.sin_family, &clientAddr.sin_addr, clientStr, sizeof(clientAddr)); + if (nullptr == clientAddrStr) { + // logger::info() << "[Socket] new unix socket client connected." << endl; + NETNATIVE_LOGI("[Socket] new unix socket client connected."); + } else { + // logger::info() << "[Socket] new client:" << std::string(clientAddrStr) << endl; + NETNATIVE_LOGI("[Socket] new client: %{public}s", std::string(clientAddrStr).c_str()); + } + + this->event_.events = EPOLLIN; + this->event_.data.fd = clientFd; + epoll_ctl(this->epollFd_, EPOLL_CTL_ADD, clientFd, &this->event_); + } else { + uint8_t buf[BUF_SIZE] = {'\0'}; + ssize_t readSize = read(this->epollEvents_[i].data.fd, buf, BUF_SIZE); + if (readSize == 0) { + epoll_ctl(this->epollFd_, EPOLL_CTL_DEL, this->epollEvents_[i].data.fd, NULL); + close(this->epollEvents_[i].data.fd); + // logger::info() << "[Socket] closed client:" << this->epollEvents_[i].data.fd << endl; + NETNATIVE_LOGI("[Socket] closed client: %{public}d", this->epollEvents_[i].data.fd); + } else if (readSize < 0) { + if (errno == ECONNRESET) { + epoll_ctl(this->epollFd_, EPOLL_CTL_DEL, this->epollEvents_[i].data.fd, NULL); + close(this->epollEvents_[i].data.fd); + // logger::info() << "[Socket] closed client:" << this->epollEvents_[i].data.fd << endl; + NETNATIVE_LOGI("[Socket] closed client: %{public}d", this->epollEvents_[i].data.fd); + } else { + // logger::info() << "[Socket] read error fd:" << this->epollEvents_[i].data.fd << endl; + NETNATIVE_LOGI("[Socket] read error fd: %{public}d", this->epollEvents_[i].data.fd); + } + } else { + this->handler_(this->epollEvents_[i].data.fd, buf, static_cast(readSize)); + } + } + } + return 0; +} + +int nmd::common::socket_base::connectSocket(struct sockaddr_in serverAddr) +{ + int connectFd = -1; + if ((connectFd = connect(this->socketFd_, reinterpret_cast(&serverAddr), sizeof(serverAddr))) == + -1) { + // logger::error() << "[Socket] Unable to connect the Socket" << endl; + NETNATIVE_LOGE("[Socket] Unable to connect the Socket"); + exit(0); + }; + return connectFd; +} + +ssize_t nmd::common::socket_base::sendSocket(const char *buffer) +{ + ssize_t size = -1; + if ((size = send(this->socketFd_, buffer, strlen(buffer), 0)) == -1) { + // logger::error() << "[Socket] Unable to send to Socket" << this->socketFd_ << endl; + NETNATIVE_LOGE("[Socket] Unable to send to Socket %{public}d", this->socketFd_); + }; + return size; +} + +ssize_t nmd::common::socket_base::sendSocket(int socketFd, const char *buffer) +{ + ssize_t size = -1; + if ((size = send(socketFd, buffer, strlen(buffer), 0)) == -1) { + // logger::error() << "[Socket] Unable to send to Socket" << socketFd << endl; + NETNATIVE_LOGE("[Socket] Unable to send to Socket %{public}d", socketFd); + }; + return size; +} + +ssize_t nmd::common::socket_base::sendMsg(const int socketFd, const msghdr &msg) +{ + ssize_t size = -1; + if ((size = sendmsg(socketFd, &msg, 0)) == -1) { + // logger::error() << "[Socket] Unable to sendmsg to Socket" << socketFd << endl; + NETNATIVE_LOGE("[Socket] Unable to sendmsg to Socket %{public}d", socketFd); + }; + return size; +} +} // namespace nmd +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netmanagernative/common/src/thread_pool.cpp b/http/services/netmanagernative/common/src/thread_pool.cpp new file mode 100644 index 000000000..cba3110b6 --- /dev/null +++ b/http/services/netmanagernative/common/src/thread_pool.cpp @@ -0,0 +1,66 @@ +#include "thread_pool.h" +#include +namespace OHOS { +namespace nmd { +thread_pool::thread_pool(unsigned int threadNums, unsigned int queueSize) + : threadNums_(threadNums), queueSize_(queueSize) +{ + this->workQueue_ = new blocking_queue(this->queueSize_); + + for (unsigned int i = 0; i < this->threadNums_; ++i) { + this->workers_.push_back(new std::thread(std::bind(&thread_pool::threadLoop, this))); + } + + this->running_ = true; +} + +thread_pool::~thread_pool() +{ + this->running_ = false; + cond_.notify_all(); + for (unsigned int i = 0; i < this->threadNums_; ++i) { + auto &thread = this->workers_[i]; + thread->join(); + delete thread; + } + + if (nullptr != this->workQueue_) { + delete this->workQueue_; + } +} + +nmd::job *thread_pool::takeJobFromQueue() +{ + std::unique_lock lock(this->mutex_); + while (this->workQueue_->isEmpty() && this->running_) { + this->cond_.wait(lock); + } + nmd::job *j = nullptr; + if (!this->workQueue_->isEmpty() && this->running_) { + j = this->workQueue_->pop(); + } + return j; +} + +void thread_pool::threadLoop() +{ + while (this->running_) { + nmd::job *j = takeJobFromQueue(); + if (j) { + j->run(); + delete j; + } + } +} + +void thread_pool::execute(nmd::job *j) +{ + std::unique_lock lock(this->mutex_); + while (this->workQueue_->isFull()) { + } + this->workQueue_->push(j); + this->cond_.notify_one(); +} + +} // namespace nmd +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netmanagernative/common/src/utils.cpp b/http/services/netmanagernative/common/src/utils.cpp new file mode 100644 index 000000000..3932ea427 --- /dev/null +++ b/http/services/netmanagernative/common/src/utils.cpp @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace OHOS { +namespace nmd { +namespace common { + +std::time_t utils::getCurrentTime() +{ + auto now = std::chrono::system_clock::now(); + return std::chrono::system_clock::to_time_t(now); +} + +int nmd::common::utils::removeDirectory(const char *path) +{ + DIR *d = opendir(path); + size_t path_len = strlen(path); + int r = -1; + + if (d) { + struct dirent *p = nullptr; + + r = 0; + while (!r && (p = readdir(d))) { + int r2 = -1; + char *buf = nullptr; + + /* Skip the names "." and ".." as we don't want to recurse on them. */ + if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) { + continue; + } + + size_t len = path_len + strlen(p->d_name) + 2; + buf = reinterpret_cast(malloc(len)); + + if (buf) { + struct stat statbuf; + + snprintf(buf, len, "%s/%s", path, p->d_name); + if (!stat(buf, &statbuf)) { + if (S_ISDIR(statbuf.st_mode)) { + r2 = removeDirectory(buf); + } else { + r2 = unlink(buf); + } + } + free(buf); + } + r = r2; + } + closedir(d); + } + + if (!r) { + r = rmdir(path); + } + + return r; +} +} // namespace common +} // namespace nmd +} // namespace OHOS diff --git a/http/services/netmanagernative/net_mgr_native/client/include/dnsresolv_client.h b/http/services/netmanagernative/net_mgr_native/client/include/dnsresolv_client.h new file mode 100644 index 000000000..e06702df3 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/client/include/dnsresolv_client.h @@ -0,0 +1,50 @@ +#ifndef __INCLUDE_DNSRESOLV_CLIENT_H__ +#define __INCLUDE_DNSRESOLV_CLIENT_H__ +#include +#include +#include "dnsresolv.h" + +namespace OHOS { +namespace nmd { + +enum dnsresolv_query_state { QUERY_START, QUERY_WAIT_REPONSE, QUERY_OK, QUERY_FAILED, QUERY_RESULT, QUERY_END }; + +class dnsresolv_client { +private: + dnsresolv_query_state queryState_ = QUERY_START; + int socketFd_ = -1; + +public: + dnsresolv_client(/* args */) = default; + ~dnsresolv_client() = default; + + int init(); + int initConfiguration(const dnsresolver_params ¶m); + int unInitConfiguration(const dnsresolver_params ¶m); + +public: + int getaddrinfo( + const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res); + int getaddrinfo_proxy(const char *hostname, const char *servname, const struct addrinfo *hints, + struct addrinfo **res, uint16_t netid); + +private: + dnsresolv_query_state startQuery( + const char *hostname, const char *servname, const struct addrinfo *hints, int &result); + dnsresolv_query_state sendRequest(struct dnsresolver_request_cmd &reqCmd, int &result); + dnsresolv_query_state recvResponese(int &result, struct dnsresolver_response_cmd &repcmd); + dnsresolv_query_state recvResult( + int &result, const struct dnsresolver_response_cmd &repcmdState, p_dnsresolver_response_cmd &repcmdResult); + dnsresolv_query_state parseResult( + int &result, const p_dnsresolver_response_cmd repcmdResult, struct addrinfo **res); + + int createNetworkCache(const uint16_t netid); + int destroyNetworkCache(const uint16_t netid); + int setResolverConfig(const dnsresolver_params ¶m); + int sendRequestWithResponse(const dnsresolver_request_cmd &reqcmd, dnsresolver_response_cmd &repcmd); + void setNameList(char *buffer, const size_t bufferSize, const std::vector namelist); +}; +} // namespace nmd +} // namespace OHOS + +#endif //!__INCLUDE_DNSRESOLV_CLIENT_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/client/include/fwmark_client.h b/http/services/netmanagernative/net_mgr_native/client/include/fwmark_client.h new file mode 100644 index 000000000..44d2b8318 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/client/include/fwmark_client.h @@ -0,0 +1,19 @@ +#ifndef __INCLUDE_FWMARK_CLIENT_H__ +#define __INCLUDE_FWMARK_CLIENT_H__ + +#include "fwmark_command.h" + +namespace nmd { +class fwmark_client { +private: + int channel_ = -1; + +public: + fwmark_client(); + ~fwmark_client(); + + int send(fwmark_command *data); +}; +} // namespace nmd + +#endif //!__INCLUDE_FWMARK_CLIENT_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/client/src/dnsresolv_client.cpp b/http/services/netmanagernative/net_mgr_native/client/src/dnsresolv_client.cpp new file mode 100644 index 000000000..d6cf34f45 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/client/src/dnsresolv_client.cpp @@ -0,0 +1,432 @@ +#include "dnsresolv_client.h" +#include +#include +#include "logger.h" +#include +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { +constexpr const char *DNSRESOLV_SERVICE_SOCK_PATH = "/dev/socket/dnsresolvproxy.sock"; +} // namespace nmd + +int nmd::dnsresolv_client::init() +{ + socketFd_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (socketFd_ == -1) { + // common::logger::error() << "[dnsresolv_client] Unable to create socket ." << endl; + NETNATIVE_LOGE("[dnsresolv_client] Unable to create socket ."); + return EAI_SYSTEM; + } + + struct sockaddr_un addr {}; + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, DNSRESOLV_SERVICE_SOCK_PATH); + + struct sockaddr addr_ {}; + struct sockaddr *ad = reinterpret_cast(&addr); + memcpy(&(addr_), ad, sizeof(*ad)); + int ret = connect(socketFd_, &addr_, sizeof(addr_)); + if (ret < 0) { + // common::logger::error() << "[dnsresolv_client] Unable to connect server: " << DNSRESOLV_SERVICE_SOCK_PATH + // << " error: " << ret << strerror(errno) << endl; + NETNATIVE_LOGE("[dnsresolv_client] Unable to connect server: %{public}s, error: %{public}d, %{public}s", + DNSRESOLV_SERVICE_SOCK_PATH, ret, strerror(errno)); + return EAI_SYSTEM; + } + + return 0; +} + +int nmd::dnsresolv_client::initConfiguration(const dnsresolver_params ¶m) +{ + auto ret = createNetworkCache(param.netId); + if (ret < 0) { + if (ret == -2) { + // common::logger::warn() << "[dnsresolv_client] Network cache of netid: " << param.netId + // << " has been created." << endl; + NETNATIVE_LOGE("[dnsresolv_client] Network cache of netid: %{public}d has been created.", param.netId); + } + } + // common::logger::info() << "[dnsresolv_client] Create network cache for netid: " << param.netId << endl; + NETNATIVE_LOGE("[dnsresolv_client] Network cache of netid: %{public}d ", param.netId); + + ret = setResolverConfig(param); + if (ret < 0) { + // common::logger::error() << "[dnsresolv_client] Unable to set resolv config for netid: " << param.netId + // << endl; + NETNATIVE_LOGE("[dnsresolv_client] Unable to set resolv config for netid: %{public}d ", param.netId); + return ret; + } + + return 0; +} + +int nmd::dnsresolv_client::unInitConfiguration(const dnsresolver_params ¶m) +{ + auto ret = destroyNetworkCache(param.netId); + if (ret < 0) { + // common::logger::error() << "[dnsresolv_client] Unable to destroy network cache for netid: " << param.netId + // << endl; + NETNATIVE_LOGE("[dnsresolv_client] Unable to destroy network cache for netid: %{public}d ", param.netId); + return ret; + } + + // common::logger::info() << "[dnsresolv_client] Destroy network cache for netid: " << param.netId << endl; + NETNATIVE_LOGE("[dnsresolv_client] Destroy network cache for netid: %{public}d ", param.netId); + return 0; +} + +int nmd::dnsresolv_client::getaddrinfo( + const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) +{ + int ret = 0; + dnsresolver_response_cmd repCmdState; + queryState_ = QUERY_START; + p_dnsresolver_response_cmd repCmdResult(nullptr); + while (queryState_ != QUERY_END) { + switch (queryState_) { + case QUERY_START: + queryState_ = startQuery(hostname, servname, hints, ret); + break; + case QUERY_WAIT_REPONSE: + queryState_ = recvResponese(ret, repCmdState); + break; + case QUERY_OK: + queryState_ = recvResult(ret, repCmdState, repCmdResult); + break; + case QUERY_FAILED: + queryState_ = QUERY_END; + break; + case QUERY_RESULT: + queryState_ = parseResult(ret, repCmdResult, res); + break; + case QUERY_END: + break; + + default: + break; + } + } + + if (nullptr != repCmdResult) { + delete repCmdResult; + repCmdResult = nullptr; + } + + return ret; +} + +nmd::dnsresolv_query_state nmd::dnsresolv_client::sendRequest(dnsresolver_request_cmd &reqCmd, int &result) +{ + if (socketFd_ < 0) { + // common::logger::error() << "[dnsresolv_client] Unable to send request invalid socketFd_: " << socketFd_ + // << endl; + NETNATIVE_LOGE("[dnsresolv_client] Unable to send request invalid socketFd_: %{public}d ", socketFd_); + result = EAI_SYSTEM; + return QUERY_END; + } + + iovec iov[1] = {{&reqCmd, sizeof(reqCmd)}}; + + msghdr hdr; + memset(&hdr, 0, sizeof(hdr)); + hdr.msg_iov = iov; + hdr.msg_iovlen = 1; + + auto ret = sendmsg(socketFd_, &hdr, 0); + if (ret < 0) { + // common::logger::error() << "[dnsresolv_client] Unable to send request cmdid: " << reqCmd.cmdID + // << " error: " << ret << strerror(errno) << endl; + NETNATIVE_LOGE("[dnsresolv_client] Unable to send request cmdid: %{public}d, error : %{public}s ", + reqCmd.cmdID, strerror(errno)); + result = EAI_SYSTEM; + return QUERY_END; + } + + return QUERY_WAIT_REPONSE; +} + +nmd::dnsresolv_query_state nmd::dnsresolv_client::recvResponese(int &result, dnsresolver_response_cmd &repcmdRes) +{ + if (socketFd_ < 0) { + // common::logger::error() << "[dnsresolv_client] Unable to recv response. invalid socketFd_: " << socketFd_ + // << endl; + NETNATIVE_LOGE(" [dnsresolv_client] Unable to recv response. invalid socketFd_: %{public}d ", socketFd_); + result = EAI_SYSTEM; + return QUERY_END; + } + + const size_t buffSize = dnsresolver_response_cmd::cmd_id::QUERY_STATE_BUTT == repcmdRes.cmdID ? + sizeof(dnsresolver_response_cmd) : + (sizeof(dnsresolver_response_cmd) + repcmdRes.resSize); + std::vector buff(buffSize, 0); + + auto ret = recv(socketFd_, buff.data(), buffSize, 0); + if (ret < 0) { + // common::logger::error() << "[dnsresolv_client] Unable to recv response. " + // << " error : " << ret << strerror(errno) << endl; + NETNATIVE_LOGE("[dnsresolv_client] Unable to recv response. error : ret = %{public}d, %{public}s ", ret, + strerror(errno)); + result = EAI_SYSTEM; + return QUERY_END; + } + + dnsresolver_response_cmd *repCmd = reinterpret_cast(buff.data()); + + if (nullptr == repCmd) { + // common::logger::error() << "[dnsresolv_client] Unable to recv response. " + // << "recv buffer is null." << endl; + NETNATIVE_LOGE("[dnsresolv_client] Unable to recv response. recv buffer is null."); + result = EAI_SYSTEM; + return QUERY_END; + } + + switch (repCmd->cmdID) { + case dnsresolver_response_cmd::cmd_id::QUERY_STATE_FAIL: { + result = repCmd->result; + return QUERY_FAILED; + } break; + + case dnsresolver_response_cmd::cmd_id::QUERY_STATE_OK: { + result = repCmd->result; + repcmdRes = *repCmd; + return QUERY_OK; + } break; + + case dnsresolver_response_cmd::cmd_id::QUERY_SUCCESS_WITH_RESULT: { + result = repCmd->result; + repcmdRes = *repCmd; + memcpy(repcmdRes.resData, repCmd->resData, repCmd->resSize); + return QUERY_RESULT; + } break; + default: + // unreachable + abort(); + break; + } + + return QUERY_END; +} + +nmd::dnsresolv_query_state nmd::dnsresolv_client::startQuery( + const char *hostname, const char *servname, const struct addrinfo *hints, int &result) +{ + if ((hostname != nullptr && strcspn(hostname, " \n\r\t^'\"") != strlen(hostname)) || + (servname != nullptr && strcspn(servname, " \n\r\t^'\"") != strlen(servname))) { + result = EAI_NODATA; + return QUERY_END; + } + + dnsresolver_request_cmd_t reqCmd; + bzero(&reqCmd, sizeof(reqCmd)); + reqCmd.cmdID = dnsresolver_request_cmd::cmd_id::GET_ADDR_INFO; + if (nullptr != hostname) { + strncpy(reqCmd.cmd_hostName, hostname, MAX_NAME_LEN); + } + + if (nullptr != servname) { + strncpy(reqCmd.cmd_serverName, servname, MAX_NAME_LEN); + } + + if (nullptr != hints) { + reqCmd.cmd_hints = *hints; + } + + return sendRequest(reqCmd, result); +} + +nmd::dnsresolv_query_state nmd::dnsresolv_client::recvResult( + int &result, const struct dnsresolver_response_cmd &repcmdState, p_dnsresolver_response_cmd &repcmdResult) +{ + if (dnsresolver_response_cmd::cmd_id::QUERY_STATE_OK != repcmdState.cmdID) { + result = EAI_SYSTEM; + return QUERY_END; + } + + repcmdResult = reinterpret_cast( + malloc(offsetof(dnsresolver_response_cmd, resData[repcmdState.resSize]))); + if (nullptr == repcmdResult) { + result = EAI_SYSTEM; + return QUERY_END; + } + *repcmdResult = repcmdState; + + for (size_t i = 0; i < repcmdResult->resSize; ++i) { + repcmdResult->resData[i] = 0; + } + + return recvResponese(result, *repcmdResult); +} + +nmd::dnsresolv_query_state nmd::dnsresolv_client::parseResult( + int &result, const p_dnsresolver_response_cmd repcmdResult, struct addrinfo **res) +{ + if (nullptr == repcmdResult) { + result = EAI_SYSTEM; + *res = nullptr; + return QUERY_END; + } + + *res = nullptr; + struct addrinfo *ai(nullptr); + struct addrinfo **nextres = res; + size_t bufferCount(0); + uint8_t *bufferCur = repcmdResult->resData; + struct addrinfo *tmpAddrInfo(nullptr); + result = repcmdResult->result; + while (bufferCount < repcmdResult->resSize) { + ai = reinterpret_cast( + calloc(1, sizeof(struct addrinfo) + sizeof(struct sockaddr_storage))); + if (ai == NULL) { + result = EAI_SYSTEM; + break; + } + + tmpAddrInfo = reinterpret_cast(bufferCur); + ai->ai_flags = tmpAddrInfo->ai_flags; + ai->ai_family = tmpAddrInfo->ai_family; + ai->ai_socktype = tmpAddrInfo->ai_socktype; + ai->ai_protocol = tmpAddrInfo->ai_protocol; + + // set ai_addrlen and ai_addrinfo + ai->ai_addr = reinterpret_cast(ai + 1); + ai->ai_addrlen = tmpAddrInfo->ai_addrlen; + if (ai->ai_addrlen > sizeof(struct sockaddr_storage)) { + // unreachable in case of too big + result = EAI_SYSTEM; + break; + } + bufferCur += sizeof(addrinfo); + bufferCount += sizeof(addrinfo); + memcpy(ai->ai_addr, bufferCur, ai->ai_addrlen); + + // set ai_cannonname if need + bufferCur += ai->ai_addrlen; + bufferCount += ai->ai_addrlen; + if (nullptr != tmpAddrInfo->ai_canonname) { + size_t namelen = strlen(reinterpret_cast(bufferCur)) + 1; + ai->ai_canonname = reinterpret_cast(malloc(namelen)); + memcpy(ai->ai_canonname, bufferCur, namelen); + + if (ai->ai_canonname[namelen - 1] != '\0') { + result = EAI_SYSTEM; + break; + } + bufferCur += namelen; + bufferCount += namelen; + } + + *nextres = ai; + nextres = &ai->ai_next; + ai = nullptr; + }; + + if (result != repcmdResult->result && nullptr != *res) { + // something error, clean result + freeaddrinfo(*res); + *res = nullptr; + } + + return QUERY_END; +} + +int nmd::dnsresolv_client::createNetworkCache(const uint16_t netid) +{ + dnsresolver_request_cmd reqCmd; + bzero(&reqCmd, sizeof(reqCmd)); + reqCmd.cmdID = dnsresolver_request_cmd::cmd_id::CREATE_NETWORK_CACHE; + reqCmd.netid = netid; + + dnsresolver_response_cmd repCmd; + auto ret = sendRequestWithResponse(reqCmd, repCmd); + if (ret != 0) { + return ret; + } + + return repCmd.cmdID == dnsresolver_response_cmd::cmd_id::QUERY_STATE_OK ? 0 : -1; +} + +int nmd::dnsresolv_client::destroyNetworkCache(const uint16_t netid) +{ + dnsresolver_request_cmd reqCmd; + bzero(&reqCmd, sizeof(reqCmd)); + reqCmd.cmdID = dnsresolver_request_cmd::cmd_id::DESOTRY_NETWORK_CACHE; + reqCmd.netid = netid; + + dnsresolver_response_cmd repCmd; + auto ret = sendRequestWithResponse(reqCmd, repCmd); + if (ret != 0) { + return ret; + } + + return repCmd.cmdID == dnsresolver_response_cmd::cmd_id::QUERY_STATE_OK ? 0 : -1; +} + +int nmd::dnsresolv_client::setResolverConfig(const dnsresolver_params ¶m) +{ + dnsresolver_request_cmd reqCmd; + bzero(&reqCmd, sizeof(reqCmd)); + reqCmd.cmdID = dnsresolver_request_cmd::cmd_id::SET_RESOLVER_CONFIG; + reqCmd.netid = param.netId; + reqCmd.cmd_baseTimeoutMsec = param.baseTimeoutMsec; + reqCmd.cmd_retryCount = param.retryCount; + reqCmd.cmd_serverCount = static_cast(param.servers.size()); + reqCmd.cmd_domainCount = static_cast(param.domains.size()); + setNameList(reqCmd.cmd_servers, MAX_NAME_LIST_LEN, param.servers); + setNameList(reqCmd.cmd_domains, MAX_NAME_LIST_LEN, param.domains); + + dnsresolver_response_cmd repCmd; + auto ret = sendRequestWithResponse(reqCmd, repCmd); + if (ret != 0) { + return ret; + } + + return repCmd.cmdID == dnsresolver_response_cmd::cmd_id::QUERY_STATE_OK ? 0 : -1; +} + +int nmd::dnsresolv_client::sendRequestWithResponse( + const dnsresolver_request_cmd &reqcmd, dnsresolver_response_cmd &repcmd) +{ + int ret(0); + sendRequest(const_cast(reqcmd), ret); + if (ret < 0) { + return ret; + } + + recvResponese(ret, repcmd); + if (ret < 0) { + return ret; + } + + return ret; +} + +void nmd::dnsresolv_client::setNameList( + char *buffer, const size_t bufferSize, const std::vector namelist) +{ + if (nullptr == buffer || 0 == bufferSize || namelist.empty()) { + // common::logger::error() << "[dnsresolv_client] Unable to setNameList: invalid param. " << endl; + NETNATIVE_LOGE("[dnsresolv_client] Unable to setNameList: invalid param. "); + return; + } + + char *buffCur = buffer; + size_t buffCount(0); + for (auto &name : namelist) { + if (name.empty()) { + continue; + } + + if ((bufferSize - buffCount) < (name.length() + 1)) { + // common::logger::warn() << "[dnsresolv_client] No  enough buffer to setNameList. " << endl; + NETNATIVE_LOGD("[dnsresolv_client] No  enough buffer to setNameList."); + break; + } + + strcpy(buffCur, name.c_str()); + buffCur += (name.length() + 1); + buffCount += (name.length() + 1); + } +} +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/client/src/fwmark_client.cpp b/http/services/netmanagernative/net_mgr_native/client/src/fwmark_client.cpp new file mode 100644 index 000000000..3b99f5ae5 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/client/src/fwmark_client.cpp @@ -0,0 +1,55 @@ +#include "fwmark_client.h" +#include +#include +#include +#include +#include +#include +#include +#include + +const char *FWMARK_SERVICE_SOCK_PATH = "/dev/socket/fwmarkd.sock"; +nmd::fwmark_client::fwmark_client(/* args */) {} + +nmd::fwmark_client::~fwmark_client() {} + +int nmd::fwmark_client::send(fwmark_command *data) +{ + this->channel_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (this->channel_ == -1) { + return -errno; + } + + struct sockaddr_un addr {}; + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, FWMARK_SERVICE_SOCK_PATH); + + struct sockaddr addr_ {}; + struct sockaddr *ad = reinterpret_cast(&addr); + memcpy(&(addr_), ad, sizeof(*ad)); + if (connect(this->channel_, &addr_, sizeof(addr_)) == -1) { + close(this->channel_); + return -errno; + } + + iovec iov[1] = {{data, sizeof(*data)}}; + + msghdr hdr; + memset(&hdr, 0, sizeof(hdr)); + hdr.msg_iov = iov; + hdr.msg_iovlen = 1; + + if (sendmsg(this->channel_, &hdr, 0) == -1) { + close(this->channel_); + return -errno; + } + char buf[sizeof(int)] = {'\0'}; + auto ret = recv(this->channel_, buf, sizeof(int), 0); + if (ret == -1 || ret == 0) { + close(this->channel_); + return -errno; + } + close(this->channel_); + common::logger::info() << "[FwmarkClient] recv:" << atoi(buf) << endl; + return atoi(buf); +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/dnsresolv.h b/http/services/netmanagernative/net_mgr_native/include/dnsresolv.h new file mode 100644 index 000000000..03592b489 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/dnsresolv.h @@ -0,0 +1,226 @@ +#ifndef __INCLUDE_DNSRESOLV_H__ +#define __INCLUDE_DNSRESOLV_H__ +#include "net_utils.h" +#include "warning_disable.h" +#include +#include +#include + +#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV | AI_ADDRCONFIG) + +#define GET_AI(ai, afd, addr) \ + do { \ + /* external reference: pai, error, and label free */ \ + (ai) = getAi(pai, (afd), (addr)); \ + if ((ai) == NULL) { \ + error = EAI_MEMORY; \ + goto free; \ + } \ + } while (0) + +#define GET_PORT(ai, serv) \ + do { \ + /* external reference: error and label free */ \ + error = getPort((ai), (serv), 0); \ + if (error != 0) \ + goto free; \ + } while (0) + +#define MATCH_FAMILY(x, y, w) ((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) +#define MATCH(x, y, w) ((x) == (y) || ((w) && ((x) == ANY_SOCK_TYPE || (y) == ANY_SOCK_TYPE))) + +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 (nullptr == netcontext) { + 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/http/services/netmanagernative/net_mgr_native/include/dnsresolv_cache.h b/http/services/netmanagernative/net_mgr_native/include/dnsresolv_cache.h new file mode 100644 index 000000000..69786bd40 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/dnsresolv_cache.h @@ -0,0 +1,128 @@ +#ifndef __INCLUDE_DNSRESOLV_CACHE_H__ +#define __INCLUDE_DNSRESOLV_CACHE_H__ +#include "dnsresolv.h" +#include "rwlock.h" +#include +#include +#include +#include +#include +#include +#include + +namespace OHOS { +namespace nmd { + +enum dnsresolv_cache_status { + RESOLV_CACHE_UNSUPPORTED, /* the cache can't handle that kind of queries */ + /* or the answer buffer is too small */ + RESOLV_CACHE_NOTFOUND, /* the cache doesn't know about this query */ + RESOLV_CACHE_FOUND, /* the cache found the answer */ + RESOLV_CACHE_SKIP /* Don't do anything on cache */ +}; + +class dns_packet { + const uint32_t FNV_MULT = 16777619U; + const uint32_t FNV_BASIS = 2166136261U; + using PackIterator = std::vector::const_iterator; + +public: + explicit dns_packet(const uint8_t *packet, const size_t packageLen, const std::time_t expires = -1) + : packet_(packet, packet + packageLen), itCursor_(packet_.begin()), expirationTime_(expires) + {} + + dns_packet(const dns_packet &dp) + : packet_(dp.packet_), itCursor_(packet_.begin()), expirationTime_(dp.expirationTime_) + {} + + void operator=(const dns_packet &dp) + { + this->packet_ = dp.packet_; + this->itCursor_ = this->packet_.begin(); + this->expirationTime_ = dp.expirationTime_; + } + + bool operator==(const dns_packet &dp) const; + uint32_t hash() const; + + bool isExpired(); + const std::vector &getDnsPacket() const + { + return packet_; + } + +private: + void rewind() const; + void skip(const long index) const; + uint32_t hashBytes(int numBytes, uint32_t hash) const; + int readInt16() const; + uint32_t hashQR(uint32_t hash) const; + uint32_t hashRR(uint32_t hash) const; + uint32_t hashQName(uint32_t hash) const; + bool isEqualQR(const dns_packet &dp) const; + bool isEqualRR(const dns_packet &dp) const; + bool isEqualDomainName(const dns_packet &dp) const; + bool isEqualBytes(const dns_packet &dp, const int numberByte) const; + +private: + std::vector packet_; + mutable PackIterator itCursor_; + std::time_t expirationTime_; +}; + +struct dns_packet_hash_func { + uint32_t operator()(const dns_packet &dp) const + { + return dp.hash(); + } +}; + +using ResolvCache = std::unordered_map; + +struct network_config { + explicit network_config(const uint16_t _netid) : netid(_netid), resolvCache(std::make_unique()) {} + + const uint16_t netid; + std::unique_ptr resolvCache; + std::vector nameservers; + std::vector nameserverSockAddrs; + dns_res_params params {}; + std::vector searchDomains; +}; + +using NetworkConfigMap = std::unordered_map>; + +class dnsresolv_cache { +public: + static dnsresolv_cache_status lookupFromResolvCache(uint16_t netid, const uint8_t *query, size_t querylen, + uint8_t *answer, const size_t answersize, size_t *answerlen, uint32_t flags); + + static int resolvCacheAdd(const uint16_t netid, const uint8_t *query, const size_t querylen, + const uint8_t *answer, const size_t answerlen); + static network_config *lookupResolvConfig(const uint16_t netid); + static int getResolverInfo(const uint16_t netid, std::vector &servers, + std::vector &domains, dns_res_params ¶m); + static int setResolverConfig(const dnsresolver_params &resolvParams); + static int createNetworkCache(const uint16_t netid); + static int destoryNetworkCache(const uint16_t netid); + static int flushNetworkCache(const uint16_t netid); + +public: + dnsresolv_cache(/* args */) = default; + ~dnsresolv_cache() = default; + +private: + static bool isValidServer(const std::string &server); + static ResolvCache *findResolvCache(const uint16_t netid); + static std::time_t getTTLFromAnswer(const uint8_t *answer, const size_t answerlen); + static uint32_t getNegativeTTL(ns_msg handle); + static int skipName(const uint8_t *ptr, const uint8_t *eom); + +private: + static nmd::common::rwlock sCacheLock_; + static NetworkConfigMap sNetworkConfig_; +}; + +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_DNSRESOLV_CACHE_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/dnsresolv_controller.h b/http/services/netmanagernative/net_mgr_native/include/dnsresolv_controller.h new file mode 100644 index 000000000..6b641a34e --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/dnsresolv_controller.h @@ -0,0 +1,31 @@ +#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); + 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__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/dnsresolv_service.h b/http/services/netmanagernative/net_mgr_native/include/dnsresolv_service.h new file mode 100644 index 000000000..47207d07f --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/dnsresolv_service.h @@ -0,0 +1,75 @@ +#ifndef __INCLUDE_DNSRESOLV_SERVICE_H__ +#define __INCLUDE_DNSRESOLV_SERVICE_H__ +#include "dnsresolv.h" +#include "dnsresolv_controller.h" +#include "job.h" +#include "server_template.h" +#include +#include +#include +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); + +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_ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/event_reporter.h b/http/services/netmanagernative/net_mgr_native/include/event_reporter.h new file mode 100644 index 000000000..82f14ba59 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/event_reporter.h @@ -0,0 +1,34 @@ +#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 { +private: + inetd_unsolicited_event_listener listener_; + +public: + event_reporter() = default; + void registerEventListener(inetd_unsolicited_event_listener &listener); + inetd_unsolicited_event_listener getListener() + { + return this->listener_; + } + ~event_reporter(); +}; +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_EVENT_REPORTER_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/fwmark.h b/http/services/netmanagernative/net_mgr_native/include/fwmark.h new file mode 100644 index 000000000..1482391b9 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/fwmark.h @@ -0,0 +1,18 @@ +#ifndef __INCLUDE_FWMARK_H__ +#define __INCLUDE_FWMARK_H__ + +#include "network.h" +namespace OHOS { +namespace nmd { +union fwmark { + uint32_t val; + struct { + uint16_t netId : 16; + NetworkPermission permission : 2; + uint16_t reserved : 14; + } bits; + constexpr fwmark() : val(0) {} +}; +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_FWMARK_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/fwmark_command.h b/http/services/netmanagernative/net_mgr_native/include/fwmark_command.h new file mode 100644 index 000000000..55f57db54 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/fwmark_command.h @@ -0,0 +1,15 @@ +#ifndef __INCLUDE_FWMARK_COMMAND_H__ +#define __INCLUDE_FWMARK_COMMAND_H__ +#include +namespace OHOS { +namespace nmd { +struct fwmark_command { + enum cmd_id { + SELECT_NETWORK, + } cmdId; + uint16_t netId; + unsigned fd; +}; +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_FWMARK_COMMAND_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/fwmark_server.h b/http/services/netmanagernative/net_mgr_native/include/fwmark_server.h new file mode 100644 index 000000000..eeaaf204b --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/fwmark_server.h @@ -0,0 +1,38 @@ +#ifndef __INCLUDE_FWMARK_SERVER_H__ +#define __INCLUDE_FWMARK_SERVER_H__ + +#include "job.h" +#include "server_template.h" +#include +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/http/services/netmanagernative/net_mgr_native/include/get_addr_info.h b/http/services/netmanagernative/net_mgr_native/include/get_addr_info.h new file mode 100644 index 000000000..141ddf8c7 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/get_addr_info.h @@ -0,0 +1,169 @@ +#ifndef __INCLUDE_GET_ADDR_INFO_H__ +#define __INCLUDE_GET_ADDR_INFO_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "net_utils.h" + +#define _PATH_HOSTS "/etc/hosts" +#define SCOPE_DELIMITER '%' +#define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */ +#define DNS_LABELTYPE_BITSTRING 0x41 +#define NETDB_SUCCESS 0 +static const char digits[] = "0123456789"; +static const char digitvalue[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /*256*/ +}; + +class get_addr_info_unit_test; +namespace OHOS { +namespace nmd { + +struct netd_net_context; +struct afd; +struct dns_res_state; +struct res_target; +struct dns_res_state; +struct dns_res_params; +typedef bool (*res_n_ok_func)(const char *dn); + +class get_addr_info { +#ifdef UNIT_TEST + friend get_addr_info_unit_test; +#endif +public: + get_addr_info(/* args */) = default; + ~get_addr_info() = default; + +public: + static int getaddrinfoFornetContext(const char *hostname, const char *servname, const addrinfo *hints, + const netd_net_context *netcontext, addrinfo **res); + + static int resolvGetAddrInfo(const char *hostname, const char *servname, const addrinfo *hints, + const netd_net_context *netcontext, addrinfo **res); + static int getaddrinfoNumeric(const char *hostname, const char *servname, addrinfo hints, addrinfo **result); + + static int ns_name_pton(const char *, unsigned char *, size_t); + static int ns_name_pton2(const char *, unsigned char *, size_t, size_t *); + static int ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz, const unsigned char **dnptrs, + const unsigned char **lastdnptr); + static int ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom); + static int labellen(const unsigned char *lp); + static int encode_bitsring( + const char **bp, const char *end, unsigned char **labelp, unsigned char **dst, unsigned const char *eom); + static int ns_name_pack(const unsigned char *src, unsigned char *dst, int dstsiz, const unsigned char **dnptrs, + const unsigned char **lastdnptr); + static int dn_find(const unsigned char *domain, const unsigned char *msg, const unsigned char *const *dnptrs, + const unsigned char *const *lastdnptr); + static int mklower(int ch); + static int ns_makecanon(const char *src, char *dst, size_t dstsize); + static int ns_samename(const char *a, const char *b); + +private: + static int validateHints(const addrinfo *hints); + static int checkHostNameAndExplore( + const addrinfo &ai, const char *hostname, const char *servname, addrinfo *cur); + static int getPort(const addrinfo *ai, const char *servname, bool matchonly); + static int strToNumber(const char *p); + static int exploreNull(const addrinfo *pai, const char *servname, addrinfo **res); + static const afd *findAfd(int af); + static addrinfo *getAi(const addrinfo *pai, const afd *pafd, const char *addr); + static int exploreNumericScope(const addrinfo *pai, const char *hostname, const char *servname, addrinfo **res); + static int exploreNumeric( + const addrinfo *pai, const char *hostname, const char *servname, addrinfo **res, const char *canonname); + static int ip6StrToScopeid(const char *scope, const struct sockaddr_in6 &sin6, uint32_t &scopeid); + static int getCanonName(const addrinfo *pai, addrinfo *ai, const char *str); + static int exploreFqdn(const addrinfo *pai, const char *hostname, const char *servname, addrinfo **res, + const netd_net_context *netcontext); + static bool getAddrinfoFromFile(const char *name, const addrinfo *pai, addrinfo **res); + static int dnsGetaddrinfo( + const char *name, const addrinfo *pai, const netd_net_context *netcontext, addrinfo **rv); + static bool haveIpv6(uint32_t mark, uid_t uid); + static bool haveIpv4(uint32_t mark, uid_t uid); + + static int findSrcAddr(const sockaddr *addr, sockaddr *src_addr, unsigned mark, uid_t uid); + static int resSearchN(const char *name, res_target *target, dns_res_state &res, int &herrno); + static int resQueryDomainN( + const char *name, const char *domain, res_target *target, dns_res_state &res, int &herrno); + static int resQueryN(const char *name, res_target *target, dns_res_state &res, int &herrno); + static int resMakePacketForQuery(uint32_t op, // opcode of query + const uint8_t *dname, // domain name + int cl, int type, // class and type of query + const uint8_t *data, // resource record data + size_t datalen, // length of data + uint8_t *buf, // buffer to put query + size_t buflen); // size of buffer + static int resQueryPacketSend(dns_res_state &statp, const uint8_t *buf, size_t buflen, uint8_t *ans, + size_t anssiz, int &rcode, uint32_t flags); + static int getHerrnoFromRcode(int rcode); + + static int dnCompress( + const uint8_t *src, uint8_t *dst, size_t dstsiz, const uint8_t **dnptrs, const uint8_t **lastdnptr); + static int sendViaUdp(dns_res_state &statp, dns_res_params ¶ms, const uint8_t *buf, const size_t buflen, + uint8_t *ans, size_t anssiz, int &terrno, size_t &ns, bool &needTcp, int &gotsomewhere, time_t &at, + int &rcode, int &delay); + static int sendViaTcp(dns_res_state &statp, dns_res_params ¶ms, const uint8_t *buf, const size_t buflen, + uint8_t *ans, size_t anssiz, int &terrno, const size_t ns, time_t &at, int &rcode, int &delay); + static int randomBind(const int s, const sa_family_t family); + static timespec getTimeout(const dns_res_params ¶ms); + static timespec evNowTime(void); + static timespec evAddTime(const timespec &addend1, const timespec &addend2); + static int evCmpTime(const timespec &a, const timespec &b); + static timespec evSubTime(const timespec &minuend, const timespec &subtrahend); + static timespec evConsTime(const time_t sec, const long nsec); + static int calculateElapsedTime(const timespec &t1, const timespec &t0); + static int udpRetryingPollWrapper( + dns_res_state &statp, const size_t ns, const timespec &finish, std::vector &fdAvailable); + static int retryingPoll(const int sock, const short events, const timespec &finish); + static bool isInvalidAnswer(dns_res_state &statp, const sockaddr_storage &from, const uint8_t *buf, + size_t buflen, uint8_t *ans, size_t anssiz, size_t &receivedFromNs); + + static addrinfo *getAnswer(const std::vector &answer, size_t anslen, const char *qname, int qtype, + const struct addrinfo *pai, int &herrno); + + static int dnExpand(const uint8_t *msg, const uint8_t *eom, const uint8_t *src, char *dst, size_t dstsiz); + static void getResolvConfigFromCache(dns_res_state &statp); + + static int lookupNameserverFromResNs(dns_res_state &statp, const sockaddr *sa); + static bool resQueriesMatch(const uint8_t *buf1, const uint8_t *eom1, const uint8_t *buf2, const uint8_t *eom2); + static bool findNameInQueryPacket( + const std::string &name, int type, int cl, const uint8_t *buf, const uint8_t *eom); + static bool sockEq(const struct sockaddr *socka, const struct sockaddr *sockb); + static int connect_with_timeout(int sock, const sockaddr *nsap, socklen_t salen, const timespec timeout); + static bool isTrailingWithDot(const std::string &name, uint32_t &dots); + static int tryQueyWithDomain(const bool trailingDot, const std::string &name, const uint32_t dots, + res_target *target, dns_res_state &res, int &herrno); + static bool resetNsSock( + nmd::common::net_utils::socket_fd &sock, const int type, const sockaddr *nsap, int &terrno, int &ret); + static int waitForReply(dns_res_state &statp, dns_res_params ¶ms, const uint8_t *buf, const size_t buflen, + uint8_t *ans, size_t anssiz, int &terrno, size_t &ns, bool &needTcp, int &gotsomewhere, int &rcode, + int &delay); + + static void closeInvalidSock(dns_res_state &statp, const struct sockaddr *nsap); + + static res_n_ok_func getResNOkFunc(int qtype); + +private: + class hostfd_wrapper; +}; + +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_GET_ADDR_INFO_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/interface_controller.h b/http/services/netmanagernative/net_mgr_native/include/interface_controller.h new file mode 100644 index 000000000..10b6c7c23 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/interface_controller.h @@ -0,0 +1,55 @@ +#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 { +private: + /* data */ +public: + interface_controller(/* args */); + ~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/http/services/netmanagernative/net_mgr_native/include/iptables_process.h b/http/services/netmanagernative/net_mgr_native/include/iptables_process.h new file mode 100644 index 000000000..47b906356 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/iptables_process.h @@ -0,0 +1,37 @@ +#ifndef __INCLUDE_IPTABLES_PROCESS_H__ +#define __INCLUDE_IPTABLES_PROCESS_H__ + +#include +#include +#include +#include +#include +namespace OHOS { +namespace nmd { +class iptables_process { +public: + pid_t pid_; + int stdin_; + int stdout_; + int stderr_; + +private: + std::string errBuf; + + struct pollfd pollFds_[2]; + +public: + iptables_process(); + iptables_process(pid_t pid, int in, int out, int err); + ~iptables_process(); + + bool waitForAck(std::string &output); + void terminate(); + + static std::shared_ptr forkAndExecute(); +}; + +} // namespace nmd + +} // namespace OHOS +#endif //!__INCLUDE_IPTABLES_PROCESS_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/native_netd_service.h b/http/services/netmanagernative/net_mgr_native/include/native_netd_service.h new file mode 100644 index 000000000..ab1f57e01 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/native_netd_service.h @@ -0,0 +1,116 @@ +#ifndef __INCLUDE_NATIVE_NTED_SERVICE_H__ +#define __INCLUDE_NATIVE_NTED_SERVICE_H__ + +#include "event_reporter.h" +#include +#include +#include +#include +#include +#include +#include + +#include "dnsresolv_service.h" + +typedef char byte; +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 NativeNetdService { +private: + std::shared_ptr networkController_; + std::shared_ptr routeController_; + std::shared_ptr interfaceController_; + static std::vector interfaceIdex_; + +public: + NativeNetdService(); + ~NativeNetdService(); + + 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); + void networkAddRouteParcel(int netId, route_info_parcel routeInfo); + void 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(); +}; +} // namespace nmd +} // namespace OHOS + +#endif //!__INCLUDE_NATIVE_NTED_SERVICE_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/netlink_event.h b/http/services/netmanagernative/net_mgr_native/include/netlink_event.h new file mode 100644 index 000000000..f3fbc8611 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/netlink_event.h @@ -0,0 +1,61 @@ +#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 { +private: + Action action_; + std::map params_; + +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(); +}; +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_NETLINK_EVENT_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/netlink_handler.h b/http/services/netmanagernative/net_mgr_native/include/netlink_handler.h new file mode 100644 index 000000000..8629415e7 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/netlink_handler.h @@ -0,0 +1,47 @@ +#ifndef __INCLUDE_NETLINK_HANDLER_H__ +#define __INCLUDE_NETLINK_HANDLER_H__ + +#include "netlink_listener.h" +#include +#include "netlink_event.h" +#include +#include "event_reporter.h" + +namespace OHOS { +namespace nmd { +class netlink_handler : public netlink_listener { +private: + std::shared_ptr reporter_; + +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(); +}; + +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_NETLINK_HANDLER_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/netlink_listener.h b/http/services/netmanagernative/net_mgr_native/include/netlink_listener.h new file mode 100644 index 000000000..044640009 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/netlink_listener.h @@ -0,0 +1,31 @@ +#ifndef __INCLUDE_NETLINK_LISTENER_H__ +#define __INCLUDE_NETLINK_LISTENER_H__ + +#include +#include +#include "netlink_event.h" + +namespace OHOS { +namespace nmd { +class netlink_listener : public netlink_socket { +private: + bool running_ = false; + std::function)> onEventHandler_; + + void onDataAvaliable(int fd, char *buf, ssize_t size); + +public: + netlink_listener(int protocol, int pid); + ~netlink_listener(); + + void setOnEventHandler(const std::function)> &handler); + int listen(); + + void stopListen(); + bool getNetlinkListenerState(); +}; + +} // namespace nmd +} // namespace OHOS + +#endif //!__INCLUDE_NETLINK_LISTENER_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/netlink_manager.h b/http/services/netmanagernative/net_mgr_native/include/netlink_manager.h new file mode 100644 index 000000000..8e3892f83 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/netlink_manager.h @@ -0,0 +1,58 @@ +#ifndef __INCLUDE_NETLINK_MANAGER_H__ +#define __INCLUDE_NETLINK_MANAGER_H__ +#include "netlink_handler.h" +#include +#include "event_reporter.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 { +private: + static int pid_; + static std::shared_ptr reporter_; + + std::shared_ptr routeHandler_; + void startRouteHandler(); + +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(); +}; + +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_NETLINK_MANAGER_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/netlink_msg.h b/http/services/netmanagernative/net_mgr_native/include/netlink_msg.h new file mode 100644 index 000000000..82ec2f2bd --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/netlink_msg.h @@ -0,0 +1,55 @@ +#ifndef __INCLUDE_NETLINK_MSG_H__ +#define __INCLUDE_NETLINK_MSG_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "warning_disable.h" +#include +#include +#include +#include + +namespace OHOS { +namespace nmd { + +class netlink_msg { +private: + struct nlmsghdr *netlinkMessage_; + size_t maxBufLen_; + +public: + netlink_msg(uint16_t flags, size_t maxBufLen, int pid); + + void addRoute(unsigned short action, struct rtmsg msg); + void addRule(unsigned short action, struct fib_rule_hdr msg); + void addRouteNextHop(unsigned short action, struct rtnexthop msg); + void addRouteAttributeCacheInfo(unsigned short action, struct rta_cacheinfo msg); + void addInterfaceAddress(unsigned short action, struct ifaddrmsg msg); + void addInterfaceAddressCacheInfo(unsigned short action, struct ifa_cacheinfo msg); + void addNeighborDiscovery(unsigned short action, struct ndmsg msg); + void addNeighborDiscoveryAttributeCacheInfo(unsigned short action, struct nda_cacheinfo msg); + void addInterfaceInfo(unsigned short action, struct ifinfomsg msg); + void addTrafficControl(unsigned short action, struct tcmsg msg); + void addInetDiag(unsigned short action, struct inet_diag_req_v2 msg); + + int addAttr(unsigned int rtaType, void *buf, size_t bufLen); + int addAttr16(unsigned int rtaType, uint16_t data); + int addAttr32(unsigned int rtaType, uint32_t data); + + struct nlmsghdr *getNetLinkMessage(); + ~netlink_msg(); +}; +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_NETLINK_MSG_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/netlink_socket.h b/http/services/netmanagernative/net_mgr_native/include/netlink_socket.h new file mode 100644 index 000000000..51e316450 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/netlink_socket.h @@ -0,0 +1,67 @@ +#ifndef __INCLUDE_NETLINK_SOCKET_H__ +#define __INCLUDE_NETLINK_SOCKET_H__ + +#include +#include +#include +#include +#include +#include + +namespace OHOS { +namespace nmd { +class netlink_socket { +private: + std::function handler_; + struct sockaddr addr_ {}; + +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: + /** + * 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/http/services/netmanagernative/net_mgr_native/include/netnative_log_wrapper.h b/http/services/netmanagernative/net_mgr_native/include/netnative_log_wrapper.h new file mode 100644 index 000000000..3642b1a01 --- /dev/null +++ b/http/services/netmanagernative/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 "NetManagerNative" +#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/http/services/netmanagernative/net_mgr_native/include/network.h b/http/services/netmanagernative/net_mgr_native/include/network.h new file mode 100644 index 000000000..8776aeea1 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/network.h @@ -0,0 +1,60 @@ +#ifndef __INCLUDE_NETWORK_H__ +#define __INCLUDE_NETWORK_H__ + +#include +#include +namespace OHOS { +namespace nmd { + +typedef enum Permission { + PERMISSION_NONE = 0x0, + PERMISSION_NETWORK = 0x1, + PERMISSION_SYSTEM = 0x3, +} NetworkPermission; + +class network { +private: + uint16_t netId_; + + bool isDefault_ = false; + + NetworkPermission permission_; + + std::set interfaces_; + +public: + network(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 ~network(); +}; + +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_NETWORK_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/network_controller.h b/http/services/netmanagernative/net_mgr_native/include/network_controller.h new file mode 100644 index 000000000..326c9dde8 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/network_controller.h @@ -0,0 +1,53 @@ +#ifndef __INCLUDE_NETWORK_CONTROLLER_H__ +#define __INCLUDE_NETWORK_CONTROLLER_H__ + +#include "network.h" +#include +#include +#include +#include +namespace OHOS { +namespace nmd { +class network_controller { +private: + int defaultNetId_; + std::map networks_; + +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::network *getNetwork(int netId); + +private: + 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/http/services/netmanagernative/net_mgr_native/include/route_controller.h b/http/services/netmanagernative/net_mgr_native/include/route_controller.h new file mode 100644 index 000000000..10cfafec5 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/route_controller.h @@ -0,0 +1,50 @@ +#ifndef __INCLUDE_ROUTE_CONTROLLER_H__ +#define __INCLUDE_ROUTE_CONTROLLER_H__ + +#include "network.h" +#include +#include + +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 { +private: + static int executeIptablesRestore(std::string command); + static void updateTableNamesFile(); + static std::map interfaceToTable_; + static uint32_t getRouteTableForInterface(const char *interfaceName); + +public: + route_controller(/* args */); + ~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: + 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/http/services/netmanagernative/net_mgr_native/include/sock_diag.h b/http/services/netmanagernative/net_mgr_native/include/sock_diag.h new file mode 100644 index 000000000..69a623a88 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/sock_diag.h @@ -0,0 +1,34 @@ +#ifndef __INCLUDE_SOCK_DIAG_H__ +#define __INCLUDE_SOCK_DIAG_H__ + +#include +#include +#include +#include +#include + +#define IN_LOOPBACK(a) ((((long int)(a)) & 0xff000000) == 0x7f000000) +namespace OHOS { +namespace nmd { +typedef std::function netlink_dump_callback; + +class sock_diag { +private: + void closeSocks(); + + netlink_socket sock_; + netlink_socket writeSock_; + +public: + sock_diag() = default; + ~sock_diag(); + bool open(); + void destroySockets(std::string ifName); + int sockDestroy(int proto, const struct inet_diag_msg *msg); + int processDestroy(int sock, netlink_dump_callback callback); + bool isLoopbackSocket(const inet_diag_msg *msg); + void socketDump(int proto, int family, int states); +}; +} // namespace nmd +} // namespace OHOS +#endif //!__INCLUDE_SOCK_DIAG_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/include/traffic_controller.h b/http/services/netmanagernative/net_mgr_native/include/traffic_controller.h new file mode 100644 index 000000000..6f3fef9c2 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/include/traffic_controller.h @@ -0,0 +1,79 @@ +#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 { +private: +public: + traffic_controller(/* args */); + ~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/http/services/netmanagernative/net_mgr_native/src/dnsresolv_cache.cpp b/http/services/netmanagernative/net_mgr_native/src/dnsresolv_cache.cpp new file mode 100644 index 000000000..a2665f847 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/dnsresolv_cache.cpp @@ -0,0 +1,587 @@ + +#include "dnsresolv_cache.h" +#include "get_addr_info.h" +#include "utils.h" +#include "warning_disable.h" +#include +#include "logger.h" +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { + +int memcasecmp(const void *vs1, const void *vs2, const size_t n) +{ + unsigned int i; + unsigned char const *s1 = reinterpret_cast(vs1); + unsigned char const *s2 = reinterpret_cast(vs2); + for (i = 0; i < n; i++) { + unsigned char u1 = *s1++; + unsigned char u2 = *s2++; + if (toupper(u1) != toupper(u2)) + return toupper(u1) - toupper(u2); + } + return 0; +} + +nmd::NetworkConfigMap nmd::dnsresolv_cache::sNetworkConfig_; +nmd::common::rwlock nmd::dnsresolv_cache::sCacheLock_; + +nmd::dnsresolv_cache_status nmd::dnsresolv_cache::lookupFromResolvCache(uint16_t netid, const uint8_t *query, + size_t querylen, uint8_t *answer, const size_t answersize, size_t *answerlen, uint32_t flags) +{ + if (flags & (NETD_DNS_RESOLV_NO_CACHE_STORE | NETD_DNS_RESOLV_NO_CACHE_LOOKUP)) { + return flags & NETD_DNS_RESOLV_NO_CACHE_STORE ? RESOLV_CACHE_SKIP : RESOLV_CACHE_NOTFOUND; + } + + sCacheLock_.write_guard(); + auto resolvCache = findResolvCache(netid); + if (nullptr == resolvCache) { + return RESOLV_CACHE_UNSUPPORTED; + } + + auto find = resolvCache->find(dns_packet(query, querylen)); + if (find == resolvCache->end()) { + return RESOLV_CACHE_NOTFOUND; + } + + if (find->second.isExpired()) { + // remove expired cache + resolvCache->erase(find); + return RESOLV_CACHE_NOTFOUND; + } + + auto ansPack = find->second.getDnsPacket(); + *answerlen = ansPack.size(); + if (*answerlen > answersize) { + return RESOLV_CACHE_UNSUPPORTED; + } + + std::copy(ansPack.begin(), ansPack.end(), answer); + + return RESOLV_CACHE_FOUND; +} + +int nmd::dnsresolv_cache::resolvCacheAdd(const uint16_t netid, const uint8_t *query, const size_t querylen, + const uint8_t *answer, const size_t answerlen) +{ + sCacheLock_.write_guard(); + auto resolvCache = findResolvCache(netid); + if (nullptr == resolvCache) { + return -1; + } + + dns_packet key(query, querylen); + auto find = resolvCache->find(key); + if (find != resolvCache->end() && !(find->second.isExpired())) { + // already in cache, no need cache + return 0; + } + + auto ttl = getTTLFromAnswer(answer, answerlen); + if (ttl > 0) { + auto now = nmd::common::utils::getCurrentTime(); + dns_packet value(answer, answerlen, now + ttl); + // update + resolvCache->erase(key); + resolvCache->insert(std::make_pair(key, value)); + } + + return 0; +} + +int nmd::dnsresolv_cache::setResolverConfig(const dnsresolver_params &resolvParams) +{ + if (resolvParams.servers.empty()) { + // common::logger::error() + // << "[dnsresolv_cache] Unable to setResolverConfig: invalid param: servers is empty() " << endl; + NETNATIVE_LOGE("[dnsresolv_cache] Unable to setResolverConfig: invalid param: servers is empty()"); + return -1; + } + + sCacheLock_.write_guard(); + auto config = lookupResolvConfig(resolvParams.netId); + if (nullptr == config) { + // common::logger::error() << "[dnsresolv_cache] Unable to setResolverConfig: can not find config if netid: " + // << resolvParams.netId << endl; + NETNATIVE_LOGE("[dnsresolv_cache] Unable to setResolverConfig: can not find config if netid: %{public}d", + resolvParams.netId); + return -1; + } + + std::vector ipSockAddrs; + ipSockAddrs.reserve(resolvParams.servers.size()); + for (const auto &server : resolvParams.servers) { + if (!isValidServer(server)) { + // common::logger::error() << "[dnsresolv_cache] Unable to setResolverConfig: invalid server." << endl; + NETNATIVE_LOGE("[dnsresolv_cache] Unable to setResolverConfig: invalid server."); + return -1; + } + ipSockAddrs.push_back(nmd::common::net_utils::ip_sock_addr::toIPSockAddr(server, DNS_REQ_PORT)); + } + + config->nameservers = std::move(resolvParams.servers); + config->nameserverSockAddrs = std::move(ipSockAddrs); + config->searchDomains = std::move(resolvParams.domains); + + return 0; +} + +int nmd::dnsresolv_cache::createNetworkCache(const uint16_t netid) +{ + sCacheLock_.write_guard(); + auto config = lookupResolvConfig(netid); + if (config != nullptr) { + // common::logger::error() + // << "[dnsresolv_cache] Unable to createNetworkCache: cache already exist. netid: " << netid << endl; + NETNATIVE_LOGE( + "[dnsresolv_cache] Unable to createNetworkCache: cache already exist. netid: %{public}d", netid); + return -2; + } + + sNetworkConfig_.insert(std::make_pair(netid, std::make_unique(netid))); + + return 0; +} + +int nmd::dnsresolv_cache::destoryNetworkCache(const uint16_t netid) +{ + sCacheLock_.write_guard(); + sNetworkConfig_.erase(netid); + return 0; +} + +int nmd::dnsresolv_cache::flushNetworkCache(const uint16_t netid) +{ + sCacheLock_.write_guard(); + + auto config = lookupResolvConfig(netid); + if (nullptr == config) { + // common::logger::error() + // << "[dnsresolv_cache] Unable to setResolverConfig: config is nullptr. netid: " << netid << endl; + NETNATIVE_LOGE( + "[dnsresolv_cache] Unable to setResolverConfig: config is nullptr. netid: %{public}d", netid); + return -1; + } + + config->resolvCache->clear(); + + return 0; +} + +int nmd::dnsresolv_cache::getResolverInfo(const uint16_t netid, std::vector &servers, + std::vector &domains, nmd::dns_res_params ¶m) +{ + sCacheLock_.write_guard(); + + auto config = lookupResolvConfig(netid); + if (nullptr == config) { + // common::logger::error() + // << "[dnsresolv_cache] Unable to getResolverInfo: config is nullptr. netid: " << netid << endl; + NETNATIVE_LOGE("[dnsresolv_cache] Unable to getResolverInfo: config is nullptr. netid: %{public}d", netid); + return -1; + } + + servers = config->nameservers; + domains = config->searchDomains; + param.baseTimeoutMsec = config->params.baseTimeoutMsec; + param.retryCount = config->params.retryCount; + + return 0; +} + +nmd::network_config *nmd::dnsresolv_cache::lookupResolvConfig(const uint16_t netid) +{ + auto find = sNetworkConfig_.find(netid); + if (find == sNetworkConfig_.end()) { + return nullptr; + } + return find->second.get(); +} + +bool nmd::dnsresolv_cache::isValidServer(const std::string &server) +{ + addrinfo hints {}; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + addrinfo *result = nullptr; + int err = nmd::get_addr_info::getaddrinfoNumeric(server.c_str(), DNS_REQ_PORT_STR, hints, &result); + if (err != 0) { + // common::logger::error() << "[dnsresolv_cache] Unable to getaddrinfoNumeric: server " << server + // << "error: " << gai_strerror(err) << endl; + NETNATIVE_LOGE("[dnsresolv_cache] Unable to getaddrinfoNumeric: server %{public}s error: %{public}s", + server.c_str(), gai_strerror(err)); + return false; + } + // freeaddrinfo(result); + return true; +} + +nmd::ResolvCache *nmd::dnsresolv_cache::findResolvCache(const uint16_t netid) +{ + auto config = lookupResolvConfig(netid); + return nullptr == config ? nullptr : config->resolvCache.get(); +} + +std::time_t nmd::dnsresolv_cache::getTTLFromAnswer(const uint8_t *answer, const size_t answerlen) +{ + ns_msg handle; + uint32_t result = 0; + if (ns_initparse(answer, static_cast(answerlen), &handle) >= 0) { + // get number of answer records + int ancount = ns_msg_count(handle, ns_s_an); + + if (ancount == 0) { + result = getNegativeTTL(handle); + } else { + uint32_t ttl(0); + ns_rr rr; + for (int n = 0; n < ancount; n++) { + if (ns_parserr(&handle, ns_s_an, n, &rr) == 0) { + ttl = rr.ttl; + if (n == 0 || ttl < result) { + result = ttl; + } + } else { + // common::logger::info() + // << "[dnsresolv_cache] Unable to getTTLFromAnswer: ns_parserr failed ancount no = " << n + // << endl; + NETNATIVE_LOGI( + "[dnsresolv_cache] Unable to getTTLFromAnswer: ns_parserr failed ancount no = %{public}d", + n); + } + } + } + } else { + // common::logger::info() << "[dnsresolv_cache] Unable to getTTLFromAnswer: ns_initparse failed " << endl; + NETNATIVE_LOGI("[dnsresolv_cache] Unable to getTTLFromAnswer: ns_initparse failed "); + } + + return std::time_t(result); +} + +uint32_t nmd::dnsresolv_cache::getNegativeTTL(ns_msg handle) +{ + int n, nscount; + uint32_t result = 0; + ns_rr rr; + + nscount = ns_msg_count(handle, ns_s_ns); + for (n = 0; n < nscount; n++) { + if ((ns_parserr(&handle, ns_s_ns, n, &rr) == 0) && (ns_rr_type(rr) == ns_t_soa)) { + const uint8_t *rdata = ns_rr_rdata(rr); // find the data + const uint8_t *edata = rdata + ns_rr_rdlen(rr); // add the len to find the end + int len; + uint32_t ttl, rec_result = rr.ttl; + + // find the MINIMUM-TTL field from the blob of binary data for this record + // skip the server name + len = skipName(rdata, edata); + if (len == -1) + continue; // error skipping + rdata += len; + + // skip the admin name + len = skipName(rdata, edata); + if (len == -1) + continue; // error skipping + rdata += len; + + if (edata - rdata != 5 * NS_INT32SZ) + continue; + // skip: serial number + refresh interval + retry interval + expiry + rdata += NS_INT32SZ * 4; + // finally read the MINIMUM TTL + ttl = ntohl(*reinterpret_cast(rdata)); + if (ttl < rec_result) { + rec_result = ttl; + } + // Now that the record is read successfully, apply the new min TTL + if (n == 0 || rec_result < result) { + result = rec_result; + } + } + } + return result; +} + +int nmd::dnsresolv_cache::skipName(const uint8_t *ptr, const uint8_t *eom) +{ + const uint8_t *saveptr = ptr; + + if (-1 == nmd::get_addr_info::ns_name_skip(&ptr, eom)) { + return -1; + } + return static_cast(ptr - saveptr); +} + +bool nmd::dns_packet::operator==(const dns_packet &dp) const +{ + this->rewind(); + dp.rewind(); + + // compare RD, ignore TC, see comment in _dnsPacket_checkQuery + if ((packet_[2] & 1) != (dp.packet_[2] & 1)) { + return false; + } + + if (packet_[3] != dp.packet_[3]) { + return false; + } + + // mark ID and header bytes as compared + this->skip(4); + dp.skip(4); + + // compare QDCOUNT + int count1 = this->readInt16(); + int count2 = dp.readInt16(); + if (count1 != count2 || count1 < 0) { + return false; + } + + // assume: ANcount and NScount are 0 + this->skip(4); + dp.skip(4); + + // compare ARCOUNT + int arcount1 = this->readInt16(); + int arcount2 = dp.readInt16(); + if (arcount1 != arcount2 || arcount1 < 0) { + return false; + } + + // compare the QDCOUNT QRs + for (; count1 > 0; count1--) { + if (!this->isEqualQR(dp)) { + return false; + } + } + + // compare the ARCOUNT RRs + for (; arcount1 > 0; arcount1--) { + if (!this->isEqualRR(dp)) { + return 0; + } + } + + return true; +} + +uint32_t nmd::dns_packet::hash() const +{ + uint32_t hash = FNV_BASIS; + rewind(); + // ignore the ID + skip(2); + hash = hash * FNV_MULT ^ (packet_[2] & 1); + + // mark the first header byte as processed + skip(1); + + // process the second header byte + hash = hashBytes(1, hash); + + // read QDCOUNT + int count = readInt16(); + + // assume: ANcount and NScount are 0 + skip(4); + + // read ARCOUNT + int arcount = readInt16(); + + // hash QDCOUNT QRs + for (; count > 0; count--) { + hash = hashQR(hash); + } + + // hash ARCOUNT RRs + for (; arcount > 0; arcount--) { + hash = hashRR(hash); + } + + return hash; +} + +void nmd::dns_packet::rewind() const +{ + itCursor_ = packet_.begin(); +} + +void nmd::dns_packet::skip(const long index) const +{ + const PackIterator it = (itCursor_ + index) > packet_.end() ? packet_.end() : (itCursor_ + index); + itCursor_ = it; +} + +uint32_t nmd::dns_packet::hashBytes(int numBytes, uint32_t hash) const +{ + PackIterator it = itCursor_; + + while (numBytes > 0 && it < packet_.end()) { + hash = hash * FNV_MULT ^ *it++; + numBytes--; + } + + itCursor_ = it; + return hash; +} + +int nmd::dns_packet::readInt16() const +{ + PackIterator it = itCursor_; + if (it + 2 > packet_.end()) { + return -1; + } + + itCursor_ = it + 2; + return (*it << 8) | *(it + 1); +} + +uint32_t nmd::dns_packet::hashQR(uint32_t hash) const +{ + hash = hashQName(hash); + hash = hashBytes(4, hash); // TYPE and CLASS + return hash; +} + +uint32_t nmd::dns_packet::hashRR(uint32_t hash) const +{ + int rdlength; + hash = hashQR(hash); + hash = hashBytes(4, hash); // TTL + rdlength = readInt16(); + hash = hashBytes(rdlength, hash); // RDATA + return hash; +} + +uint32_t nmd::dns_packet::hashQName(uint32_t hash) const +{ + PackIterator it = itCursor_; + while (true) { + if (it >= packet_.end()) { + break; + } + + int c = *it++; + + if (c == 0) { + break; + } + + if (c >= 64) { + break; + } + if (it + c >= packet_.end()) { + break; + } + + while (c > 0) { + uint8_t ch = *it++; + ch = static_cast(std::tolower(static_cast(ch))); + hash = hash * FNV_MULT ^ ch; + c--; + } + } + itCursor_ = it; + return hash; +} + +bool nmd::dns_packet::isEqualQR(const dns_packet &dp) const +{ + // compare domain name encoding + TYPE + CLASS + if (!this->isEqualDomainName(dp) || !this->isEqualBytes(dp, 2 + 2)) { + return false; + } + + return true; +} +bool nmd::dns_packet::isEqualRR(const dns_packet &dp) const +{ + // compare query + TTL + if (!isEqualQR(dp) || !isEqualBytes(dp, 4)) { + return false; + } + + // compare RDATA + int rdlength1 = readInt16(); + int rdlength2 = dp.readInt16(); + if (rdlength1 != rdlength2 || !isEqualBytes(dp, rdlength1)) { + return 0; + } + + return 1; +} + +bool nmd::dns_packet::isEqualDomainName(const dns_packet &dp) const +{ + PackIterator p1 = itCursor_; + PackIterator p2 = dp.itCursor_; + + for (;;) { + if (p1 >= packet_.end() || p2 >= dp.packet_.end()) { + break; + } + int c1 = *p1++; + int c2 = *p2++; + if (c1 != c2) { + break; + } + + if (c1 == 0) { + itCursor_ = p1; + dp.itCursor_ = p2; + return true; + } + if (c1 >= 64) { + break; + } + if ((p1 + c1 > packet_.end()) || (p2 + c1 > dp.packet_.end())) { + break; + } + if (memcasecmp(&(*p1), &(*p2), static_cast(c1)) != 0) { + break; + } + p1 += c1; + p2 += c1; + } + return 0; +} + +bool nmd::dns_packet::isEqualBytes(const dns_packet &dp, const int numberByte) const +{ + PackIterator it = this->itCursor_; + PackIterator it2 = dp.itCursor_; + + if (numberByte < 0) { + return false; + } + + if (it + numberByte > this->packet_.end() || it2 + numberByte > dp.packet_.end()) { + return false; + } + + if (std::memcmp(&(*it), &(*it2), static_cast(numberByte)) != 0) { + return false; + } + + it += numberByte; + it2 += numberByte; + return true; +} + +bool nmd::dns_packet::isExpired() +{ + if (-1 == expirationTime_) { + return false; + } + auto now = nmd::common::utils::getCurrentTime(); + if (now >= expirationTime_) { + return true; + } + return false; +} + +} // namespace nmd +} // namespace OHOS diff --git a/http/services/netmanagernative/net_mgr_native/src/dnsresolv_controller.cpp b/http/services/netmanagernative/net_mgr_native/src/dnsresolv_controller.cpp new file mode 100644 index 000000000..0ca2dd47a --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/dnsresolv_controller.cpp @@ -0,0 +1,60 @@ +#include "dnsresolv_controller.h" +#include "dnsresolv.h" +#include "dnsresolv_cache.h" +#include "get_addr_info.h" +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { +int nmd::dnsresolv_controller::getaddrinfo( + const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) +{ + return getaddrinfoForNet(hostname, servname, hints, NETID_UNSET, MARK_UNSET, res); +} + +int nmd::dnsresolv_controller::getaddrinfoForNet(const char *hostname, const char *servname, + const struct addrinfo *hints, uint16_t netid, unsigned mark, struct addrinfo **res) +{ + netd_net_context netcontext = {}; + netcontext.appNetId = netid; + netcontext.appMark = mark; + netcontext.dnsNetId = netid; + netcontext.dnsMark = mark; + netcontext.uid = NET_CONTEXT_INVALID_UID; + + return nmd::get_addr_info::getaddrinfoFornetContext(hostname, servname, hints, &netcontext, res); +} + +int nmd::dnsresolv_controller::getaddrinfoFornetContext(const char *hostname, const char *servname, + const addrinfo *hints, const netd_net_context &netcontext, addrinfo **res) +{ + return nmd::get_addr_info::getaddrinfoFornetContext(hostname, servname, hints, &netcontext, res); +} + +int nmd::dnsresolv_controller::setResolverConfig(const nmd::dnsresolver_params &resolvParams) +{ + return dnsresolv_cache::setResolverConfig(resolvParams); +} + +int nmd::dnsresolv_controller::createNetworkCache(const uint16_t netid) +{ + return dnsresolv_cache::createNetworkCache(netid); +} + +int nmd::dnsresolv_controller::destoryNetworkCache(const uint16_t netid) +{ + return dnsresolv_cache::destoryNetworkCache(netid); +} + +int nmd::dnsresolv_controller::flushNetworkCache(const uint16_t netid) +{ + return dnsresolv_cache::flushNetworkCache(netid); +} + +int nmd::dnsresolv_controller::getResolverInfo(const uint16_t netid, std::vector &servers, + std::vector &domains, nmd::dns_res_params ¶m) +{ + return dnsresolv_cache::getResolverInfo(netid, servers, domains, param); +} +} // namespace nmd +} // namespace OHOS diff --git a/http/services/netmanagernative/net_mgr_native/src/dnsresolv_service.cpp b/http/services/netmanagernative/net_mgr_native/src/dnsresolv_service.cpp new file mode 100644 index 000000000..b1625df38 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/dnsresolv_service.cpp @@ -0,0 +1,312 @@ +#include "dnsresolv_service.h" +#include "utils.h" +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { +int dnsresolv_service::getResolverInfo(const uint16_t netid, std::vector &servers, + std::vector &domains, dns_res_params ¶m) +{ + return dnsresolvCtrl_.getResolverInfo(netid, servers, domains, param); +} + +int dnsresolv_service::setResolverConfig(const nmd::dnsresolver_params &resolvParams) +{ + return dnsresolvCtrl_.setResolverConfig(resolvParams); +} + +int dnsresolv_service::createNetworkCache(const uint16_t netid) +{ + return dnsresolvCtrl_.createNetworkCache(netid); +} +int dnsresolv_service::flushNetworkCache(const uint16_t netid) +{ + return dnsresolvCtrl_.flushNetworkCache(netid); +} +int dnsresolv_service::destoryNetworkCache(const uint16_t netid) +{ + return dnsresolvCtrl_.destoryNetworkCache(netid); +} + +int dnsresolv_service::getaddrinfo( + const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) +{ + return dnsresolvCtrl_.getaddrinfo(hostname, servname, hints, res); +} + +bool dnsresolv_service::init(const dnsresolv_callbacks &callbacks) +{ + NETNATIVE_LOGE("dnsresolv_service::init"); + if (nullptr == callbacks.getNetworkContext) { + return false; + } + dnsresolvCallbacks_ = callbacks; + return true; +} + +void dnsresolv_service::initJob(const int socketFd, const uint8_t *msg, const size_t msgLen) +{ + auto job = new nmd::dnsresolv_job(socketFd, msg, msgLen, this->server_); + job->setupCallbacks(dnsresolvCallbacks_); + this->job_ = job; +} + +void dnsresolv_job::run() +{ + if (fd_ < 0 || msg_.empty() || nullptr == serverSocket_) { + return; + } + dnsresolver_request_cmd *command = reinterpret_cast(msg_.data()); + + switch (command->cmdID) { + case dnsresolver_request_cmd::cmd_id::CREATE_NETWORK_CACHE: + doCreateNetworkCache(command); + break; + case dnsresolver_request_cmd::cmd_id::SET_RESOLVER_CONFIG: + doSetResolverConfig(command); + break; + case dnsresolver_request_cmd::cmd_id::DESOTRY_NETWORK_CACHE: + doDestroyNetworkCache(command); + break; + case dnsresolver_request_cmd::cmd_id::GET_ADDR_INFO: + doGetAddrInfo(command); + break; + case dnsresolver_request_cmd::cmd_id::GET_ADDR_INFO_PROXY: + doGetAddrInfoProxy(command); + break; + default: + break; + } +} + +void dnsresolv_job::responseOk() +{ + dnsresolver_response_cmd cmdRepStateOK; + bzero(&cmdRepStateOK, sizeof(cmdRepStateOK)); + + cmdRepStateOK.cmdID = dnsresolver_response_cmd::cmd_id::QUERY_STATE_OK; + + auto sendRet = sendResponseResult(cmdRepStateOK); + if (sendRet < 0) { + // common::logger::error() << "[dnsresolv_job] Unable to send response result. error: " << sendRet << endl; + NETNATIVE_LOGE("[dnsresolv_job] Unable to send response result. error: %{public}d", sendRet); + return; + } +} + +void dnsresolv_job::responseOk(const struct addrinfo *res) +{ + if (nullptr == res) { + return; + } + + size_t resSize(0); + for (const struct addrinfo *res_p = res; res_p != NULL; res_p = res_p->ai_next) { + resSize += sizeof(addrinfo); + resSize += res_p->ai_addrlen; + if (nullptr != res_p->ai_canonname) { + resSize += (strlen(res_p->ai_canonname) + 1); + } + } + + dnsresolver_response_cmd cmdRepStateOK; + bzero(&cmdRepStateOK, sizeof(cmdRepStateOK)); + + cmdRepStateOK.cmdID = dnsresolver_response_cmd::cmd_id::QUERY_STATE_OK; + cmdRepStateOK.resSize = resSize; + + auto sendRet = sendResponseResult(cmdRepStateOK); + if (sendRet < 0) { + // common::logger::error() << "[dnsresolv_job] Unable to send response result. error: " << sendRet << endl; + NETNATIVE_LOGE("[dnsresolv_job] Unable to send response result. error: %{public}d", sendRet); + return; + } + + auto cmdFreeFunc = [](p_dnsresolver_response_cmd cmd) { + if (nullptr == cmd) { + return; + } + free(cmd); + }; + + p_dnsresolver_response_cmd cmdRepResult = + reinterpret_cast(malloc(offsetof(dnsresolver_response_cmd, resData[resSize]))); + common::utils::auto_destroyer autoDeleteCmd(cmdRepResult, cmdFreeFunc); + if (nullptr == cmdRepResult) { + // common::logger::error() << "[dnsresolv_job] Unable to send response result. error: no memory. " << endl; + NETNATIVE_LOGE("[dnsresolv_job] Unable to send response result. error: no memory. "); + return; + } + + cmdRepResult->result = 0; + cmdRepResult->resSize = resSize; + for (size_t i = 0; i < resSize; ++i) { + cmdRepResult->resData[i] = 0; + } + + cmdRepResult->cmdID = dnsresolver_response_cmd::cmd_id::QUERY_SUCCESS_WITH_RESULT; + uint8_t *cur = cmdRepResult->resData; + for (const struct addrinfo *res_p = res; res_p != NULL; res_p = res_p->ai_next) { + memcpy(cur, res_p, sizeof(addrinfo)); + cur += sizeof(addrinfo); + memcpy(cur, res_p->ai_addr, res_p->ai_addrlen); + cur += res_p->ai_addrlen; + + if (nullptr != res_p->ai_canonname) { + memcpy(cur, res_p->ai_canonname, strlen(res_p->ai_canonname)); + cur += (strlen(res_p->ai_canonname) + 1); // include "\0" + } + } + + sendRet = sendResponseResult(*cmdRepResult); + if (sendRet < 0) { + // common::logger::error() << "[dnsresolv_job] Unable to send response result. error: " << sendRet << endl; + NETNATIVE_LOGE("[dnsresolv_job] Unable to send response result. error: %{public}d", sendRet); + return; + } +} + +void dnsresolv_job::responseFailed(const int ret) +{ + dnsresolver_response_cmd cmdRep; + bzero(&cmdRep, sizeof(cmdRep)); + + cmdRep.cmdID = dnsresolver_response_cmd::cmd_id::QUERY_STATE_FAIL; + cmdRep.result = ret; + + auto sendRet = sendResponseResult(cmdRep); + if (sendRet < 0) { + // common::logger::error() << "[dnsresolv_job] Unable to send response result. error: " << sendRet << endl; + NETNATIVE_LOGE("[dnsresolv_job] Unable to send response result. error: %{public}d", sendRet); + return; + } +} + +ssize_t dnsresolv_job::sendResponseResult(dnsresolver_response_cmd &cmdRep) +{ + size_t repSize = cmdRep.cmdID == dnsresolver_response_cmd::cmd_id::QUERY_SUCCESS_WITH_RESULT ? + (sizeof(cmdRep) + cmdRep.resSize) : + sizeof(cmdRep); + iovec iov[1] = {{&cmdRep, repSize}}; + + msghdr hdr; + bzero(&hdr, sizeof(hdr)); + hdr.msg_iov = iov; + hdr.msg_iovlen = 1; + + return this->serverSocket_->sendMsg(this->fd_, hdr); +} + +void dnsresolv_job::doCreateNetworkCache(const dnsresolver_request_cmd *command) +{ + auto ret = dnsresolvCtrl_.createNetworkCache(command->netid); + if (ret != 0) { + responseFailed(ret); + return; + } + + responseOk(); +} + +void dnsresolv_job::doDestroyNetworkCache(const dnsresolver_request_cmd *command) +{ + auto ret = dnsresolvCtrl_.destoryNetworkCache(command->netid); + if (ret != 0) { + responseFailed(ret); + return; + } + + responseOk(); +} + +void dnsresolv_job::doSetResolverConfig(const dnsresolver_request_cmd *command) +{ + dnsresolver_params param; + param.netId = command->netid; + param.baseTimeoutMsec = command->cmd_baseTimeoutMsec; + param.retryCount = command->cmd_retryCount; + auto ret = getNameList(command->cmd_servers, MAX_NAME_LIST_LEN, param.servers); + if (ret != command->cmd_serverCount) { + // common::logger::error() << "[dnsresolv_job] Unable to getNameList: invalid param.servers " << endl; + NETNATIVE_LOGE("[dnsresolv_job] Unable to getNameList: invalid param.servers "); + responseFailed(static_cast(ret)); + return; + } + + ret = getNameList(command->cmd_domains, MAX_NAME_LIST_LEN, param.domains); + if (ret != command->cmd_domainCount) { + // common::logger::error() << "[dnsresolv_job] Unable to getNameList: invalid param.domains " << endl; + NETNATIVE_LOGE("[dnsresolv_job] Unable to getNameList: invalid param.domains "); + responseFailed(static_cast(ret)); + return; + } + + auto result = dnsresolvCtrl_.setResolverConfig(param); + if (result != 0) { + // common::logger::error() << "[dnsresolv_job] Unable to setResolverConfig: error code: " << result << endl; + NETNATIVE_LOGE("[dnsresolv_job] Unable to setResolverConfig: error code: %{public}d", result); + responseFailed(result); + return; + } + + responseOk(); +} + +void dnsresolv_job::doGetAddrInfo(const dnsresolver_request_cmd *command) +{ + const char *hostname = 0 == strlen(command->cmd_hostName) ? nullptr : command->cmd_hostName; + const char *servername = 0 == strlen(command->cmd_serverName) ? nullptr : command->cmd_serverName; + + struct addrinfo *res = nullptr; + auto ret = dnsresolv_controller::getaddrinfo(hostname, servername, &(command->cmd_hints), &res); + if (ret != 0) { + responseFailed(ret); + return; + } + + responseOk(res); + freeaddrinfo(res); +} + +void dnsresolv_job::doGetAddrInfoProxy(const dnsresolver_request_cmd *command) +{ + netd_net_context netContext; + dnsresolvCallbacks_.getNetworkContext(command->netid, command->cmd_uid, netContext); + + struct addrinfo *res = nullptr; + auto ret = dnsresolv_controller::getaddrinfoFornetContext( + command->cmd_hostName, command->cmd_serverName, &(command->cmd_hints), netContext, &res); + if (ret != 0) { + responseFailed(ret); + return; + } + + responseOk(res); +} + +size_t dnsresolv_job::getNameList(const char *buffer, const size_t bufferSize, std::vector &namelist) +{ + if (nullptr == buffer || 0 == bufferSize || !namelist.empty()) { + // common::logger::error() << "[dnsresolv_client] Unable to getNameList: invalid param. " << endl; + NETNATIVE_LOGE("[dnsresolv_client] Unable to getNameList: invalid param. "); + return 0; + } + + char *buffCur = const_cast(buffer); + size_t buffCount(0); + std::string name; + while (buffCount < bufferSize) { + name.clear(); + name.assign(buffCur); + if (name.empty()) { + break; + } + namelist.push_back(name); + buffCur += (name.length() + 1); + buffCount += (name.length() + 1); + } + + return namelist.size(); +} +} // namespace nmd +} // namespace OHOS diff --git a/http/services/netmanagernative/net_mgr_native/src/event_reporter.cpp b/http/services/netmanagernative/net_mgr_native/src/event_reporter.cpp new file mode 100644 index 000000000..8ab4edf9e --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/event_reporter.cpp @@ -0,0 +1,9 @@ +#include "event_reporter.h" +namespace OHOS { +void nmd::event_reporter::registerEventListener(inetd_unsolicited_event_listener &listener) +{ + this->listener_ = listener; +} + +nmd::event_reporter::~event_reporter() {} +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/src/fwmark_server.cpp b/http/services/netmanagernative/net_mgr_native/src/fwmark_server.cpp new file mode 100644 index 000000000..dfa395b96 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/fwmark_server.cpp @@ -0,0 +1,52 @@ +#include "fwmark_server.h" +#include "fwmark.h" +#include "fwmark_command.h" +#include "logger.h" +#include "string.h" +#include +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { +void fwmark_server::initJob(const int socketFd, const uint8_t *msg, const size_t msgLen) +{ + this->job_ = new nmd::fwmark_job(socketFd, msg, msgLen, this->server_); +} + +void fwmark_job::run() +{ + if (fd_ < 0 || msg_.empty() || nullptr == serverSocket_) { + return; + } + struct fwmark_command *command = reinterpret_cast(msg_.data()); + fwmark mark; + socklen_t fwmarkLen = sizeof(mark.val); + if (getsockopt(static_cast(command->fd), SOL_SOCKET, SO_MARK, &mark.val, &fwmarkLen) == -1) { + // LogError << "[FwmarkServer]: socket get " << command->fd << "'s fwmark failed: " << strerror(errno) << endl; + NETNATIVE_LOGE( + "[FwmarkServer]: socket get %{public}d 's fwmark failed: %{public}s", command->fd, strerror(errno)); + this->responseFailed(); + return; + } + + mark.bits.netId = command->netId; + if (setsockopt(static_cast(command->fd), SOL_SOCKET, SO_MARK, &mark.val, sizeof(mark.val)) == -1) { + // LogError << "[FwmarkServer]: socket set fwmark failed: " << strerror(errno) << endl; + NETNATIVE_LOGD("[FwmarkServer]: socket set fwmark failed: %{public}s", strerror(errno)); + this->responseFailed(); + return; + } + this->responseOk(); +} + +void fwmark_job::responseOk() +{ + this->serverSocket_->sendSocket(this->fd_, "1"); +} + +void fwmark_job::responseFailed() +{ + this->serverSocket_->sendSocket(this->fd_, "0"); +} +} // namespace nmd +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/src/get_addr_info.cpp b/http/services/netmanagernative/net_mgr_native/src/get_addr_info.cpp new file mode 100644 index 000000000..b0bbd085b --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/get_addr_info.cpp @@ -0,0 +1,2792 @@ + +#include "get_addr_info.h" +#include "dnsresolv.h" +#include "dnsresolv_cache.h" +#include "net_utils.h" +#include "error_code.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" +#include +#include +#include +#include "logger.h" +#include "netnative_log_wrapper.h" + +DISABLE_WARNING_PUSH +DISABLE_WARNING_IMPLICIT_INT_CONVERSION +DISABLE_WARNING_SHORTEN_64_TO_32 +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_SIGN_COMPARE +DISABLE_WARNING_OLD_STYLE_CAST +DISABLE_WARNING_CAST_ALIGN +DISABLE_WARNING_SIGN_CONVERSION + +namespace OHOS { +namespace nmd { + +#define BOUNDED_INCR(x) \ + do { \ + BOUNDS_CHECK(cp, x); \ + cp += (x); \ + } while (0) + +#define BOUNDS_CHECK(ptr, count) \ + do { \ + if (eom - (ptr) < (count)) { \ + herrno = NO_RECOVERY; \ + return nullptr; \ + } \ + } while (0) + +#define PERIOD 0x2e +#define hyphenchar(c) ((c) == 0x2d) +#define bslashchar(c) ((c) == 0x5c) +#define periodchar(c) ((c) == PERIOD) +#define asterchar(c) ((c) == 0x2a) +#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || ((c) >= 0x61 && (c) <= 0x7a)) +#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) +#define underscorechar(c) ((c) == 0x5f) + +#define borderchar(c) (alphachar(c) || digitchar(c)) +#define middlechar(c) (borderchar(c) || hyphenchar(c) || underscorechar(c)) +#define domainchar(c) ((c) > 0x20 && (c) < 0x7f) + +bool res_hnok(const char *dn) +{ + char pch = PERIOD, ch = *dn++; + + while (ch != '\0') { + char nch = *dn++; + + if (periodchar(ch)) { + } else if (periodchar(pch) || periodchar(nch) || nch == '\0') { + if (!borderchar(ch)) { + return false; + } + } else { + if (!middlechar(ch)) { + return false; + } + } + pch = ch, ch = nch; + } + return true; +} + +const char in_addrany[] = {0, 0, 0, 0}; +const char in_loopback[] = {127, 0, 0, 1}; +const char in6_addrany[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +const char in6_loopback[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; + +const struct afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; + const char *a_addrany; + const char *a_loopback; + int a_scoped; +} afdl[] = { + {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), offsetof(struct sockaddr_in6, sin6_addr), + in6_addrany, in6_loopback, 1}, + {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), offsetof(struct sockaddr_in, sin_addr), + in_addrany, in_loopback, 0}, + {0, 0, 0, 0, nullptr, nullptr, 0}, +}; + +struct Explore { + int e_af; + int e_socktype; + int e_protocol; + int e_wild; +#define WILD_AF(ex) ((ex).e_wild & 0x01) +#define WILD_SOCKTYPE(ex) ((ex).e_wild & 0x02) +#define WILD_PROTOCOL(ex) ((ex).e_wild & 0x04) +}; + +const Explore explore_options[] = { + {PF_INET6, SOCK_DGRAM, IPPROTO_UDP, 0x07}, + {PF_INET6, SOCK_STREAM, IPPROTO_TCP, 0x07}, + {PF_INET6, SOCK_RAW, ANY_SOCK_TYPE, 0x05}, + {PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0x07}, + {PF_INET, SOCK_STREAM, IPPROTO_TCP, 0x07}, + {PF_INET, SOCK_RAW, ANY_SOCK_TYPE, 0x05}, + {PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, 0x07}, + {PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0x07}, + {PF_UNSPEC, SOCK_RAW, ANY_SOCK_TYPE, 0x05}, +}; + +class get_addr_info::hostfd_wrapper { +public: + void sethtent() + { + if (nullptr == hostfd) { + hostfd = fopen(_PATH_HOSTS, "re"); + } else { + rewind(hostfd); + } + } + + void ednhtent() + { + if (nullptr == hostfd) { + return; + } + fclose(hostfd); + hostfd = nullptr; + } + + addrinfo *gethtent(const char *name, const addrinfo *pai) + { + if (nullptr == hostfd) { + sethtent(); + } + + if (nullptr == hostfd) { + return nullptr; + } + + char hostbuf[MAX_PACKET] = {}; + char *p(nullptr); + char *cp(nullptr); + char *cname(nullptr); + char *tname(nullptr); + const char *addr(nullptr); + again: + if (!(p = fgets(hostbuf, sizeof(hostbuf), hostfd))) { + return nullptr; + } + if (*p == '#') { + goto again; + } + if (!(cp = strpbrk(p, "#\n"))) { + goto again; + } + *cp = '\0'; + if (!(cp = strpbrk(p, " \t"))) { + goto again; + } + *cp++ = '\0'; + addr = p; + cname = nullptr; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (!cname) { + cname = cp; + } + tname = cp; + if ((cp = strpbrk(cp, " \t")) != nullptr) { + *cp++ = '\0'; + } + if (strcasecmp(name, tname) == 0) { + goto found; + } + } + goto again; + + found: + addrinfo *result(nullptr); + int error = getaddrinfoNumeric(addr, nullptr, *pai, &result); + if (error) { + goto again; + } + + for (addrinfo *cur = result; cur; cur = cur->ai_next) { + cur->ai_flags = pai->ai_flags; + + if (pai->ai_flags & AI_CANONNAME) { + if (getCanonName(pai, cur, cname) != 0) { + freeaddrinfo(result); + goto again; + } + } + } + return result; + } + +private: + FILE *hostfd = nullptr; +}; + +int nmd::get_addr_info::getaddrinfoFornetContext(const char *hostname, const char *servname, const addrinfo *hints, + const netd_net_context *netcontext, addrinfo **res) +{ + if (nullptr == netcontext || nullptr == res) { + return -1; + } + + addrinfo sentinel = {}; + addrinfo *cur = &sentinel; + int ret = 0; + do { + if (nullptr == hostname && nullptr == servname) { + ret = EAI_NONAME; + break; + } + + if (nullptr != hints && ((ret = validateHints(hints)) != 0)) { + break; + } + + addrinfo tmpAdrrInfo = nullptr != hints ? *hints : addrinfo {}; + + if ((ret = checkHostNameAndExplore(tmpAdrrInfo, hostname, servname, cur)) != 0) { + break; + } + + if (sentinel.ai_next != nullptr) { + break; + } + + if (hostname == nullptr) { + ret = EAI_NODATA; + break; + } + + if (tmpAdrrInfo.ai_flags & AI_NUMERICHOST) { + ret = EAI_NONAME; + break; + } + + return resolvGetAddrInfo(hostname, servname, hints, netcontext, res); + + } while (0); + + if (ret != 0) { + freeaddrinfo(sentinel.ai_next); + *res = nullptr; + } else { + *res = sentinel.ai_next; + } + + return ret; +} + +int nmd::get_addr_info::validateHints(const addrinfo *hints) +{ + if (nullptr == hints) { + return static_cast(common::dnsresolv_error_code::errBadHints); + } + + // error check for hints + if (0 != hints->ai_addrlen || nullptr != hints->ai_canonname || nullptr != hints->ai_addr || + nullptr != hints->ai_next) { + return static_cast(common::dnsresolv_error_code::errBadHints); + } + + if (hints->ai_flags & ~AI_MASK) { + return EAI_BADFLAGS; + } + + if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET || hints->ai_family == PF_INET6)) { + return EAI_FAMILY; + } + + // Socket types which are not in explore_options. + switch (hints->ai_socktype) { + case SOCK_RAW: + case SOCK_DGRAM: + case SOCK_STREAM: + case ANY_SOCK_TYPE: + break; + default: + return EAI_SOCKTYPE; + } + + if (hints->ai_socktype == ANY_SOCK_TYPE || hints->ai_protocol == ANY_SOCK_TYPE) { + return 0; + } + + // if both socktype/protocol are specified, check if they are meaningful combination. + for (const Explore &ex : explore_options) { + if (hints->ai_family != ex.e_af) { + continue; + } + if (ex.e_socktype == ANY_SOCK_TYPE) { + continue; + } + if (ex.e_protocol == ANY_SOCK_TYPE) { + continue; + } + if (hints->ai_socktype == ex.e_socktype && hints->ai_protocol != ex.e_protocol) { + return static_cast(common::dnsresolv_error_code::errBadHints); + } + } + + return 0; +} + +int nmd::get_addr_info::checkHostNameAndExplore( + const addrinfo &ai, const char *hostname, const char *servname, addrinfo *cur) +{ + // Check for special cases: + // (1) numeric servname is disallowed if socktype/protocol are left unspecified. + // (2) servname is disallowed for raw and other inet{,6} sockets. + if (MATCH_FAMILY(ai.ai_family, PF_INET, 1) || MATCH_FAMILY(ai.ai_family, PF_INET6, 1)) { + addrinfo tmp = ai; + if (tmp.ai_family == PF_UNSPEC) { + tmp.ai_family = PF_INET6; + } + auto ret = getPort(&tmp, servname, true); + if (0 != ret) { + return ret; + } + } + + // NULL hostname, or numeric hostname + int error = 0; + for (const Explore &ex : explore_options) { + /* PF_UNSPEC entries are prepared for DNS queries only */ + if (ex.e_af == PF_UNSPEC) { + continue; + } + + if (!MATCH_FAMILY(ai.ai_family, ex.e_af, WILD_AF(ex))) { + continue; + } + + if (!MATCH(ai.ai_socktype, ex.e_socktype, WILD_SOCKTYPE(ex))) { + continue; + } + + if (!MATCH(ai.ai_protocol, ex.e_protocol, WILD_PROTOCOL(ex))) { + continue; + } + + addrinfo tmp = ai; + if (tmp.ai_family == PF_UNSPEC) { + tmp.ai_family = ex.e_af; + } + + if (tmp.ai_socktype == ANY_SOCK_TYPE && ex.e_socktype != ANY_SOCK_TYPE) { + tmp.ai_socktype = ex.e_socktype; + } + + if (tmp.ai_protocol == ANY_SOCK_TYPE && ex.e_protocol != ANY_SOCK_TYPE) { + tmp.ai_protocol = ex.e_protocol; + } + + if (hostname == nullptr) { + error = exploreNull(&tmp, servname, &cur->ai_next); + } else { + error = exploreNumericScope(&tmp, hostname, servname, &cur->ai_next); + } + + if (error != 0) { + return -1; + }; + + while (cur->ai_next) + cur = cur->ai_next; + } + return 0; +} + +int nmd::get_addr_info::strToNumber(const char *p) +{ + if (*p == '\0') { + return -1; + } + char *ep = nullptr; + errno = 0; + unsigned long v = strtoul(p, &ep, 10); + if (errno == 0 && ep && *ep == '\0' && v <= std::numeric_limits::max()) { + return static_cast(v); + } else { + return -1; + } +} + +int nmd::get_addr_info::exploreNull(const addrinfo *pai, const char *servname, addrinfo **res) +{ + *res = nullptr; + struct addrinfo sentinel; + sentinel.ai_next = nullptr; + struct addrinfo *cur = &sentinel; + + int socketFd = socket(pai->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (socketFd < 0) { + if (errno != EMFILE) { + return 0; + } + } else { + close(socketFd); + } + + // if the servname does not match socktype/protocol, ignore it. + if (getPort(pai, servname, true) != 0) { + return 0; + } + + const struct afd *pafd = findAfd(pai->ai_family); + if (pafd == nullptr) { + return 0; + } + + int error; + if (pai->ai_flags & AI_PASSIVE) { + GET_AI(cur->ai_next, pafd, pafd->a_addrany); + GET_PORT(cur->ai_next, servname); + } else { + GET_AI(cur->ai_next, pafd, pafd->a_loopback); + GET_PORT(cur->ai_next, servname); + } + cur = cur->ai_next; + + *res = sentinel.ai_next; + return 0; +free: + freeaddrinfo(sentinel.ai_next); + return error; +} + +const nmd::afd *nmd::get_addr_info::findAfd(int af) +{ + if (af == PF_UNSPEC) { + return nullptr; + } + + for (const nmd::afd *pafd = afdl; pafd->a_af; pafd++) { + if (pafd->a_af == af) { + return pafd; + } + } + return nullptr; +} + +addrinfo *nmd::get_addr_info::getAi(const addrinfo *pai, const afd *pafd, const char *addr) +{ + struct addrinfo *ai = + reinterpret_cast(malloc(sizeof(struct addrinfo) + sizeof(sockaddr_union))); + if (nullptr == ai) { + return nullptr; + } + + memcpy(ai, pai, sizeof(struct addrinfo)); + ai->ai_addr = reinterpret_cast(ai + 1); + memset(ai->ai_addr, 0, sizeof(sockaddr_union)); + + ai->ai_addrlen = static_cast(pafd->a_socklen); + ai->ai_addr->sa_family = static_cast(ai->ai_family = pafd->a_af); + char *p = reinterpret_cast(ai->ai_addr); + memcpy(p + pafd->a_off, addr, static_cast(pafd->a_addrlen)); + return ai; +} + +int nmd::get_addr_info::getPort(const addrinfo *ai, const char *servname, bool matchonly) +{ + if (nullptr == servname) { + return 0; + } + + switch (ai->ai_family) { + case AF_INET: + case AF_INET6: + break; + default: + return 0; + } + + bool allownumeric(false); + switch (ai->ai_socktype) { + case SOCK_RAW: + return EAI_SERVICE; + case SOCK_DGRAM: + case SOCK_STREAM: + case ANY_SOCK_TYPE: + allownumeric = true; + break; + default: + return EAI_SOCKTYPE; + } + + auto port = strToNumber(servname); + if (port >= 0) { + if (!allownumeric) { + return EAI_SERVICE; + } + if (port < 0 || port > 65535) { + return EAI_SERVICE; + } + port = htons(static_cast(port)); + } else { + if (ai->ai_flags & AI_NUMERICSERV) { + return EAI_NONAME; + } + + std::string proto; + switch (ai->ai_socktype) { + case SOCK_DGRAM: + proto = "udp"; + break; + case SOCK_STREAM: + proto = "tcp"; + break; + default: + proto.clear(); + break; + } + + auto srv = getservbyname(servname, proto.c_str()); + if (nullptr == srv) { + return EAI_SERVICE; + } + port = srv->s_port; + } + + if (!matchonly) { + switch (ai->ai_family) { + case AF_INET: + (reinterpret_cast(ai->ai_addr))->sin_port = static_cast(port); + break; + case AF_INET6: + (reinterpret_cast(ai->ai_addr))->sin6_port = static_cast(port); + break; + } + } + + return 0; +} + +int nmd::get_addr_info::exploreNumericScope( + const addrinfo *pai, const char *hostname, const char *servname, addrinfo **res) +{ + // if the servname does not match socktype/protocol, ignore it. + if (getPort(pai, servname, true) != 0) { + return 0; + } + + const struct afd *pafd = findAfd(pai->ai_family); + if (pafd == nullptr) { + return 0; + } + + if (!pafd->a_scoped) { + return exploreNumeric(pai, hostname, servname, res, hostname); + } + + const char *cp = strchr(hostname, SCOPE_DELIMITER); + if (cp == nullptr) { + return exploreNumeric(pai, hostname, servname, res, hostname); + } + + auto hostFreeFunc = [](char *host) { + if (nullptr == host) { + return; + } + free(host); + }; + char *hostname2 = strdup(hostname); + common::utils::auto_destroyer autoFreeHost(hostname2, hostFreeFunc); + if (nullptr == hostname2) { + return EAI_MEMORY; + } + + hostname2[cp - hostname] = '\0'; + const char *addr = hostname2; + const char *scope = cp + 1; + + int error = exploreNumeric(pai, addr, servname, res, hostname); + if (error == 0) { + for (struct addrinfo *cur = *res; cur; cur = cur->ai_next) { + if (cur->ai_family != AF_INET6) { + continue; + } + struct sockaddr_in6 *sin6 = reinterpret_cast(cur->ai_addr); + + uint32_t scopeid(0); + if (ip6StrToScopeid(scope, *sin6, scopeid) != 0) { + return EAI_NODATA; + } + sin6->sin6_scope_id = scopeid; + } + } + + return error; +} + +int nmd::get_addr_info::exploreNumeric( + const addrinfo *pai, const char *hostname, const char *servname, addrinfo **res, const char *canonname) +{ + int error; + const struct afd *pafd(nullptr); + struct addrinfo *cur(nullptr); + struct addrinfo sentinel; + char pton[PTON_MAX] = {}; + + *res = nullptr; + sentinel.ai_next = nullptr; + cur = &sentinel; + + if (getPort(pai, servname, true) != 0) { + return 0; + } + + pafd = findAfd(pai->ai_family); + if (nullptr == pafd) { + return 0; + } + + if (inet_pton(pafd->a_af, hostname, pton) == 1) { + if (pai->ai_family == pafd->a_af || pai->ai_family == PF_UNSPEC) { + GET_AI(cur->ai_next, pafd, pton); + GET_PORT(cur->ai_next, servname); + if ((pai->ai_flags & AI_CANONNAME)) { + /* + * Set the numeric address itself as + * the canonical name, based on a + * clarification in rfc2553bis-03. + */ + error = getCanonName(pai, cur->ai_next, canonname); + if (error != 0) { + freeaddrinfo(sentinel.ai_next); + return error; + } + } + while (cur->ai_next) + cur = cur->ai_next; + } else { + return EAI_FAMILY; + } + } + + *res = sentinel.ai_next; + return 0; + +free: + freeaddrinfo(sentinel.ai_next); + return error; +} + +int nmd::get_addr_info::ip6StrToScopeid(const char *scope, const struct sockaddr_in6 &sin6, uint32_t &scopeid) +{ + const struct in6_addr *a6 = &sin6.sin6_addr; + + // empty scopeid portion is invalid + if (*scope == '\0') { + return -1; + } + + if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { + /* + * We currently assume a one-to-one mapping between links + * and interfaces, so we simply use interface indices for + * like-local scopes. + */ + scopeid = if_nametoindex(scope); + if (scopeid != 0) { + return 0; + } + } + + // try to convert to a numeric id as a last resort + errno = 0; + char *ep(nullptr); + uint64_t lscopeid = strtoul(scope, &ep, 10); + scopeid = static_cast(lscopeid & 0xffffffffUL); + if (errno == 0 && ep && *ep == '\0' && scopeid == lscopeid) { + return 0; + } else { + return -1; + } +} + +int nmd::get_addr_info::getCanonName(const addrinfo *pai, addrinfo *ai, const char *str) +{ + if ((pai->ai_flags & AI_CANONNAME) != 0) { + ai->ai_canonname = strdup(str); + if (nullptr == ai->ai_canonname) { + return EAI_MEMORY; + } + } + return 0; +} + +int nmd::get_addr_info::resolvGetAddrInfo(const char *hostname, const char *servname, const addrinfo *hints, + const netd_net_context *netcontext, addrinfo **res) +{ + if (hostname == nullptr && servname == nullptr) { + return EAI_NONAME; + } + + if (hostname == nullptr) { + return EAI_NODATA; + } + + int error = EAI_FAIL; + if (hints && (error = validateHints(hints))) { + *res = nullptr; + return error; + } + + addrinfo ai = hints ? *hints : addrinfo {}; + addrinfo sentinel = {}; + addrinfo *cur = &sentinel; + // hostname as alphanumeric name. + // We would like to prefer AF_INET6 over AF_INET, so we'll make a outer loop by AFs. + for (const Explore &ex : explore_options) { + // Require exact match for family field + if (ai.ai_family != ex.e_af) { + continue; + } + + if (!MATCH(ai.ai_socktype, ex.e_socktype, WILD_SOCKTYPE(ex))) { + continue; + } + + if (!MATCH(ai.ai_protocol, ex.e_protocol, WILD_PROTOCOL(ex))) { + continue; + } + + addrinfo tmp = ai; + if (tmp.ai_socktype == ANY_SOCK_TYPE && ex.e_socktype != ANY_SOCK_TYPE) { + tmp.ai_socktype = ex.e_socktype; + } + + if (tmp.ai_protocol == ANY_SOCK_TYPE && ex.e_protocol != ANY_SOCK_TYPE) { + tmp.ai_protocol = ex.e_protocol; + } + + error = exploreFqdn(&tmp, hostname, servname, &cur->ai_next, netcontext); + + while (cur->ai_next) + cur = cur->ai_next; + } + + if ((*res = sentinel.ai_next)) { + return 0; + } + + freeaddrinfo(sentinel.ai_next); + *res = nullptr; + return (error == 0) ? EAI_FAIL : error; +} + +int nmd::get_addr_info::exploreFqdn(const addrinfo *pai, const char *hostname, const char *servname, + addrinfo **res, const netd_net_context *netcontext) +{ + addrinfo *result = nullptr; + int error = 0; + + // If the servname does not match socktype/protocol, return error code. + if ((error = getPort(pai, servname, true))) { + return error; + } + + if (!getAddrinfoFromFile(hostname, pai, &result)) { + error = dnsGetaddrinfo(hostname, pai, netcontext, &result); + } + if (error) { + freeaddrinfo(result); + return error; + } + + for (addrinfo *cur = result; cur; cur = cur->ai_next) { + // canonname should be filled already + if ((error = getPort(cur, servname, 0))) { + freeaddrinfo(result); + return error; + } + } + *res = result; + return 0; +} + +bool nmd::get_addr_info::getAddrinfoFromFile(const char *name, const addrinfo *pai, addrinfo **res) +{ + struct addrinfo sentinel = {}; + struct addrinfo *cur = &sentinel; + hostfd_wrapper hostfd; + struct addrinfo *p(nullptr); + while ((p = hostfd.gethtent(name, pai)) != nullptr) { + cur->ai_next = p; + while (cur && cur->ai_next) + cur = cur->ai_next; + } + + *res = sentinel.ai_next; + return sentinel.ai_next != nullptr; +} + +int nmd::get_addr_info::dnsGetaddrinfo( + const char *name, const addrinfo *pai, const netd_net_context *netcontext, addrinfo **rv) +{ + res_target q = {}; + res_target q2 = {}; + + switch (pai->ai_family) { + case AF_UNSPEC: { + /* prefer IPv6 */ + q.name = name; + q.qclass = C_IN; + bool query_ipv6(true); + bool query_ipv4(true); + if (pai->ai_flags & AI_ADDRCONFIG) { + query_ipv6 = haveIpv6(netcontext->appMark, netcontext->uid); + query_ipv4 = haveIpv4(netcontext->appMark, netcontext->uid); + } + if (query_ipv6) { + q.qtype = T_AAAA; + if (query_ipv4) { + q.next = &q2; + q2.name = name; + q2.qclass = C_IN; + q2.qtype = T_A; + } + } else if (query_ipv4) { + q.qtype = T_A; + } else { + return EAI_NODATA; + } + break; + } + case AF_INET: + q.name = name; + q.qclass = C_IN; + q.qtype = T_A; + break; + case AF_INET6: + q.name = name; + q.qclass = C_IN; + q.qtype = T_AAAA; + break; + default: + return EAI_FAMILY; + } + + dns_res_state res; + res.init(netcontext); + + int error(0); + if (resSearchN(name, &q, res, error) < 0) { + return error; + } + + addrinfo sentinel = {}; + addrinfo *cur = &sentinel; + addrinfo *ai = getAnswer(q.answer, q.n, q.name, q.qtype, pai, error); + if (nullptr != ai) { + cur->ai_next = ai; + while (cur && cur->ai_next) + cur = cur->ai_next; + } + if (q.next) { + ai = getAnswer(q2.answer, q2.n, q2.name, q2.qtype, pai, error); + if (nullptr != ai) { + cur->ai_next = ai; + } + } + + if (nullptr == sentinel.ai_next) { + return error; + } + + *rv = sentinel.ai_next; + return 0; +} + +bool nmd::get_addr_info::haveIpv6(uint32_t mark, uid_t uid) +{ + DISABLE_WARNING_PUSH + DISABLE_WARNING_C99_EXTENSIONS + static const struct sockaddr_in6 sin6_test = {.sin6_family = AF_INET6, + .sin6_addr.s6_addr = {// 2000:: + 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + sockaddr_union addr = {.sin6 = sin6_test}; + DISABLE_WARNING_POP + return findSrcAddr(&addr.sa, nullptr, mark, uid) == 1; +} + +bool nmd::get_addr_info::haveIpv4(uint32_t mark, uid_t uid) +{ + static sockaddr_in sin_test = {}; + sin_test.sin_family = AF_INET, + sin_test.sin_addr.s_addr = inet_addr("8.8.8.8"); // 8.8.8.8 + sockaddr_union addr = {}; + addr.sin = sin_test; + return findSrcAddr(&addr.sa, nullptr, mark, uid) == 1; +} + +int nmd::get_addr_info::findSrcAddr(const sockaddr *addr, sockaddr *src_addr, unsigned mark, uid_t uid) +{ + socklen_t len(0); + + switch (addr->sa_family) { + case AF_INET: + len = sizeof(struct sockaddr_in); + break; + case AF_INET6: + len = sizeof(struct sockaddr_in6); + break; + default: + return 0; + } + + int sock = socket(addr->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); + if (sock == -1) { + if (errno == EAFNOSUPPORT) { + return 0; + } else { + return -1; + } + } + if (mark != MARK_UNSET && setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) { + close(sock); + return 0; + } + if (uid > 0 && uid != NET_CONTEXT_INVALID_UID && fchown(sock, uid, static_cast(-1)) < 0) { + close(sock); + return 0; + } + + int ret(-1); + do { + ret = connect(sock, addr, len); + } while (ret == -1 && errno == EINTR); + + if (ret == -1) { + close(sock); + return 0; + } + + if (src_addr && getsockname(sock, src_addr, &len) == -1) { + close(sock); + return -1; + } + close(sock); + return 1; +} + +bool nmd::get_addr_info::isTrailingWithDot(const std::string &name, uint32_t &dots) +{ + const char *cp(nullptr); + for (cp = name.c_str(); *cp; cp++) { + dots += (*cp == '.'); + } + return (cp > name && *--cp == '.') ? true : false; +} + +int nmd::get_addr_info::tryQueyWithDomain(const bool trailingDot, const std::string &name, const uint32_t dots, + res_target *target, dns_res_state &res, int &herrno) +{ + HEADER *hp = reinterpret_cast
(target->answer.data()); + int saved_herrno = -1; + int gotNoData = 0; + int gotServFail = 0; + int triedAsIs = 0; + int ret = 0; + if (dots >= res.ndots) { + ret = resQueryDomainN(name.c_str(), nullptr, target, res, herrno); + if (ret > 0) { + return ret; + } + saved_herrno = herrno; + triedAsIs++; + } + + if ((!dots) || (dots && !trailingDot)) { + int done = 0; + + getResolvConfigFromCache(res); + + for (const auto &domain : res.searchDomains) { + ret = resQueryDomainN(name.c_str(), domain.c_str(), target, res, herrno); + if (ret > 0) { + return ret; + } + + /* + * If no server present, give up. + * If name isn't found in this domain, + * keep trying higher domains in the search list + * (if that's enabled). + * On a NO_DATA error, keep trying, otherwise + * a wildcard entry of another type could keep us + * from finding this entry higher in the domain. + * If we get some other error (negative answer or + * server failure), then stop searching up, + * but try the input name below in case it's + * fully-qualified. + */ + if (errno == ECONNREFUSED) { + herrno = TRY_AGAIN; + return -1; + } + + switch (herrno) { + case NO_DATA: + gotNoData++; + [[fallthrough]]; + case HOST_NOT_FOUND: + break; + case TRY_AGAIN: + if (hp->rcode == SERVFAIL) { + // try next search element, if any + gotServFail++; + break; + } + [[fallthrough]]; + default: + // anything else implies that we're done + done++; + } + } + } + + /* + * if we have not already tried the name "as is", do that now. + * note that we do this regardless of how many dots were in the + * name or whether it ends with a dot. + */ + if (!triedAsIs) { + ret = resQueryDomainN(name.c_str(), nullptr, target, res, herrno); + if (ret > 0) { + return ret; + } + } + + /* + * if we got here, we didn't satisfy the search. + * if we did an initial full query, return that query's h_errno + * (note that we wouldn't be here if that query had succeeded). + * else if we ever got a nodata, send that back as the reason. + * else send back meaningless h_errno, that being the one from + * the last DNSRCH we did. + */ + if (saved_herrno != -1) { + herrno = saved_herrno; + } else if (gotNoData) { + herrno = NO_DATA; + } else if (gotServFail) { + herrno = TRY_AGAIN; + } + return -1; +} + +int nmd::get_addr_info::resSearchN(const char *name, res_target *target, dns_res_state &res, int &herrno) +{ + errno = 0; + herrno = HOST_NOT_FOUND; + uint32_t dots = 0; + const bool trailingDot = isTrailingWithDot(name, dots); + + /* + * If there are dots in the name already, let's just give it a try + * 'as is'. The threshold can be set with the "ndots" option. + */ + return tryQueyWithDomain(trailingDot, name, dots, target, res, herrno); +} + +int nmd::get_addr_info::resQueryDomainN( + const char *name, const char *domain, res_target *target, dns_res_state &res, int &herrno) +{ + char nbuf[MAXDNAME] = {}; + const char *longname(nbuf); + size_t n(0); + size_t d(0); + if (domain == nullptr) { + // Check for trailing '.'; copy without '.' if present. + n = strlen(name); + if (n + 1 > sizeof(nbuf)) { + herrno = NO_RECOVERY; + return -1; + } + if (n > 0 && name[--n] == '.') { + strncpy(nbuf, name, n); + nbuf[n] = '\0'; + } else { + longname = name; + } + } else { + n = strlen(name); + d = strlen(domain); + if (n + 1 + d + 1 > sizeof(nbuf)) { + herrno = NO_RECOVERY; + return -1; + } + snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); + } + return resQueryN(longname, target, res, herrno); +} + +int nmd::get_addr_info::resQueryN(const char *name, res_target *target, dns_res_state &res, int &herrno) +{ + int rcode = NOERROR; + int ancount = 0; + + for (res_target *t = target; t; t = t->next) { + HEADER *hp = reinterpret_cast
(t->answer.data()); + hp->rcode = NOERROR; /* default */ + + int cl = t->qclass; + int type = t->qtype; + const size_t anslen = t->answer.size(); + + uint8_t buf[MAX_PACKET] = {}; + int n = resMakePacketForQuery( + QUERY, reinterpret_cast(name), cl, type, nullptr, 0, buf, sizeof(buf)); + if (n <= 0) { + // common::logger::error() << "[get_addr_info] Unable to resMakePacketForQuery. " << endl; + NETNATIVE_LOGE("[get_addr_info] Unable to resMakePacketForQuery. "); + herrno = NO_RECOVERY; + return n; + } + + n = resQueryPacketSend(res, buf, static_cast(n), t->answer.data(), anslen, rcode, 0); + if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { + if (rcode != RCODE_TIMEOUT) { + rcode = hp->rcode; // record most recent error + } + continue; + } + + ancount += ntohs(hp->ancount); + t->n = static_cast(n); + } + + if (ancount == 0) { + herrno = getHerrnoFromRcode(rcode); + return -1; + } + return ancount; +} + +int nmd::get_addr_info::resMakePacketForQuery(uint32_t op, const uint8_t *dname, int cl, int type, + const uint8_t *data, size_t datalen, uint8_t *buf, size_t buflen) +{ + if ((buf == nullptr) || (buflen < HFIXEDSZ)) { + return -1; + } + memset(buf, 0, HFIXEDSZ); + HEADER *hp = reinterpret_cast
(buf); + std::random_device rd; // Will be used to obtain a seed for the random number engine + std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() + std::uniform_int_distribution<> distrib(0, 65536); + hp->id = htons(static_cast(distrib(gen))); + hp->opcode = op; + hp->rd = true; + hp->ad = false; + hp->rcode = NOERROR; + uint8_t *cp = buf + HFIXEDSZ; + uint8_t *ep = buf + buflen; + + const uint8_t *dnptrs[20] = {}; + const uint8_t **dpp = dnptrs; + *dpp++ = buf; + *dpp++ = nullptr; + const uint8_t **lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; + + // perform opcode specific processing + switch (op) { + case QUERY: + [[fallthrough]]; + case NS_NOTIFY_OP: { + if (ep - cp < QFIXEDSZ) { + return -1; + } + int n(-1); + if ((n = dnCompress(dname, cp, static_cast(ep - cp - QFIXEDSZ), dnptrs, lastdnptr)) < 0) { + return -1; + } + cp += n; + *reinterpret_cast(cp) = htons(static_cast(type)); + cp += INT16SZ; + *reinterpret_cast(cp) = htons(static_cast(cl)); + cp += INT16SZ; + hp->qdcount = htons(1); + if (op == QUERY || data == nullptr) { + break; + } + + // Make an additional record for completion domain. + if ((ep - cp) < RRFIXEDSZ) { + return -1; + } + n = dnCompress(data, cp, static_cast(ep - cp - RRFIXEDSZ), dnptrs, lastdnptr); + if (n < 0) { + return -1; + } + cp += n; + *reinterpret_cast(cp) = htons(ns_t_null); + cp += INT16SZ; + *reinterpret_cast(cp) = htons(static_cast(cl)); + cp += INT16SZ; + *reinterpret_cast(cp) = htonl(0); + cp += INT32SZ; + *reinterpret_cast(cp) = htons(0); + cp += INT16SZ; + hp->arcount = htons(1); + } break; + + case IQUERY: + // Initialize answer section + if ((ep - cp) < static_cast(1 + RRFIXEDSZ + datalen)) { + return (-1); + } + *cp++ = '\0'; /* no domain name */ + *reinterpret_cast(cp) = htons(static_cast(type)); + cp += INT16SZ; + *reinterpret_cast(cp) = htons(static_cast(cl)); + cp += INT16SZ; + *reinterpret_cast(cp) = htonl(0); + cp += INT32SZ; + *reinterpret_cast(cp) = htons(static_cast(datalen)); + cp += INT16SZ; + if (datalen) { + memcpy(cp, data, datalen); + cp += datalen; + } + hp->ancount = htons(1); + break; + + default: + return -1; + } + return static_cast(cp - buf); +} + +int nmd::get_addr_info::resQueryPacketSend(dns_res_state &statp, const uint8_t *buf, size_t buflen, uint8_t *ans, + size_t anssiz, int &rcode, uint32_t flags) +{ + size_t anslen = 0; + dnsresolv_cache_status cache_status = + nmd::dnsresolv_cache::lookupFromResolvCache(statp.netid, buf, buflen, ans, anssiz, &anslen, flags); + if (cache_status == RESOLV_CACHE_FOUND) { + HEADER *hp = reinterpret_cast
(ans); + rcode = hp->rcode; + // common::logger::info() << "[get_addr_info] get answer form cache. anslen: " << anslen << endl; + NETNATIVE_LOGE("[get_addr_info] get answer form cache. anslen: %{public}d", anslen); + return static_cast(anslen); + } + + if (cache_status != RESOLV_CACHE_UNSUPPORTED) { + getResolvConfigFromCache(statp); + } + + if (statp.nameserverCount() == 0) { + errno = ESRCH; + return -ESRCH; + } + + dns_res_state stats[MAXNS] {}; + dns_res_params params; + // Send request, RETRY times, or until successful. + uint8_t retryTimes = (flags & NETD_DNS_RESOLV_NO_RETRY) ? 1 : params.retryCount; + bool useTcp = buflen > PACKETSZ; + int gotsomewhere = 0; + // Use an impossible error code as default value + int terrno = ETIME; + + for (int attempt = 0; attempt < retryTimes; ++attempt) { + for (size_t ns = 0; ns < statp.nsaddrs.size(); ++ns) { + rcode = RCODE_INTERNAL_ERROR; + time_t query_time = 0; + int delay = 0; + bool fallbackTCP = false; + int resplen(-1); + size_t actualNs = ns; + terrno = ETIME; + if (useTcp) { + // TCP; at most one attempt per server. + attempt = retryTimes; + resplen = sendViaTcp(statp, params, buf, buflen, ans, anssiz, terrno, ns, query_time, rcode, delay); + // common::logger::info() << "[get_addr_info] send dns request by tcp. resplen: " << resplen + // << " terrno: " << terrno << endl; + NETNATIVE_LOGE("[get_addr_info] send dns request by tcp. resplen: %{public}d terrno: %{public}d", + resplen, terrno); + } else { + // UDP + resplen = sendViaUdp(statp, params, buf, buflen, ans, anssiz, terrno, actualNs, useTcp, + gotsomewhere, query_time, rcode, delay); + fallbackTCP = useTcp ? true : false; + // common::logger::info() << "[get_addr_info] send dns request by udp. resplen: " << resplen + // << " terrno: " << terrno << endl; + NETNATIVE_LOGE("[get_addr_info] send dns request by udp. resplen: %{public}d terrno: %{public}d", + resplen, terrno); + } + + if (resplen == 0) { + continue; + } + + if (fallbackTCP) { + ns--; + continue; + } + + if (resplen < 0) { + statp.closeSockets(); + return -terrno; + }; + + if (cache_status == RESOLV_CACHE_NOTFOUND) { + nmd::dnsresolv_cache::resolvCacheAdd(statp.netid, buf, buflen, ans, static_cast(resplen)); + } + statp.closeSockets(); + return (resplen); + } // for each ns + } // for each retry + statp.closeSockets(); + terrno = useTcp ? terrno : gotsomewhere ? ETIMEDOUT : ECONNREFUSED; + errno = useTcp ? terrno : + gotsomewhere ? ETIMEDOUT // no answer obtained + : + ECONNREFUSED; // no nameservers found + + return -terrno; +} + +int nmd::get_addr_info::getHerrnoFromRcode(int rcode) +{ + switch (rcode) { + case RCODE_TIMEOUT: + return RCODE_TIMEOUT; // extended h_errno. + case NXDOMAIN: + return HOST_NOT_FOUND; + case SERVFAIL: + return TRY_AGAIN; + case NOERROR: + return NO_DATA; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + return NO_RECOVERY; + } +} + +int nmd::get_addr_info::dnCompress( + const uint8_t *src, uint8_t *dst, size_t dstsiz, const uint8_t **dnptrs, const uint8_t **lastdnptr) +{ + return (ns_name_compress(reinterpret_cast(src), dst, dstsiz, + reinterpret_cast(dnptrs), lastdnptr)); +} + +bool nmd::get_addr_info::resetNsSock( + nmd::common::net_utils::socket_fd &sock, const int type, const sockaddr *nsap, int &terrno, int &ret) +{ + sock.reset(socket(nsap->sa_family, type, 0)); + if (sock < 0) { + terrno = errno; + switch (errno) { + case EPROTONOSUPPORT: + case EPFNOSUPPORT: + case EAFNOSUPPORT: { + ret = 0; + return false; + } + default: { + ret = -1; + return false; + } + } + } + return true; +} + +int nmd::get_addr_info::waitForReply(dns_res_state &statp, dns_res_params ¶ms, const uint8_t *buf, + const size_t buflen, uint8_t *ans, size_t anssiz, int &terrno, size_t &ns, bool &needTcp, int &gotsomewhere, + int &rcode, int &delay) +{ + delay = 0; + timespec timeout = getTimeout(params); + timespec start_time = evNowTime(); + timespec finish = evAddTime(start_time, timeout); + for (;;) { + // Wait for reply. + std::vector fdAvailable; + auto result = udpRetryingPollWrapper(statp, ns, finish, fdAvailable); + + if (fdAvailable.empty()) { + const bool isTimeout = (result == ETIMEDOUT); + rcode = (isTimeout) ? RCODE_TIMEOUT : rcode; + terrno = (isTimeout) ? ETIMEDOUT : errno; + gotsomewhere = (isTimeout) ? 1 : gotsomewhere; + // Leave the UDP sockets open on timeout so we can keep listening for + // a late response from this server while retrying on the next server. + if (!isTimeout) { + statp.closeSockets(); + } + return 0; + } + bool needRetry = false; + for (const int &fd : fdAvailable) { + needRetry = false; + sockaddr_storage from; + socklen_t fromlen = sizeof(from); + ssize_t resplen = recvfrom(fd, ans, anssiz, 0, reinterpret_cast(&from), &fromlen); + if (resplen <= 0) { + terrno = errno; + continue; + } + gotsomewhere = 1; + if (resplen < HFIXEDSZ) { + // Undersized message. + terrno = EMSGSIZE; + continue; + } + + size_t receivedFromNs = ns; + needRetry = isInvalidAnswer(statp, from, buf, buflen, ans, anssiz, receivedFromNs); + if (needRetry) { + continue; + } + + timespec done = evNowTime(); + delay = calculateElapsedTime(done, start_time); + + HEADER *anhp = reinterpret_cast
(ans); + if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || anhp->rcode == REFUSED) { + // common::logger::debug() << "[get_addr_info] server rejected query. " << endl; + NETNATIVE_LOGD("[get_addr_info] server rejected query. "); + rcode = anhp->rcode; + continue; + } + if (anhp->tc) { + // To get the rest of answer, + // use TCP with same server. + // common::logger::debug() << "[get_addr_info] truncated answer. " << endl; + NETNATIVE_LOGD("[get_addr_info] truncated answer. "); + terrno = E2BIG; + needTcp = true; + return 1; + } + + rcode = anhp->rcode; + ns = receivedFromNs; + terrno = 0; + return static_cast(resplen); + } + + if (!needRetry) { + return 0; + } + } +} + +int nmd::get_addr_info::sendViaUdp(dns_res_state &statp, dns_res_params ¶ms, const uint8_t *buf, + const size_t buflen, uint8_t *ans, size_t anssiz, int &terrno, size_t &ns, bool &needTcp, int &gotsomewhere, + time_t &at, int &rcode, int &delay) +{ + if (ns >= statp.nsaddrs.size()) { + // common::logger::error() << "[get_addr_info] Unable to sendViaUdp: invalid param ns: " << ns + // << " nsaddr.size: " << statp.nsaddrs.size() << endl; + NETNATIVE_LOGE( + "[get_addr_info] Unable to sendViaUdp: invalid param ns: %{public}d nsaddr.size: %{public}d", ns, + statp.nsaddrs.size()); + terrno = EINVAL; + return -1; + } + + at = time(nullptr); + const sockaddr_storage ss = statp.nsaddrs[ns]; + const sockaddr *nsap = reinterpret_cast(&ss); + const socklen_t nsaplen = nmd::common::net_utils::sock_addr_utils::sockaddrSize(nsap); + + if (statp.nssocks[ns] == -1) { + int ret(0); + bool reset = resetNsSock(statp.nssocks[ns], SOCK_DGRAM | SOCK_CLOEXEC, nsap, terrno, ret); + if (!reset) { + return ret; + } + + if (statp.mark != MARK_UNSET) { + if (setsockopt(statp.nssocks[ns], SOL_SOCKET, SO_MARK, &(statp.mark), sizeof(statp.mark)) < 0) { + terrno = errno; + statp.closeSockets(); + return -1; + } + } + // Use a "connected" datagram socket to receive an ECONNREFUSED error + // on the next socket operation when the server responds with an + // ICMP port-unreachable error. This way we can detect the absence of + // a nameserver without timing out. + if (randomBind(statp.nssocks[ns], nsap->sa_family) < 0) { + terrno = errno; + statp.closeSockets(); + return 0; + } + + if (connect(statp.nssocks[ns], nsap, nsaplen) < 0) { + terrno = errno; + statp.closeSockets(); + return 0; + } + } + if (send(statp.nssocks[ns], buf, buflen, 0) != static_cast(buflen)) { + terrno = errno; + statp.closeSockets(); + return 0; + } + + return waitForReply(statp, params, buf, buflen, ans, anssiz, terrno, ns, needTcp, gotsomewhere, rcode, delay); +} +void nmd::get_addr_info::closeInvalidSock(dns_res_state &statp, const struct sockaddr *nsap) +{ + struct sockaddr_storage peer; + socklen_t size = sizeof(peer); + unsigned old_mark; + socklen_t mark_size = sizeof(old_mark); + if (getpeername(statp.tcpNsSock, reinterpret_cast(&peer), &size) < 0 || + !sockEq((reinterpret_cast(&peer)), nsap) || + getsockopt(statp.tcpNsSock, SOL_SOCKET, SO_MARK, &old_mark, &mark_size) < 0 || old_mark != statp.mark) { + statp.closeSockets(); + } +} + +int nmd::get_addr_info::sendViaTcp(dns_res_state &statp, dns_res_params ¶ms, const uint8_t *buf, + const size_t buflen, uint8_t *ans, size_t anssiz, int &terrno, const size_t ns, time_t &at, int &rcode, + int &delay) +{ + at = time(NULL); + delay = 0; + const HEADER *hp = reinterpret_cast(buf); + HEADER *anhp = reinterpret_cast
(ans); + + if (ns >= statp.nsaddrs.size()) { + // common::logger::error() << "[get_addr_info] Unable to sendViaTcp: invalid param ns: " << ns + // << " nsaddr.size: " << statp.nsaddrs.size() << endl; + NETNATIVE_LOGE( + "[get_addr_info] Unable to sendViaTcp: invalid param ns: %{public}d nsaddr.size: %{public}d", ns, + statp.nsaddrs.size()); + terrno = EINVAL; + return -1; + } + + sockaddr_storage ss = statp.nsaddrs[ns]; + struct sockaddr *nsap = reinterpret_cast(&ss); + auto nsaplen = nmd::common::net_utils::sock_addr_utils::sockaddrSize(nsap); + + bool connreset(false); +same_ns: + bool truncating(false); + + struct timespec start_time = evNowTime(); + + // Are we still talking to whom we want to talk to? + if (statp.tcpNsSock >= 0 && statp.isTcp) { + closeInvalidSock(statp, nsap); + } + + if (statp.tcpNsSock < 0 || !statp.isTcp) { + if (statp.tcpNsSock >= 0) { + statp.closeSockets(); + } + + int ret(0); + bool reset = resetNsSock(statp.tcpNsSock, SOCK_STREAM | SOCK_CLOEXEC, nsap, terrno, ret); + if (!reset) { + return ret; + } + + if (statp.mark != MARK_UNSET) { + if (setsockopt(statp.tcpNsSock, SOL_SOCKET, SO_MARK, &statp.mark, sizeof(statp.mark)) < 0) { + terrno = errno; + return -1; + } + } + errno = 0; + if (randomBind(statp.tcpNsSock, nsap->sa_family) < 0) { + terrno = errno; + statp.closeSockets(); + return 0; + } + + if (connect_with_timeout(statp.tcpNsSock, nsap, nsaplen, getTimeout(params)) < 0) { + terrno = errno; + statp.closeSockets(); + /* + * The way connect_with_timeout() is implemented prevents us from reliably + * determining whether this was really a timeout or e.g. ECONNREFUSED. Since + * currently both cases are handled in the same way, there is no need to + * change this (yet). If we ever need to reliably distinguish between these + * cases, both connect_with_timeout() and retrying_poll() need to be + * modified, though. + */ + rcode = RCODE_TIMEOUT; + return (0); + } + statp.isTcp = true; + } + + // Send length & message + uint16_t len = htons(static_cast(buflen)); + const iovec iov[] = { + {&len, INT16SZ}, + {const_cast(buf), static_cast(buflen)}, + }; + + if (writev(statp.tcpNsSock, iov, 2) != static_cast(INT16SZ + buflen)) { + terrno = errno; + statp.closeSockets(); + return 0; + } + + // Receive length & response +read_len: + uint8_t *cp = ans; + len = INT16SZ; + ssize_t n(0); + while ((n = read(statp.tcpNsSock, reinterpret_cast(cp), static_cast(len))) > 0) { + cp += n; + if ((len -= n) == 0) { + break; + } + } + if (n <= 0) { + terrno = errno; + statp.closeSockets(); + /* + * A long running process might get its TCP + * connection reset if the remote server was + * restarted. Requery the server instead of + * trying a new one. When there is only one + * server, this means that a query might work + * instead of failing. We only allow one reset + * per query to prevent looping. + */ + if (terrno == ECONNRESET && !connreset) { + connreset = true; + goto same_ns; + } + return (0); + } + uint16_t resplen = ntohs(*reinterpret_cast(ans)); + if (resplen > anssiz) { + truncating = true; + len = static_cast(anssiz); + } else { + len = resplen; + } + if (len < HFIXEDSZ) { + // Undersized message. + terrno = EMSGSIZE; + statp.closeSockets(); + return 0; + } + cp = ans; + while (len != 0 && (n = read(statp.tcpNsSock, reinterpret_cast(cp), static_cast(len))) > 0) { + cp += n; + len -= n; + } + + if (n <= 0) { + terrno = errno; + statp.closeSockets(); + return 0; + } + + if (truncating) { + // Flush rest of answer so connection stays in synch. + anhp->tc = 1; + len = static_cast(resplen - anssiz); + while (len != 0) { + char junk[PACKETSZ]; + + n = read(statp.tcpNsSock, junk, (len > sizeof junk) ? sizeof junk : len); + if (n > 0) { + len -= n; + } else { + break; + } + } + resplen = static_cast(anssiz); + } + /* + * If the calling application has bailed out of + * a previous call and failed to arrange to have + * the circuit closed or the server has got + * itself confused, then drop the packet and + * wait for the correct one. + */ + if (hp->id != anhp->id) { + goto read_len; + } + + /* + * All is well, or the error is fatal. Signal that the + * next nameserver ought not be tried. + */ + if (resplen > 0) { + struct timespec done = evNowTime(); + delay = calculateElapsedTime(done, start_time); + rcode = anhp->rcode; + } + terrno = 0; + return resplen; +} + +int nmd::get_addr_info::connect_with_timeout( + int sock, const sockaddr *nsap, socklen_t salen, const timespec timeout) +{ + int res(-1); + auto origflags = fcntl(sock, F_GETFL, 0); + + do { + fcntl(sock, F_SETFL, origflags | O_NONBLOCK); + res = connect(sock, nsap, salen); + if (res < 0 && errno != EINPROGRESS) { + res = -1; + break; + } + + if (res != 0) { + timespec now = evNowTime(); + timespec finish = evAddTime(now, timeout); + res = retryingPoll(sock, POLLIN | POLLOUT, finish); + if (res <= 0) { + res = -1; + } + } + + } while (false); + + fcntl(sock, F_SETFL, origflags); + return res; +} + +int nmd::get_addr_info::randomBind(const int s, const sa_family_t family) +{ + // clear all, this also sets the IP4/6 address to 'any' + sockaddr_union u; + memset(&u, 0, sizeof u); + + socklen_t slen(0); + switch (family) { + case AF_INET: + u.sin.sin_family = family; + slen = sizeof(u.sin); + break; + case AF_INET6: + u.sin6.sin6_family = family; + slen = sizeof(u.sin6); + break; + default: + errno = EPROTO; + return -1; + } + + std::random_device rd; // Will be used to obtain a seed for the random number engine + std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() + std::uniform_int_distribution<> distrib(1025, 65534); + for (uint8_t j = 0; j < 10; j++) { + // find a random port between 1025 .. 65534 + int port = distrib(gen); + if (family == AF_INET) { + u.sin.sin_port = htons(static_cast(port)); + } else { + u.sin6.sin6_port = htons(static_cast(port)); + } + + if (!bind(s, &u.sa, slen)) { + return 0; + } + } + + // nothing after 10 attempts, our network table is probably busy + // let the system decide which port is best + if (family == AF_INET) { + u.sin.sin_port = 0; + } else { + u.sin6.sin6_port = 0; + } + + return bind(s, &u.sa, slen); +} + +timespec nmd::get_addr_info::getTimeout(const dns_res_params ¶ms) +{ + auto timeout = params.baseTimeoutMsec == 0 ? RES_DEFAULT_TIMEOUT : params.baseTimeoutMsec; + if (timeout < 1) { + timeout = 1; + } + + struct timespec result = {}; + result.tv_sec = timeout; + result.tv_nsec = (timeout % 1000) * 1000000; + return result; +} + +timespec nmd::get_addr_info::evNowTime(void) +{ + struct timespec tsnow; + clock_gettime(CLOCK_REALTIME, &tsnow); + return tsnow; +} + +timespec nmd::get_addr_info::evAddTime(const timespec &addend1, const timespec &addend2) +{ + struct timespec x; + + x.tv_sec = addend1.tv_sec + addend2.tv_sec; + x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec; + if (x.tv_nsec >= BILLION) { + x.tv_sec++; + x.tv_nsec -= BILLION; + } + return x; +} +int nmd::get_addr_info::evCmpTime(const timespec &a, const timespec &b) +{ +#define SGN(x) ((x) < 0 ? (-1) : (x) > 0 ? (1) : (0)); + time_t s = a.tv_sec - b.tv_sec; + long n; + + if (s != 0) { + return SGN(s); + } + + n = a.tv_nsec - b.tv_nsec; + return SGN(n); +} + +timespec nmd::get_addr_info::evSubTime(const timespec &minuend, const timespec &subtrahend) +{ + struct timespec x; + + x.tv_sec = minuend.tv_sec - subtrahend.tv_sec; + if (minuend.tv_nsec >= subtrahend.tv_nsec) { + x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec; + } else { + x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec; + x.tv_sec--; + } + return x; +} + +timespec nmd::get_addr_info::evConsTime(const time_t sec, const long nsec) +{ + struct timespec x; + + x.tv_sec = sec; + x.tv_nsec = nsec; + return x; +} + +int nmd::get_addr_info::udpRetryingPollWrapper( + dns_res_state &statp, const size_t ns, const timespec &finish, std::vector &fdAvailable) +{ + int n = retryingPoll(statp.nssocks[ns], POLLIN, finish); + if (n <= 0) { + return errno; + } + fdAvailable.push_back(statp.nssocks[ns]); + return 0; +} + +int nmd::get_addr_info::retryingPoll(const int sock, const short events, const timespec &finish) +{ +retry: + timespec now = evNowTime(); + timespec timeout; + if (evCmpTime(finish, now) > 0) { + timeout = evSubTime(finish, now); + } else { + timeout = evConsTime(0L, 0L); + } + + struct pollfd fds = {}; + fds.fd = sock; + fds.events = events; + int n = ppoll(&fds, 1, &timeout, nullptr); + if (n == 0) { + errno = ETIMEDOUT; + return 0; + } + if (n < 0) { + if (errno == EINTR) { + goto retry; + } + return n; + } + if (fds.revents & (POLLIN | POLLOUT | POLLERR)) { + int error; + socklen_t len = sizeof(error); + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error) { + errno = error; + // common::logger::error() << "[get_addr_info] retryingPoll getsockopt failed. " << endl; + NETNATIVE_LOGI("[get_addr_info] retryingPoll getsockopt failed. "); + return -1; + } + } + // common::logger::info() << "[get_addr_info] retryingPoll returning. " << endl; + NETNATIVE_LOGI("[get_addr_info] retryingPoll returning. "); + return n; +} + +bool nmd::get_addr_info::isInvalidAnswer(dns_res_state &statp, const sockaddr_storage &from, const uint8_t *buf, + size_t buflen, uint8_t *ans, size_t anssiz, size_t &receivedFromNs) +{ + const HEADER *hp = reinterpret_cast(buf); + HEADER *anhp = reinterpret_cast
(ans); + if (hp->id != anhp->id) { + // response from old query, ignore it. + return true; + } + + int ret = lookupNameserverFromResNs(statp, reinterpret_cast(&from)); + if (ret < 0) { + // response from wrong server? ignore it. + return true; + } + receivedFromNs = static_cast(ret); + + if (!resQueriesMatch(buf, buf + buflen, ans, ans + anssiz)) { + // response contains wrong query? ignore it. + return true; + } + return false; +} + +// Looks up the nameserver address in res.nsaddrs[], returns the ns number if found, otherwise -1. +int nmd::get_addr_info::lookupNameserverFromResNs(dns_res_state &statp, const sockaddr *sa) +{ + int ns = 0; + if (AF_INET == sa->sa_family) { + const sockaddr_in *inp = reinterpret_cast(sa); + + const sockaddr_in *srv(nullptr); + for (const auto &ipsa : statp.nsaddrs) { + sockaddr_storage ss = ipsa; + srv = reinterpret_cast(&ss); + if (srv->sin_family == inp->sin_family && srv->sin_port == inp->sin_port && + (srv->sin_addr.s_addr == INADDR_ANY || srv->sin_addr.s_addr == inp->sin_addr.s_addr)) { + return ns; + } + ++ns; + } + } + + if (AF_INET6 == sa->sa_family) { + const sockaddr_in6 *in6p = reinterpret_cast(sa); + for (const auto &ipsa : statp.nsaddrs) { + sockaddr_storage ss = ipsa; + const sockaddr_in6 *srv6 = reinterpret_cast(&ss); + if (srv6->sin6_family == in6p->sin6_family && srv6->sin6_port == in6p->sin6_port && +#ifdef HAVE_SIN6_SCOPE_ID + (srv6->sin6_scope_id == 0 || srv6->sin6_scope_id == in6p->sin6_scope_id) && +#endif + (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) || + IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr))) { + return ns; + } + ++ns; + } + } + + return -1; +} + +bool nmd::get_addr_info::resQueriesMatch( + const uint8_t *buf1, const uint8_t *eom1, const uint8_t *buf2, const uint8_t *eom2) +{ + const uint8_t *cp = buf1 + HFIXEDSZ; + int qdcount = ntohs((reinterpret_cast(buf1))->qdcount); + + if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) { + return -1; + } + + /* + * Only header section present in replies to + * dynamic update packets. + */ + if (((reinterpret_cast(buf1))->opcode == ns_o_update) && + ((reinterpret_cast(buf2))->opcode == ns_o_update)) { + return true; + } + + if (qdcount != ntohs((reinterpret_cast(buf2))->qdcount)) + return (0); + while (qdcount-- > 0) { + char tname[MAXDNAME + 1]; + int n = dnExpand(buf1, eom1, cp, tname, sizeof tname); + if (n < 0) { + return false; + } + cp += n; + if (cp + 2 * INT16SZ > eom1) { + return false; + } + int ttype = ntohs(*reinterpret_cast(cp)); + cp += INT16SZ; + int tclass = ntohs(*reinterpret_cast(cp)); + cp += INT16SZ; + if (!findNameInQueryPacket(tname, ttype, tclass, buf2, eom2)) { + return false; + } + } + return true; +} + +bool nmd::get_addr_info::sockEq(const struct sockaddr *socka, const struct sockaddr *sockb) +{ + if (nullptr == socka || nullptr == sockb) { + return false; + } + + if (socka->sa_family != sockb->sa_family) { + return false; + } + + if (AF_INET == socka->sa_family) { + const struct sockaddr_in *a4 = reinterpret_cast(socka); + const struct sockaddr_in *b4 = reinterpret_cast(sockb); + return a4->sin_port == b4->sin_port && a4->sin_addr.s_addr == b4->sin_addr.s_addr; + } + + if (AF_INET6 == socka->sa_family) { + const struct sockaddr_in6 *a6 = reinterpret_cast(socka); + const struct sockaddr_in6 *b6 = reinterpret_cast(sockb); + return a6->sin6_port == b6->sin6_port && +#ifdef HAVE_SIN6_SCOPE_ID + a6->sin6_scope_id == b6->sin6_scope_id && +#endif + IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr); + } + return false; +} + +bool nmd::get_addr_info::findNameInQueryPacket( + const std::string &name, int type, int cl, const uint8_t *buf, const uint8_t *eom) +{ + const uint8_t *cp = buf + HFIXEDSZ; + int qdcount = ntohs((reinterpret_cast(buf))->qdcount); + + while (qdcount-- > 0) { + char tname[MAXDNAME + 1]; + int n = dnExpand(buf, eom, cp, tname, sizeof tname); + if (n < 0) { + return false; + } + cp += n; + if (cp + 2 * INT16SZ > eom) { + return false; + } + int ttype = ntohs(*reinterpret_cast(cp)); + cp += INT16SZ; + int tclass = ntohs(*reinterpret_cast(cp)); + cp += INT16SZ; + if (ttype == type && tclass == cl && ns_samename(tname, name.c_str()) == 1) { + return true; + } + } + return false; +} + +int nmd::get_addr_info::calculateElapsedTime(const timespec &t1, const timespec &t0) +{ + long ms0 = t0.tv_sec * 1000 + t0.tv_nsec / 1000000; + long ms1 = t1.tv_sec * 1000 + t1.tv_nsec / 1000000; + return static_cast(ms1 - ms0); +} +nmd::res_n_ok_func nmd::get_addr_info::getResNOkFunc(int qtype) +{ + switch (qtype) { + case T_A: + case T_AAAA: + case T_ANY: // use T_ANY only for T_A/T_AAAA lookup + return res_hnok; + break; + default: + return nullptr; + } +} + +addrinfo *nmd::get_addr_info::getAnswer(const std::vector &answer, size_t anslen, const char *qname, + int qtype, const struct addrinfo *pai, int &herrno) +{ + struct addrinfo sentinel = {}; + addrinfo *cur = &sentinel; + + char *canonname = nullptr; + const uint8_t *eom = answer.data() + anslen; + + res_n_ok_func pnameOk = getResNOkFunc(qtype); + if (nullptr == pnameOk) { + return nullptr; + } + + // find first satisfactory answer + const HEADER *hp = reinterpret_cast(answer.data()); + int ancount = ntohs(hp->ancount); + int qdcount = ntohs(hp->qdcount); + char hostbuf[8 * 1024] = {}; + char *bp = hostbuf; + char *ep = hostbuf + sizeof(hostbuf); + const uint8_t *cp = answer.data(); + BOUNDED_INCR(HFIXEDSZ); + if (qdcount != 1) { + herrno = NO_RECOVERY; + return (nullptr); + } + + int n = dnExpand(answer.data(), eom, cp, bp, static_cast(ep - bp)); + if ((n < 0) || !(*pnameOk)(bp)) { + herrno = NO_RECOVERY; + return (nullptr); + } + BOUNDED_INCR(n + QFIXEDSZ); + if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { + /* res_send() has already verified that the query name is the + * same as the one we sent; this just gets the expanded name + * (i.e., with the succeeding search-domain tacked on). + */ + n = static_cast(strlen(bp) + 1); /* for the \0 */ + if (n >= MAX_NAME_LEN) { + herrno = NO_RECOVERY; + return (nullptr); + } + canonname = bp; + bp += n; + // The qname can be abbreviated, but h_name is now absolute. + qname = canonname; + } + int haveanswer(0); + int had_error(0); + char tbuf[MAXDNAME] = {}; + while (ancount-- > 0 && cp < eom && !had_error) { + n = dnExpand(answer.data(), eom, cp, bp, static_cast(ep - bp)); + if ((n < 0) || !(*pnameOk)(bp)) { + had_error++; + continue; + } + cp += n; // name + BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); + int type = ntohs(*reinterpret_cast(cp)); + cp += INT16SZ; // type + int cl = ntohs(*reinterpret_cast(cp)); + cp += INT16SZ + INT32SZ; // class, TTL + n = ntohs(*reinterpret_cast(cp)); + cp += INT16SZ; // len + BOUNDS_CHECK(cp, n); + if (cl != C_IN) { + cp += n; + continue; + } + if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && type == T_CNAME) { + n = dnExpand(answer.data(), eom, cp, tbuf, sizeof tbuf); + if ((n < 0) || !(*pnameOk)(tbuf)) { + had_error++; + continue; + } + cp += n; + // Get canonical name. + n = static_cast(strlen(tbuf) + 1); // for the \0 + if (n > ep - bp || n >= MAX_NAME_LEN) { + had_error++; + continue; + } + strncpy(bp, tbuf, static_cast(ep - bp)); + canonname = bp; + bp += n; + continue; + } + if (qtype == T_ANY) { + if (!(type == T_A || type == T_AAAA)) { + cp += n; + continue; + } + } else if (type != qtype) { + cp += n; + continue; + } + switch (type) { + case T_A: + case T_AAAA: { + if (strcasecmp(canonname, bp) != 0) { + cp += n; + continue; + } + if (type == T_A && n != INADDRSZ) { + cp += n; + continue; + } + if (type == T_AAAA && n != IN6ADDRSZ) { + cp += n; + continue; + } + if (type == T_AAAA) { + struct in6_addr in6; + memcpy(&in6, cp, IN6ADDRSZ); + if (IN6_IS_ADDR_V4MAPPED(&in6)) { + cp += n; + continue; + } + } + if (!haveanswer) { + canonname = bp; + size_t nn = strlen(bp) + 1; // for the \0 + bp += nn; + } + + // don't overwrite pai + addrinfo ai = *pai; + ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; + const nmd::afd *afd = findAfd(ai.ai_family); + if (afd == nullptr) { + cp += n; + continue; + } + cur->ai_next = getAi(&ai, afd, reinterpret_cast(cp)); + if (cur->ai_next == nullptr) + had_error++; + while (cur && cur->ai_next) + cur = cur->ai_next; + cp += n; + } break; + default: + abort(); + } + if (!had_error) { + haveanswer++; + } + } + if (haveanswer) { + if (!canonname) { + getCanonName(pai, sentinel.ai_next, qname); + } else { + getCanonName(pai, sentinel.ai_next, canonname); + } + herrno = NETDB_SUCCESS; + return sentinel.ai_next; + } + + herrno = NO_RECOVERY; + return nullptr; +} + +int nmd::get_addr_info::dnExpand( + const uint8_t *msg, const uint8_t *eom, const uint8_t *src, char *dst, size_t dstsiz) +{ + int n = ns_name_uncompress(msg, eom, src, dst, dstsiz); + + if (n > 0 && dst[0] == '.') + dst[0] = '\0'; + return n; +} + +void nmd::get_addr_info::getResolvConfigFromCache(dns_res_state &statp) +{ + auto config = nmd::dnsresolv_cache::lookupResolvConfig(statp.netid); + if (nullptr == config) { + // common::logger::error() << "[dnsresolv_client] Unable to getResolvConfigFromCache. netid: " << statp.netid + // << endl; + NETNATIVE_LOGE("[dnsresolv_client] Unable to getResolvConfigFromCache. netid: %{public}d", statp.netid); + return; + } + statp.nsaddrs = config->nameserverSockAddrs; + statp.searchDomains = config->searchDomains; +} + +int nmd::get_addr_info::getaddrinfoNumeric( + const char *hostname, const char *servname, addrinfo hints, addrinfo **result) +{ + hints.ai_flags = AI_NUMERICHOST; + netd_net_context netcontext = {}; + netcontext.appNetId = NETID_UNSET; + netcontext.appMark = MARK_UNSET; + netcontext.dnsNetId = NETID_UNSET; + netcontext.dnsMark = MARK_UNSET; + netcontext.uid = NET_CONTEXT_INVALID_UID; + netcontext.pid = NET_CONTEXT_INVALID_PID; + return getaddrinfoFornetContext(hostname, servname, &hints, &netcontext, result); +} + +int nmd::get_addr_info::ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz, + const unsigned char **dnptrs, const unsigned char **lastdnptr) +{ + unsigned char tmp[NS_MAXCDNAME]; + + if (ns_name_pton(src, tmp, sizeof tmp) == -1) + return (-1); + return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr)); +} + +int nmd::get_addr_info::ns_name_pton(const char *src, unsigned char *dst, size_t dstsiz) +{ + return (ns_name_pton2(src, dst, dstsiz, NULL)); +} + +int nmd::get_addr_info::ns_name_pton2(const char *src, unsigned char *dst, size_t dstsiz, size_t *dstlen) +{ + unsigned char *label, *bp, *eom; + int c, n, escaped, e = 0; + char *cp; + + escaped = 0; + bp = dst; + eom = dst + dstsiz; + label = bp++; + + while ((c = *src++) != 0) { + if (escaped) { + if (c == '[') { /* start a bit string label */ + if ((cp = (char *)strchr(src, ']')) == NULL) { + errno = EINVAL; /* ??? */ + return (-1); + } + if ((e = encode_bitsring(&src, cp + 2, &label, &bp, eom)) != 0) { + errno = e; + return (-1); + } + escaped = 0; + label = bp++; + if ((c = *src++) == 0) + goto done; + else if (c != '.') { + errno = EINVAL; + return (-1); + } + continue; + } else if ((cp = (char *)strchr(digits, c)) != NULL) { + n = (int)(cp - digits) * 100; + if ((c = *src++) == 0 || (cp = (char *)strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (int)(cp - digits) * 10; + if ((c = *src++) == 0 || (cp = (char *)strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (int)(cp - digits); + if (n > 255) { + errno = EMSGSIZE; + return (-1); + } + c = n; + } + escaped = 0; + } else if (c == '\\') { + escaped = 1; + continue; + } else if (c == '.') { + c = (int)(bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + /* Fully qualified ? */ + if (*src == '\0') { + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = '\0'; + } + if ((bp - dst) > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + if (dstlen != NULL) + *dstlen = (bp - dst); + return (1); + } + if (c == 0 || *src == '.') { + errno = EMSGSIZE; + return (-1); + } + label = bp++; + continue; + } + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = (unsigned char)c; + } + c = (int)(bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } +done: + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = 0; + } + if ((bp - dst) > MAXCDNAME) { /* src too big */ + errno = EMSGSIZE; + return (-1); + } + if (dstlen != NULL) + *dstlen = (bp - dst); + return (0); +} + +int nmd::get_addr_info::ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom) +{ + const unsigned char *cp; + unsigned int n; + int l; + + cp = *ptrptr; + while (cp < eom && (n = *cp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + cp += n; + continue; + case NS_TYPE_ELT: /* EDNS0 extended label */ + if ((l = labellen(cp - 1)) < 0) { + errno = EMSGSIZE; /* XXX */ + return (-1); + } + cp += l; + continue; + case NS_CMPRSFLGS: /* indirection */ + cp++; + break; + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + break; + } + if (cp > eom) { + errno = EMSGSIZE; + return (-1); + } + *ptrptr = cp; + return (0); +} + +int nmd::get_addr_info::labellen(const unsigned char *lp) +{ + int bitlen; + unsigned char l = *lp; + + if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* should be avoided by the caller */ + return (-1); + } + + if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { + if (l == DNS_LABELTYPE_BITSTRING) { + if ((bitlen = *(lp + 1)) == 0) + bitlen = 256; + return ((bitlen + 7) / 8 + 1); + } + return (-1); /* unknwon ELT */ + } + return (l); +} + +int nmd::get_addr_info::encode_bitsring( + const char **bp, const char *end, unsigned char **labelp, unsigned char **dst, unsigned const char *eom) +{ + int afterslash = 0; + const char *cp = *bp; + unsigned char *tp; + char c; + const char *beg_blen; + char *end_blen = NULL; + int value = 0, count = 0, tbcount = 0, blen = 0; + + beg_blen = end_blen = NULL; + + /* a bitstring must contain at least 2 characters */ + if (end - cp < 2) + return (EINVAL); + + /* XXX: currently, only hex strings are supported */ + if (*cp++ != 'x') + return (EINVAL); + if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */ + return (EINVAL); + + for (tp = *dst + 1; cp < end && tp < eom; cp++) { + switch ((c = *cp)) { + case ']': /* end of the bitstring */ + if (afterslash) { + if (beg_blen == NULL) + return (EINVAL); + blen = (int)strtol(beg_blen, &end_blen, 10); + if (*end_blen != ']') + return (EINVAL); + } + if (count) + *tp++ = ((value << 4) & 0xff); + cp++; /* skip ']' */ + goto done; + case '/': + afterslash = 1; + break; + default: + if (afterslash) { + if (!isdigit(c & 0xff)) + return (EINVAL); + if (beg_blen == NULL) { + if (c == '0') { + /* blen never begings with 0 */ + return (EINVAL); + } + beg_blen = cp; + } + } else { + if (!isxdigit(c & 0xff)) + return (EINVAL); + value <<= 4; + value += digitvalue[(int)c]; + count += 4; + tbcount += 4; + if (tbcount > 256) + return (EINVAL); + if (count == 8) { + *tp++ = value; + count = 0; + } + } + break; + } + } +done: + if (cp >= end || tp >= eom) + return (EMSGSIZE); + + /* + * bit length validation: + * If a is present, the number of digits in the + * MUST be just sufficient to contain the number of bits specified + * by the . If there are insignificant bits in a final + * hexadecimal or octal digit, they MUST be zero. + * RFC 2673, Section 3.2. + */ + if (blen > 0) { + int traillen; + + if (((blen + 3) & ~3) != tbcount) + return (EINVAL); + traillen = tbcount - blen; /* between 0 and 3 */ + if (((value << (8 - traillen)) & 0xff) != 0) + return (EINVAL); + } else + blen = tbcount; + if (blen == 256) + blen = 0; + + /* encode the type and the significant bit fields */ + **labelp = DNS_LABELTYPE_BITSTRING; + **dst = blen; + + *bp = cp; + *dst = tp; + + return (0); +} + +int nmd::get_addr_info::ns_name_pack(const unsigned char *src, unsigned char *dst, int dstsiz, + const unsigned char **dnptrs, const unsigned char **lastdnptr) +{ + unsigned char *dstp; + const unsigned char **cpp, **lpp, *eob, *msg; + const unsigned char *srcp; + int n, l, first = 1; + + srcp = src; + dstp = dst; + eob = dstp + dstsiz; + lpp = cpp = NULL; + if (dnptrs != NULL) { + if ((msg = *dnptrs++) != NULL) { + for (cpp = dnptrs; *cpp != NULL; cpp++) + continue; + lpp = cpp; /* end of list to search */ + } + } else + msg = NULL; + + /* make sure the domain we are about to add is legal */ + l = 0; + do { + int l0; + + n = *srcp; + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + errno = EMSGSIZE; + return (-1); + } + if ((l0 = labellen(srcp)) < 0) { + errno = EINVAL; + return (-1); + } + l += l0 + 1; + if (l > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + srcp += l0 + 1; + } while (n != 0); + + /* from here on we need to reset compression pointer array on error */ + srcp = src; + do { + /* Look to see if we can use pointers. */ + n = *srcp; + if (n != 0 && msg != NULL) { + l = dn_find(srcp, msg, (const unsigned char *const *)dnptrs, (const unsigned char *const *)lpp); + if (l >= 0) { + if (dstp + 1 >= eob) { + goto cleanup; + } + *dstp++ = ((unsigned int)l >> 8) | NS_CMPRSFLGS; + *dstp++ = l % 256; + // _DIAGASSERT(__type_fit(int, dstp - dst)); + return (int)(dstp - dst); + } + /* Not found, save it. */ + if (lastdnptr != NULL && cpp < lastdnptr - 1 && (dstp - msg) < 0x4000 && first) { + *cpp++ = dstp; + *cpp = NULL; + first = 0; + } + } + /* copy label to buffer */ + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Should not happen. */ + goto cleanup; + } + n = labellen(srcp); + if (dstp + 1 + n >= eob) { + goto cleanup; + } + memcpy(dstp, srcp, (size_t)(n + 1)); + srcp += n + 1; + dstp += n + 1; + } while (n != 0); + + if (dstp > eob) { + cleanup: + if (msg != NULL) + *lpp = NULL; + errno = EMSGSIZE; + return (-1); + } + // _DIAGASSERT(__type_fit(int, dstp - dst)); + return (int)(dstp - dst); +} + +int nmd::get_addr_info::dn_find(const unsigned char *domain, const unsigned char *msg, + const unsigned char *const *dnptrs, const unsigned char *const *lastdnptr) +{ + const unsigned char *dn, *cp, *sp; + const unsigned char *const *cpp; + unsigned int n; + + for (cpp = dnptrs; cpp < lastdnptr; cpp++) { + sp = *cpp; + /* + * terminate search on: + * root label + * compression pointer + * unusable offset + */ + while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && (sp - msg) < 0x4000) { + dn = domain; + cp = sp; + while ((n = *cp++) != 0) { + /* + * check for indirection + */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + n = labellen(cp - 1); /* XXX */ + + if (n != *dn++) + goto next; + + for (; n > 0; n--) + if (mklower(*dn++) != mklower(*cp++)) + goto next; + /* Is next root for both ? */ + if (*dn == '\0' && *cp == '\0') { + // _DIAGASSERT(__type_fit(int, sp - msg)); + return (int)(sp - msg); + } + if (*dn) + continue; + goto next; + case NS_CMPRSFLGS: /* indirection */ + cp = msg + (((n & 0x3f) << 8) | *cp); + break; + + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + } + next:; + sp += *sp + 1; + } + } + errno = ENOENT; + return (-1); +} + +int nmd::get_addr_info::mklower(int ch) +{ + if (ch >= 0x41 && ch <= 0x5A) + return (ch + 0x20); + return (ch); +} + +int nmd::get_addr_info::ns_makecanon(const char *src, char *dst, size_t dstsize) +{ + size_t n = strlen(src); + + if (n + sizeof "." > dstsize) { /* Note: sizeof == 2 */ + errno = EMSGSIZE; + return (-1); + } + strcpy(dst, src); + while (n >= 1U && dst[n - 1] == '.') /* Ends in "." */ + if (n >= 2U && dst[n - 2] == '\\' && /* Ends in "\." */ + (n < 3U || dst[n - 3] != '\\')) /* But not "\\." */ + break; + else + dst[--n] = '\0'; + dst[n++] = '.'; + dst[n] = '\0'; + return (0); +} + +int nmd::get_addr_info::ns_samename(const char *a, const char *b) +{ + char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; + + if (ns_makecanon(a, ta, sizeof ta) < 0 || ns_makecanon(b, tb, sizeof tb) < 0) + return (-1); + if (strcasecmp(ta, tb) == 0) + return (1); + else + return (0); +} +} // namespace nmd +} // namespace OHOS +DISABLE_WARNING_POP \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/src/interface_controller.cpp b/http/services/netmanagernative/net_mgr_native/src/interface_controller.cpp new file mode 100644 index 000000000..2e8b2329b --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/interface_controller.cpp @@ -0,0 +1,359 @@ +#include "interface_controller.h" +#include "interface_utils.h" +#include "logger.h" +#include "error_code.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netnative_log_wrapper.h" + +DISABLE_WARNING_PUSH +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_OLD_STYLE_CAST +DISABLE_WARNING_CAST_ALIGN +DISABLE_WARNING_C99_EXTENSIONS + +#define IFNAMSIZ 16 +const char gSysNetPath[] = "/sys/class/net/"; +const char gProcNetPath[] = "/proc/sys/net/"; + +namespace OHOS { +namespace nmd { +interface_controller::interface_controller(/* args */) {} + +interface_controller::~interface_controller() {} + +bool isIfaceName(const std::string &name) +{ + size_t i; + if ((name.empty()) || (name.size() > IFNAMSIZ)) { + return false; + } + + /* First character must be alphanumeric */ + if (!isalnum(name[0])) { + return false; + } + + for (i = 1; i < name.size(); i++) { + if (!isalnum(name[i]) && (name[i] != '_') && (name[i] != '-') && (name[i] != ':') && (name[i] != '.')) { + return false; + } + } + + return true; +} + +int interface_controller::getMtu(const char *interfaceName) +{ + if (!isIfaceName(interfaceName)) { + std::error_code err = nmd::common::error_code::errNoInfName; + // LogError << err.message() << endl; + NETNATIVE_LOGE("interface_controller::getMtu isIfaceName fail %{public}s", err.message().c_str()); + return -1; + } + std::string setMtuPath = std::string(gSysNetPath).append(interfaceName).append("/mtu"); + int fd = open(setMtuPath.c_str(), 0, 0666); + if (fd == -1) { + // LogError << strerror(errno) << endl; + NETNATIVE_LOGE("interface_controller::getMtu open fail %{public}s", strerror(errno)); + return -1; + } + char originMtuValue[100] = {0}; + if (read(fd, originMtuValue, sizeof(int)) == -1) { + // LogError << strerror(errno) << endl; + NETNATIVE_LOGE("interface_controller::getMtu read fail %{public}s", strerror(errno)); + } + close(fd); + return atoi(originMtuValue); +} + +int interface_controller::setMtu(const char *interfaceName, const char *mtuValue) +{ + if (!isIfaceName(interfaceName)) { + std::error_code err = nmd::common::error_code::errNoInfName; + // LogError << err.message() << endl; + NETNATIVE_LOGE("interface_controller::setMtu isIfaceName fail %{public}s", err.message().c_str()); + return -1; + } + std::string setMtuPath = std::string(gSysNetPath).append(interfaceName).append("/mtu"); + int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC; + int fd = open(setMtuPath.c_str(), flags, 0666); + + if (fd == -1) { + // LogError << strerror(errno) << endl; + NETNATIVE_LOGE("interface_controller::setMtu open fail %{public}s", strerror(errno)); + return -1; + } + if (write(fd, mtuValue, strlen(mtuValue)) == -1) { + // LogError << strerror(errno) << endl; + NETNATIVE_LOGE("interface_controller::setMtu write fail %{public}s", strerror(errno)); + close(fd); + return -1; + } + close(fd); + return 0; +} + +std::vector interface_controller::getInterfaceNames() +{ + std::vector ifaceNames; + DIR *d(nullptr); + struct dirent *de(nullptr); + if (!(d = opendir(gSysNetPath))) { + std::error_code err = std::error_code(errno, std::system_category()); + // LogError << err.message() << endl; + NETNATIVE_LOGE("interface_controller::getInterfaceNames opendir fail %{public}s", err.message().c_str()); + return ifaceNames; + } + while ((de = readdir(d))) { + if ((de->d_type != DT_DIR) && (de->d_type != DT_LNK)) + continue; + if (de->d_name[0] == '.') + continue; + ifaceNames.push_back(std::string(de->d_name)); + } + closedir(d); + return ifaceNames; +} + +int interface_controller::clearAddrs(const std::string &ifName) +{ + nmd::common::interface_utils::ifcClearAddresses(ifName.c_str()); + return 0; +} + +int interface_controller::interfaceAddAddress( + const std::string &ifName, const std::string &addr, const int prefixLen) +{ + if (ifName.empty() || addr.empty() || prefixLen < 0) { + return -1; + } + + return nmd::common::interface_utils::ifcAddAddr(ifName.c_str(), addr.c_str(), prefixLen); +} + +int interface_controller::interfaceDelAddress( + const std::string &ifName, const std::string &addr, const int prefixLen) +{ + if (ifName.empty() || addr.empty() || prefixLen < 0) { + return -1; + } + + return nmd::common::interface_utils::ifcDelAddr(ifName.c_str(), addr.c_str(), prefixLen); +} + +inline bool isAddressFamilyPathComponent(const char *component) +{ + return strcmp(component, "ipv4") == 0 || strcmp(component, "ipv6") == 0; +} + +inline bool isNormalPathComponent(const char *component) +{ + return (strcmp(component, ".") != 0) && (strcmp(component, "..") != 0) && (strchr(component, '/') == nullptr); +} + +inline bool isInterfaceName(const char *name) +{ + return isNormalPathComponent(name) && (strcmp(name, "default") != 0) && (strcmp(name, "all") != 0); +} + +std::string getParameterPathname( + const char *family, const char *which, const char *interface, const char *parameter) +{ + if (!isAddressFamilyPathComponent(family)) { + errno = EAFNOSUPPORT; + return ""; + } else if (!isNormalPathComponent(which) || !isInterfaceName(interface) || !isNormalPathComponent(parameter)) { + errno = EINVAL; + return ""; + } + return std::string(gProcNetPath) + .append(family) + .append("/") + .append(which) + .append("/") + .append(interface) + .append("/") + .append(parameter); +} + +int interface_controller::setParameter( + const char *family, const char *which, const char *ifName, const char *parameter, const char *value) +{ + const std::string path(getParameterPathname(family, which, ifName, parameter)); + if (path.empty()) { + return -1; + } + int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC; + int fd = open(path.c_str(), flags, 0666); + + if (fd == -1) { + // LogError << strerror(errno) << endl; + NETNATIVE_LOGE("interface_controller::setParameter opendir fail %{public}s", strerror(errno)); + return -1; + } + if (write(fd, value, strlen(value)) == -1) { + // LogError << strerror(errno) << endl; + NETNATIVE_LOGE("interface_controller::setParameter write fail %{public}s", strerror(errno)); + close(fd); + return -1; + } + close(fd); + return 0; +} + +int interface_controller::getParameter( + const char *family, const char *which, const char *ifName, const char *parameter, std::string *value) +{ + const std::string path(getParameterPathname(family, which, ifName, parameter)); + if (path.empty()) { + return -1; + } + int fd = open(path.c_str(), 0, 0666); + + if (fd == -1) { + // LogError << strerror(errno) << endl; + NETNATIVE_LOGE("interface_controller::getParameter open fail %{public}s", strerror(errno)); + return -1; + } + char buf[100] = {0}; + if (read(fd, buf, sizeof(int)) == -1) { + // LogError << strerror(errno) << endl; + NETNATIVE_LOGE("interface_controller::getParameter read fail %{public}s", strerror(errno)); + close(fd); + return -1; + } + *value = buf; + close(fd); + return 0; +} + +int ipv4NetmaskToPrefixLength(in_addr_t mask) +{ + int prefixLength = 0; + uint32_t m = ntohl(mask); + while (m & (1 << 31)) { + prefixLength++; + m = m << 1; + } + return prefixLength; +} + +std::string hwAddrToStr(unsigned char *hwaddr) +{ + char buf[64] = {'\0'}; + sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); + return std::string(buf); +} + +interface_configuration_parcel interface_controller::getConfig(const std::string &ifName) +{ + struct in_addr addr = {}; + int prefixLength = 0; + unsigned char hwaddr[ETH_ALEN] = {}; + unsigned flags = 0; + nmd::interface_configuration_parcel cfgResult; + + int fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + + struct ifreq ifr = {}; + strcpy(ifr.ifr_name, ifName.c_str()); + + if (ioctl(fd, SIOCGIFADDR, &ifr) != -1) { + addr.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; + } + + if (ioctl(fd, SIOCGIFNETMASK, &ifr) != -1) { + prefixLength = ipv4NetmaskToPrefixLength(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr); + } + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1) { + flags = ifr.ifr_flags; + } + + if (ioctl(fd, SIOCGIFHWADDR, &ifr) != -1) { + memcpy((void *)hwaddr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); + } else { + // LogError << "Failed to retrieve HW addr for " << ifName << " (" << strerror(errno) << ")"; + NETNATIVE_LOGE("interface_controller::getConfig Failed to retrieve HW addr for %{public}s (%{public}s)", + ifName.c_str(), strerror(errno)); + } + + cfgResult.ifName = ifName; + cfgResult.hwAddr = hwAddrToStr(hwaddr); + cfgResult.ipv4Addr = std::string(inet_ntoa(addr)); + cfgResult.prefixLength = prefixLength; + cfgResult.flags.push_back(flags & IFF_UP ? "up" : "down"); + if (flags & IFF_BROADCAST) + cfgResult.flags.push_back("broadcast"); + if (flags & IFF_LOOPBACK) + cfgResult.flags.push_back("loopback"); + if (flags & IFF_POINTOPOINT) + cfgResult.flags.push_back("point-to-point"); + if (flags & IFF_RUNNING) + cfgResult.flags.push_back("running"); + if (flags & IFF_MULTICAST) + cfgResult.flags.push_back("multicast"); + + return cfgResult; +} + +int interface_controller::setConfig(const nmd::interface_configuration_parcel &cfg) +{ + int fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + struct ifreq ifr = { + .ifr_addr = {.sa_family = AF_INET}, // Clear the IPv4 address. + }; + strcpy(ifr.ifr_name, cfg.ifName.c_str()); + + // Make sure that clear IPv4 address before set flag + // SIOCGIFFLAGS might override ifr and caused clear IPv4 addr ioctl error + if (ioctl(fd, SIOCSIFADDR, &ifr) == -1) { + return -1; + } + + if (!cfg.flags.empty()) { + if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { + return -1; + } + uint16_t flags = ifr.ifr_flags; + for (const auto &flag : cfg.flags) { + if (flag == std::string("up")) { + ifr.ifr_flags = ifr.ifr_flags | IFF_UP; + } else if (flag == std::string("down")) { + ifr.ifr_flags = (ifr.ifr_flags & (~IFF_UP)); + } + } + + if (ifr.ifr_flags != flags) { + if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) { + return -1; + } + } + } + + if (interfaceAddAddress(cfg.ifName.c_str(), cfg.ipv4Addr.c_str(), cfg.prefixLength) == -1) { + // LogError << "Failed to add addr"; + NETNATIVE_LOGE("interface_controller::setConfig Failed to add addr"); + return -1; + } + return 1; +} + +} // namespace nmd +} // namespace OHOS +DISABLE_WARNING_POP \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/src/iptables_process.cpp b/http/services/netmanagernative/net_mgr_native/src/iptables_process.cpp new file mode 100644 index 000000000..f4fbf26d7 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/iptables_process.cpp @@ -0,0 +1,179 @@ +#include "iptables_process.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netnative_log_wrapper.h" + +static int MAX_RETRIES = 50; +static int POLL_TIMEOUT_MS = 100; +static constexpr size_t STDOUT_IDX = 0; +static constexpr char PING[] = "#PING\n"; +static constexpr size_t PING_SIZE = sizeof(PING) - 1; + +namespace OHOS { +namespace nmd { +iptables_process::iptables_process(/* args */) {} + +iptables_process::~iptables_process() {} + +iptables_process::iptables_process(pid_t pid, int in, int out, int err) + : pid_(pid), stdin_(in), stdout_(out), stderr_(err) +{} + +void iptables_process::terminate() +{ + int err = kill(this->pid_, SIGTERM); + if (err) { + NETNATIVE_LOGE( + "iptables_process::terminate [IpTablesRestore] terminate failed: %{public}s", strerror(errno)); + } +} + +bool iptables_process::waitForAck(std::string &output) +{ + bool receivedAck = false; + int timeout = 0; + while (!receivedAck && (timeout++ < MAX_RETRIES)) { + int numEvents = poll(this->pollFds_, 2, POLL_TIMEOUT_MS); + if (numEvents == -1) { + NETNATIVE_LOGE("iptables_process::waitForAck: [IpTablesRestore] poll failed:"); + return false; + } + if (numEvents == 0) { + continue; + } + char buffer[PIPE_BUF]; + for (size_t i = 0; i < 2; ++i) { + const struct pollfd &pollfd = this->pollFds_[i]; + if (pollfd.revents & POLLIN) { + ssize_t size; + do { + size = read(pollfd.fd, buffer, sizeof(buffer)); + + if (size == -1) { + if (errno != EAGAIN) { + NETNATIVE_LOGE( + "[IpTablesRestore] unable to read from descriptor: %{public}s", strerror(errno)); + } + break; + } + + if (i == STDOUT_IDX) { + output.append(buffer, static_cast(size)); + size_t pos = output.find(PING); + if (pos != std::string::npos) { + if (output.size() > pos + PING_SIZE) { + size_t extra = output.size() - (pos + PING_SIZE); + NETNATIVE_LOGE( + "[IpTablesRestore] %{public}d extra characters after iptables response: " + "%{public}s", + extra, output.substr(pos + PING_SIZE, 128).c_str()); + } + output.resize(pos); + receivedAck = true; + } + } else { + this->errBuf.append(buffer, static_cast(size)); + } + } while (size > 0); + } + if (pollfd.revents & POLLHUP) { + this->terminate(); + break; + } + } + } + return true; +} + +/*********************************************************************/ +struct data_test { + int stdin_pipe[2] = {}; + int stdout_pipe[2] = {}; + int stderr_pipe[2] = {}; +}; + +static std::shared_ptr pProcess = nullptr; +std::shared_ptr publicProcess = NULL; + +static pthread_mutex_t test_lock; + +data_test data; + +static void *Test_Function(void *tmp) +{ + NETNATIVE_LOGI("[IpTablesRestore] iptables_restore starting..."); + if (dup2(data.stdin_pipe[0], 0) == -1 || dup2(data.stdout_pipe[1], 1) == -1 || + dup2(data.stderr_pipe[1], 2) == -1) { + NETNATIVE_LOGE("[IpTablesRestore] iptables_restore command execute failed"); + } + // char *argv[] = {const_cast("iptables-restore"), const_cast("--noflush"),const_cast("-v"), NULL}; if (execvp("iptables-restore", argv) == -1) { NETNATIVE_LOGE("[IpTablesRestore] + //iptables_restore command execute failed."); + //} + NETNATIVE_LOGI("[IpTablesRestore] iptables_restore running... "); + + if (close(data.stdin_pipe[0]) == -1 || close(data.stdout_pipe[1]) == -1 || close(data.stderr_pipe[1]) == -1) { + // LogError (0, data->stdin_pipe[1], data->stdout_pipe[0], + // data->st< "[IpTablesRestore] close unusing fds in pipe failed." << endl; + NETNATIVE_LOGE("[IpTablesRestore] close unusing fds in pipe failed."); + } + pthread_mutex_lock(&test_lock); + // std::make_shared(0, data->stdin_pipe[1], data->stdout_pipe[0], data->stderr_pipe[0]); + pProcess = + std::make_shared(0, data.stdin_pipe[1], data.stdout_pipe[0], data.stderr_pipe[0]); + pthread_mutex_unlock(&test_lock); + return NULL; +} + +std::shared_ptr nmd::iptables_process::forkAndExecute() +{ + // int stdin_pipe[2] = {}; + // int stdout_pipe[2] = {}; + // int stderr_pipe[2] = {}; + + if (pipe2(data.stdin_pipe, O_CLOEXEC) == -1 || pipe2(data.stdout_pipe, O_CLOEXEC | O_NONBLOCK) == -1 || + pipe2(data.stderr_pipe, O_CLOEXEC | O_NONBLOCK) == -1) { + NETNATIVE_LOGE("[IpTablesRestore] pipe create failed."); + } + + pthread_t thread_test; + pthread_create(&thread_test, NULL, Test_Function, NULL); + + pthread_mutex_lock(&test_lock); + publicProcess = pProcess; + pthread_mutex_unlock(&test_lock); + return publicProcess; + + /* + if (fork() == 0) { + common::logger::info() << "[IpTablesRestore] iptables_restore starting..." << endl; + if (dup2(stdin_pipe[0], 0) == -1 || dup2(stdout_pipe[1], 1) == -1 || dup2(stderr_pipe[1], 2) == -1) { + LogError << "[IpTablesRestore] iptables_restore command execute failed" << endl; + } + char *argv[] = {const_cast("iptables-restore"), const_cast("--noflush"), + const_cast("-v"), NULL}; + if (execvp("iptables-restore", argv) == -1) { + LogError << "[IpTablesRestore] iptables_restore command execute failed," << strerror(errno) << endl; + } + common::logger::info() << "[IpTablesRestore] iptables_restore running... " << endl; + return nullptr; + } + + if (close(stdin_pipe[0]) == -1 || close(stdout_pipe[1]) == -1 || close(stderr_pipe[1]) == -1) { + LogError << "[IpTablesRestore] close unusing fds in pipe failed." << endl; + } + + return std::make_shared(0, stdin_pipe[1], stdout_pipe[0], stderr_pipe[0]); + */ +} +} // namespace nmd +} // namespace OHOS diff --git a/http/services/netmanagernative/net_mgr_native/src/native_netd_service.cpp b/http/services/netmanagernative/net_mgr_native/src/native_netd_service.cpp new file mode 100644 index 000000000..c9d1110e6 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/native_netd_service.cpp @@ -0,0 +1,332 @@ +#include "native_netd_service.h" +#include "interface_controller.h" +//#include "logger.h" +//#include "error_code.h" +#include "netlink_manager.h" +#include "network_controller.h" +#include "route_controller.h" +#include "traffic_controller.h" +#include "interface_controller.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netnative_log_wrapper.h" + +std::vector OHOS::nmd::NativeNetdService::interfaceIdex_; + +namespace OHOS { +namespace nmd { + +NativeNetdService::NativeNetdService(/* args */) + : networkController_(std::make_shared()), + routeController_(std::make_shared()), + interfaceController_(std::make_shared()) +{} + +NativeNetdService::~NativeNetdService() {} + +void NativeNetdService::initChildChains() +{ + NETNATIVE_LOGD("nmd::NativeNetdService::initChildChains()"); + + route_controller::createChildChains("mangle", "INPUT", "routectrl_mangle_INPUT"); + route_controller::createChildChains("filter", "FORWARD", "TETHER_TRAFFIC"); +} + +void NativeNetdService::initUnixSocket() +{ + NETNATIVE_LOGD("nmd::NativeNetdService::initUnixSocket()"); + static const char *filePath = "/dev/socket"; + if ((common::utils::removeDirectory(filePath) == -2) || (mkdir(filePath, 0643) == -1)) { + NETNATIVE_LOGD("[Socket] Unable to remove dir: '%{public}s' %{public}s", filePath, strerror(errno)); + exit(-1); + } +} + +void NativeNetdService::getOriginInterfaceIdex() +{ + NETNATIVE_LOGD("nmd::NativeNetdService::getOriginInterfaceIdex()"); + std::vector ifNameList = interface_controller::getInterfaceNames(); + NativeNetdService::interfaceIdex_.clear(); + for (auto iter = ifNameList.begin(); iter != ifNameList.end(); ++iter) { + unsigned int infIndex = if_nametoindex((*iter).c_str()); + NativeNetdService::interfaceIdex_.push_back(infIndex); + } +} + +void NativeNetdService::updateInterfaceIdex(unsigned int infIndex) +{ + NativeNetdService::interfaceIdex_.push_back(infIndex); +} + +std::vector NativeNetdService::getCurrentInterfaceIdex() +{ + return NativeNetdService::interfaceIdex_; +} + +void NativeNetdService::init() +{ + NETNATIVE_LOGD("nmd::NativeNetdService::init()"); + this->initChildChains(); + this->initUnixSocket(); + this->getOriginInterfaceIdex(); +} + +int NativeNetdService::networkCreatePhysical(int netId, int permission) +{ + return this->networkController_->createPhysicalNetwork( + static_cast(netId), static_cast(permission)); +} + +int NativeNetdService::networkDestroy(int netId) +{ + return this->networkController_->destroyNetwork(netId); +} + +int NativeNetdService::networkAddInterface(int netId, std::string interfaceName) +{ + return this->networkController_->addInterfaceToNetwork(netId, interfaceName); +} + +int NativeNetdService::networkRemoveInterface(int netId, std::string interfaceName) +{ + return this->networkController_->removeInterfaceFromNetwork(netId, interfaceName); +} + +void NativeNetdService::socketDestroy(std::string ifName) +{ + sock_diag dg; + if (dg.open()) { + dg.destroySockets(ifName); + } +} + +void NativeNetdService::socketDestroy(int netId) +{ + nmd::network *nw = this->networkController_->getNetwork(netId); + if (nw != nullptr) { + sock_diag dg; + if (dg.open()) { + for (std::string ifName : nw->getAllInterface()) { + dg.destroySockets(ifName); + } + } + } +} + +int NativeNetdService::interfaceAddAddress(std::string ifName, std::string addrString, int prefixLength) +{ + return nmd::interface_controller::interfaceAddAddress(ifName, addrString, prefixLength); +} + +int NativeNetdService::interfaceDelAddress(std::string ifName, std::string addrString, int prefixLength) +{ + return nmd::interface_controller::interfaceDelAddress(ifName, addrString, prefixLength); +} + +int NativeNetdService::networkAddRoute( + int netId, std::string interfaceName, std::string destination, std::string nextHop) +{ + return this->networkController_->addRoute(netId, interfaceName, destination, nextHop); +} + +int NativeNetdService::networkRemoveRoute( + int netId, std::string interfaceName, std::string destination, std::string nextHop) +{ + return this->networkController_->removeRoute(netId, interfaceName, destination, nextHop); +} + +int NativeNetdService::networkGetDefault() +{ + return this->networkController_->getDefaultNetwork(); +} + +int NativeNetdService::networkSetDefault(int netId) +{ + return this->networkController_->setDefaultNetwork(netId); +} + +int NativeNetdService::networkClearDefault() +{ + return this->networkController_->clearDefaultNetwork(); +} + +int NativeNetdService::networkSetPermissionForNetwork(int netId, NetworkPermission permission) +{ + return this->networkController_->setPermissionForNetwork(netId, permission); +} + +std::vector NativeNetdService::interfaceGetList() +{ + return interface_controller::getInterfaceNames(); +} + +nmd::interface_configuration_parcel NativeNetdService::interfaceGetConfig(std::string interfaceName) +{ + return interface_controller::getConfig(interfaceName.c_str()); +} + +void NativeNetdService::interfaceSetConfig(nmd::interface_configuration_parcel parcel) +{ + interface_controller::setConfig(parcel); +} + +void NativeNetdService::interfaceClearAddrs(const std::string ifName) +{ + interface_controller::clearAddrs(ifName.c_str()); +} + +int NativeNetdService::interfaceGetMtu(std::string ifName) +{ + return interface_controller::getMtu(ifName.c_str()); +} + +int NativeNetdService::interfaceSetMtu(std::string ifName, int mtuValue) +{ + std::string mtu = std::to_string(mtuValue); + return interface_controller::setMtu(ifName.c_str(), mtu.c_str()); +} + +void NativeNetdService::registerUnsolicitedEventListener(nmd::inetd_unsolicited_event_listener listener) +{ + nmd::netlink_manager::getReporter()->registerEventListener(listener); +} + +nmd::mark_mask_parcel NativeNetdService::getFwmarkForNetwork(int netId) +{ + nmd::mark_mask_parcel mark; + mark.mark = this->networkController_->getFwmarkForNetwork(netId); + mark.mask = 0XFFFF; + return mark; +} + +void NativeNetdService::networkAddRouteParcel(int netId, route_info_parcel parcel) +{ + this->networkController_->addRoute(netId, parcel.ifName, parcel.destination, parcel.nextHop); +} + +void NativeNetdService::networkRemoveRouteParcel(int netId, route_info_parcel parcel) +{ + this->networkController_->removeRoute(netId, parcel.ifName, parcel.destination, parcel.nextHop); +} + +std::tuple getPathComponents(int32_t ipversion, int which) +{ + const char *ipversionStr = nullptr; + switch (ipversion) { + case nmd::set_proc_sys_net::IPV4: + ipversionStr = "ipv4"; + break; + case nmd::set_proc_sys_net::IPV6: + ipversionStr = "ipv6"; + break; + default: + return {"Bad Ip address", ""}; + } + const char *whichStr = nullptr; + switch (which) { + case nmd::set_proc_sys_net::CONF: + whichStr = "conf"; + break; + case nmd::set_proc_sys_net::NEIGH: + whichStr = "neigh"; + break; + default: + return {"", "Bad which"}; + } + return {ipversionStr, whichStr}; +} + +int NativeNetdService::setProcSysNet(int32_t ipversion, int32_t which, const std::string ifname, + const std::string parameter, const std::string value) +{ + const auto pathParts = getPathComponents(ipversion, which); + if (std::string(std::get<0>(pathParts)) == std::string("Bad Ip address") || + std::string(std::get<1>(pathParts)) == std::string("Bad which")) { + return -1; + } + return nmd::interface_controller::setParameter( + std::get<0>(pathParts), std::get<1>(pathParts), ifname.c_str(), parameter.c_str(), value.c_str()); +} + +int NativeNetdService::getProcSysNet( + int32_t ipversion, int32_t which, const std::string ifname, const std::string parameter, std::string *value) +{ + const auto pathParts = getPathComponents(ipversion, which); + if (std::string(std::get<0>(pathParts)) == std::string("Bad Ip address") || + std::string(std::get<1>(pathParts)) == std::string("Bad which")) { + return -1; + } + return nmd::interface_controller::getParameter( + std::get<0>(pathParts), std::get<1>(pathParts), ifname.c_str(), parameter.c_str(), value); +} + +long NativeNetdService::getCellularRxBytes() +{ + return nmd::traffic_controller::getCellularRxTraffic(); +} + +long NativeNetdService::getCellularTxBytes() +{ + return nmd::traffic_controller::getCellularTxTraffic(); +} + +long NativeNetdService::getAllRxBytes() +{ + return nmd::traffic_controller::getAllRxTraffic(); +} + +long NativeNetdService::getAllTxBytes() +{ + return nmd::traffic_controller::getAllTxTraffic(); +} + +long NativeNetdService::getUidTxBytes(int uid) +{ + return nmd::traffic_controller::getTxUidTraffic(uid); +} + +long NativeNetdService::getUidRxBytes(int uid) +{ + return nmd::traffic_controller::getRxUidTraffic(uid); +} + +nmd::traffic_stats_parcel NativeNetdService::interfaceGetStats(std::string ifName) +{ + return nmd::traffic_controller::getInterfaceTraffic(ifName); +} + +long NativeNetdService::getIfaceRxBytes(std::string interfaceName) +{ + nmd::traffic_stats_parcel interfaceTraffic = nmd::traffic_controller::getInterfaceTraffic(interfaceName); + return interfaceTraffic.rxBytes; +} + +long NativeNetdService::getIfaceTxBytes(std::string interfaceName) +{ + nmd::traffic_stats_parcel interfaceTraffic = nmd::traffic_controller::getInterfaceTraffic(interfaceName); + return interfaceTraffic.txBytes; +} + +long NativeNetdService::getTetherRxBytes() +{ + return nmd::traffic_controller::getRxTetherTraffic(); +} + +long NativeNetdService::getTetherTxBytes() +{ + return nmd::traffic_controller::getTxTetherTraffic(); +} + +} // namespace nmd +} // namespace OHOS diff --git a/http/services/netmanagernative/net_mgr_native/src/netlink_event.cpp b/http/services/netmanagernative/net_mgr_native/src/netlink_event.cpp new file mode 100644 index 000000000..1da4ffd65 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/netlink_event.cpp @@ -0,0 +1,344 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "native_netd_service.h" +#include "netnative_log_wrapper.h" + +DISABLE_WARNING_PUSH +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_IMPLICIT_INT_CONVERSION +DISABLE_WARNING_SHORTEN_64_TO_32 +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_SIGN_COMPARE +DISABLE_WARNING_OLD_STYLE_CAST +DISABLE_WARNING_CAST_ALIGN +DISABLE_WARNING_SIGN_CONVERSION + +namespace OHOS { +namespace nmd { +netlink_event::~netlink_event() {} + +const char *netlink_event::rtMessageName(int type) +{ + switch (type) { + case RTM_NEWLINK: + return "RTM_NEWLINK"; + case RTM_DELLINK: + return "RTM_DELLINK"; + case RTM_NEWADDR: + return "RTM_NEWADDR"; + case RTM_DELADDR: + return "RTM_DELADDR"; + case RTM_NEWROUTE: + return "RTM_NEWROUTE"; + case RTM_DELROUTE: + return "RTM_DELROUTE"; + case RTM_NEWRULE: + return "RTM_NEWRULE"; + case RTM_DELRULE: + return "RTM_DELRULE"; + case RTM_NEWNDUSEROPT: + return "RTM_NEWNDUSEROPT"; + default: + return nullptr; + } +} + +bool netlink_event::parseInterfaceInfoInfoMessage(struct nlmsghdr *hdr) +{ + struct ifinfomsg *interfaceInfo = (struct ifinfomsg *)NLMSG_DATA(hdr); + struct rtattr *rta; + + if (hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*interfaceInfo))) { + return false; + } + + std::vector currentInterfaceList = NativeNetdService::getCurrentInterfaceIdex(); + char name[32] = {'\0'}; + if_indextoname(interfaceInfo->ifi_index, name); + switch (hdr->nlmsg_type) { + case RTM_NEWLINK: + for (size_t i = 0; i < currentInterfaceList.size(); i++) { + if (currentInterfaceList[i] == interfaceInfo->ifi_index) { + goto LINK_CHANGE; + } + } + this->params_.insert(std::pair("INTERFACE", name)); + this->action_ = Action::Add; + NativeNetdService::updateInterfaceIdex(interfaceInfo->ifi_index); + return true; + case RTM_DELLINK: + this->params_.insert(std::pair("INTERFACE", name)); + this->action_ = Action::Remove; + return true; + } +LINK_CHANGE: + int len = IFLA_PAYLOAD(hdr); + for (rta = IFLA_RTA(interfaceInfo); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { + switch (rta->rta_type) { + case IFLA_IFNAME: + this->params_.insert( + std::pair("INTERFACE", std::string((char *)RTA_DATA(rta)))); + this->params_.insert( + std::pair("IFINDEX", std::to_string(interfaceInfo->ifi_index))); + this->action_ = (interfaceInfo->ifi_flags & /*IFF_LOWER_UP*/ 1 << 16) ? Action::LinkUp : + Action::LinkDown; + return true; + } + } + return false; +} + +bool netlink_event::parseInterafaceAddressMessage(struct nlmsghdr *hdr) +{ + struct ifaddrmsg *interfaceAddress = (struct ifaddrmsg *)NLMSG_DATA(hdr); + struct ifa_cacheinfo *cacheinfo = nullptr; + char ifname[IFNAMSIZ] = ""; + char addrstr[46] = ""; + uint32_t flags; + + if (hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*interfaceAddress))) { + return false; + } + + uint8_t type = hdr->nlmsg_type; + if ((type != RTM_NEWADDR) && (type != RTM_DELADDR)) { + return false; + } + + const char *msgtype = rtMessageName(type); + struct rtattr *rta; + int len = IFA_PAYLOAD(hdr); + for (rta = IFA_RTA(interfaceAddress); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { + if (rta->rta_type == IFA_ADDRESS) { + if (interfaceAddress->ifa_family == AF_INET) { + struct in_addr *addr4 = (struct in_addr *)RTA_DATA(rta); + if (RTA_PAYLOAD(rta) < sizeof(*addr4)) { + NETNATIVE_LOGD("[NetlinkEvent] Short IPv4 address (%{public}d bytes) in %{public}s", + RTA_PAYLOAD(rta), msgtype); + // LogError << "[NetlinkEvent] Short IPv4 address (" << RTA_PAYLOAD(rta) << " bytes) in " + // << msgtype << endl; + continue; + } + inet_ntop(AF_INET, addr4, addrstr, sizeof(addrstr)); + } else if (interfaceAddress->ifa_family == AF_INET6) { + struct in6_addr *addr6 = (struct in6_addr *)RTA_DATA(rta); + if (RTA_PAYLOAD(rta) < sizeof(*addr6)) { + NETNATIVE_LOGD("[NetlinkEvent] Short IPv6 address (%{public}d bytes) in %{public}s", + RTA_PAYLOAD(rta), msgtype); + // LogError << "[NetlinkEvent] Short IPv6 address (" << RTA_PAYLOAD(rta) << " bytes) in " + // << msgtype << endl; + continue; + } + inet_ntop(AF_INET6, addr6, addrstr, sizeof(addrstr)); + } else { + NETNATIVE_LOGD("[NetlinkEvent] Unknown address family %{public}d", interfaceAddress->ifa_family); + // LogError << "[NetlinkEvent] Unknown address family " << interfaceAddress->ifa_family << endl; + continue; + } + + if (!if_indextoname(interfaceAddress->ifa_index, ifname)) { + NETNATIVE_LOGD("[NetlinkEvent] Unknown ifindex %{public}d in %{public}s", + interfaceAddress->ifa_index, msgtype); + // LogError << "[NetlinkEvent] Unknown ifindex " << interfaceAddress->ifa_index << " in " << msgtype + // << endl; + } + } else if (rta->rta_type == IFA_CACHEINFO) { + if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) { + NETNATIVE_LOGD( + "[NetlinkEvent] Short IFA_CACHEINFO (%{public}d vs. %{public}d bytes) in %{public}s", + RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype); + // LogError << "[NetlinkEvent] Short IFA_CACHEINFO (" << RTA_PAYLOAD(rta) << " vs." + // << sizeof(cacheinfo) << " bytes) in " << msgtype << endl; + continue; + } + cacheinfo = (struct ifa_cacheinfo *)RTA_DATA(rta); + } else if (rta->rta_type == IFA_FLAGS) { + flags = *(uint32_t *)RTA_DATA(rta); + } + } + + this->action_ = (type == RTM_NEWADDR) ? Action::AddressUpdated : Action::AddressRemoved; + char *tmpBuf[1]; + asprintf(tmpBuf, "%s/%d", addrstr, interfaceAddress->ifa_prefixlen); + this->params_.insert(std::pair("ADDRESS", std::string(tmpBuf[0]))); + this->params_.insert(std::pair("INTERFACE", ifname)); + this->params_.insert(std::pair("FLAGS", std::to_string(flags))); + this->params_.insert(std::pair("SCOPE", std::to_string(interfaceAddress->ifa_scope))); + this->params_.insert( + std::pair("IFINDEX", std::to_string(interfaceAddress->ifa_index))); + + if (cacheinfo) { + this->params_.insert( + std::pair("PREFERRED", std::to_string(cacheinfo->ifa_prefered))); + this->params_.insert(std::pair("VALID", std::to_string(cacheinfo->ifa_valid))); + this->params_.insert(std::pair("CSTAMP", std::to_string(cacheinfo->cstamp))); + this->params_.insert(std::pair("TSTAMP", std::to_string(cacheinfo->tstamp))); + } + free(tmpBuf[0]); + return true; +} + +bool netlink_event::parseRuleMessage(struct nlmsghdr *hdr) +{ + uint8_t type = hdr->nlmsg_type; + const char *msgname = rtMessageName(type); + + if (type != RTM_NEWRULE && type != RTM_DELRULE) { + NETNATIVE_LOGD("[NetLinkEvent] incorrect message type %{public}d : %{public}s", type, msgname); + // LogError << "[NetLinkEvent] incorrect message type " << type << ":" << msgname << endl; + return false; + } + this->action_ = type == RTM_NEWRULE ? Action::NewRule : Action::DelRule; + return true; +} + +bool netlink_event::parseRouteMessage(struct nlmsghdr *hdr) +{ + uint8_t type = hdr->nlmsg_type; + const char *msgname = rtMessageName(type); + + if (type != RTM_NEWROUTE && type != RTM_DELROUTE) { + NETNATIVE_LOGD("[NetLinkEvent] incorrect message type %{public}d : %{public}s", type, msgname); + // LogError << "[NetLinkEvent] incorrect message type " << type << ":" << msgname << endl; + return false; + } + + struct rtmsg *rtm = (struct rtmsg *)NLMSG_DATA(hdr); + if (hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*rtm))) { + NETNATIVE_LOGD("[NetLinkEvent] nl less than rt"); + // LogError << "[NetLinkEvent] nl less than rt" << endl; + return false; + } + + int family = rtm->rtm_family; + int prefixLength = rtm->rtm_dst_len; + + // Currently we only support: destination, (one) next hop, ifindex. + char dst[INET6_ADDRSTRLEN] = ""; + char gw[INET6_ADDRSTRLEN] = ""; + char dev[IFNAMSIZ] = ""; + + size_t len = RTM_PAYLOAD(hdr); + struct rtattr *rta; + for (rta = RTM_RTA(rtm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { + switch (rta->rta_type) { + case RTA_DST: + if (!inet_ntop(family, RTA_DATA(rta), dst, sizeof(dst))) { + return false; + } + continue; + case RTA_GATEWAY: + if (!inet_ntop(family, RTA_DATA(rta), gw, sizeof(gw))) { + return false; + } + continue; + case RTA_OIF: + if (!if_indextoname(*(int *)RTA_DATA(rta), dev)) { + return false; + } + continue; + default: + continue; + } + } + + // If there's no RTA_DST attribute, then: + // - If the prefix length is zero, it's the default route. + // - If the prefix length is nonzero, there's something we don't understand. + // Ignore the event. + if (!*dst && !prefixLength) { + if (family == AF_INET) { + strncpy(dst, "0.0.0.0", sizeof(dst)); + } else if (family == AF_INET6) { + strncpy(dst, "::", sizeof(dst)); + } + } + + if (!*dst || (!*gw && !*dev)) { + return false; + } + + this->action_ = (type == RTM_NEWROUTE) ? Action::RouteUpdated : Action::RouteRemoved; + + char *tmpBuf[1]; + asprintf(tmpBuf, "%s/%d", dst, prefixLength); + this->params_.insert(std::pair("ROUTE", std::string(tmpBuf[0]))); + this->params_.insert(std::pair("GATEWAY", std::string((*gw) ? gw : ""))); + this->params_.insert(std::pair("INTERFACE", std::string((*dev) ? dev : ""))); + free(tmpBuf[0]); + return true; +} + +bool netlink_event::parseNetLinkMessage(char *buffer, ssize_t size) +{ + struct nlmsghdr *nh; + for (nh = (struct nlmsghdr *)buffer; NLMSG_OK(nh, (unsigned)size) && (nh->nlmsg_type != NLMSG_DONE); + nh = NLMSG_NEXT(nh, size)) { + const char *msgname = rtMessageName(nh->nlmsg_type); + if (!msgname) { + NETNATIVE_LOGD("[NetlinkEvent] Unexpected netlink message type : %{public}d", nh->nlmsg_type); + // LogError << "[NetlinkEvent] Unexpected netlink message type :" << nh->nlmsg_type << endl; + continue; + } + // common::logger::info() << "[NetlinkEvent] got message: " << msgname << endl; + NETNATIVE_LOGI("[NetlinkEvent] got message: %{public}s", msgname); + + if (nh->nlmsg_type == RTM_NEWLINK || nh->nlmsg_type == RTM_DELLINK) { + if (parseInterfaceInfoInfoMessage(nh)) { + return true; + } + } else if (nh->nlmsg_type == RTM_NEWADDR || nh->nlmsg_type == RTM_DELADDR) { + if (parseInterafaceAddressMessage(nh)) { + return true; + } + } else if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE) { + if (parseRouteMessage(nh)) { + return true; + } + } else if (nh->nlmsg_type == RTM_NEWRULE || nh->nlmsg_type == RTM_DELRULE) { + if (parseRuleMessage(nh)) { + return true; + } + } else { + NETNATIVE_LOGI("[NetlinkEvent] can not parse message type: %{public}s", msgname); + // common::logger::info() << "[NetlinkEvent] can not parse message type: " << msgname << endl; + } + } + return false; +} + +const char *netlink_event::findParam(const char *key) +{ + std::map::iterator it; + if ((it = this->params_.find(std::string(key))) != this->params_.end()) { + return it->second.data(); + } + return ""; +} + +} // namespace nmd +} // namespace OHOS +DISABLE_WARNING_POP diff --git a/http/services/netmanagernative/net_mgr_native/src/netlink_handler.cpp b/http/services/netmanagernative/net_mgr_native/src/netlink_handler.cpp new file mode 100644 index 000000000..40f864a06 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/netlink_handler.cpp @@ -0,0 +1,160 @@ +#include "netlink_handler.h" +#include "logger.h" +#include +#include +#include +#include +#include +#include +#include +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { +netlink_handler::netlink_handler(int protocol, int pid) : netlink_listener(protocol, pid) +{ + this->setOnEventHandler(std::bind(&netlink_handler::onEvent, this, std::placeholders::_1)); +} + +netlink_handler::~netlink_handler() {} + +static long parseIfIndex(const char *ifIndex) +{ + if (ifIndex == nullptr) { + return 0; + } + long ifaceIndex = strtol(ifIndex, nullptr, 10); + // strtol returns 0 on error, which is fine because 0 is not a valid ifindex. + if (errno == ERANGE && (ifaceIndex == LONG_MAX || ifaceIndex == LONG_MIN)) { + return 0; + } + return ifaceIndex; +} + +void netlink_handler::onEvent(std::shared_ptr evt) +{ + const char *iface = evt->findParam("INTERFACE"); + const char *address = evt->findParam("ADDRESS"); + const char *flags = evt->findParam("FLAGS"); + const char *scope = evt->findParam("SCOPE"); + const char *ifIndex = evt->findParam("IFINDEX"); + const char *route = evt->findParam("ROUTE"); + const char *gateway = evt->findParam("GATEWAY"); + // yep, we got the netlink message action, so let's notify the user + switch (evt->getAction()) { + case Action::Unknown: + // LogError << "[NetlinkHandler]: unknown action." << endl; + NETNATIVE_LOGE("[NetlinkHandler]: unknown action."); + break; + case Action::Add: { + notifyInterfaceAdded(iface); + break; + } + case Action::Remove: { + // std::cout << "remvoe interface onEvent" << std::endl; + NETNATIVE_LOGI("remvoe interface onEvent"); + notifyInterfaceRemoved(iface); + break; + } + case Action::Change: + break; + case Action::LinkUp: { + notifyInterfaceLinkChanged(iface, true); + break; + } + case Action::LinkDown: { + notifyInterfaceLinkChanged(iface, false); + break; + } + case Action::AddressUpdated: + case Action::AddressRemoved: + char addrstr[INET6_ADDRSTRLEN + 4]; + strncpy(addrstr, address, sizeof(addrstr)); + if (!parseIfIndex(ifIndex)) { + // LogError << "invalid interface index: " << iface << "(" << ifIndex << ")" << endl; + NETNATIVE_LOGE("invalid interface index: %{public}s (%{public}s)", iface, ifIndex); + } + // Note: if this interface was deleted, iface is "" and we don't notify. + if (iface && iface[0] && address && flags && scope) { + if (evt->getAction() == Action::AddressUpdated) { + notifyAddressUpdated(address, iface, std::stoi(flags), std::stoi(scope)); + } else { + notifyAddressRemoved(address, iface, std::stoi(flags), std::stoi(scope)); + } + } + break; + case Action::RouteUpdated: { + if (route && (gateway || iface)) { + notifyRouteChange( + true, route, (gateway == nullptr) ? "" : gateway, (iface == nullptr) ? "" : iface); + } + break; + } + case Action::RouteRemoved: { + if (route && (gateway || iface)) { + notifyRouteChange( + false, route, (gateway == nullptr) ? "" : gateway, (iface == nullptr) ? "" : iface); + } + break; + } + case Action::DelRule: + case Action::NewRule: { + // common::logger::info() << "[NetlinkHandler]: rule changed." << endl; + NETNATIVE_LOGI("[NetlinkHandler]: rule changed."); + break; + } + default: + break; + } +} + +void netlink_handler::notifyInterfaceAdded(const std::string &ifName) +{ + this->reporter_->getListener().onInterfaceAdded(ifName); +} + +void netlink_handler::notifyInterfaceRemoved(const std::string &ifName) +{ + this->reporter_->getListener().onInterfaceRemoved(ifName); +} + +void netlink_handler::notifyInterfaceChanged(const std::string &ifName, bool isUp) +{ + this->reporter_->getListener().onInterfaceChanged(ifName, isUp); +} + +void netlink_handler::notifyInterfaceLinkChanged(const std::string &ifName, bool isUp) +{ + this->reporter_->getListener().onInterfaceLinkStateChanged(ifName, isUp); +} + +void netlink_handler::notifyAddressUpdated(const std::string &addr, const std::string &ifName, int flags, int scope) +{ + this->reporter_->getListener().onInterfaceAddressUpdated(addr, ifName, flags, scope); +} + +void netlink_handler::notifyAddressRemoved(const std::string &addr, const std::string &ifName, int flags, int scope) +{ + this->reporter_->getListener().onInterfaceAddressRemoved(addr, ifName, flags, scope); +} + +void netlink_handler::notifyRouteChange( + bool updated, const std::string &route, const std::string &gateway, const std::string &ifName) +{ + this->reporter_->getListener().onRouteChanged(updated, route, gateway, ifName); +} + +int netlink_handler::start() +{ + // common::logger::info() << "[NetLinkHandler] start." << endl; + NETNATIVE_LOGI("[NetLinkHandler] start."); + return this->listen(); +} + +void netlink_handler::stop() +{ + this->stopListen(); +} + +} // namespace nmd +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/src/netlink_listener.cpp b/http/services/netmanagernative/net_mgr_native/src/netlink_listener.cpp new file mode 100644 index 000000000..c0b53cf7a --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/netlink_listener.cpp @@ -0,0 +1,61 @@ +#include +#include +#include "logger.h" +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { +netlink_listener::netlink_listener(int protocol, int pid) +{ + this->create(protocol); + this->pid_ = pid; + this->setOnDataReceiveHandler(std::bind(&netlink_listener::onDataAvaliable, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)); +} + +netlink_listener::~netlink_listener() {} + +void netlink_listener::onDataAvaliable(int, char *buf, ssize_t size) +{ + // common::logger::info() << "[NetlinkListener] netlink message come." << endl; + NETNATIVE_LOGI("[NetlinkListener] netlink message come."); + std::shared_ptr event = std::make_shared(); + + if (!event->parseNetLinkMessage(buf, size)) { + // LogError << "[NetlinkListener] netlink message parse failed." << endl; + NETNATIVE_LOGE("[NetlinkListener] netlink message parse failed."); + } else { + this->onEventHandler_(event); + } +} + +void netlink_listener::setOnEventHandler(const std::function)> &handler) +{ + this->onEventHandler_ = handler; +} + +int netlink_listener::listen() +{ + if (this->binding() == -1) { + return -1; + } + // common::logger::info() << "[NetlinkListener] start listen at pid:" << this->pid_ << endl; + NETNATIVE_LOGI("[NetlinkListener] start listen at pid: %{public}d", this->pid_); + this->running_ = true; + while (this->running_) { + this->acceptAndListen(); + } + return 1; +} + +void netlink_listener::stopListen() +{ + this->running_ = false; +} + +bool netlink_listener::getNetlinkListenerState() +{ + return this->running_; +} +} // namespace nmd +} // namespace OHOS diff --git a/http/services/netmanagernative/net_mgr_native/src/netlink_manager.cpp b/http/services/netmanagernative/net_mgr_native/src/netlink_manager.cpp new file mode 100644 index 000000000..fd5956d4b --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/netlink_manager.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { +int netlink_manager::pid_; +std::shared_ptr netlink_manager::reporter_; + +void listeners::defaultOnInterfaceAddressUpdated(const std::string &, const std::string &, int, int) {} +void listeners::defaultOnInterfaceAddressRemoved(const std::string &, const std::string &, int, int) {} +void listeners::defaultOnInterfaceAdded(const std::string &) {} +void listeners::defaultOnInterfaceRemoved(const std::string &) {} +void listeners::defaultOnInterfaceChanged(const std::string &, bool) {} +void listeners::defaultOnInterfaceLinkStateChanged(const std::string &, bool) {} +void listeners::defaultOnRouteChanged(bool, const std::string &, const std::string &, const std::string &) {} + +netlink_manager::netlink_manager(int pid) : routeHandler_(std::make_shared(NETLINK_ROUTE, pid)) +{ + this->pid_ = pid; + this->reporter_ = std::make_shared(); + + DISABLE_WARNING_PUSH + DISABLE_WARNING_C99_EXTENSIONS + + inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = listeners::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = listeners::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = listeners::defaultOnInterfaceAdded, + .onInterfaceRemoved = listeners::defaultOnInterfaceRemoved, + .onInterfaceChanged = listeners::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = listeners::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = listeners::defaultOnRouteChanged, + }; + + DISABLE_WARNING_POP + + this->reporter_->registerEventListener(glistener); + this->routeHandler_->setEventListener(this->reporter_); +} + +netlink_manager::~netlink_manager() {} + +void netlink_manager::startRouteHandler() +{ + NETNATIVE_LOGE("[NetlinkManager] startRouteHandler"); + if (this->routeHandler_->start() == -1) { + // LogError << "[NetlinkManager] satrt failed." << endl; + NETNATIVE_LOGE("[NetlinkManager] satrt failed."); + } else { + // common::logger::info() << "[NetlinkManager] satrted." << endl; + NETNATIVE_LOGI("[NetlinkManager] satrted."); + } +} + +void netlink_manager::start() +{ + this->startRouteHandler(); +} + +void netlink_manager::stop() +{ + this->routeHandler_->stop(); +} +} // namespace nmd +} // namespace OHOS diff --git a/http/services/netmanagernative/net_mgr_native/src/netlink_msg.cpp b/http/services/netmanagernative/net_mgr_native/src/netlink_msg.cpp new file mode 100644 index 000000000..813ce5390 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/netlink_msg.cpp @@ -0,0 +1,160 @@ +#include "netlink_msg.h" +#include "netnative_log_wrapper.h" +#include "logger.h" + +DISABLE_WARNING_PUSH +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_IMPLICIT_INT_CONVERSION +DISABLE_WARNING_SHORTEN_64_TO_32 +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_SIGN_COMPARE +DISABLE_WARNING_OLD_STYLE_CAST +DISABLE_WARNING_CAST_ALIGN +DISABLE_WARNING_SIGN_CONVERSION + +namespace OHOS { +namespace nmd { +netlink_msg::netlink_msg(uint16_t flags, size_t maxBufLen, int pid) +{ + this->maxBufLen_ = maxBufLen; + this->netlinkMessage_ = reinterpret_cast(malloc(NLMSG_SPACE(maxBufLen))); + memset(this->netlinkMessage_, 0, NLMSG_SPACE(maxBufLen)); + this->netlinkMessage_->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags; + this->netlinkMessage_->nlmsg_pid = pid; + this->netlinkMessage_->nlmsg_seq = 1; +} + +netlink_msg::~netlink_msg() +{ + delete this->netlinkMessage_; +} + +void netlink_msg::addRoute(unsigned short action, struct rtmsg msg) +{ + this->netlinkMessage_->nlmsg_type = action; + memcpy(NLMSG_DATA(this->netlinkMessage_), &msg, sizeof(struct rtmsg)); + this->netlinkMessage_->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); +} + +void netlink_msg::addRule(unsigned short action, struct fib_rule_hdr msg) +{ + this->netlinkMessage_->nlmsg_type = action; + memcpy(NLMSG_DATA(this->netlinkMessage_), &msg, sizeof(struct fib_rule_hdr)); + this->netlinkMessage_->nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)); +} + +void netlink_msg::addRouteNextHop(unsigned short action, struct rtnexthop msg) +{ + this->netlinkMessage_->nlmsg_type = action; + memcpy(NLMSG_DATA(this->netlinkMessage_), &msg, sizeof(struct rtnexthop)); + this->netlinkMessage_->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtnexthop)); +} + +void netlink_msg::addRouteAttributeCacheInfo(unsigned short action, struct rta_cacheinfo msg) +{ + this->netlinkMessage_->nlmsg_type = action; + memcpy(NLMSG_DATA(this->netlinkMessage_), &msg, sizeof(struct rta_cacheinfo)); + this->netlinkMessage_->nlmsg_len = NLMSG_LENGTH(sizeof(struct rta_cacheinfo)); +} + +void netlink_msg::addInterfaceAddress(unsigned short action, struct ifaddrmsg msg) +{ + this->netlinkMessage_->nlmsg_type = action; + memcpy(NLMSG_DATA(this->netlinkMessage_), &msg, sizeof(struct ifaddrmsg)); + this->netlinkMessage_->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); +} + +void netlink_msg::addInterfaceAddressCacheInfo(unsigned short action, struct ifa_cacheinfo msg) +{ + this->netlinkMessage_->nlmsg_type = action; + memcpy(NLMSG_DATA(this->netlinkMessage_), &msg, sizeof(struct rta_cacheinfo)); + this->netlinkMessage_->nlmsg_len = NLMSG_LENGTH(sizeof(struct rta_cacheinfo)); +} + +void netlink_msg::addNeighborDiscovery(unsigned short action, struct ndmsg msg) +{ + this->netlinkMessage_->nlmsg_type = action; + memcpy(NLMSG_DATA(this->netlinkMessage_), &msg, sizeof(struct ndmsg)); + this->netlinkMessage_->nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); +} + +void netlink_msg::addNeighborDiscoveryAttributeCacheInfo(unsigned short action, struct nda_cacheinfo msg) +{ + this->netlinkMessage_->nlmsg_type = action; + memcpy(NLMSG_DATA(this->netlinkMessage_), &msg, sizeof(struct nda_cacheinfo)); + this->netlinkMessage_->nlmsg_len = NLMSG_LENGTH(sizeof(struct nda_cacheinfo)); +} + +void netlink_msg::addInterfaceInfo(unsigned short action, struct ifinfomsg msg) +{ + this->netlinkMessage_->nlmsg_type = action; + memcpy(NLMSG_DATA(this->netlinkMessage_), &msg, sizeof(struct ifinfomsg)); + this->netlinkMessage_->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); +} + +void netlink_msg::addTrafficControl(unsigned short action, struct tcmsg msg) +{ + this->netlinkMessage_->nlmsg_type = action; + memcpy(NLMSG_DATA(this->netlinkMessage_), &msg, sizeof(struct tcmsg)); + this->netlinkMessage_->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); +} + +void netlink_msg::addInetDiag(unsigned short action, struct inet_diag_req_v2 msg) +{ + this->netlinkMessage_->nlmsg_type = action; + memcpy(NLMSG_DATA(this->netlinkMessage_), &msg, sizeof(struct inet_diag_req_v2)); + this->netlinkMessage_->nlmsg_len = NLMSG_LENGTH(sizeof(struct inet_diag_req_v2)); +} + +int netlink_msg::addAttr(unsigned int type, void *data, size_t alen) +{ + if (!alen) { + // LogError << "[NetlinkMessage]: length data can not be 0" << endl; + NETNATIVE_LOGE("[NetlinkMessage]: length data can not be 0"); + return -1; + } + + if (!data) { + // LogError << "[NetlinkMessage]: attr data can not be null" << endl; + NETNATIVE_LOGE("[NetlinkMessage]: attr data can not be null"); + return -1; + } + + int len = RTA_LENGTH(alen); + + if (NLMSG_ALIGN(this->netlinkMessage_->nlmsg_len) + RTA_ALIGN(len) > this->maxBufLen_) { + // LogError << "[NetlinkMessage]: attr length than max len:" << this->maxBufLen_ << endl; + NETNATIVE_LOGE("[NetlinkMessage]: attr length than max len: %{public}d", this->maxBufLen_); + return -1; + } + + struct rtattr *rta = + (struct rtattr *)(((char *)this->netlinkMessage_) + NLMSG_ALIGN(this->netlinkMessage_->nlmsg_len)); + rta->rta_type = type; + rta->rta_len = len; + + if (data) { + memcpy(RTA_DATA(rta), data, alen); + } + + this->netlinkMessage_->nlmsg_len = NLMSG_ALIGN(this->netlinkMessage_->nlmsg_len) + RTA_ALIGN(len); + return 1; +} + +int netlink_msg::addAttr16(unsigned int type, uint16_t data) +{ + return this->addAttr(type, &data, sizeof(uint16_t)); +} + +int netlink_msg::addAttr32(unsigned int type, uint32_t data) +{ + return this->addAttr(type, &data, sizeof(uint32_t)); +} + +nlmsghdr *netlink_msg::getNetLinkMessage() +{ + return this->netlinkMessage_; +} +} // namespace nmd +} // namespace OHOS +DISABLE_WARNING_POP \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/src/netlink_socket.cpp b/http/services/netmanagernative/net_mgr_native/src/netlink_socket.cpp new file mode 100644 index 000000000..63d0942dc --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/netlink_socket.cpp @@ -0,0 +1,217 @@ +#include "netlink_socket.h" +#include "traffic_controller.h" +#include "warning_disable.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netnative_log_wrapper.h" + +DISABLE_WARNING_PUSH +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_IMPLICIT_INT_CONVERSION +DISABLE_WARNING_SHORTEN_64_TO_32 +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_SIGN_COMPARE +DISABLE_WARNING_OLD_STYLE_CAST +DISABLE_WARNING_CAST_ALIGN +DISABLE_WARNING_SIGN_CONVERSION + +#define EPOLL_SIZE 50 + +#define MAX_PAYLOAD 4096 + +namespace OHOS { +namespace nmd { +namespace { +__u32 nl_mgrp(__u32 group) +{ + if (group > 31) { + printf("Netlink: Use setsockopt for this group: %d\n", group); + return 0; + } + return group ? (1 << (group - 1)) : 0; +} +} // namespace + +netlink_socket::~netlink_socket() +{ + close(this->socketFd_); +} + +int netlink_socket::create(int protocol) +{ + return this->create(SOCK_RAW, protocol); +} + +int netlink_socket::create(int type, int protocol) +{ + this->socketFd_ = -1; + if ((this->socketFd_ = socket(AF_NETLINK, type, protocol)) == -1) { + // LogError << "[NetlinkSocket] create socket failed:" << strerror(errno) << endl; + NETNATIVE_LOGE("[NetlinkSocket] create socket failed: %{public}s", strerror(errno)); + return -1; + } + return this->socketFd_; +} + +int netlink_socket::binding() +{ + struct sockaddr_nl local; + memset(&local, 0, sizeof(local)); + local.nl_family = AF_NETLINK; + local.nl_pid = this->pid_; + local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_RULE | + nl_mgrp(RTNLGRP_NEIGH); + + struct sockaddr *ad = reinterpret_cast(&local); + memcpy(&(this->addr_), ad, sizeof(*ad)); + + int retval = bind(this->socketFd_, &this->addr_, sizeof(this->addr_)); + if (retval == -1) { + // LogError << "[NetlinkSocket] bind socket(" << this->socketFd_ << ") failed: " << strerror(errno) << endl; + NETNATIVE_LOGE( + "[NetlinkSocket] bind socket %{public}d failed: %{public}s", this->socketFd_, strerror(errno)); + close(this->socketFd_); + return -1; + } + return retval; +} + +int netlink_socket::acceptAndListen() +{ + char buffer[8192] = {}; + struct iovec iov = {buffer, sizeof(buffer)}; + struct sockaddr_nl netlinkAddr; + struct msghdr msg = {(void *)&netlinkAddr, sizeof(netlinkAddr), &iov, 1, ((void *)0), 0, 0}; + + ssize_t size = recvmsg(this->socketFd_, &msg, 0); + if (size < 0) { + return 0; + } + + if (netlinkAddr.nl_pid != 0) { + // LogError << "[NetlinkSocket] Ignore non kernel message from pid:" << netlinkAddr.nl_pid << endl; + NETNATIVE_LOGE("[NetlinkSocket] Ignore non kernel message from pid: %{public}d", netlinkAddr.nl_pid); + return 0; + } + + if (size == 0) { + // LogError << "[NetlinkSocket] EOF." << endl; + NETNATIVE_LOGE("[NetlinkSocket] EOF."); + return -1; + } + + if (msg.msg_namelen != sizeof(netlinkAddr)) { + // LogError << "[NetlinkSocket] sender address length error." << endl; + NETNATIVE_LOGE("[NetlinkSocket] sender address length error."); + return -1; + } + + for (struct nlmsghdr *hdr = (struct nlmsghdr *)buffer; NLMSG_OK(hdr, size); hdr = NLMSG_NEXT(hdr, size)) { + switch (hdr->nlmsg_type) { + case NLMSG_DONE: + return 0; + case NLMSG_ERROR: { + struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr); + if (err->error == 0) { + return 0; + } + if (hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { + // LogError << "[NetlinkSocket] Socket error: message truncated" << endl; + NETNATIVE_LOGE("[NetlinkSocket] Socket error: message truncated"); + return -1; + } + // LogError << "[NetlinkSocket] Socket error: " << strerror(-err->error) + // << ", type=" << err->msg.nlmsg_type << ", seq=" << err->msg.nlmsg_seq + // << ", pid=" << err->msg.nlmsg_pid << endl; + NETNATIVE_LOGE( + "[NetlinkSocket] Socket error: %{public}s, type=%{public}d, seq=%{public}d, pid=%{public}d", + strerror(-err->error), err->msg.nlmsg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); + return -1; + } + case RTM_NEWNEIGH: + case RTM_DELNEIGH: { + int isTetherEnable = 1; // mock tether is enable + if (isTetherEnable == 1) { + // nmd::traffic_controller::getTetherClientInfo(); + nmd::traffic_controller::startTrafficTether(); + } + return 0; + } + default: + this->handler_(this->socketFd_, buffer, size); + break; + } + } + return 0; +} + +int netlink_socket::sendNetlinkMsgToKernel(struct nlmsghdr *msg) +{ + if (!msg) { + // LogError << "[NetlinkSocket] msg can not be null " << endl; + NETNATIVE_LOGE("[NetlinkSocket] msg can not be null "); + return -1; + } + struct iovec ioVector; + ioVector.iov_base = msg; + ioVector.iov_len = msg->nlmsg_len; + + struct msghdr msgHeader; + memset(&msgHeader, 0, sizeof(msgHeader)); + + struct sockaddr_nl kernel; + memset(&kernel, 0, sizeof(kernel)); + kernel.nl_family = AF_NETLINK; + kernel.nl_groups = 0; + + msgHeader.msg_name = &kernel; + msgHeader.msg_namelen = sizeof(kernel); + msgHeader.msg_iov = &ioVector; + msgHeader.msg_iovlen = 1; + + long msgState = sendmsg(this->socketFd_, &msgHeader, 0); + if (msgState == -1) { + // LogError << "[NetlinkSocket] socket: " << this->socketFd_ << ",msg send failed: " << strerror(errno) + // << endl; + NETNATIVE_LOGE("[NetlinkSocket] msg can not be null "); + return -1; + } else if (msgState == 0) { + // LogError << "[NetlinkSocket] 0 bytes send." << endl; + NETNATIVE_LOGE("[NetlinkSocket] 0 bytes send."); + return -1; + } + return msgState; +} + +ssize_t netlink_socket::receive(void *buf) +{ + struct nlmsghdr *msg = reinterpret_cast(buf); + memset(msg, 0, NLMSG_SPACE(MAX_PAYLOAD)); + ssize_t size = recv(this->socketFd_, reinterpret_cast(msg), MAX_PAYLOAD, 0); + return size; +} + +int netlink_socket::shutdown() +{ + return close(this->socketFd_); +} + +void netlink_socket::setOnDataReceiveHandler(const std::function &handler) +{ + this->handler_ = handler; +} + +} // namespace nmd +} // namespace OHOS +DISABLE_WARNING_POP \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/src/network.cpp b/http/services/netmanagernative/net_mgr_native/src/network.cpp new file mode 100644 index 000000000..b5529b3ba --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/network.cpp @@ -0,0 +1,80 @@ +#include "network.h" +#include "interface_utils.h" +#include "route_controller.h" +#include +#include +#include +#include + +namespace OHOS { +namespace nmd { +network::network(uint16_t netId, NetworkPermission permission) : netId_(netId), permission_(permission) {} + +network::~network() {} + +void network::asDefault() +{ + std::set::iterator it; + for (it = this->interfaces_.begin(); it != this->interfaces_.end(); ++it) { + route_controller::addInterfaceToDefaultNetwork(it->c_str(), this->permission_); + } + this->isDefault_ = true; +} + +void network::removeAsDefault() +{ + std::set::iterator it; + for (it = this->interfaces_.begin(); it != this->interfaces_.end(); ++it) { + route_controller::removeInterfaceFromDefaultNetwork(it->c_str(), this->permission_); + } + this->isDefault_ = true; +} + +int network::addInterface(std::string &interfaceName) +{ + if (hasInterface(interfaceName)) { + return 1; + } + + route_controller::addInterfaceToPhysicalNetwork(this->netId_, interfaceName.c_str(), this->permission_); + + if (this->isDefault_) { + route_controller::addInterfaceToDefaultNetwork(interfaceName.c_str(), this->permission_); + } + + this->interfaces_.insert(interfaceName); + return 1; +} + +int network::removeInterface(std::string &interfaceName) +{ + if (!hasInterface(interfaceName)) { + return 1; + } + + route_controller::removeInterfaceFromPhysicalNetwork(this->netId_, interfaceName.c_str(), this->permission_); + + if (this->isDefault_) { + route_controller::removeInterfaceFromDefaultNetwork(interfaceName.c_str(), this->permission_); + } + + this->interfaces_.erase(interfaceName); + return 1; +} + +int network::clearInterfaces() +{ + std::set::iterator it; + for (it = this->interfaces_.begin(); it != this->interfaces_.end(); ++it) { + route_controller::removeInterfaceFromPhysicalNetwork(this->netId_, it->c_str(), this->permission_); + } + this->interfaces_.clear(); + return 1; +} + +bool network::hasInterface(std::string &interfaceName) +{ + return this->interfaces_.find(interfaceName) != this->interfaces_.end(); +} +} // namespace nmd +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/src/network_controller.cpp b/http/services/netmanagernative/net_mgr_native/src/network_controller.cpp new file mode 100644 index 000000000..0e39e8d90 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/network_controller.cpp @@ -0,0 +1,189 @@ +#include "network_controller.h" +#include "route_controller.h" +#include "fwmark.h" +#include + +#define INTERFACE_UNSET -1 +namespace OHOS { +namespace nmd { +network_controller::~network_controller() +{ + std::map::iterator it = networks_.begin(); + for (it = networks_.begin(); it != networks_.end(); ++it) { + delete it->second; + } +} + +int network_controller::createPhysicalNetwork(uint16_t netId, Permission permission) +{ + network *nw = new network(netId, permission); + this->networks_.insert(std::pair(netId, nw)); + return netId; +} + +int network_controller::destroyNetwork(int netId) +{ + std::tuple net = this->findNetworkById(netId); + network *nw = std::get<1>(net); + + if (this->defaultNetId_ == netId) { + nw->removeAsDefault(); + this->defaultNetId_ = 0; + } + + if (std::get<0>(net)) { + nw->clearInterfaces(); + } + + this->networks_.erase(netId); + delete nw; + return 1; +} + +int network_controller::setDefaultNetwork(int netId) +{ + if (this->defaultNetId_ == netId) { + return netId; + } + + // check is this network exists + + std::tuple net = this->findNetworkById(netId); + if (std::get<0>(net)) { + network *nw = std::get<1>(net); + nw->asDefault(); + } + + if (this->defaultNetId_ != 0) { + net = this->findNetworkById(this->defaultNetId_); + if (std::get<0>(net)) { + network *nw = std::get<1>(net); + nw->removeAsDefault(); + } + } + this->defaultNetId_ = netId; + return this->defaultNetId_; +} + +int network_controller::clearDefaultNetwork() +{ + if (this->defaultNetId_ != 0) { + std::tuple net = this->findNetworkById(this->defaultNetId_); + if (std::get<0>(net)) { + network *nw = std::get<1>(net); + nw->removeAsDefault(); + } + } + this->defaultNetId_ = 0; + return 1; +} + +std::tuple network_controller::findNetworkById(int netId) +{ + std::map::iterator it; + for (it = this->networks_.begin(); it != this->networks_.end(); ++it) { + if (netId == it->first) { + return std::make_tuple(true, it->second); + } + } + return std::make_tuple(false, nullptr); +} + +int network_controller::getDefaultNetwork() +{ + return this->defaultNetId_; +} + +int network_controller::getNetworkForInterface(std::string &interfaceName) +{ + std::map::iterator it; + for (it = this->networks_.begin(); it != this->networks_.end(); ++it) { + if (it->second->hasInterface(interfaceName)) { + return it->first; + } + } + return INTERFACE_UNSET; +} + +int network_controller::addInterfaceToNetwork(int netId, std::string &interafceName) +{ + int alreadySetNetId = getNetworkForInterface(interafceName); + if (alreadySetNetId != netId && alreadySetNetId != INTERFACE_UNSET) { + return -1; + } + std::tuple net = this->findNetworkById(netId); + if (std::get<0>(net)) { + network *nw = std::get<1>(net); + return nw->addInterface(interafceName); + } + return -1; +} + +int network_controller::removeInterfaceFromNetwork(int netId, std::string &interafceName) +{ + int alreadySetNetId = getNetworkForInterface(interafceName); + if (alreadySetNetId != netId || alreadySetNetId == INTERFACE_UNSET) { + return 1; + } else if (alreadySetNetId == netId) { + std::tuple net = this->findNetworkById(netId); + if (std::get<0>(net)) { + network *nw = std::get<1>(net); + return nw->removeInterface(interafceName); + } + } + return 1; +} + +int network_controller::addRoute(int netId, std::string interfaceName, std::string destination, std::string nextHop) +{ + return route_controller::addRoute(netId, interfaceName, destination, nextHop); +} + +int network_controller::removeRoute( + int netId, std::string interfaceName, std::string destination, std::string nextHop) +{ + return route_controller::removeRoute(netId, interfaceName, destination, nextHop); +} + +int network_controller::getFwmarkForNetwork(int netId) +{ + std::tuple net = this->findNetworkById(netId); + if (std::get<0>(net)) { + network *nw = std::get<1>(net); + fwmark mark; + mark.bits.netId = nw->getNetId(); + mark.bits.permission = nw->getPermission(); + return static_cast(mark.val); + } + return 0; +} + +int network_controller::setPermissionForNetwork(int netId, Permission permission) +{ + std::tuple net = this->findNetworkById(netId); + if (std::get<0>(net)) { + network *nw = std::get<1>(net); + fwmark mark; + mark.bits.netId = nw->getNetId(); + mark.bits.permission = permission; + return 1; + } + return 0; +} + +network *network_controller::getNetwork(int netId) +{ + return networks_.find(netId)->second; +} + +std::vector network_controller::getNetworks() +{ + std::vector nws; + std::map::iterator it; + for (it = this->networks_.begin(); it != this->networks_.end(); ++it) { + nws.push_back(it->second); + } + return nws; +} +} // namespace nmd +} // namespace OHOS \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/src/route_controller.cpp b/http/services/netmanagernative/net_mgr_native/src/route_controller.cpp new file mode 100644 index 000000000..82ec089c3 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/route_controller.cpp @@ -0,0 +1,487 @@ +#include "route_controller.h" + +#include "bitcast.h" +#include "fwmark.h" +#include "interface_utils.h" +#include "iptables_process.h" +//#include "logger.h" +#include "netlink_manager.h" +#include "warning_disable.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netnative_log_wrapper.h" + +DISABLE_WARNING_PUSH +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_IMPLICIT_INT_CONVERSION +DISABLE_WARNING_SHORTEN_64_TO_32 +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_SIGN_COMPARE +DISABLE_WARNING_OLD_STYLE_CAST +DISABLE_WARNING_CAST_ALIGN +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_C99_EXTENSIONS + +constexpr char PING[] = "#PING\n"; +constexpr size_t PING_SIZE = sizeof(PING) - 1; + +const char *const ROUTE_TABLE_NAME_LOCAL = "local"; +const char *const ROUTE_TABLE_NAME_MAIN = "main"; + +const uint32_t ROUTE_TABLE_LOCAL_NETWORK = 97; +const uint32_t ROUTE_TABLE_LEGACY_NETWORK = 98; +const uint32_t ROUTE_TABLE_LEGACY_SYSTEM = 99; + +const char *const ROUTE_TABLE_NAME_LOCAL_NETWORK = "local_network"; +const char *const ROUTE_TABLE_NAME_LEGACY_NETWORK = "legacy_network"; +const char *const ROUTE_TABLE_NAME_LEGACY_SYSTEM = "legacy_system"; + +const char *const RT_TABLES_PATH = "/data/misc/net/rt_tables"; + +const uint32_t NETID_UNSET = 0u; + +namespace OHOS { +namespace nmd { + +std::map route_controller::interfaceToTable_; + +route_controller::route_controller() {} + +route_controller::~route_controller() {} + +int route_controller::addInterfaceToDefaultNetwork(const char *interfaceName, NetworkPermission permission) +{ + uint32_t table = getRouteTableForInterface(interfaceName); + if (table == RT_TABLE_UNSPEC) { + return -ESRCH; + } + + fwmark mark; + mark.bits.netId = NETID_UNSET; + mark.bits.permission = permission; + + uint32_t fwmask = 0xFFFF; + + nmd::netlink_socket netLinker; + netLinker.create(NETLINK_ROUTE); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, netlink_manager::getPid()); + struct fib_rule_hdr msg; + msg.action = FR_ACT_TO_TBL; + msg.family = AF_INET; + nlmsg.addRule(RTM_NEWRULE, msg); + nlmsg.addAttr32(FRA_FWMARK, mark.val); + nlmsg.addAttr32(FRA_FWMASK, fwmask); + msg.table = RT_TABLE_UNSPEC; + + if (table == RT_TABLE_UNSPEC) { + return -1; + } + nlmsg.addAttr32(FRA_TABLE, table); + + return netLinker.sendNetlinkMsgToKernel(nlmsg.getNetLinkMessage()); +} +int route_controller::removeInterfaceFromDefaultNetwork(const char *interfaceName, NetworkPermission permission) +{ + uint32_t table = getRouteTableForInterface(interfaceName); + if (table == RT_TABLE_UNSPEC) { + return -ESRCH; + } + + fwmark mark; + mark.bits.netId = NETID_UNSET; + mark.bits.permission = permission; + + uint32_t fwmask = 0xFFFF; + + nmd::netlink_socket netLinker; + netLinker.create(NETLINK_ROUTE); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, netlink_manager::getPid()); + struct fib_rule_hdr msg; + msg.action = FR_ACT_TO_TBL; + msg.family = AF_INET; + nlmsg.addRule(RTM_DELRULE, msg); + nlmsg.addAttr32(FRA_FWMARK, mark.val); + nlmsg.addAttr32(FRA_FWMASK, fwmask); + msg.table = RT_TABLE_UNSPEC; + + if (table == RT_TABLE_UNSPEC) { + return -1; + } + nlmsg.addAttr32(FRA_TABLE, table); + + return netLinker.sendNetlinkMsgToKernel(nlmsg.getNetLinkMessage()); +} + +void addTableName(uint32_t table, const std::string &name, std::string *contents) +{ + char tableString[10]; + snprintf(tableString, sizeof(tableString), "%u", table); + *contents += tableString; + *contents += " "; + *contents += name; + *contents += "\n"; +} + +void route_controller::updateTableNamesFile() +{ + std::string contents; + + addTableName(RT_TABLE_LOCAL, ROUTE_TABLE_NAME_LOCAL, &contents); + addTableName(RT_TABLE_MAIN, ROUTE_TABLE_NAME_MAIN, &contents); + + addTableName(ROUTE_TABLE_LOCAL_NETWORK, ROUTE_TABLE_NAME_LOCAL_NETWORK, &contents); + addTableName(ROUTE_TABLE_LEGACY_NETWORK, ROUTE_TABLE_NAME_LEGACY_NETWORK, &contents); + addTableName(ROUTE_TABLE_LEGACY_SYSTEM, ROUTE_TABLE_NAME_LEGACY_SYSTEM, &contents); + + for (const auto &entry : interfaceToTable_) { + addTableName(entry.second, entry.first, &contents); + } + + int fd = -1; + if ((fd = open(RT_TABLES_PATH, O_CREAT | O_EXCL, 0777)) != -1) { + write(fd, contents.c_str(), contents.length()); + } +} + +int route_controller::createChildChains(const char *table, const char *parentChain, const char *childChain) +{ + std::string command("*"); + command.append(table); + command.append("\n"); + + command.append(":"); + command.append(childChain); + command.append(" -\n"); + + command.append("-A "); + command.append(parentChain); + command.append(" -j "); + command.append(childChain); + command.append("\n"); + + command.append("COMMIT\n"); + + // if (route_controller::executeIptablesRestore(command) == -1) { + // return -1; + //} + + return 0; +} + +std::mutex iptablesRestoreLock; +int route_controller::executeIptablesRestore(std::string command) +{ + std::lock_guard lk(iptablesRestoreLock); + std::shared_ptr process = iptables_process::forkAndExecute(); + + NETNATIVE_LOGE("executeIptablesRestore::write to iptable_restore process failed"); + if (write(process->stdin_, command.c_str(), command.length()) == -1) { + NETNATIVE_LOGE("executeIptablesRestore::write to iptable_restore process failed"); + } + NETNATIVE_LOGE("executeIptablesRestore::write to iptable_restore process succ"); + if (write(process->stdin_, PING, PING_SIZE) == -1) { + NETNATIVE_LOGE("executeIptablesRestore::ping to iptable_restore process failed"); + } + + std::string result; + if (!process->waitForAck(result)) { + // LogError << "iptables restore failed." << endl; + NETNATIVE_LOGE("executeIptablesRestore::iptables restore failed."); + return -1; + } + NETNATIVE_LOGI("executeIptablesRestore::command::%{public}s", command.c_str()); + NETNATIVE_LOGI("executeIptablesRestore::command::iptables restored:%{public}s", result.c_str()); + // common::logger::info() << "command:" << command << endl; + // common::logger::info() << "iptables restored:" << result << endl; + return 0; +} + +int nmd::route_controller::addInterfaceToPhysicalNetwork( + uint16_t netId, const char *interfaceName, NetworkPermission permission) +{ + // 0. build a fwmark which contain the netid and permision + fwmark mark; + mark.bits.netId = netId; + mark.bits.permission = permission; + + uint32_t fwmask = 0xFFFFFFFF; + + // modify incoming package with fwmark + // *mangle + // -A routectrl_mangle_INPUT -i interface -j MARK --set-mark fwmark/mask + // COMMIT + std::string command("*mangle\n-A routectrl_mangle_INPUT -i "); + command.append(interfaceName); + command.append(" -j MARK --set-mark 0x"); + + std::stringstream stream; + stream << std::hex << mark.val; + std::string fwmarkString(stream.str()); + command.append(fwmarkString); + command.append("/0x"); + + std::stringstream maskStream; + maskStream << std::hex << fwmask; + std::string fwmaskString(maskStream.str()); + + command.append(fwmaskString); + command.append("\n"); + + command.append("COMMIT\n"); + + if (route_controller::executeIptablesRestore(command) == -1) { + return -1; + } + + // 2. change out rule + nmd::netlink_socket netLinker; + netLinker.create(NETLINK_ROUTE); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, netlink_manager::getPid()); + struct fib_rule_hdr msg; + msg.action = FR_ACT_TO_TBL; + msg.family = AF_INET; + nlmsg.addRule(RTM_NEWRULE, msg); + nlmsg.addAttr32(FRA_FWMARK, mark.val); + nlmsg.addAttr32(FRA_FWMASK, fwmask); + msg.table = RT_TABLE_UNSPEC; + + uint32_t table = getRouteTableForInterface(interfaceName); + if (table == RT_TABLE_UNSPEC) { + return -1; + } + nlmsg.addAttr32(FRA_TABLE, table); + + netLinker.sendNetlinkMsgToKernel(nlmsg.getNetLinkMessage()); + + updateTableNamesFile(); + return 1; +} + +int nmd::route_controller::removeInterfaceFromPhysicalNetwork( + uint16_t netId, const char *interfaceName, NetworkPermission permission) +{ + fwmark mark; + mark.bits.netId = netId; + mark.bits.permission = permission; + uint32_t fwmask = 0xFFFFFFFF; + + nmd::netlink_socket netLinker; + netLinker.create(NETLINK_ROUTE); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, netlink_manager::getPid()); + struct fib_rule_hdr msg; + msg.action = FR_ACT_TO_TBL; + msg.family = AF_INET; + nlmsg.addRule(RTM_DELRULE, msg); + nlmsg.addAttr32(FRA_FWMARK, mark.val); + nlmsg.addAttr32(FRA_FWMASK, fwmask); + msg.table = RT_TABLE_UNSPEC; + + uint32_t table = getRouteTableForInterface(interfaceName); + if (table == RT_TABLE_UNSPEC) { + return -1; + } + nlmsg.addAttr32(FRA_TABLE, table); + netLinker.sendNetlinkMsgToKernel(nlmsg.getNetLinkMessage()); + + interfaceToTable_.erase(interfaceName); + + updateTableNamesFile(); + + return 1; +} + +int nmd::route_controller::read_addr_gw(const char *addr, _inet_addr *res) +{ + std::string addressString(addr); + if (strchr(addr, ':')) { + res->family = AF_INET6; + res->bitlen = 128; + } else { + res->family = AF_INET; + res->bitlen = 32; + } + + return inet_pton(res->family, addressString.c_str(), res->data); +} + +int nmd::route_controller::read_addr(const char *addr, _inet_addr *res) +{ + const char *slash = strchr(addr, '/'); + const char *prefixlenString = slash + 1; + if (!slash || !*prefixlenString) { + return -EINVAL; + } + + char *endptr = nullptr; + unsigned templen = strtoul(prefixlenString, &endptr, 10); + if (*endptr || templen > 255) { + return -EINVAL; + } + res->prefixlen = templen; + + std::string addressString(addr, slash - addr); + if (strchr(addr, ':')) { + res->family = AF_INET6; + res->bitlen = 128; + } else { + res->family = AF_INET; + res->bitlen = 32; + } + + return inet_pton(res->family, addressString.c_str(), res->data); +} + +int nmd::route_controller::addRoute(int, std::string interfaceName, std::string destination, std::string nextHop) +{ + nmd::netlink_socket netLinker; + netLinker.create(NETLINK_ROUTE); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, netlink_manager::getPid()); + + struct rtmsg msg; + msg.rtm_family = AF_INET; + msg.rtm_dst_len = 32; + msg.rtm_protocol = RTPROT_STATIC; + msg.rtm_scope = RT_SCOPE_NOWHERE; + msg.rtm_type = RTN_UNICAST; + + nlmsg.addRoute(RTM_NEWROUTE, msg); + + unsigned int table = getRouteTableForInterface(interfaceName.c_str()); + if (table == RT_TABLE_UNSPEC) { + return -1; + } + msg.rtm_table = RT_TABLE_UNSPEC; + nlmsg.addAttr32(RTA_TABLE, table); + + _inet_addr dst; + int readAddrResult = 0; + if ((readAddrResult = read_addr(destination.c_str(), &dst)) != 1) { + // LogError << "dest parse failed:" << readAddrResult << endl; + NETNATIVE_LOGE("dest parse failed:%{public}d", readAddrResult); + return -1; + } else { + msg.rtm_family = dst.family; + msg.rtm_dst_len = dst.bitlen; + if (dst.family == AF_INET) { + msg.rtm_scope = RT_SCOPE_LINK; + } else if (dst.family == AF_INET6) { + msg.rtm_scope = RT_SCOPE_UNIVERSE; + } + nlmsg.addAttr(RTA_DST, (void *)dst.data, dst.bitlen / 8); + } + + _inet_addr gw; + if ((readAddrResult = read_addr_gw(nextHop.c_str(), &gw)) != 1) { + // LogError << "gw parse failed:" << readAddrResult << endl; + NETNATIVE_LOGE("gw parse failed:%{public}d", readAddrResult); + return -1; + } else { + if (gw.bitlen != 0) { + msg.rtm_scope = 0; + msg.rtm_family = gw.family; + } + nlmsg.addAttr(RTA_GATEWAY, (void *)gw.data, gw.bitlen / 8); + } + unsigned int index = if_nametoindex(interfaceName.c_str()); + nlmsg.addAttr32(RTA_OIF, index); + + netLinker.sendNetlinkMsgToKernel(nlmsg.getNetLinkMessage()); + + return 1; +} + +int route_controller::removeRoute(int, std::string interfaceName, std::string destination, std::string nextHop) +{ + nmd::netlink_socket netLinker; + netLinker.create(NETLINK_ROUTE); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, netlink_manager::getPid()); + + struct rtmsg msg; + msg.rtm_family = AF_INET; + msg.rtm_dst_len = 32; + msg.rtm_scope = RT_SCOPE_NOWHERE; + + nlmsg.addRoute(RTM_DELROUTE, msg); + + unsigned int table = getRouteTableForInterface(interfaceName.c_str()); + if (table == RT_TABLE_UNSPEC) { + return -1; + } + msg.rtm_table = RT_TABLE_UNSPEC; + nlmsg.addAttr32(RTA_TABLE, table); + + _inet_addr dst; + int readAddrResult = 0; + if ((readAddrResult = read_addr(destination.c_str(), &dst)) != 1) { + // LogError << "dest parse failed:" << readAddrResult << endl; + NETNATIVE_LOGE("dest parse failed:%{public}d", readAddrResult); + return -1; + } else { + msg.rtm_family = dst.family; + msg.rtm_dst_len = dst.bitlen; + if (dst.family == AF_INET) { + msg.rtm_scope = RT_SCOPE_LINK; + } else if (dst.family == AF_INET6) { + msg.rtm_scope = RT_SCOPE_UNIVERSE; + } + nlmsg.addAttr(RTA_DST, (void *)dst.data, dst.bitlen / 8); + } + + _inet_addr gw; + if ((readAddrResult = read_addr_gw(nextHop.c_str(), &gw)) != 1) { + // LogError << "gw parse failed:" << readAddrResult << endl; + NETNATIVE_LOGE("gw parse failed:%{public}d", readAddrResult); + return -1; + } else { + if (gw.bitlen != 0) { + msg.rtm_scope = 0; + msg.rtm_family = gw.family; + } + nlmsg.addAttr(RTA_GATEWAY, (void *)gw.data, gw.bitlen / 8); + } + unsigned int index = if_nametoindex(interfaceName.c_str()); + nlmsg.addAttr32(RTA_OIF, index); + + netLinker.sendNetlinkMsgToKernel(nlmsg.getNetLinkMessage()); + + return 1; +} + +uint32_t route_controller::getRouteTableForInterface(const char *interfaceName) +{ + auto iter = interfaceToTable_.find(interfaceName); + if (iter != interfaceToTable_.end()) { + return iter->second; + } + + uint32_t index = if_nametoindex(interfaceName); + if (index == 0) { + // LogError << "[RouteController] cannot find interface " << interfaceName << ",error:" << strerror(errno) + // << endl; + NETNATIVE_LOGE( + "[RouteController] cannot find interface %{public}s,error:%{public}s", interfaceName, strerror(errno)); + return RT_TABLE_UNSPEC; + } + index += 1000; + interfaceToTable_[interfaceName] = index; + return index; +} + +} // namespace nmd +} // namespace OHOS +DISABLE_WARNING_POP diff --git a/http/services/netmanagernative/net_mgr_native/src/sock_diag.cpp b/http/services/netmanagernative/net_mgr_native/src/sock_diag.cpp new file mode 100644 index 000000000..d3df4a247 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/sock_diag.cpp @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netnative_log_wrapper.h" + +DISABLE_WARNING_PUSH +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_IMPLICIT_INT_CONVERSION +DISABLE_WARNING_SHORTEN_64_TO_32 +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_SIGN_COMPARE +DISABLE_WARNING_OLD_STYLE_CAST +DISABLE_WARNING_CAST_ALIGN +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_C99_EXTENSIONS + +namespace OHOS { +namespace nmd { +void sock_diag::closeSocks() +{ + this->writeSock_.shutdown(); + this->sock_.shutdown(); +} + +sock_diag::~sock_diag() +{ + closeSocks(); +} + +bool sock_diag::isLoopbackSocket(const inet_diag_msg *msg) +{ + switch (msg->idiag_family) { + case AF_INET: + // Old kernels only copy the IPv4 address and leave the other 12 bytes uninitialized. + return IN_LOOPBACK(htonl(msg->id.idiag_src[0])) || IN_LOOPBACK(htonl(msg->id.idiag_dst[0])) || + msg->id.idiag_src[0] == msg->id.idiag_dst[0]; + + case AF_INET6: { + const struct in6_addr *src = (const struct in6_addr *)&msg->id.idiag_src; + const struct in6_addr *dst = (const struct in6_addr *)&msg->id.idiag_dst; + return (IN6_IS_ADDR_V4MAPPED(src) && IN_LOOPBACK(src->s6_addr32[3])) || + (IN6_IS_ADDR_V4MAPPED(dst) && IN_LOOPBACK(dst->s6_addr32[3])) || IN6_IS_ADDR_LOOPBACK(src) || + IN6_IS_ADDR_LOOPBACK(dst) || !memcmp(src, dst, sizeof(*src)); + } + default: + return false; + } +} + +bool sock_diag::open() +{ + this->sock_.create(SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_INET_DIAG); + this->writeSock_.create(SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_INET_DIAG); + + if (this->sock_.socketFd_ == -1 || this->writeSock_.socketFd_ == -1) { + closeSocks(); + return false; + } + + sockaddr_nl nl = {.nl_family = AF_NETLINK}; + if ((connect(this->sock_.socketFd_, reinterpret_cast(&nl), sizeof(nl)) == -1) || + (connect(this->writeSock_.socketFd_, reinterpret_cast(&nl), sizeof(nl)) == -1)) { + // LogError << "[Diag] connect sock failed." << endl; + NETNATIVE_LOGE("[Diag] connect sock failed."); + closeSocks(); + return false; + } + return true; +} + +int sock_diag::sockDestroy(int proto, const struct inet_diag_msg *msg) +{ + if (msg == nullptr) { + return 0; + } + + netlink_msg nlMsg(NLM_F_REQUEST, 4096, getpid()); + inet_diag_req_v2 diagMsg; + diagMsg.sdiag_family = msg->idiag_family, diagMsg.sdiag_protocol = proto, + diagMsg.idiag_states = (uint32_t)(1 << msg->idiag_state), diagMsg.id = msg->id, + nlMsg.addInetDiag(SOCK_DESTROY, diagMsg); + + if (write(writeSock_.socketFd_, nlMsg.getNetLinkMessage(), nlMsg.getNetLinkMessage()->nlmsg_len) < + nlMsg.getNetLinkMessage()->nlmsg_len) { + return -errno; + } + + return 1; +} + +int sock_diag::processDestroy(int sock, netlink_dump_callback callback) +{ + char buf[8192]; + + ssize_t bytesread; + do { + bytesread = read(sock, buf, sizeof(buf)); + if (bytesread < 0) { + return -errno; + } + + uint32_t len = bytesread; + for (nlmsghdr *nlh = reinterpret_cast(buf); NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) { + switch (nlh->nlmsg_type) { + case NLMSG_DONE: + return 0; + case NLMSG_ERROR: { + nlmsgerr *err = reinterpret_cast(NLMSG_DATA(nlh)); + // LogError << "[DiagNetlinkSocket] Socket error: " << strerror(-err->error) + // << ", type=" << err->msg.nlmsg_type << ", seq=" << err->msg.nlmsg_seq + // << ", pid=" << err->msg.nlmsg_pid << endl; + NETNATIVE_LOGE( + "[DiagNetlinkSocket] Socket error: %{public}s, type=%{public}d, seq=%{public}d, " + "pid=%{public}d", + strerror(-err->error), err->msg.nlmsg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); + return err->error; + } + default: + // common::logger::info() << "[DiagNetlinkSocket] dump: " + // << "type=" << nlh->nlmsg_type << endl; + NETNATIVE_LOGI("[DiagNetlinkSocket] dump: type=%{public}d", nlh->nlmsg_type); + callback(nlh); + } + } + } while (bytesread > 0); + + return 0; +} + +void sock_diag::socketDump(int proto, int family, int states) +{ + netlink_msg nlMsg(NLM_F_REQUEST | NLM_F_DUMP, 4096, getpid()); + inet_diag_req_v2 diagMsg; + diagMsg.sdiag_family = family, diagMsg.sdiag_protocol = proto, diagMsg.idiag_states = states, + nlMsg.addInetDiag(SOCK_DIAG_BY_FAMILY, diagMsg); + this->sock_.sendNetlinkMsgToKernel(nlMsg.getNetLinkMessage()); +} + +void sock_diag::destroySockets(std::string ifName) +{ + enum { + TCP_ESTABLISHED = 1, + TCP_SYN_SENT, + TCP_SYN_RECV, + TCP_FIN_WAIT1, + TCP_FIN_WAIT2, + TCP_TIME_WAIT, + TCP_CLOSE, + TCP_CLOSE_WAIT, + TCP_LAST_ACK, + TCP_LISTEN, + TCP_CLOSING + }; + + const int proto = IPPROTO_TCP; + const uint32_t states = (1 << TCP_ESTABLISHED) | (1 << TCP_SYN_SENT) | (1 << TCP_SYN_RECV); + + netlink_dump_callback callback = [this, ifName](nlmsghdr *nlh) { + const inet_diag_msg *msg = reinterpret_cast(NLMSG_DATA(nlh)); + if (msg != nullptr && msg->id.idiag_if == if_nametoindex(ifName.c_str()) && !isLoopbackSocket(msg)) { + sockDestroy(proto, msg); + } + }; + for (const int family : {AF_INET, AF_INET6}) { + socketDump(proto, family, states); + processDestroy(sock_.socketFd_, callback); + } +} +} // namespace nmd +} // namespace OHOS +DISABLE_WARNING_POP diff --git a/http/services/netmanagernative/net_mgr_native/src/traffic_controller.cpp b/http/services/netmanagernative/net_mgr_native/src/traffic_controller.cpp new file mode 100644 index 000000000..3ee0b2a1a --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/src/traffic_controller.cpp @@ -0,0 +1,376 @@ +#include "traffic_controller.h" +#include "logger.h" +#include "native_netd_service.h" +#include "error_code.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netnative_log_wrapper.h" + +namespace OHOS { +namespace nmd { +constexpr const char *ARP_CACHE = "/proc/net/arp"; +constexpr uint32_t ARP_STRING_LEN = 200; +constexpr uint32_t ARP_BUFFER_LEN = (ARP_STRING_LEN + 1); +constexpr const char *ARP_LINE_FORMAT = "%100s %*s 0x%100s %100s %*s %100s"; +const std::string interfaceListDir = "/sys/class/net/"; +std::vector tetherIptablesRuleCache; + +std::vector getInterfaceList() +{ + DIR *dir(nullptr); + struct dirent *ptr(nullptr); + std::vector ifList; + if ((dir = opendir(interfaceListDir.c_str())) == NULL) { + nmd::traffic_controller::traffic_controller_log(); + return ifList; + } + while ((ptr = readdir(dir)) != NULL) { + if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) + continue; + ifList.push_back(ptr->d_name); + } + closedir(dir); + return ifList; +} + +long getInterfaceTrafficByType(const std::string &path, const std::string &type) +{ + std::string trafficPath = path + type; + if (path.empty()) { + return -1; + } + int fd = open(trafficPath.c_str(), 0, 0666); + if (fd == -1) { + nmd::traffic_controller::traffic_controller_log(); + return -1; + } + char buf[100] = {0}; + if (read(fd, buf, sizeof(long)) == -1) { + nmd::traffic_controller::traffic_controller_log(); + close(fd); + return -1; + } + close(fd); + long infBytes = atol(buf); + return infBytes; +} + +void splitIptablesResult(std::string &s, std::vector &sv, const char *delim) +{ + sv.clear(); + char *buffer = new char[s.size() + 1]; + buffer[s.size()] = '\0'; + std::copy(s.begin(), s.end(), buffer); + char *p = std::strtok(buffer, delim); + do { + sv.push_back(p); + } while ((p = std::strtok(NULL, delim))); + delete[] buffer; + return; +} + +void getAllTetherTrafficStats( + const std::string &iptablesRule, std::vector &tetherTrafficAccount) +{ + FILE *pp = popen(iptablesRule.c_str(), "r"); + if (!pp) { + nmd::traffic_controller::traffic_controller_log(); + return; + } + char tmp[1024] = {}; + int i = 0; + while (fgets(tmp, sizeof(tmp), pp) != NULL) { + if (i < 2) { + i++; + continue; + } + std::string iptableResult = tmp; + std::vector splitResult; + splitIptablesResult(iptableResult, splitResult, " "); + nmd::tether_traffic_account tmpTetherTrafficAccount = {"", "", ""}; + tmpTetherTrafficAccount.bytes = splitResult[1]; + tmpTetherTrafficAccount.sourceIp = splitResult[6]; + tmpTetherTrafficAccount.destinationIp = splitResult[7]; + tetherTrafficAccount.push_back(tmpTetherTrafficAccount); + } + pclose(pp); +} + +void traffic_controller::traffic_controller_log() +{ + std::error_code err = std::error_code(errno, std::system_category()); + // LogError << err.message() << endl; + NETNATIVE_LOGD("traffic_controller::traffic_controller_log() %{public}s", err.message().c_str()); +} + +void traffic_controller::execIptablesRuleMethod(std::string &cmd) +{ + FILE *pp = popen(cmd.c_str(), "r"); + if (!pp) { + nmd::traffic_controller::traffic_controller_log(); + return; + } + char tmp[1024]; + while (fgets(tmp, sizeof(tmp), pp) != NULL) { + // LogError << tmp << endl; + NETNATIVE_LOGD("traffic_controller::execIptablesRuleMethod fgets %{public}s", tmp); + } + pclose(pp); + return; +} + +traffic_stats_parcel traffic_controller::getInterfaceTraffic(const std::string &ifName) +{ + nmd::traffic_stats_parcel interfaceTrafficBytes = {"", 0, 0, 0, 0, 0}; + std::vector ifNameList = getInterfaceList(); + if (ifNameList.empty()) { + return interfaceTrafficBytes; + } + for (auto iter = ifNameList.begin(); iter != ifNameList.end(); iter++) { + if (ifName == *iter) { + std::string base_traffic_path = interfaceListDir + (*iter) + "/" + "statistics" + "/"; + long infRxBytes = getInterfaceTrafficByType(base_traffic_path, "rx_bytes"); + long infRxPackets = getInterfaceTrafficByType(base_traffic_path, "rx_packets"); + long infTxBytes = getInterfaceTrafficByType(base_traffic_path, "tx_bytes"); + long infTxPackets = getInterfaceTrafficByType(base_traffic_path, "tx_packets"); + + interfaceTrafficBytes.iface = ifName; + interfaceTrafficBytes.ifIndex = if_nametoindex(ifName.c_str()); + + interfaceTrafficBytes.rxBytes = infRxBytes == -1 ? 0 : infRxBytes; + interfaceTrafficBytes.rxPackets = infRxPackets == -1 ? 0 : infRxPackets; + interfaceTrafficBytes.txBytes = infTxBytes == -1 ? 0 : infTxBytes; + interfaceTrafficBytes.txPackets = infTxPackets == -1 ? 0 : infTxPackets; + } + } + return interfaceTrafficBytes; +} + +long traffic_controller::getCellularRxTraffic() +{ + long allCelluRxBytes = 0; + std::vector ifNameList = getInterfaceList(); + if (ifNameList.empty()) { + return allCelluRxBytes; + } + for (auto iter = ifNameList.begin(); iter != ifNameList.end(); iter++) { + if ((*iter) == "rmnet0") { + std::string base_traffic_path = interfaceListDir + (*iter) + "/" + "statistics" + "/"; + long rxBytes = getInterfaceTrafficByType(base_traffic_path, "rx_bytes"); + allCelluRxBytes = allCelluRxBytes + rxBytes; + break; + } + } + return allCelluRxBytes; +} + +long traffic_controller::getCellularTxTraffic() +{ + long allCelluTxBytes = 0; + std::vector ifNameList = getInterfaceList(); + if (ifNameList.empty()) { + return allCelluTxBytes; + } + for (auto iter = ifNameList.begin(); iter != ifNameList.end(); iter++) { + if ((*iter) == "rmnet0") { + std::string base_traffic_path = interfaceListDir + (*iter) + "/" + "statistics" + "/"; + long txBytes = getInterfaceTrafficByType(base_traffic_path, "tx_bytes"); + allCelluTxBytes = allCelluTxBytes + txBytes; + break; + } + } + return allCelluTxBytes; +} + +long traffic_controller::getAllRxTraffic() +{ + long allRxBytes = 0; + std::vector ifNameList = getInterfaceList(); + if (ifNameList.empty()) { + return allRxBytes; + } + for (auto iter = ifNameList.begin(); iter != ifNameList.end(); iter++) { + if (*iter != "lo") { + std::string base_traffic_path = interfaceListDir + (*iter) + "/" + "statistics" + "/"; + long rxBytes = getInterfaceTrafficByType(base_traffic_path, "rx_bytes"); + allRxBytes = allRxBytes + rxBytes; + } + } + return allRxBytes; +} + +long traffic_controller::getAllTxTraffic() +{ + long allTxBytes = 0; + std::vector ifNameList = getInterfaceList(); + if (ifNameList.empty()) { + return allTxBytes; + } + for (auto iter = ifNameList.begin(); iter != ifNameList.end(); iter++) { + if (*iter != "lo") { + std::string base_traffic_path = interfaceListDir + (*iter) + "/" + "statistics" + "/"; + long txBytes = getInterfaceTrafficByType(base_traffic_path, "tx_bytes"); + allTxBytes = allTxBytes + txBytes; + } + } + return allTxBytes; +} + +std::vector traffic_controller::getTetherClientInfo() +{ + std::vector tetherClientInfo; + FILE *arpCache = fopen(ARP_CACHE, "r"); + if (!arpCache) { + traffic_controller_log(); + return tetherClientInfo; + } + + char header[ARP_BUFFER_LEN]; + if (!fgets(header, sizeof(header), arpCache)) { + fclose(arpCache); + return tetherClientInfo; + } + + char ipAddr[ARP_BUFFER_LEN] = {0}, hwAddr[ARP_BUFFER_LEN] = {0}, device[ARP_BUFFER_LEN] = {0}, + state[ARP_BUFFER_LEN] = {0}; + while (4 == fscanf(arpCache, ARP_LINE_FORMAT, ipAddr, state, hwAddr, device)) { + arp_cache_information tmpArpCacheInfo = {"", "", "", ""}; + tmpArpCacheInfo.dev = device; + tmpArpCacheInfo.ipAddr = ipAddr; + tmpArpCacheInfo.macAddr = hwAddr; + tmpArpCacheInfo.state = state; + tetherClientInfo.push_back(tmpArpCacheInfo); + memset(ipAddr, 0, ARP_BUFFER_LEN); + memset(hwAddr, 0, ARP_BUFFER_LEN); + memset(device, 0, ARP_BUFFER_LEN); + memset(state, 0, ARP_BUFFER_LEN); + } + fclose(arpCache); + return tetherClientInfo; +} + +void traffic_controller::startTrafficTether() +{ + auto tetherClientInfo = nmd::traffic_controller::getTetherClientInfo(); + + if (tetherClientInfo.empty()) { + return; + } else { + for (auto iter = tetherClientInfo.begin(); iter != tetherClientInfo.end(); iter++) { + // find in cache , to prevent iptables if one ip to exec many times + auto it = find(tetherIptablesRuleCache.begin(), tetherIptablesRuleCache.end(), (*iter).ipAddr); + if (it != tetherIptablesRuleCache.end()) { + continue; + } else { + std::string trafficInputIptables = + "iptables -I TETHER_TRAFFIC -d " + iter->ipAddr; //相对于这个ip的入网,即input的流量 + execIptablesRuleMethod(trafficInputIptables); + std::string trafficOutputIptables = + "iptables -I TETHER_TRAFFIC -s " + iter->ipAddr; //相对于这个ip的出网,即output的流量 + execIptablesRuleMethod(trafficOutputIptables); + std::string trafficInputIptablesAttach = + "iptables -I FORWARD -d " + iter->ipAddr + " -j TETHER_TRAFFIC"; + execIptablesRuleMethod(trafficInputIptablesAttach); + std::string trafficOutputIptablesAttach = + "iptables -I FORWARD -s " + iter->ipAddr + " -j TETHER_TRAFFIC"; + execIptablesRuleMethod(trafficOutputIptablesAttach); + tetherIptablesRuleCache.push_back((*iter).ipAddr); + } + } + } +} + +long traffic_controller::getTxTetherTraffic() +{ + std::vector tetherTrafficAccount; + long tetherTrafficBytes = 0; + std::string getIptablesResutlRule = "iptables -n -v -L TETHER_TRAFFIC -t filter -x"; + getAllTetherTrafficStats(getIptablesResutlRule, tetherTrafficAccount); + for (auto iter = tetherTrafficAccount.begin(); iter != tetherTrafficAccount.end(); ++iter) { + if ((*iter).destinationIp != "0.0.0.0/0") { + tetherTrafficBytes = tetherTrafficBytes + atol(((*iter).bytes).c_str()); + } + } + return tetherTrafficBytes; +} + +long traffic_controller::getRxTetherTraffic() +{ + std::vector tetherTrafficAccount; + long tetherTrafficBytes = 0; + std::string getIptablesResutlRule = "iptables -n -v -L TETHER_TRAFFIC -t filter -x"; + getAllTetherTrafficStats(getIptablesResutlRule, tetherTrafficAccount); + for (auto iter = tetherTrafficAccount.begin(); iter != tetherTrafficAccount.end(); ++iter) { + if ((*iter).sourceIp != "0.0.0.0/0") { + tetherTrafficBytes = tetherTrafficBytes + atol(((*iter).bytes).c_str()); + } + } + return tetherTrafficBytes; +} +int logForGetUidTraffic(int sock) +{ + nmd::traffic_controller::traffic_controller_log(); + close(sock); + return -1; +} +long getUidTrafficFromBPF(int uid, int cgroupType) +{ + int sock; + sockaddr_un s_un; + char buf[128]; + ssize_t writeRet; + ssize_t readRet; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + return logForGetUidTraffic(sock); + } + s_un.sun_family = AF_UNIX; + strcpy(s_un.sun_path, "/dev/socket/traffic"); + DISABLE_WARNING_PUSH + DISABLE_WARNING_OLD_STYLE_CAST + if (connect(sock, (sockaddr *)&s_un, sizeof(s_un)) != 0) { + return logForGetUidTraffic(sock); + } + memset(buf, 0, sizeof(buf)); + std::string query = std::to_string(uid) + "," + std::to_string(cgroupType); + strcpy(buf, query.c_str()); + writeRet = write(sock, buf, strlen(buf)); + if (writeRet < 0) { + return logForGetUidTraffic(sock); + } + memset(buf, 0, sizeof(buf)); + readRet = read(sock, buf, sizeof(buf)); + if (readRet < 0) { + return logForGetUidTraffic(sock); + } + close(sock); + return atol(buf); +} + +long traffic_controller::getRxUidTraffic(int uid) +{ + long result = getUidTrafficFromBPF(uid, 0); + return result; +} + +long traffic_controller::getTxUidTraffic(int uid) +{ + long result = getUidTrafficFromBPF(uid, 1); + return result; +} + +} // namespace nmd +} // namespace OHOS +DISABLE_WARNING_POP \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/BUILD.gn b/http/services/netmanagernative/net_mgr_native/tests/BUILD.gn new file mode 100644 index 000000000..30d652fba --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/BUILD.gn @@ -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. + +import("//build/ohos.gni") + +SUBSYSTEM_DIR = "//foundation/communication" +NETMANAGER_ROOT = "$SUBSYSTEM_DIR/netstack/http" +NETMANAGERNATIVE_ROOT = "$NETMANAGER_ROOT/services/netmanagernative" +INNERKITS_ROOT = "$NETMANAGER_ROOT/interfaces/innerkits" +NETCONNMANAGER_SOURCE_DIR = "$NETMANAGER_ROOT/services/netconnmanager" + +ohos_executable("net_manager_native_test") { + sources = [ + "main.cpp", + "dns_query.cpp", + "set_param.cpp", + ] + + include_dirs = [ + "$NETCONNMANAGER_SOURCE_DIR/include", + "$NETCONNMANAGER_SOURCE_DIR/include/ipc", + "$NETCONNMANAGER_SOURCE_DIR/include/net_controller", + "$INNERKITS_ROOT/native/netconnmanager/include", + "$NETMANAGERNATIVE_ROOT/net_mgr_native/include", + "$NETMANAGERNATIVE_ROOT/common/include" , + "$NETMANAGERNATIVE_ROOT/net_mgr_native/client/include", + "$NETMANAGERNATIVE_ROOT/net_mgr_native/tests/include", + "//foundation/communication/netstack/http/services/netmanagernative/common/include" + ] + + deps = [ + "$NETMANAGER_ROOT/utils:net_manager_common", + "$INNERKITS_ROOT/native/netconnmanager:net_conn_manager_if", + "//utils/native/base:utils", + "$NETMANAGER_ROOT/services/netmanagernative:net_manager_native" + ] + + external_deps = [ + "safwk:system_ability_fwk", + "appexecfwk_standard:libeventhandler", + "samgr_L2:samgr_proxy", + "ipc:ipc_core", + "aafwk_standard:want", + ] + + defines = [ + "NETMGR_LOG_TAG = \"NetManagerNative\"", + "LOG_DOMAIN = 0xD0015B0", + ] + + if (is_standard_system) { + external_deps += [ "hiviewdfx_hilog_native:libhilog" ] + } else { + external_deps += [ "hilog:libhilog" ] + } + + part_name = "netstack" + subsystem_name = "communication" +} + + diff --git a/http/services/netmanagernative/net_mgr_native/tests/api_time_elapsed.cpp b/http/services/netmanagernative/net_mgr_native/tests/api_time_elapsed.cpp new file mode 100644 index 000000000..60166e964 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/api_time_elapsed.cpp @@ -0,0 +1,124 @@ +#include "time_elapsed.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include "netlink_manager.h" +#include "netlink_msg.h" +#include "netlink_socket.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dnsresolv_service.h" +#include +#include "traffic_init.h" + +int main() +{ + nmd::native_nted_service nns; + + GEN_INVOKE_US(createNetwork, 创建网络, nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE)); + createNetwork(); + + GEN_INVOKE_US(addInterface, 网络添加interface, nns.networkAddInterface(12, "eth0")); + addInterface(); + + GEN_INVOKE_US(removeInterface, 网络移除interface, nns.networkRemoveInterface(12, "eth0")); + removeInterface(); + + GEN_INVOKE_US(interfaceAddAddress, interface添加地址, nns.interfaceAddAddress("lo", "192.168.0.12", 32)); + interfaceAddAddress(); + + GEN_INVOKE_US(interfaceRemoveAddress, interface移除地址, nns.interfaceDelAddress("lo", "192.168.0.12", 32)); + interfaceRemoveAddress(); + + GEN_INVOKE_US(interfaceAddRoute, interface添加路由, + nns.networkAddRoute(12, "eth0", "47.94.251.146/32", "10.205.127.254")); + interfaceAddRoute(); + + GEN_INVOKE_US(interfaceRemoveRoute, interface删除路由, + nns.networkRemoveRoute(12, "eth0", "47.94.251.146/32", "10.205.127.254")); + interfaceRemoveRoute(); + + GEN_INVOKE_US(setDefaultNetwork, 设置默认网络, nns.networkSetDefault(12)); + setDefaultNetwork(); + + GEN_INVOKE_US(getDefaultNetwork, 获取默认网络, nns.networkGetDefault()); + getDefaultNetwork(); + + GEN_INVOKE_US(clearDefaultNetwork, 清除默认网络, nns.networkClearDefault()); + clearDefaultNetwork(); + + GEN_INVOKE_US(getInterfaceList, 获取interface列表, nns.interfaceGetList()); + getInterfaceList(); + + GEN_INVOKE_US(setPermissionForNetwork, 设置网络权限, + nns.networkSetPermissionForNetwork(12, nmd::NetworkPermission::PERMISSION_NETWORK)); + setPermissionForNetwork(); + + GEN_INVOKE_US(interfaceSetMtu, 设置网络MTU, nns.interfaceSetMtu("eth0", 1500)); + interfaceSetMtu(); + + GEN_INVOKE_US(setProcSysNet, 设置网络参数, + nns.setProcSysNet(nmd::set_proc_sys_net::IPV4, nmd::set_proc_sys_net::CONF, "eth0", "forwarding", "1")); + setProcSysNet(); + + // std::string vv=""; + // GEN_INVOKE_US(getProcSysNet, 获取网络参数, nns.getProcSysNet(nmd::set_proc_sys_net::IPV4, + // nmd::get_proc_sys_net::CONF, "eth0", "forwarding", &vv)); getProcSysNet(); + + GEN_INVOKE_US(destroyNetwork, 销毁网络, nns.networkDestroy(12)); + destroyNetwork(); + + GEN_INVOKE_US(getInterfaceConfig, 获取interface配置, nmd::interface_controller::getConfig("eth0")); + getInterfaceConfig(); + + GEN_INVOKE_US(getInterfaceTraffic, 获取interface的流量, nmd::traffic_controller::getInterfaceTraffic("eth0")); + getInterfaceTraffic(); + + GEN_INVOKE_US(getCellularRxTraffic, 获取蜂窝下行流量, nmd::traffic_controller::getCellularRxTraffic()); + getCellularRxTraffic(); + + GEN_INVOKE_US(getCellularTxTraffic, 获取蜂窝上行流量, nmd::traffic_controller::getCellularTxTraffic()); + getCellularTxTraffic(); + + GEN_INVOKE_US(getRxTetherTraffic, 获取热点下行流量, nmd::traffic_controller::getRxTetherTraffic()); + getRxTetherTraffic(); + + GEN_INVOKE_US(getTxTetherTraffic, 获取热点上行流量, nmd::traffic_controller::getTxTetherTraffic()); + getTxTetherTraffic(); + + GEN_INVOKE_US(getAllRx, 获取所有下行流量, nmd::traffic_controller::getAllRxTraffic()); + getAllRx(); + + GEN_INVOKE_US(getAddTx, 获取所有上行流量, nmd::traffic_controller::getAllTxTraffic()); + getAddTx(); + + GEN_INVOKE_US(getUid0Tx, 获取UID0的上行流量, nmd::traffic_controller::getTxUidTraffic(0)); + getUid0Tx(); + + GEN_INVOKE_US(getUid0Rx, 获取UID0的下行流量, nmd::traffic_controller::getRxUidTraffic(0)); + getUid0Rx(); + + return 1; +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/bit_cast_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/bit_cast_test.cpp new file mode 100644 index 000000000..2d1beec59 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/bit_cast_test.cpp @@ -0,0 +1,11 @@ +#include +#include + +TEST(bit_cast, can_cast_different_type) +{ + constexpr double f64v = 19880124.0; + auto u64v = nmd::common::bit_cast(f64v); + std::stringstream ss; + ss << std::hex << u64v; + EXPECT_EQ(ss.str(), "4172f58bc0000000"); +} diff --git a/http/services/netmanagernative/net_mgr_native/tests/dns_query.cpp b/http/services/netmanagernative/net_mgr_native/tests/dns_query.cpp new file mode 100644 index 000000000..fc518ed20 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/dns_query.cpp @@ -0,0 +1,186 @@ +#include "main.h" +#include "dnsresolv.h" +#include "native_netd_service.h" +#include "netlink_manager.h" +#include "fwmark_server.h" +#include "dnsresolv_service.h" + +#include "netnative_log_wrapper.h" +#include + +const uint16_t TEST_NETID = 65501; +const uint32_t NETID_UNSET = 0u; +void jobRunBadParam() +{ + auto job = std::make_shared(-1, nullptr, 0, nullptr); + // ASSERT_THAT(job, ::testing::Ne(nullptr)); + if (job == nullptr) { + std::cout << "job is null!" << std::endl; + } + job->run(); +} + +void TestSetResolverConfig() +{ + NETNATIVE_LOGE("TestSetResolverConfig:: begin"); + OHOS::nmd::NativeNetdService service; + service.init(); + + int pid = getpid(); + OHOS::nmd::netlink_manager manager(pid); + std::thread nlManager([&] { manager.start(); }); + + OHOS::nmd::fwmark_server fwmarkServer; + std::thread fwserve([&] { fwmarkServer.start(); }); + + OHOS::nmd::dnsresolv_service dnsresolvService; + std::thread dnsresolvServe([&] { dnsresolvService.start(); }); + + nlManager.detach(); + fwserve.detach(); + dnsresolvServe.detach(); + + NETNATIVE_LOGE("TestSetResolverConfig:: createNetworkCache"); + //先创建 + dnsresolvService.createNetworkCache(NETID_UNSET); + NETNATIVE_LOGE("TestSetResolverConfig::end createNetworkCache"); + + const OHOS::nmd::dnsresolver_params param = { + NETID_UNSET, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + NETNATIVE_LOGE("TestSetResolverConfig begin to setResolverConfig"); + dnsresolvService.setResolverConfig(param); + NETNATIVE_LOGE("TestSetResolverConfig end "); +} + +void TestCreateNetworkCache() +{ + OHOS::nmd::NativeNetdService service; + service.init(); + + int pid = getpid(); + OHOS::nmd::netlink_manager manager(pid); + std::thread nlManager([&] { manager.start(); }); + + OHOS::nmd::fwmark_server fwmarkServer; + std::thread fwserve([&] { fwmarkServer.start(); }); + + OHOS::nmd::dnsresolv_service dnsresolvService; + std::thread dnsresolvServe([&] { dnsresolvService.start(); }); + + nlManager.detach(); + fwserve.detach(); + dnsresolvServe.detach(); + + NETNATIVE_LOGE("TestCreateNetworkCache:: begin"); + dnsresolvService.createNetworkCache(NETID_UNSET); + NETNATIVE_LOGE("TestCreateNetworkCache:: end"); +} + +void TestFlushNetworkCache() +{ + OHOS::nmd::NativeNetdService service; + service.init(); + + int pid = getpid(); + OHOS::nmd::netlink_manager manager(pid); + std::thread nlManager([&] { manager.start(); }); + + OHOS::nmd::fwmark_server fwmarkServer; + std::thread fwserve([&] { fwmarkServer.start(); }); + + OHOS::nmd::dnsresolv_service dnsresolvService; + std::thread dnsresolvServe([&] { dnsresolvService.start(); }); + + nlManager.detach(); + fwserve.detach(); + dnsresolvServe.detach(); + + NETNATIVE_LOGE("TestflushNetworkCache:: begin"); + dnsresolvService.flushNetworkCache(TEST_NETID); + NETNATIVE_LOGE("TestflushNetworkCache:: end"); +} + +void TestDestoryNetworkCache() +{ + OHOS::nmd::NativeNetdService service; + service.init(); + + int pid = getpid(); + OHOS::nmd::netlink_manager manager(pid); + std::thread nlManager([&] { manager.start(); }); + + OHOS::nmd::fwmark_server fwmarkServer; + std::thread fwserve([&] { fwmarkServer.start(); }); + + OHOS::nmd::dnsresolv_service dnsresolvService; + std::thread dnsresolvServe([&] { dnsresolvService.start(); }); + + nlManager.detach(); + fwserve.detach(); + dnsresolvServe.detach(); + + NETNATIVE_LOGE("destoryNetworkCache:: begin"); + dnsresolvService.destoryNetworkCache(NETID_UNSET); + NETNATIVE_LOGE("destoryNetworkCache:: end"); +} + +void TestGetaddrinfo() +{ + OHOS::nmd::NativeNetdService service; + service.init(); + + int pid = getpid(); + OHOS::nmd::netlink_manager manager(pid); + std::thread nlManager([&] { manager.start(); }); + + OHOS::nmd::fwmark_server fwmarkServer; + std::thread fwserve([&] { fwmarkServer.start(); }); + + OHOS::nmd::dnsresolv_service dnsresolvService; + std::thread dnsresolvServe([&] { dnsresolvService.start(); }); + + nlManager.detach(); + fwserve.detach(); + dnsresolvServe.detach(); + + //先创建 + NETNATIVE_LOGE("createNetworkCache:: begin"); + dnsresolvService.createNetworkCache(NETID_UNSET); + + const OHOS::nmd::dnsresolver_params param = { + OHOS::nmd::NETID_UNSET, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + //配置 + NETNATIVE_LOGE("setResolverConfig:: begin"); + dnsresolvService.setResolverConfig(param); + + char hostName[OHOS::nmd::MAX_NAME_LEN]; + strncpy(hostName, "www.baidu.com", OHOS::nmd::MAX_NAME_LEN); + char serverName[OHOS::nmd::MAX_NAME_LEN] = ""; + struct addrinfo hints; + bzero(&hints, sizeof(addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + + //域名解析 + NETNATIVE_LOGI("getaddrinfo:: begin"); + struct addrinfo *res1, *res_p1; + int ret = dnsresolvService.getaddrinfo(hostName, serverName, &hints, &res1); + if (ret != 0) { + // printf("getaddrinfo: %s\n", gai_strerror(ret)); + NETNATIVE_LOGE("getaddrinfo error: %{public}s", gai_strerror(ret)); + return; + } + + for (res_p1 = res1; res_p1 != NULL; res_p1 = res_p1->ai_next) { + char host[1024] = {0}; + ret = getnameinfo(res_p1->ai_addr, res_p1->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST); + if (ret != 0) + printf("getnameinfo: %s\n", gai_strerror(ret)); + else + printf("ip: %s\n", host); + } + freeaddrinfo(res1); + NETNATIVE_LOGI("getaddrinfo:: end"); +} diff --git a/http/services/netmanagernative/net_mgr_native/tests/dnsresolv_client_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/dnsresolv_client_test.cpp new file mode 100644 index 000000000..c09513ad8 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/dnsresolv_client_test.cpp @@ -0,0 +1,53 @@ + +#include "dnsresolv_client_test.h" +#include +#include + +nmd::dnsresolv_client dnsresolv_client_test::dnsresolvClient_; + +int dnsresolv_client_test::initConfig() +{ + dnsresolvClient_.init(); + auto ret = dnsresolvClient_.initConfiguration(params); + if (ret != 0) { + printf("getaddrinfo: error, can not initConfiguration\n"); + return -1; + } + return 0; +} + +int dnsresolv_client_test::get_addr_info_test(const char *hostname) +{ + int ret = 0; + + if (!hostname) { + printf("invalid params\n"); + return -1; + } + + struct addrinfo hints; + struct addrinfo *res, *res_p; + std::memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + + ret = dnsresolvClient_.getaddrinfo(hostname, NULL, &hints, &res); + if (ret != 0) { + printf("getaddrinfo: %s\n", gai_strerror(ret)); + return -1; + } + + for (res_p = res; res_p != NULL; res_p = res_p->ai_next) { + char host[1024] = {0}; + ret = getnameinfo(res_p->ai_addr, res_p->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST); + if (ret != 0) + printf("getnameinfo: %s\n", gai_strerror(ret)); + else + printf("ip: %s\n", host); + } + + freeaddrinfo(res); + return ret; +} diff --git a/http/services/netmanagernative/net_mgr_native/tests/dnsresolv_client_test.h b/http/services/netmanagernative/net_mgr_native/tests/dnsresolv_client_test.h new file mode 100644 index 000000000..6cf0aa8f0 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/dnsresolv_client_test.h @@ -0,0 +1,25 @@ +#ifndef __CASE_DNSRESOLV_CLIENT_TEST_H__ +#define __CASE_DNSRESOLV_CLIENT_TEST_H__ +#include "dnsresolv_client.h" + +class dnsresolv_client_test { + const nmd::dnsresolver_params params = { + nmd::NETID_UNSET, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + +private: + static nmd::dnsresolv_client dnsresolvClient_; + +public: + dnsresolv_client_test() {} + + ~dnsresolv_client_test() + { + dnsresolvClient_.unInitConfiguration(params); + } + +public: + int initConfig(); + int get_addr_info_test(const char *hostname); +}; + +#endif //!__CASE_DNSRESOLV_CLIENT_TEST_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/error_code_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/error_code_test.cpp new file mode 100644 index 000000000..893e17e09 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/error_code_test.cpp @@ -0,0 +1,12 @@ +#include "error_code.h" +#include +#include +#include + +// test error_code +TEST(error_code, error_code_is_1) +{ + std::error_code ec1 = nmd::common::error_code::errNoInfName; + EXPECT_EQ(ec1.value(), 1); + EXPECT_EQ(ec1.message(), "no such interface name"); +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/fwmark_client_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/fwmark_client_test.cpp new file mode 100644 index 000000000..1911f0abb --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/fwmark_client_test.cpp @@ -0,0 +1,13 @@ +#include +#include +#include + +TEST(fwmark_client, bindSocket) +{ + nmd::fwmark_client client; + nmd::fwmark_command command; + command.cmdId = nmd::fwmark_command::SELECT_NETWORK; + command.fd = 1; + command.netId = 12; + client.send(&command); +} diff --git a/http/services/netmanagernative/net_mgr_native/tests/interface_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/interface_test.cpp new file mode 100644 index 000000000..731396003 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/interface_test.cpp @@ -0,0 +1,338 @@ +#include "interface_controller.h" +#include "interface_utils.h" +#include "native_netd_service.h" +#include "net_utils.h" +#include "warning_disable.h" +#include "utils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +struct IfaddrsDeleter { + void operator()(struct ifaddrs *p) const + { + if (p != nullptr) { + freeifaddrs(p); + } + } +}; + +typedef std::unique_ptr ScopedIfaddrs; + +int netmaskToPrefixLength(const uint8_t *buf, size_t buflen) +{ + if (buf == nullptr) + return -1; + + int prefixLength = 0; + bool endOfContiguousBits = false; + for (unsigned int i = 0; i < buflen; i++) { + const uint8_t value = buf[i]; + + // Bad bit sequence: check for a contiguous set of bits from the high + // end by verifying that the inverted value + 1 is a power of 2 + // (power of 2 iff. (v & (v - 1)) == 0). + const uint8_t inverse = ~value + 1; + if ((inverse & (inverse - 1)) != 0) + return -1; + + prefixLength += (value == 0) ? 0 : CHAR_BIT - ffs(value) + 1; + + // Bogus netmask. + if (endOfContiguousBits && value != 0) + return -1; + + if (value != 0xff) + endOfContiguousBits = true; + } + + return prefixLength; +} + +template +int netmaskToPrefixLength(const T *p) +{ + return netmaskToPrefixLength(reinterpret_cast(p), sizeof(T)); +} + +bool interfaceHasAddress(const std::string &ifname, const char *addrString, int prefixLength) +{ + struct addrinfo *addrinfoList = nullptr; + + DISABLE_WARNING_PUSH + DISABLE_WARNING_MISSING_FIELD_INITIALIZERS + + const struct addrinfo hints = {AI_NUMERICHOST, AF_UNSPEC, SOCK_DGRAM}; + + DISABLE_WARNING_POP + + if (getaddrinfo(addrString, nullptr, &hints, &addrinfoList) != 0 || addrinfoList == nullptr || + addrinfoList->ai_addr == nullptr) { + return false; + } + nmd::common::net_utils::ScopedAddrinfo addrinfoCleanup(addrinfoList); + + struct ifaddrs *ifaddrsList = nullptr; + + int getIfaddrResult = getifaddrs(&ifaddrsList); + ScopedIfaddrs ifaddrsCleanup(ifaddrsList); + + if (getIfaddrResult != 0) { + return false; + } + + for (struct ifaddrs *addr = ifaddrsList; addr != nullptr; addr = addr->ifa_next) { + if (std::string(addr->ifa_name) != ifname || addr->ifa_addr == nullptr || + addr->ifa_addr->sa_family != addrinfoList->ai_addr->sa_family) { + continue; + } + + switch (addr->ifa_addr->sa_family) { + case AF_INET: { + auto *addr4 = reinterpret_cast(addr->ifa_addr); + auto *want = reinterpret_cast(addrinfoList->ai_addr); + if (memcmp(&addr4->sin_addr, &want->sin_addr, sizeof(want->sin_addr)) != 0) { + continue; + } + + if (prefixLength < 0) + return true; // not checking prefix lengths + + if (addr->ifa_netmask == nullptr) + return false; + auto *nm = reinterpret_cast(addr->ifa_netmask); + EXPECT_EQ(prefixLength, netmaskToPrefixLength(&nm->sin_addr)); + return (prefixLength == netmaskToPrefixLength(&nm->sin_addr)); + } + case AF_INET6: { + auto *addr6 = reinterpret_cast(addr->ifa_addr); + auto *want = reinterpret_cast(addrinfoList->ai_addr); + if (memcmp(&addr6->sin6_addr, &want->sin6_addr, sizeof(want->sin6_addr)) != 0) { + continue; + } + + if (prefixLength < 0) + return true; // not checking prefix lengths + + if (addr->ifa_netmask == nullptr) + return false; + auto *nm = reinterpret_cast(addr->ifa_netmask); + EXPECT_EQ(prefixLength, netmaskToPrefixLength(&nm->sin6_addr)); + return (prefixLength == netmaskToPrefixLength(&nm->sin6_addr)); + } + default: + // Cannot happen because we have already screened for matching + // address families at the top of each iteration. + continue; + } + } + return false; +} +void getValueFromFilesystem(const std::string &filePath, char *returnValue) +{ + int fd = open(filePath.c_str(), 0, 0666); + read(fd, returnValue, sizeof(int)); + close(fd); +} +} // namespace + +TEST(interface, loIpAddrShouldClear) +{ + // get origin addr + unsigned orignAddr, afterClearAddr, recoverAddr; + nmd::common::interface_utils::ifcInit(); + nmd::common::interface_utils::ifcGetAddr("lo", &orignAddr); + // clear addr + nmd::native_nted_service nativeNetdService; + nativeNetdService.interfaceClearAddrs("lo"); + // recover addr + nmd::common::interface_utils::ifcGetAddr("lo", &afterClearAddr); + EXPECT_EQ(afterClearAddr, 0u); + nmd::common::interface_utils::ifcInit(); + nmd::common::interface_utils::ifcSetAddr("lo", orignAddr); + nmd::common::interface_utils::ifcGetAddr("lo", &recoverAddr); + EXPECT_EQ(recoverAddr, orignAddr); +} + +TEST(interface, InterfaceMtuShouldBe2000AfterSetMtu) +{ + std::string testMtu("2000"); + std::string ifName = "eth0"; + std::string setMtuPath = std::string("/sys/class/net/") + ifName + std::string("/mtu"); + // get origin mtu + char originMtuValue[100] = {0}; + getValueFromFilesystem(setMtuPath, originMtuValue); + // set mtu + nmd::native_nted_service nativeNetdService; + EXPECT_EQ(nativeNetdService.interfaceSetMtu(ifName, 2000), 0); + char updateMtuValue[100] = {0}; + getValueFromFilesystem(setMtuPath, updateMtuValue); + EXPECT_EQ(std::string(updateMtuValue), testMtu); + // recover origin mtu + nmd::interface_controller::setMtu(ifName.c_str(), originMtuValue); + char recoverMtuValue[100] = {0}; + getValueFromFilesystem(setMtuPath, recoverMtuValue); + EXPECT_EQ(std::string(recoverMtuValue), originMtuValue); +} + +TEST(interface, InterfaceMtuShouldBe2000AfterGetMtu) +{ + std::string ifName = "eth0"; + std::string setMtuPath = std::string("/sys/class/net/") + ifName + std::string("/mtu"); + // get origin mtu + char originMtuValue[100] = {0}; + getValueFromFilesystem(setMtuPath, originMtuValue); + // get mtu + nmd::native_nted_service nativeNetdService; + EXPECT_EQ(nativeNetdService.interfaceGetMtu(ifName), atoi(originMtuValue)); +} + +TEST(interface, InterfaceMtuShouldGetMtuFailedWhenNameIsFault) +{ + std::string ifName = "__xx"; + EXPECT_EQ(nmd::interface_controller::getMtu(ifName.c_str()), -1); +} + +TEST(interface, InterfaceMtuShouldGetMtuFailedWhenNameIsNotExists) +{ + std::string ifName = "xxxxx20"; + EXPECT_EQ(nmd::interface_controller::getMtu(ifName.c_str()), -1); +} + +TEST(interface, InterfaceMtuShouldSetMtuFailedWhenNameIsFault) +{ + std::string testMtu("2000"); + std::string ifName = "__xx"; + std::string setMtuPath = std::string("/sys/class/net/") + ifName + std::string("/mtu"); + // get origin mtu + char originMtuValue[100] = {0}; + getValueFromFilesystem(setMtuPath, originMtuValue); + // set mtu + EXPECT_EQ(nmd::interface_controller::setMtu(ifName.c_str(), testMtu.c_str()), -1); +} + +TEST(interface, InterfaceMtuShouldSetMtuFailedWhenNameIsFault1) +{ + std::string testMtu("2000"); + std::string ifName = "a4_-:.xx"; + std::string setMtuPath = std::string("/sys/class/net/") + ifName + std::string("/mtu"); + // get origin mtu + char originMtuValue[100] = {0}; + getValueFromFilesystem(setMtuPath, originMtuValue); + // set mtu + EXPECT_EQ(nmd::interface_controller::setMtu(ifName.c_str(), testMtu.c_str()), -1); +} + +TEST(interface, interfaceAddAddressFaildWhenIfNameIsEmpty) +{ + EXPECT_EQ(nmd::interface_controller::interfaceAddAddress("", "192.168.1.1", 8), -1); +} + +TEST(interface, interfaceAddAddressFaildWhenAddrIsEmpty) +{ + EXPECT_EQ(nmd::interface_controller::interfaceAddAddress("eth0", "", 8), -1); +} + +TEST(interface, interfaceDelAddressFaildWhenIfNameIsEmpty) +{ + EXPECT_EQ(nmd::interface_controller::interfaceDelAddress("", "192.168.1.1", 8), -1); +} + +TEST(interface, interfaceDelAddressFaildWhenAddrIsEmpty) +{ + EXPECT_EQ(nmd::interface_controller::interfaceDelAddress("eth0", "", 8), -1); +} + +TEST(interface, setParameterFailedWhenParameterPathIsEmpty) +{ + EXPECT_EQ(nmd::interface_controller::setParameter("ipv8", "/", "eth0", "p", "v"), -1); +} + +TEST(interface, InterfaceMtuShouldSetMtuFailedWhenNameIsEmpty) +{ + std::string testMtu("2000"); + std::string ifName = ""; + std::string setMtuPath = std::string("/sys/class/net/") + ifName + std::string("/mtu"); + // get origin mtu + char originMtuValue[100] = {0}; + getValueFromFilesystem(setMtuPath, originMtuValue); + // set mtu + EXPECT_EQ(nmd::interface_controller::setMtu(ifName.c_str(), testMtu.c_str()), -1); +} + +TEST(interface, InterfaceListSizeShouldNotBeZero) +{ + auto interfaceList = nmd::interface_controller::getInterfaceNames(); + EXPECT_NE(interfaceList.size(), 0u); +} + +TEST(interface, InterfaceAddressShouldBeAddAndDelete) +{ + // add addr + std::string ifName = "eth0"; + std::string addrString = "10.0.0.1"; + int prefixLen = 24; + auto ret = nmd::interface_controller::interfaceAddAddress(ifName, addrString, prefixLen); + EXPECT_EQ(ret, 0); + EXPECT_TRUE(interfaceHasAddress(ifName, addrString.c_str(), prefixLen)); + + // delete addr + ret = nmd::interface_controller::interfaceDelAddress(ifName, addrString, prefixLen); + EXPECT_EQ(ret, 0); + EXPECT_FALSE(interfaceHasAddress(ifName, addrString.c_str(), prefixLen)); +} + +TEST(interface, SetProcSysNetArgShouldBeChange) +{ + nmd::native_nted_service test; + std::string path = ("/proc/sys/net/ipv4/conf/eth0/disable_policy"); + // get origin + char originDisablePolicyValue[100] = {0}; + getValueFromFilesystem(path, originDisablePolicyValue); + // set + test.setProcSysNet(4, 1, std::string("eth0"), std::string("disable_policy"), std::string("1")); + char afterSetDisablePolicyValue[100] = {0}; + getValueFromFilesystem(path, afterSetDisablePolicyValue); + EXPECT_EQ(std::string(afterSetDisablePolicyValue), std::string("1\n")); + // recover + test.setProcSysNet( + 4, 1, std::string("eth0"), std::string("disable_policy"), std::string(originDisablePolicyValue)); + char recoverSetDisablePolicyValue[100] = {0}; + getValueFromFilesystem(path, recoverSetDisablePolicyValue); + EXPECT_EQ(std::string(recoverSetDisablePolicyValue), std::string(originDisablePolicyValue)); +} + +TEST(interface, GetProcSysNetArg) +{ + nmd::native_nted_service test; + test.setProcSysNet(4, 1, std::string("eth0"), std::string("disable_policy"), std::string("1")); + std::string readValue; + test.getProcSysNet(4, 1, std::string("eth0"), std::string("disable_policy"), &readValue); + std::cout << readValue << std::endl; + EXPECT_EQ(readValue, std::string("1\n")); +} + +TEST(interface, interfaceGetInterfaceConfig) +{ + nmd::interface_configuration_parcel parcel = nmd::interface_controller::getConfig("eth0"); + EXPECT_EQ(parcel.ifName, "eth0"); +} + +TEST(interface, interfaceSetInterfaceConfig) +{ + nmd::native_nted_service nativeNetdService; + nmd::interface_configuration_parcel parcel = nmd::interface_controller::getConfig("lo"); + EXPECT_EQ(parcel.ifName, "lo"); + std::cout << parcel << std::endl; + nativeNetdService.interfaceSetConfig(parcel); + parcel = nmd::interface_controller::getConfig("lo"); + EXPECT_EQ(parcel.ifName, "lo"); +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/iptables_restore_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/iptables_restore_test.cpp new file mode 100644 index 000000000..6f2e54b39 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/iptables_restore_test.cpp @@ -0,0 +1,13 @@ +#include +#include +#include +#include +#include + +TEST(iptables_restore, IpTablesRestoreProcessForkAndExecute) +{ + std::shared_ptr process = nmd::iptables_process::forkAndExecute(); + + std::string result; + EXPECT_TRUE(process->waitForAck(result)); +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/main.cpp b/http/services/netmanagernative/net_mgr_native/tests/main.cpp new file mode 100644 index 000000000..ce323e2bc --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/main.cpp @@ -0,0 +1,113 @@ +#include +#include +#include +//#include +#include "native_netd_service.h" +#include "netlink_manager.h" +#include "fwmark_server.h" +#include "dnsresolv_service.h" +#include "netnative_log_wrapper.h" +#include "main.h" + +using namespace OHOS::nmd; +std::map g_memberFuncMap; +int32_t GetInputData() +{ + int32_t input; + std::cin >> input; + while (std::cin.fail()) { + std::cin.clear(); + std::cin.ignore(); + printf("Input error, please input number again\n"); + std::cin >> input; + } + return input; +} + +void Prompt() +{ + printf( + "\n-----------start test netd api--------------\n" + "0 TestSetResolverConfig\n" + "1 TestCreateNetworkCache\n" + "2 TestFlushNetworkCache\n" + "3 TestDestoryNetworkCache\n" + "4 TestGetaddrinfo\n" + "5 TestInterfaceSetMtu\n" + "6 TestNetworkSetDefault\n" + "7 TestNetworkGETDefault\n" + "8 TestNetworkClearDefault\n" + "9 TestNetworkCreatePhysical\n" + "10 TestInterfaceAddAddress\n" + "11 TestInterfaceDelAddress\n" + "12 TestNetworkAddInterface\n" + "13 TestNetworkRemoveInterface\n" + "14 TestGetFwmarkForNetwork\n" + "15 TestInterfaceSetCfg\n" + "100:exit \n"); +} + +void ProcessInput(bool &loopFlag) +{ + int32_t inputCMD = GetInputData(); + auto itFunc = g_memberFuncMap.find(inputCMD); + if (itFunc != g_memberFuncMap.end()) { + auto memberFunc = itFunc->second; + if (memberFunc != nullptr) { + (*memberFunc)(); + return; + } + } + printf("inputCMD is:[%d]\n", inputCMD); + switch (inputCMD) { + case INPUT_QUIT: { + loopFlag = false; + printf("exit...\n"); + break; + } + default: + printf("please input correct number...\n"); + break; + } +} + +void Init() +{ + g_memberFuncMap[SET_RESOLVER_CONFIG] = TestSetResolverConfig; + g_memberFuncMap[CREATE_NETWORK_CACHE] = TestCreateNetworkCache; + g_memberFuncMap[FLUSH_NETWORK_CACHE] = TestFlushNetworkCache; + + g_memberFuncMap[DESTORY_NETWORK_CACHE] = TestDestoryNetworkCache; + g_memberFuncMap[GET_ADDR_INFO] = TestGetaddrinfo; + g_memberFuncMap[INTERFACE_SET_MTU] = TestInterfaceSetMtu; + + g_memberFuncMap[NETWORK_SET_DEFAULT] = TestNetworkSetDefault; + g_memberFuncMap[NETWORK_GET_DEFAULT] = TestNetworkGetDefault; + g_memberFuncMap[NETWORK_ClEAR_DEFAULT] = TestNetworkClearDefault; + + g_memberFuncMap[NETWORK_CREATE_PHYSICAL] = TestNetworkCreatePhysical; + g_memberFuncMap[INTERFACE_ADD_ADDRESS] = TestInterfaceAddAddress; + g_memberFuncMap[INTERFACE_DEL_ADDRESS] = TestInterfaceDelAddress; + + g_memberFuncMap[NETWORK_ADD_INTERFACE] = TestNetworkAddInterface; + g_memberFuncMap[NETWORK_REMOVE_INTERFACE] = TestNetworkRemoveInterface; + g_memberFuncMap[GET_FWMARK_FOR_NETWORK] = TestGetFwmarkForNetwork; + + g_memberFuncMap[INTERFACE_SET_CFG] = TestInterfaceSetCfg; +} + +int main(int argc, char *argv[]) +{ + std::cout << ("netd test begin.....") << std::endl; + Init(); + + bool loopFlag = true; + while (loopFlag) { + Prompt(); + ProcessInput(loopFlag); + } + + std::cout << "Test finished, you can terminate by press Ctrl + C" << std::endl; + + return 0; +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/main.h b/http/services/netmanagernative/net_mgr_native/tests/main.h new file mode 100644 index 000000000..f422f76fa --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/main.h @@ -0,0 +1,57 @@ +#ifndef __NETD_MAIN_TEST_H__ +#define __NETD_MAIN_TEST_H__ +#include +#include +#include + +const int32_t SET_RESOLVER_CONFIG = 0; +const int32_t CREATE_NETWORK_CACHE = 1; +const int32_t FLUSH_NETWORK_CACHE = 2; +const int32_t DESTORY_NETWORK_CACHE = 3; +const int32_t GET_ADDR_INFO = 4; +const int32_t INTERFACE_SET_MTU = 5; +const int32_t NETWORK_SET_DEFAULT = 6; +const int32_t NETWORK_GET_DEFAULT = 7; +const int32_t NETWORK_ClEAR_DEFAULT = 8; +const int32_t NETWORK_CREATE_PHYSICAL = 9; +const int32_t INTERFACE_ADD_ADDRESS = 10; +const int32_t INTERFACE_DEL_ADDRESS = 11; +const int32_t NETWORK_ADD_INTERFACE = 12; +const int32_t NETWORK_REMOVE_INTERFACE = 13; +const int32_t GET_FWMARK_FOR_NETWORK = 14; +const int32_t INTERFACE_SET_CFG = 15; +const int32_t INPUT_QUIT = 100; +using NetdTestFunc = void (*)(); + +void TestSetResolverConfig(); + +void TestCreateNetworkCache(); + +void TestFlushNetworkCache(); + +void TestDestoryNetworkCache(); + +void TestGetaddrinfo(); + +void TestInterfaceSetMtu(); + +void TestNetworkSetDefault(); + +void TestNetworkGetDefault(); + +void TestNetworkClearDefault(); + +void TestNetworkCreatePhysical(); + +void TestInterfaceAddAddress(); + +void TestInterfaceDelAddress(); + +void TestNetworkAddInterface(); + +void TestNetworkRemoveInterface(); + +void TestGetFwmarkForNetwork(); + +void TestInterfaceSetCfg(); +#endif //!__NETD_MAIN_TEST_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/native_netd_service_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/native_netd_service_test.cpp new file mode 100644 index 000000000..bebdc7368 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/native_netd_service_test.cpp @@ -0,0 +1,156 @@ +#include +#include + +#include +#include + +TEST(native_netd_service, interfaceGetList) +{ + nmd::native_nted_service nns; + std::vector ifs = nns.interfaceGetList(); + for (size_t i = 0; i < ifs.size(); i++) { + std::cout << ifs.at(i) << std::endl; + } + size_t si = ifs.size(); + size_t sss = 0; + EXPECT_NE(si, sss); +} + +TEST(native_netd_service, interfaceGetConfig) +{ + nmd::native_nted_service nns; + std::cout << nns.interfaceGetConfig("eth0") << std::endl; + EXPECT_EQ(nns.interfaceGetConfig("eth0").ifName, "eth0"); +} + +TEST(native_netd_service, networkRemoveRouteParcel) +{ + nmd::native_nted_service nns; + nmd::route_info_parcel routeInfoParcel = {"", "", "", 1500}; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + nns.networkRemoveRouteParcel(12, routeInfoParcel); +} + +TEST(native_netd_service, networkAddRouteParcel) +{ + nmd::native_nted_service nns; + nmd::route_info_parcel routeInfoParcel = {"", "", "", 1500}; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + nns.networkAddRouteParcel(12, routeInfoParcel); + nmd::mark_mask_parcel testFwmark = nns.getFwmarkForNetwork(12); + EXPECT_EQ(12, testFwmark.mark); + EXPECT_EQ(65535, testFwmark.mask); +} + +TEST(native_netd_service, networkSetPermissionForNetwork) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + nns.networkSetPermissionForNetwork(12, nmd::NetworkPermission::PERMISSION_NONE); +} + +TEST(native_netd_service, init) +{ + nmd::native_nted_service nns; + nns.init(); +} + +TEST(native_netd_service, networkCreatePhysical) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkDestroy(12), -1); +} + +TEST(native_netd_service, networkRemoveInterface) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkRemoveInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkDestroy(12), -1); +} + +TEST(native_netd_service, socketDestroy) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + nns.socketDestroy(12); +} + +TEST(native_netd_service, socketDestroyByIfName) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + nns.socketDestroy("eth0"); +} + +TEST(native_netd_service, interfaceAddAddress) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.interfaceAddAddress("lo", "192.168.0.12", 32), -1); +} + +TEST(native_netd_service, interfaceDelAddress) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.interfaceDelAddress("lo", "192.168.0.12", 32), -1); +} + +TEST(native_netd_service, networkAddRoute) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkAddRoute(12, "eth0", "47.94.251.146/32", "10.205.127.254"), -1); +} + +TEST(native_netd_service, networkRemoveRoute) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkRemoveRoute(12, "eth0", "47.94.251.146/32", "10.205.127.254"), -1); +} + +TEST(native_netd_service, networkGetDefault) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_EQ(nns.networkGetDefault(), 0); +} + +TEST(native_netd_service, networkSetDefault) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkSetDefault(12), -1); +} + +TEST(native_netd_service, networkGetDefaultWhenDefaultSat) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkSetDefault(12), -1); + std::cout << nns.networkGetDefault() << std::endl; + EXPECT_EQ(nns.networkGetDefault(), 12); +} + +TEST(native_netd_service, networkGetDefaultWhenDefaultCleared) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkSetDefault(12), -1); + EXPECT_NE(nns.networkClearDefault(), -1); + EXPECT_EQ(nns.networkGetDefault(), 0); +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/native_netd_service_test1.cpp b/http/services/netmanagernative/net_mgr_native/tests/native_netd_service_test1.cpp new file mode 100644 index 000000000..bebdc7368 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/native_netd_service_test1.cpp @@ -0,0 +1,156 @@ +#include +#include + +#include +#include + +TEST(native_netd_service, interfaceGetList) +{ + nmd::native_nted_service nns; + std::vector ifs = nns.interfaceGetList(); + for (size_t i = 0; i < ifs.size(); i++) { + std::cout << ifs.at(i) << std::endl; + } + size_t si = ifs.size(); + size_t sss = 0; + EXPECT_NE(si, sss); +} + +TEST(native_netd_service, interfaceGetConfig) +{ + nmd::native_nted_service nns; + std::cout << nns.interfaceGetConfig("eth0") << std::endl; + EXPECT_EQ(nns.interfaceGetConfig("eth0").ifName, "eth0"); +} + +TEST(native_netd_service, networkRemoveRouteParcel) +{ + nmd::native_nted_service nns; + nmd::route_info_parcel routeInfoParcel = {"", "", "", 1500}; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + nns.networkRemoveRouteParcel(12, routeInfoParcel); +} + +TEST(native_netd_service, networkAddRouteParcel) +{ + nmd::native_nted_service nns; + nmd::route_info_parcel routeInfoParcel = {"", "", "", 1500}; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + nns.networkAddRouteParcel(12, routeInfoParcel); + nmd::mark_mask_parcel testFwmark = nns.getFwmarkForNetwork(12); + EXPECT_EQ(12, testFwmark.mark); + EXPECT_EQ(65535, testFwmark.mask); +} + +TEST(native_netd_service, networkSetPermissionForNetwork) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + nns.networkSetPermissionForNetwork(12, nmd::NetworkPermission::PERMISSION_NONE); +} + +TEST(native_netd_service, init) +{ + nmd::native_nted_service nns; + nns.init(); +} + +TEST(native_netd_service, networkCreatePhysical) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkDestroy(12), -1); +} + +TEST(native_netd_service, networkRemoveInterface) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkRemoveInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkDestroy(12), -1); +} + +TEST(native_netd_service, socketDestroy) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + nns.socketDestroy(12); +} + +TEST(native_netd_service, socketDestroyByIfName) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + nns.socketDestroy("eth0"); +} + +TEST(native_netd_service, interfaceAddAddress) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.interfaceAddAddress("lo", "192.168.0.12", 32), -1); +} + +TEST(native_netd_service, interfaceDelAddress) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.interfaceDelAddress("lo", "192.168.0.12", 32), -1); +} + +TEST(native_netd_service, networkAddRoute) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkAddRoute(12, "eth0", "47.94.251.146/32", "10.205.127.254"), -1); +} + +TEST(native_netd_service, networkRemoveRoute) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkRemoveRoute(12, "eth0", "47.94.251.146/32", "10.205.127.254"), -1); +} + +TEST(native_netd_service, networkGetDefault) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_EQ(nns.networkGetDefault(), 0); +} + +TEST(native_netd_service, networkSetDefault) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkSetDefault(12), -1); +} + +TEST(native_netd_service, networkGetDefaultWhenDefaultSat) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkSetDefault(12), -1); + std::cout << nns.networkGetDefault() << std::endl; + EXPECT_EQ(nns.networkGetDefault(), 12); +} + +TEST(native_netd_service, networkGetDefaultWhenDefaultCleared) +{ + nmd::native_nted_service nns; + EXPECT_NE(nns.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE), -1); + EXPECT_NE(nns.networkAddInterface(12, "eth0"), -1); + EXPECT_NE(nns.networkSetDefault(12), -1); + EXPECT_NE(nns.networkClearDefault(), -1); + EXPECT_EQ(nns.networkGetDefault(), 0); +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/netd_control_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/netd_control_test.cpp new file mode 100644 index 000000000..8264fda58 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/netd_control_test.cpp @@ -0,0 +1,25 @@ +#include "native_netd_service.h" +#include "netlink_manager.h" +#include "fwmark_server.h" +#include "dnsresolv_service.h" +#include + +void native_netd_service_init() +{ + auto netdService_ = std::make_unique(); + netdService_->init(); + + int32_t pid = getpid(); + auto manager_ = std::make_unique(pid); + std::thread nlManager([&] { manager_->start(); }); + + auto fwmarkServer_ = std::make_unique(); + std::thread fwserve([&] { fwmarkServer_->start(); }); + + auto dnsResolvService_ = std::make_unique(); + std::thread dnsresolvServe([&] { dnsResolvService_->start(); }); + + nlManager.detach(); + fwserve.detach(); + dnsresolvServe.detach(); +} diff --git a/http/services/netmanagernative/net_mgr_native/tests/netlink_event_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/netlink_event_test.cpp new file mode 100644 index 000000000..50e9322ee --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/netlink_event_test.cpp @@ -0,0 +1,275 @@ +#include "netlink_handler.h" +#include "netlink_msg.h" +#include "netlink_socket.h" +#include "netlink_event.h" +#include +#include +#include +#include +#include +#include + +DISABLE_WARNING_PUSH +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_IMPLICIT_INT_CONVERSION +DISABLE_WARNING_SHORTEN_64_TO_32 +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_SIGN_COMPARE +DISABLE_WARNING_OLD_STYLE_CAST +DISABLE_WARNING_CAST_ALIGN +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_C99_EXTENSIONS + +TEST(netlink_event, shouldGetNetlinkTypeName) +{ + nmd::netlink_event event; + EXPECT_EQ(event.rtMessageName(RTM_NEWLINK), "RTM_NEWLINK"); + EXPECT_EQ(event.rtMessageName(RTM_DELLINK), "RTM_DELLINK"); + EXPECT_EQ(event.rtMessageName(RTM_NEWADDR), "RTM_NEWADDR"); + EXPECT_EQ(event.rtMessageName(RTM_DELADDR), "RTM_DELADDR"); + EXPECT_EQ(event.rtMessageName(RTM_NEWROUTE), "RTM_NEWROUTE"); + EXPECT_EQ(event.rtMessageName(RTM_DELROUTE), "RTM_DELROUTE"); + EXPECT_EQ(event.rtMessageName(RTM_NEWRULE), "RTM_NEWRULE"); + EXPECT_EQ(event.rtMessageName(RTM_DELRULE), "RTM_DELRULE"); + EXPECT_EQ(event.rtMessageName(RTM_NEWNDUSEROPT), "RTM_NEWNDUSEROPT"); + EXPECT_EQ(event.rtMessageName(10086), nullptr); +} + +TEST(netlink_event, shouldParseIpRuleMesssage) +{ + int pid = getpid(); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 4096, pid); + struct fib_rule_hdr msg; + + msg.action = FR_ACT_TO_TBL; + msg.family = AF_INET; + nlmsg.addRule(RTM_NEWRULE, msg); + + nlmsg.addAttr32(FRA_FWMARK, 0x33); + nlmsg.addAttr32(FRA_FWMASK, 0xFF); + + msg.table = RT_TABLE_UNSPEC; + nlmsg.addAttr32(FRA_TABLE, 1009); + + nmd::netlink_event event; + EXPECT_TRUE(event.parseRuleMessage(nlmsg.getNetLinkMessage())); +} + +TEST(netlink_event, shouldParseRouteMesssage) +{ + int pid = getpid(); + + nmd::netlink_socket netLinker; + netLinker.setPid(pid); + netLinker.create(NETLINK_ROUTE); + netLinker.binding(); + + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, pid); + struct rtmsg msg; + msg.rtm_family = AF_INET; + msg.rtm_dst_len = 32; + msg.rtm_protocol = RTPROT_STATIC; + msg.rtm_type = RTN_UNICAST; + + nlmsg.addRoute(RTM_NEWROUTE, msg); + msg.rtm_table = RT_TABLE_UNSPEC; + nlmsg.addAttr32(RTA_TABLE, 1006); + + nmd::_inet_addr dst; + const char *dstStr = "47.94.251.146/32"; + int a = 0; + if ((a = nmd::route_controller::read_addr(dstStr, &dst)) != 1) { + LogError << "dest parse failed:" << a << endl; + } else { + msg.rtm_family = dst.family; + msg.rtm_dst_len = dst.bitlen; + if (dst.family == AF_INET) { + msg.rtm_scope = RT_SCOPE_LINK; + } else if (dst.family == AF_INET6) { + msg.rtm_scope = RT_SCOPE_UNIVERSE; + } + nlmsg.addAttr(RTA_DST, (char *)dst.data, dst.bitlen / 8); + } + + nmd::_inet_addr gw; + const char *gwStr = "10.205.127.254"; + if ((a = nmd::route_controller::read_addr_gw(gwStr, &gw)) != 1) { + LogError << "gw parse failed:" << a << endl; + } else { + if (gw.bitlen != 0) { + msg.rtm_scope = 0; + msg.rtm_family = gw.family; + } + nlmsg.addAttr(RTA_GATEWAY, (char *)gw.data, gw.bitlen / 8); + } + + nlmsg.addAttr32(RTA_OIF, if_nametoindex("eth0")); + + nmd::netlink_event event; + event.parseRouteMessage(nlmsg.getNetLinkMessage()); +} + +TEST(netlink_event, shouldParseNetlinkMesssage) +{ + int pid = getpid(); + + nmd::netlink_socket netLinker; + netLinker.setPid(pid); + netLinker.create(NETLINK_ROUTE); + netLinker.binding(); + + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, pid); + struct rtmsg msg; + msg.rtm_family = AF_INET; + msg.rtm_dst_len = 32; + msg.rtm_protocol = RTPROT_STATIC; + msg.rtm_type = RTN_UNICAST; + + nlmsg.addRoute(RTM_NEWROUTE, msg); + msg.rtm_table = RT_TABLE_UNSPEC; + nlmsg.addAttr32(RTA_TABLE, 1006); + + nmd::_inet_addr dst; + const char *dstStr = "47.94.251.146/32"; + int a = 0; + if ((a = nmd::route_controller::read_addr(dstStr, &dst)) != 1) { + LogError << "dest parse failed:" << a << endl; + } else { + msg.rtm_family = dst.family; + msg.rtm_dst_len = dst.bitlen; + if (dst.family == AF_INET) { + msg.rtm_scope = RT_SCOPE_LINK; + } else if (dst.family == AF_INET6) { + msg.rtm_scope = RT_SCOPE_UNIVERSE; + } + nlmsg.addAttr(RTA_DST, (char *)dst.data, dst.bitlen / 8); + } + + nmd::_inet_addr gw; + const char *gwStr = "10.205.127.254"; + if ((a = nmd::route_controller::read_addr_gw(gwStr, &gw)) != 1) { + LogError << "gw parse failed:" << a << endl; + } else { + if (gw.bitlen != 0) { + msg.rtm_scope = 0; + msg.rtm_family = gw.family; + } + nlmsg.addAttr(RTA_GATEWAY, (char *)gw.data, gw.bitlen / 8); + } + + nlmsg.addAttr32(RTA_OIF, if_nametoindex("eth0")); + + nmd::netlink_event event; + event.parseNetLinkMessage((char *)nlmsg.getNetLinkMessage(), 4096); +} + +TEST(netlink_event, parseInterfaceInfoInfoMessage) +{ + int pid = getpid(); + + nmd::netlink_socket netLinker; + netLinker.setPid(pid); + netLinker.create(NETLINK_ROUTE); + netLinker.binding(); + + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, pid); + struct ifinfomsg msg; + msg.ifi_index = if_nametoindex("eth0"); + + nlmsg.addInterfaceInfo(RTM_NEWROUTE, msg); + + nlmsg.addAttr(IFLA_IFNAME, (char *)"eth0", 16); + + nmd::netlink_event event; + event.parseInterfaceInfoInfoMessage(nlmsg.getNetLinkMessage()); +} + +TEST(netlink_event, parseInterafaceAddressMessage) +{ + int pid = getpid(); + + nmd::netlink_socket netLinker; + netLinker.setPid(pid); + netLinker.create(RTM_NEWADDR); + netLinker.binding(); + + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, pid); + struct ifaddrmsg msg; + msg.ifa_index = if_nametoindex("eth0"); + + nlmsg.addInterfaceAddress(RTM_NEWADDR, msg); + + in_addr addr; + nlmsg.addAttr(IFA_ADDRESS, &addr, sizeof(addr)); + + nmd::netlink_event event; + event.parseInterafaceAddressMessage(nlmsg.getNetLinkMessage()); +} + +TEST(netlink_event, addInterfaceAddressCacheInfo) +{ + int pid = getpid(); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, pid); + struct ifa_cacheinfo msg = {0, 0, 0, 0}; + nlmsg.addInterfaceAddressCacheInfo(0, msg); + int len = nlmsg.getNetLinkMessage()->nlmsg_len; + int len1 = NLMSG_LENGTH(sizeof(struct rta_cacheinfo)); + EXPECT_EQ(len, len1); +} + +TEST(netlink_event, addNeighborDiscovery) +{ + int pid = getpid(); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, pid); + struct ndmsg msg = {0, 0, 0, 0, 0, 0, 0}; + nlmsg.addNeighborDiscovery(0, msg); + int len = nlmsg.getNetLinkMessage()->nlmsg_len; + int len1 = NLMSG_LENGTH(sizeof(struct ndmsg)); + EXPECT_EQ(len, len1); +} + +TEST(netlink_event, addNeighborDiscoveryAttributeCacheInfo) +{ + int pid = getpid(); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, pid); + struct nda_cacheinfo nda = {0, 0, 0, 0}; + nlmsg.addNeighborDiscoveryAttributeCacheInfo(0, nda); + int len = nlmsg.getNetLinkMessage()->nlmsg_len; + int len1 = NLMSG_LENGTH(sizeof(struct nda_cacheinfo)); + EXPECT_EQ(len, len1); +} + +TEST(netlink_event, addTrafficControl) +{ + int pid = getpid(); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, pid); + struct tcmsg msg = {0, 0, 0, 0, 0, 0, 0}; + nlmsg.addTrafficControl(0, msg); + int len = nlmsg.getNetLinkMessage()->nlmsg_len; + int len1 = NLMSG_LENGTH(sizeof(struct tcmsg)); + EXPECT_EQ(len, len1); +} + +TEST(netlink_event, addRouteNextHop) +{ + int pid = getpid(); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, pid); + struct rtnexthop msg = {0, 0, 0, 0}; + nlmsg.addRouteNextHop(0, msg); + int len = nlmsg.getNetLinkMessage()->nlmsg_len; + int len1 = NLMSG_LENGTH(sizeof(struct rtnexthop)); + EXPECT_EQ(len, len1); +} + +TEST(netlink_event, addRouteAttributeCacheInfo) +{ + int pid = getpid(); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, pid); + struct rta_cacheinfo msg = {0, 0, 0, 0, 0, 0, 0, 0}; + nlmsg.addRouteAttributeCacheInfo(0, msg); + int len = nlmsg.getNetLinkMessage()->nlmsg_len; + int len1 = NLMSG_LENGTH(sizeof(struct rta_cacheinfo)); + EXPECT_EQ(len, len1); +} + +DISABLE_WARNING_POP diff --git a/http/services/netmanagernative/net_mgr_native/tests/netlink_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/netlink_test.cpp new file mode 100644 index 000000000..91501896c --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/netlink_test.cpp @@ -0,0 +1,186 @@ +#include "netlink_handler.h" +#include "netlink_msg.h" +#include "netlink_socket.h" +#include +#include +#include +#include +#include +#include + +DISABLE_WARNING_PUSH +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_IMPLICIT_INT_CONVERSION +DISABLE_WARNING_SHORTEN_64_TO_32 +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_SIGN_COMPARE +DISABLE_WARNING_OLD_STYLE_CAST +DISABLE_WARNING_CAST_ALIGN +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_C99_EXTENSIONS + +TEST(netlink, shouldCreateIpRule) +{ + int pid = getpid(); + nmd::netlink_socket netLinker; + netLinker.setPid(pid); + netLinker.create(NETLINK_ROUTE); + netLinker.binding(); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 4096, pid); + + struct fib_rule_hdr msg; + + msg.action = FR_ACT_TO_TBL; + msg.family = AF_INET; + nlmsg.addRule(RTM_NEWRULE, msg); + + nlmsg.addAttr32(FRA_FWMARK, 0x33); + nlmsg.addAttr32(FRA_FWMASK, 0xFF); + + msg.table = RT_TABLE_UNSPEC; + nlmsg.addAttr32(FRA_TABLE, 1009); + + netLinker.sendNetlinkMsgToKernel(nlmsg.getNetLinkMessage()); + + netLinker.shutdown(); +} + +TEST(netlink, shouldDeleteIpRule) +{ + int pid = getpid(); + nmd::netlink_socket netLinker; + netLinker.setPid(pid); + netLinker.create(NETLINK_ROUTE); + netLinker.binding(); + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 4096, pid); + + struct fib_rule_hdr msg; + + msg.action = FR_ACT_TO_TBL; + msg.family = AF_INET; + nlmsg.addRule(RTM_DELRULE, msg); + + nlmsg.addAttr32(FRA_FWMARK, 0x33); + nlmsg.addAttr32(FRA_FWMASK, 0xFF); + + msg.table = RT_TABLE_UNSPEC; + nlmsg.addAttr32(FRA_TABLE, 1009); + + netLinker.sendNetlinkMsgToKernel(nlmsg.getNetLinkMessage()); + + netLinker.shutdown(); +} + +TEST(netlink, shouldAddRoute) +{ + int pid = getpid(); + + nmd::netlink_socket netLinker; + netLinker.setPid(pid); + netLinker.create(NETLINK_ROUTE); + netLinker.binding(); + + nmd::netlink_msg nlmsg(NLM_F_CREATE | NLM_F_EXCL, 1024, pid); + struct rtmsg msg; + msg.rtm_family = AF_INET; + msg.rtm_dst_len = 32; + msg.rtm_protocol = RTPROT_STATIC; + msg.rtm_type = RTN_UNICAST; + + nlmsg.addRoute(RTM_NEWROUTE, msg); + msg.rtm_table = RT_TABLE_UNSPEC; + nlmsg.addAttr32(RTA_TABLE, 1006); + + nmd::_inet_addr dst; + const char *dstStr = "47.94.251.146/32"; + int a = 0; + if ((a = nmd::route_controller::read_addr(dstStr, &dst)) != 1) { + LogError << "dest parse failed:" << a << endl; + } else { + msg.rtm_family = dst.family; + msg.rtm_dst_len = dst.bitlen; + if (dst.family == AF_INET) { + msg.rtm_scope = RT_SCOPE_LINK; + } else if (dst.family == AF_INET6) { + msg.rtm_scope = RT_SCOPE_UNIVERSE; + } + nlmsg.addAttr(RTA_DST, (char *)dst.data, dst.bitlen / 8); + } + + nmd::_inet_addr gw; + const char *gwStr = "10.205.127.254"; + if ((a = nmd::route_controller::read_addr_gw(gwStr, &gw)) != 1) { + LogError << "gw parse failed:" << a << endl; + } else { + if (gw.bitlen != 0) { + msg.rtm_scope = 0; + msg.rtm_family = gw.family; + } + nlmsg.addAttr(RTA_GATEWAY, (char *)gw.data, gw.bitlen / 8); + } + + nlmsg.addAttr32(RTA_OIF, if_nametoindex("eth0")); + netLinker.sendNetlinkMsgToKernel(nlmsg.getNetLinkMessage()); + netLinker.setOnDataReceiveHandler( + [](int fd, char *buf, ssize_t size) { std::cout << fd << size << buf << std::endl; }); + netLinker.acceptAndListen(); + + netLinker.shutdown(); +} + +TEST(netlink, shouldDeleteRoute) +{ + int pid = getpid(); + + nmd::netlink_socket netLinker; + netLinker.setPid(pid); + netLinker.create(NETLINK_ROUTE); + netLinker.binding(); + + nmd::netlink_msg nlmsg(0, 1024, pid); + struct rtmsg msg; + msg.rtm_family = AF_INET; + msg.rtm_dst_len = 32; + nlmsg.addRoute(RTM_DELROUTE, msg); + + msg.rtm_table = RT_TABLE_UNSPEC; + nlmsg.addAttr32(RTA_TABLE, 1006); + + nmd::_inet_addr dst; + const char *dstStr = "47.94.251.146/32"; + int a = 0; + if ((a = nmd::route_controller::read_addr(dstStr, &dst)) != 1) { + LogError << "dest parse failed:" << a << endl; + } else { + msg.rtm_family = dst.family; + msg.rtm_dst_len = dst.bitlen; + if (dst.family == AF_INET) { + msg.rtm_scope = RT_SCOPE_LINK; + } else if (dst.family == AF_INET6) { + msg.rtm_scope = RT_SCOPE_UNIVERSE; + } + nlmsg.addAttr(RTA_DST, (char *)dst.data, dst.bitlen / 8); + } + + nmd::_inet_addr gw; + const char *gwStr = "10.205.127.254"; + if ((a = nmd::route_controller::read_addr_gw(gwStr, &gw)) != 1) { + LogError << "gw parse failed:" << a << endl; + } else { + if (gw.bitlen != 0) { + msg.rtm_scope = 0; + msg.rtm_family = gw.family; + } + nlmsg.addAttr(RTA_GATEWAY, (char *)gw.data, gw.bitlen / 8); + } + + nlmsg.addAttr32(RTA_OIF, if_nametoindex("eth0")); + netLinker.sendNetlinkMsgToKernel(nlmsg.getNetLinkMessage()); + netLinker.setOnDataReceiveHandler( + [](int fd, char *buf, ssize_t size) { std::cout << fd << size << buf << std::endl; }); + netLinker.acceptAndListen(); + + netLinker.shutdown(); +} + +DISABLE_WARNING_POP diff --git a/http/services/netmanagernative/net_mgr_native/tests/network_controller_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/network_controller_test.cpp new file mode 100644 index 000000000..50ba13855 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/network_controller_test.cpp @@ -0,0 +1,246 @@ +#include +#include +#include +#include +#include + +TEST(network_controller, should_create_network) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); +} + +TEST(network_controller, should_be_indefault_when_create) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + EXPECT_FALSE(nws[0]->isDefault()); +} + +TEST(network_controller, should_be_default_when_as_default) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + EXPECT_FALSE(nws[0]->isDefault()); + controller.setDefaultNetwork(12); + EXPECT_TRUE(nws[0]->isDefault()); +} + +TEST(network_controller, should_create_network_and_add_interface) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + + std::string interfaceNameEth0 = "eth0"; + int result = controller.addInterfaceToNetwork(12, interfaceNameEth0); + EXPECT_EQ(result, 1); + + bool hasInterfaceEth0 = nws[0]->hasInterface(interfaceNameEth0); + EXPECT_TRUE(hasInterfaceEth0); + + std::string interfaceNameEth1 = "eth1"; + bool hasInterfaceEth1 = nws[0]->hasInterface(interfaceNameEth1); + EXPECT_FALSE(hasInterfaceEth1); +} + +TEST(network_controller, should_create_network_and_add_exists_interface) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + + std::string interfaceNameEth0 = "eth0"; + int result = controller.addInterfaceToNetwork(12, interfaceNameEth0); + EXPECT_EQ(result, 1); + + bool hasInterfaceEth0 = nws[0]->hasInterface(interfaceNameEth0); + EXPECT_TRUE(hasInterfaceEth0); + + result = controller.addInterfaceToNetwork(12, interfaceNameEth0); + EXPECT_EQ(result, 1); + + std::string interfaceNameEth1 = "eth1"; + bool hasInterfaceEth1 = nws[0]->hasInterface(interfaceNameEth1); + EXPECT_FALSE(hasInterfaceEth1); +} + +TEST(network_controller, should_create_network_as_default_and_add_interface) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + controller.setDefaultNetwork(12); + + std::string interfaceNameEth0 = "eth0"; + int result = controller.addInterfaceToNetwork(12, interfaceNameEth0); + EXPECT_EQ(result, 1); + + bool hasInterfaceEth0 = nws[0]->hasInterface(interfaceNameEth0); + EXPECT_TRUE(hasInterfaceEth0); +} + +TEST(network_controller, should_create_network_as_default_and_remove_default) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + controller.setDefaultNetwork(12); + + controller.createPhysicalNetwork(13, nmd::NetworkPermission::PERMISSION_SYSTEM); + nws = controller.getNetworks(); + + size = 2; + EXPECT_EQ(nws.size(), size); + controller.setDefaultNetwork(13); + EXPECT_EQ(controller.getDefaultNetwork(), 13); +} + +TEST(network_controller, should_have_iprule_when_add_interface) +{ + int pid = getpid(); + nmd::netlink_manager::setPid(pid); + EXPECT_EQ(pid, nmd::netlink_manager::getPid()); + + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + + std::string interfaceNameEth0 = "eth0"; + int result = controller.addInterfaceToNetwork(12, interfaceNameEth0); + EXPECT_EQ(result, 1); + bool hasInterfaceEth0 = nws[0]->hasInterface(interfaceNameEth0); + EXPECT_TRUE(hasInterfaceEth0); +} + +TEST(network_controller, should_destroy_network) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + + std::string interfaceNameEth0 = "eth0"; + int result = controller.addInterfaceToNetwork(12, interfaceNameEth0); + EXPECT_EQ(result, 1); + + bool hasInterfaceEth0 = nws[0]->hasInterface(interfaceNameEth0); + EXPECT_TRUE(hasInterfaceEth0); + + std::string interfaceNameEth1 = "eth1"; + bool hasInterfaceEth1 = nws[0]->hasInterface(interfaceNameEth1); + EXPECT_FALSE(hasInterfaceEth1); + + EXPECT_EQ(controller.destroyNetwork(12), 1); +} + +TEST(network_controller, clearDefaultNetwork) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + + std::string interfaceNameEth0 = "eth0"; + int result = controller.addInterfaceToNetwork(12, interfaceNameEth0); + EXPECT_EQ(result, 1); + + bool hasInterfaceEth0 = nws[0]->hasInterface(interfaceNameEth0); + EXPECT_TRUE(hasInterfaceEth0); + + std::string interfaceNameEth1 = "eth1"; + bool hasInterfaceEth1 = nws[0]->hasInterface(interfaceNameEth1); + EXPECT_FALSE(hasInterfaceEth1); + + EXPECT_EQ(controller.clearDefaultNetwork(), 1); +} + +TEST(network_controller, removeInterfaceFromNetwork) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + + std::string interfaceNameEth0 = "eth0"; + int result = controller.addInterfaceToNetwork(12, interfaceNameEth0); + EXPECT_EQ(result, 1); + + bool hasInterfaceEth0 = nws[0]->hasInterface(interfaceNameEth0); + EXPECT_TRUE(hasInterfaceEth0); + + std::string interfaceNameEth1 = "eth1"; + bool hasInterfaceEth1 = nws[0]->hasInterface(interfaceNameEth1); + EXPECT_FALSE(hasInterfaceEth1); + + EXPECT_EQ(controller.removeInterfaceFromNetwork(12, interfaceNameEth0), 1); + + hasInterfaceEth0 = nws[0]->hasInterface(interfaceNameEth0); + EXPECT_FALSE(hasInterfaceEth0); +} + +TEST(network_controller, getFwmarkForNetwork) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + std::cout << controller.getFwmarkForNetwork(12) << std::endl; + EXPECT_EQ(controller.getFwmarkForNetwork(12), 196620); +} + +TEST(network_controller, setPermissionForNetwork) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + std::cout << controller.getFwmarkForNetwork(12) << std::endl; + controller.setPermissionForNetwork(12, nmd::NetworkPermission::PERMISSION_NONE); + EXPECT_EQ(controller.getFwmarkForNetwork(12), 196620); +} + +TEST(network_controller, getNetwork) +{ + nmd::network_controller controller; + controller.createPhysicalNetwork(12, nmd::NetworkPermission::PERMISSION_SYSTEM); + std::vector nws = controller.getNetworks(); + + unsigned long size = 1; + EXPECT_EQ(nws.size(), size); + controller.getNetwork(12); +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/resolv_dns_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/resolv_dns_test.cpp new file mode 100644 index 000000000..b16b7fea7 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/resolv_dns_test.cpp @@ -0,0 +1,309 @@ +#include "dnsresolv.h" +#include "dnsresolv_controller.h" +#include "dnsresolv_service.h" +#include "get_addr_info.h" +#include "warning_disable.h" +#include +#include +#include "time_elapsed.h" + +namespace { +int hostnameToIp(const char *hostname) +{ + int ret = 0; + + if (!hostname) { + printf("invalid params\n"); + return -1; + } + + struct addrinfo hints; + struct addrinfo *res, *res_p; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + + ret = nmd::dnsresolv_controller::getaddrinfo(hostname, NULL, &hints, &res); + if (ret != 0) { + printf("getaddrinfo: %s\n", gai_strerror(ret)); + return -1; + } + + for (res_p = res; res_p != NULL; res_p = res_p->ai_next) { + char host[1024] = {0}; + ret = getnameinfo(res_p->ai_addr, res_p->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST); + if (ret != 0) + printf("getnameinfo: %s\n", gai_strerror(ret)); + else + printf("%s ip: %s\n", hostname, host); + } + + freeaddrinfo(res); + return ret; +} + +int hostnameToIpV6(const char *hostname) +{ + int ret = 0; + + if (!hostname) { + printf("invalid params\n"); + return -1; + } + + struct addrinfo hints; + struct addrinfo *res, *res_p; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = IPPROTO_TCP; + + ret = nmd::dnsresolv_controller::getaddrinfo(hostname, "https", &hints, &res); + if (ret != 0) { + printf("getaddrinfo: %s\n", gai_strerror(ret)); + return -1; + } + + struct sockaddr_in *ipv4; + struct sockaddr_in6 *ipv6; + char host[1024] = {0}; + bzero(host, 1024); + for (res_p = res; res_p != NULL; res_p = res_p->ai_next) { + switch (res_p->ai_family) { + case AF_INET: + ipv4 = reinterpret_cast(res_p->ai_addr); + inet_ntop(res_p->ai_family, &ipv4->sin_addr, host, sizeof(host)); + break; + case AF_INET6: + ipv6 = reinterpret_cast(res_p->ai_addr); + inet_ntop(res_p->ai_family, &ipv6->sin6_addr, host, sizeof(host)); + break; + } + + printf("[IPv%d]%s\n", res_p->ai_family == AF_INET ? 4 : 6, host); + } + + freeaddrinfo(res); + return ret; +} + +int ipToHostname(const char *ip) +{ + int ret = 0; + + if (!ip) { + printf("invalid params\n"); + return -1; + } + + struct addrinfo hints; + struct addrinfo *res, *res_p; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME | AI_NUMERICHOST; + hints.ai_protocol = 0; + + ret = nmd::dnsresolv_controller::getaddrinfo(ip, NULL, &hints, &res); + if (ret != 0) { + printf("getaddrinfo: %s\n", gai_strerror(ret)); + return -1; + } + + for (res_p = res; res_p != NULL; res_p = res_p->ai_next) { + char host[1024] = {0}; + ret = getnameinfo(res_p->ai_addr, res_p->ai_addrlen, host, sizeof(host), NULL, 0, NI_NAMEREQD); + if (ret != 0) + printf("getnameinfo: %s\n", gai_strerror(ret)); + else + printf("hostname: %s\n", host); + } + + freeaddrinfo(res); + return ret; +} +} // namespace + +class dnsresolv_test : public ::testing::Test { +public: + virtual void SetUp() override + { + resolver_.createNetworkCache(TEST_NETID); + resolver_.createNetworkCache(nmd::NETID_UNSET); + } + virtual void TearDown() override + { + resolver_.flushNetworkCache(TEST_NETID); + resolver_.flushNetworkCache(nmd::NETID_UNSET); + + resolver_.destoryNetworkCache(TEST_NETID); + resolver_.destoryNetworkCache(nmd::NETID_UNSET); + } + +protected: + const uint16_t TEST_NETID = 65501; + nmd::dnsresolv_service resolver_; +}; + +TEST_F(dnsresolv_test, setGetDnsresolvParams) +{ + const nmd::dnsresolver_params params = { + TEST_NETID, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + int ret = resolver_.setResolverConfig(params); + EXPECT_EQ(ret, 0); + + std::vector servers; + std::vector domains; + nmd::dns_res_params getParam; + ret = resolver_.getResolverInfo(params.netId, servers, domains, getParam); + EXPECT_EQ(ret, 0); + + ASSERT_EQ(servers.size(), 2u); + ASSERT_EQ(domains.size(), 2u); + EXPECT_THAT(servers[0], ::testing::Eq("8.8.8.8")); + EXPECT_THAT(servers[1], ::testing::Eq("114.114.114.114")); + EXPECT_THAT(domains[0], ::testing::Eq("baidu.com")); + EXPECT_THAT(domains[1], ::testing::Eq("google.com")); +} + +TEST_F(dnsresolv_test, getAddrInfoForNet) +{ + const nmd::dnsresolver_params params = { + TEST_NETID, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + int ret = resolver_.setResolverConfig(params); + ASSERT_EQ(ret, 0); + + struct addrinfo hints; + struct addrinfo *res, *res_p; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + + ret = nmd::dnsresolv_controller::getaddrinfoForNet( + "cenocloud.com", NULL, &hints, TEST_NETID, nmd::MARK_UNSET, &res); + ASSERT_EQ(ret, 0); + + for (res_p = res; res_p != NULL; res_p = res_p->ai_next) { + char host[1024] = {0}; + ret = getnameinfo(res_p->ai_addr, res_p->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST); + if (ret != 0) + printf("getnameinfo: %s\n", gai_strerror(ret)); + else + printf("ip: %s\n", host); + } + + freeaddrinfo(res); +} + +TEST_F(dnsresolv_test, hostnameToIp) +{ + const nmd::dnsresolver_params params = { + nmd::NETID_UNSET, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + resolver_.setResolverConfig(params); + int ret = hostnameToIp("baidu.com"); + ASSERT_EQ(ret, 0); + + ret = hostnameToIp("pan"); + ASSERT_EQ(ret, 0); +} + +TEST_F(dnsresolv_test, getAddrinfo) +{ + const nmd::dnsresolver_params params = { + nmd::NETID_UNSET, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + resolver_.setResolverConfig(params); + GEN_INVOKE_US(hoooooo, dnsTime, hostnameToIp("www.baidu.com")); + int ret = hoooooo(); + ASSERT_EQ(ret, 0); + + ret = hoooooo(); + ASSERT_EQ(ret, 0); +} + +TEST_F(dnsresolv_test, getAddrinfoFromHostFile) +{ + int ret = hostnameToIp("localhost"); + ASSERT_EQ(ret, 0); +} + +TEST_F(dnsresolv_test, IPToHostName) +{ + const nmd::dnsresolver_params params = { + nmd::NETID_UNSET, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + resolver_.setResolverConfig(params); + int ret = ipToHostname("127.0.0.1"); + ASSERT_EQ(ret, 0); +} + +TEST_F(dnsresolv_test, hostnameToIpFailed) +{ + const nmd::dnsresolver_params params = { + nmd::NETID_UNSET, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + resolver_.setResolverConfig(params); + int ret = hostnameToIp("unknow"); + EXPECT_EQ(ret, -1); + + resolver_.destoryNetworkCache(nmd::NETID_UNSET); + ret = hostnameToIp("www.baidu.com"); + EXPECT_EQ(ret, -1); +} + +TEST_F(dnsresolv_test, getDnsResolvInfo) +{ + const nmd::dnsresolver_params params = { + nmd::NETID_UNSET, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + auto ret = resolver_.setResolverConfig(params); + EXPECT_THAT(ret, ::testing::Eq(0)); + + std::vector servers; + std::vector domains; + nmd::dns_res_params resolvParam; + ret = resolver_.getResolverInfo(params.netId, servers, domains, resolvParam); + EXPECT_THAT(ret, ::testing::Eq(0)); + EXPECT_THAT(servers, ::testing::Eq(params.servers)); + EXPECT_THAT(domains, ::testing::Eq(params.domains)); + EXPECT_THAT(resolvParam.baseTimeoutMsec, ::testing::Eq(params.baseTimeoutMsec)); + EXPECT_THAT(resolvParam.retryCount, ::testing::Eq(params.retryCount)); +} + +TEST_F(dnsresolv_test, getDnsResolvInfoFailed) +{ + std::vector servers; + std::vector domains; + nmd::dns_res_params resolvParam; + auto ret = resolver_.getResolverInfo(TEST_NETID, servers, domains, resolvParam); + EXPECT_THAT(ret, ::testing::Eq(0)); + EXPECT_THAT(servers.size(), ::testing::Eq(0u)); + EXPECT_THAT(domains.size(), ::testing::Eq(0u)); + + ret = resolver_.destoryNetworkCache(TEST_NETID); + EXPECT_THAT(ret, ::testing::Eq(0)); + ret = resolver_.getResolverInfo(TEST_NETID, servers, domains, resolvParam); + EXPECT_THAT(ret, ::testing::Eq(-1)); +} + +TEST_F(dnsresolv_test, getAddrinfoIpv6) +{ + const nmd::dnsresolver_params params = { + nmd::NETID_UNSET, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + resolver_.setResolverConfig(params); + int ret = hostnameToIpV6("www.google.com"); + ASSERT_EQ(ret, 0); +} +#include "dnsresolv_client_test.h" +TEST_F(dnsresolv_test, get_addr_info_client_test) +{ + dnsresolv_client_test dnsClientTest; + auto ret = dnsClientTest.initConfig(); + EXPECT_EQ(ret, 0); + + ret = dnsClientTest.get_addr_info_test("www.baidu.com"); + EXPECT_EQ(ret, 0); + ret = dnsClientTest.get_addr_info_test("www.baidu.com"); + EXPECT_EQ(ret, 0); +} diff --git a/http/services/netmanagernative/net_mgr_native/tests/set_param.cpp b/http/services/netmanagernative/net_mgr_native/tests/set_param.cpp new file mode 100644 index 000000000..e61dc93aa --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/set_param.cpp @@ -0,0 +1,126 @@ +#include "main.h" +#include "netnative_log_wrapper.h" +#include "native_netd_service.h" +#include +#include + +//设置网络MTU +void TestInterfaceSetMtu() +{ + // service.interfaceSetMtu("eth0", 1500) + NETNATIVE_LOGE("TestInterfaceSetMtu begin"); + OHOS::nmd::NativeNetdService nativeNetdSvc; + nativeNetdSvc.init(); + + int mtuVal = 1200; + std::string ifName = std::string("eth0"); + int mtuValOld = nativeNetdSvc.interfaceGetMtu(ifName); + NETNATIVE_LOGE("before SetMtu, mtuVal %{public}d", mtuValOld); + nativeNetdSvc.interfaceSetMtu(ifName, mtuVal); + mtuValOld = nativeNetdSvc.interfaceGetMtu(ifName); + NETNATIVE_LOGE("after SetMtu, mtuVal %{public}d", mtuValOld); + NETNATIVE_LOGE("TestInterfaceSetMtu end"); +} + +void TestNetworkSetDefault() +{ + NETNATIVE_LOGE("TestNetworkSetDefault begin"); + OHOS::nmd::NativeNetdService nativeNetdSvc; + nativeNetdSvc.init(); + int netId = 0; + nativeNetdSvc.networkSetDefault(netId); + NETNATIVE_LOGE("TestNetworkSetDefault end"); +} + +void TestNetworkGetDefault() +{ + NETNATIVE_LOGE("TestNetworkGetDefault begin"); + OHOS::nmd::NativeNetdService nativeNetdSvc; + nativeNetdSvc.init(); + nativeNetdSvc.networkGetDefault(); + NETNATIVE_LOGE("TestNetworkGetDefault end"); +} + +//清除默认网络 +void TestNetworkClearDefault() +{ + // service.networkClearDefault() + NETNATIVE_LOGE("TestNetworkClearDefault begin"); + OHOS::nmd::NativeNetdService nativeNetdSvc; + nativeNetdSvc.init(); + nativeNetdSvc.networkClearDefault(); + NETNATIVE_LOGE("TestNetworkClearDefault end"); +} + +//创建网络 +void TestNetworkCreatePhysical() +{ + NETNATIVE_LOGE("TestNetworkCreatePhysical begin"); + OHOS::nmd::NativeNetdService nativeNetdSvc; + nativeNetdSvc.init(); + nativeNetdSvc.networkCreatePhysical(12, OHOS::nmd::NetworkPermission::PERMISSION_NONE); + NETNATIVE_LOGE("TestNetworkCreatePhysical end"); +} + +//添加地址 +void TestInterfaceAddAddress() +{ + NETNATIVE_LOGE("TestInterfaceAddAddress begin"); + OHOS::nmd::NativeNetdService nativeNetdSvc; + nativeNetdSvc.init(); + nativeNetdSvc.interfaceAddAddress("lo", "127.0.0.4", 32); + NETNATIVE_LOGE("TestInterfaceAddAddress end"); +} + +//移除地址 +void TestInterfaceDelAddress() +{ + NETNATIVE_LOGE("TestInterfaceDelAddress begin"); + OHOS::nmd::NativeNetdService nativeNetdSvc; + nativeNetdSvc.init(); + nativeNetdSvc.interfaceDelAddress("lo", "127.0.0.4", 32); + NETNATIVE_LOGE("TestInterfaceDelAddress end"); +} + +//网络添加 +void TestNetworkAddInterface() +{ + NETNATIVE_LOGE("TestNetworkAddInterface begin"); + OHOS::nmd::NativeNetdService nativeNetdSvc; + nativeNetdSvc.init(); + nativeNetdSvc.networkAddInterface(12, "eth0"); + NETNATIVE_LOGE("TestNetworkAddInterface end"); +} +//网络移除 +void TestNetworkRemoveInterface() +{ + NETNATIVE_LOGE("TestNetworkRemoveInterface begin"); + OHOS::nmd::NativeNetdService nativeNetdSvc; + nativeNetdSvc.init(); + nativeNetdSvc.networkRemoveInterface(12, "eth0"); + NETNATIVE_LOGE("TestNetworkRemoveInterface end"); +} + +void TestGetFwmarkForNetwork() +{ + NETNATIVE_LOGE("TestGetFwmarkForNetwork begin"); + OHOS::nmd::NativeNetdService nativeNetdSvc; + nativeNetdSvc.init(); + OHOS::nmd::mark_mask_parcel testFwmark = nativeNetdSvc.getFwmarkForNetwork(12); + NETNATIVE_LOGE("mark %{public}d,mask %{public}d", testFwmark.mark, testFwmark.mask); + NETNATIVE_LOGE("TestGetFwmarkForNetwork end"); +} + +void TestInterfaceSetCfg() +{ + NETNATIVE_LOGE("TestInterfaceSetCfg begin"); + OHOS::nmd::NativeNetdService nativeNetdSvc; + nativeNetdSvc.init(); + OHOS::nmd::interface_configuration_parcel parcel = nativeNetdSvc.interfaceGetConfig("lo"); + NETNATIVE_LOGE("before: parcel get hwaddr = %{public}s", parcel.hwAddr.c_str()); + parcel.hwAddr = std::string("192.168.55.10"); + nativeNetdSvc.interfaceSetConfig(parcel); + parcel = nativeNetdSvc.interfaceGetConfig("lo"); + NETNATIVE_LOGE("after: parcel get hwaddr = %{public}s", parcel.hwAddr.c_str()); + NETNATIVE_LOGE("TestInterfaceSetCfg end"); +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/sock_diag_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/sock_diag_test.cpp new file mode 100644 index 000000000..79404b454 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/sock_diag_test.cpp @@ -0,0 +1,42 @@ +#include +#include +#include + +TEST(sock_diag, destroySocket) +{ + nmd::sock_diag diag; + diag.open(); + diag.destroySockets("eth0"); +} + +TEST(sock_diag, isINETLoopbackWhenIs) +{ + nmd::sock_diag diag; + inet_diag_msg msg; + msg.idiag_family = AF_INET; + diag.isLoopbackSocket(&msg); +} + +TEST(sock_diag, isINETNotLoopbackWhenNot) +{ + nmd::sock_diag diag; + inet_diag_msg msg; + msg.idiag_family = AF_INET; + diag.isLoopbackSocket(&msg); +} + +TEST(sock_diag, isINET6LoopbackWhenIs) +{ + nmd::sock_diag diag; + inet_diag_msg msg; + msg.idiag_family = AF_INET6; + diag.isLoopbackSocket(&msg); +} + +TEST(sock_diag, isINET6NotLoopbackWhenNot) +{ + nmd::sock_diag diag; + inet_diag_msg msg; + msg.idiag_family = AF_INET6; + diag.isLoopbackSocket(&msg); +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/stable/stability_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/stable/stability_test.cpp new file mode 100644 index 000000000..04f9e0ccf --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/stable/stability_test.cpp @@ -0,0 +1,224 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "netlink_manager.h" +#include "netlink_msg.h" +#include "netlink_socket.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dnsresolv_service.h" +#include +#include "traffic_init.h" + +#include "time_elapsed.h" +#include "dnsresolv_client_test.h" +#include + +namespace nwG { +void createPhysicalNetwork(nmd::native_nted_service service) +{ + GEN_INVOKE_US( + createNetwork, 创建网络, service.networkCreatePhysical(12, nmd::NetworkPermission::PERMISSION_NONE)); + createNetwork(); + + GEN_INVOKE_US(addInterface, 网络添加interface, service.networkAddInterface(12, "eth0")); + addInterface(); + + GEN_INVOKE_US(removeInterface, 网络移除interface, service.networkRemoveInterface(12, "eth0")); + removeInterface(); + + GEN_INVOKE_US(interfaceAddAddress, interface添加地址, service.interfaceAddAddress("lo", "192.168.0.12", 32)); + interfaceAddAddress(); + + GEN_INVOKE_US(interfaceRemoveAddress, interface移除地址, service.interfaceDelAddress("lo", "192.168.0.12", 32)); + interfaceRemoveAddress(); + + GEN_INVOKE_US(interfaceAddRoute, interface添加路由, + service.networkAddRoute(12, "eth0", "47.94.251.146/32", "10.205.127.254")); + interfaceAddRoute(); + + GEN_INVOKE_US(interfaceRemoveRoute, interface删除路由, + service.networkRemoveRoute(12, "eth0", "47.94.251.146/32", "10.205.127.254")); + interfaceRemoveRoute(); + + GEN_INVOKE_US(setDefaultNetwork, 设置默认网络, service.networkSetDefault(12)); + setDefaultNetwork(); + + GEN_INVOKE_US(getDefaultNetwork, 获取默认网络, service.networkGetDefault()); + getDefaultNetwork(); + + GEN_INVOKE_US(clearDefaultNetwork, 清除默认网络, service.networkClearDefault()); + clearDefaultNetwork(); + + GEN_INVOKE_US(getInterfaceList, 获取interface列表, service.interfaceGetList()); + getInterfaceList(); + + GEN_INVOKE_US(setPermissionForNetwork, 设置网络权限, + service.networkSetPermissionForNetwork(12, nmd::NetworkPermission::PERMISSION_NETWORK)); + setPermissionForNetwork(); + + GEN_INVOKE_US(interfaceSetMtu, 设置网络MTU, service.interfaceSetMtu("eth0", 1500)); + interfaceSetMtu(); + + GEN_INVOKE_US(setProcSysNet, 设置网络参数, + service.setProcSysNet(nmd::set_proc_sys_net::IPV4, nmd::set_proc_sys_net::CONF, "eth0", "forwarding", "1")); + setProcSysNet(); +} + +void destroyNetwork(nmd::native_nted_service service) +{ + GEN_INVOKE_US(removeInterface, 网络移除interface, service.networkRemoveInterface(12, "eth0")); + removeInterface(); + + GEN_INVOKE_US(networkDestroy, 网络销毁, service.networkDestroy(12)); + networkDestroy(); +} +}; // namespace nwG + +namespace dnsG { +dnsresolv_client_test dnsClientTest; +void getAddrInfo(nmd::native_nted_service) +{ + GEN_INVOKE_US(dnsResolve, DNS解析, dnsClientTest.get_addr_info_test("cenocloud.com")); + dnsResolve(); +} +}; // namespace dnsG + +namespace fwmarkG { +void bindSocket(nmd::native_nted_service) +{ + nmd::fwmark_client client; + nmd::fwmark_command command; + command.cmdId = nmd::fwmark_command::SELECT_NETWORK; + command.fd = 999999999; + command.netId = 12; + client.send(&command); + + GEN_INVOKE_US(bindSocketToNetwork, 绑定socket, client.send(&command)); + bindSocketToNetwork(); +} +}; // namespace fwmarkG + +namespace trfcG { +void getTraffic(nmd::native_nted_service service) +{ + GEN_INVOKE_US(getInterfaceRxTraffic, 获取interface下行的流量, service.getIfaceRxBytes("eth0")); + getInterfaceRxTraffic(); + + GEN_INVOKE_US(getInterfacTxTraffic, 获取interface上行的流量, service.getIfaceTxBytes("eth0")); + getInterfacTxTraffic(); + + GEN_INVOKE_US(getAllRx, 获取所有下行流量, service.getAllRxBytes()); + getAllRx(); + + GEN_INVOKE_US(getAllTx, 获取所有上行流量, service.getAllTxBytes()); + getAllTx(); + + GEN_INVOKE_US(getUid0Tx, 获取UID0的上行流量, service.getUidTxBytes(0)); + getUid0Tx(); + + GEN_INVOKE_US(getUid0Rx, 获取UID0的下行流量, service.getUidRxBytes(0)); + getUid0Rx(); + + GEN_INVOKE_US(getCellularRxTraffic, 获取蜂窝下行流量, service.getCellularRxBytes()); + getCellularRxTraffic(); + + GEN_INVOKE_US(getCellularTxTraffic, 获取蜂窝上行流量, service.getCellularTxBytes()); + getCellularTxTraffic(); + + GEN_INVOKE_US(getRxTetherTraffic, 获取热点下行流量, service.getTetherRxBytes()); + getRxTetherTraffic(); + + GEN_INVOKE_US(getTxTetherTraffic, 获取热点上行流量, service.getTetherTxBytes()); + getTxTetherTraffic(); +} +}; // namespace trfcG + +void startStableTest(nmd::native_nted_service service, int groupDuration, int apiDuration, int times) +{ + std::vector> networkAndRouteGroup; + networkAndRouteGroup.push_back(nwG::createPhysicalNetwork); + networkAndRouteGroup.push_back(nwG::destroyNetwork); + + dnsG::dnsClientTest.initConfig(); + std::vector> dnsGroup; + dnsGroup.push_back(dnsG::getAddrInfo); + + std::vector> fwmarkGroup; + fwmarkGroup.push_back(fwmarkG::bindSocket); + + std::vector> trafficGroup; + trafficGroup.push_back(trfcG::getTraffic); + + std::vector>> groups; + // groups.push_back(networkAndRouteGroup); + groups.push_back(dnsGroup); + // groups.push_back(fwmarkGroup); + // groups.push_back(trafficGroup); + + for (int t = 0; t < times; t++) { + for (unsigned long i = 0; i < groups.size(); i++) { + for (unsigned long j = 0; j < groups.at(i).size(); j++) { + groups.at(i).at(j)(service); + std::this_thread::sleep_for(std::chrono::milliseconds(apiDuration)); + } + std::this_thread::sleep_for(std::chrono::milliseconds(groupDuration)); + } + } +} + +int main(int argc, char *args[]) +{ + int groupDuration = 0; + int apiDuration = 0; + int times = 200; + + if (argc > 1) { + groupDuration = atoi(args[1]); + apiDuration = atoi(args[2]); + times = atoi(args[3]); + } + + nmd::native_nted_service service; + service.init(); + + int pid = getpid(); + nmd::netlink_manager manager(pid); + std::thread nlManager([&] { manager.start(); }); + + nmd::fwmark_server fwmarkServer; + std::thread fwserve([&] { fwmarkServer.start(); }); + + nmd::dnsresolv_service dnsresolvService; + std::thread dnsresolvServe([&] { dnsresolvService.start(); }); + + // wait for servers started + std::this_thread::sleep_for(std::chrono::milliseconds(3000)); + // nmd::traffic_init::start_traffic_account(); + + startStableTest(service, groupDuration, apiDuration, times); +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/tests.cpp b/http/services/netmanagernative/net_mgr_native/tests/tests.cpp new file mode 100644 index 000000000..4dd87158c --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/tests.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include +#include +#include +#include "netlink_manager.h" +#include "netlink_msg.h" +#include "netlink_socket.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dnsresolv_service.h" +#include +#include "traffic_init.h" + +DISABLE_WARNING_PUSH +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_IMPLICIT_INT_CONVERSION +DISABLE_WARNING_SHORTEN_64_TO_32 +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_SIGN_COMPARE +DISABLE_WARNING_OLD_STYLE_CAST +DISABLE_WARNING_CAST_ALIGN +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_C99_EXTENSIONS + +int main(int argc, char *argv[]) +{ + nmd::native_nted_service service; + service.init(); + + int pid = getpid(); + nmd::netlink_manager manager(pid); + std::thread nlManager([&] { manager.start(); }); + + nmd::fwmark_server fwmarkServer; + std::thread fwserve([&] { fwmarkServer.start(); }); + + nmd::dnsresolv_service dnsresolvService; + std::thread dnsresolvServe([&] { dnsresolvService.start(); }); + + // nmd::traffic_init::start_traffic_account(); + + testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + + manager.stop(); + fwmarkServer.stop(); + dnsresolvService.stop(); + + std::cout << "Test finished, you can terminate by press Ctrl + C" << std::endl; + + nlManager.join(); + fwserve.join(); + dnsresolvServe.join(); + + return result; +} + +DISABLE_WARNING_POP \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/time_elapsed.h b/http/services/netmanagernative/net_mgr_native/tests/time_elapsed.h new file mode 100644 index 000000000..c736beca7 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/time_elapsed.h @@ -0,0 +1,55 @@ +#ifndef __TESTS_TIME_ELAPSED_H__ +#define __TESTS_TIME_ELAPSED_H__ + +#include +#include +#include + +static inline int64_t elapsed_ns(std::chrono::time_point m_begin) +{ + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_begin) + .count(); +} + +static inline int64_t elapsed_us(std::chrono::time_point m_begin) +{ + return std::chrono::duration_cast( + std::chrono::high_resolution_clock::now() - m_begin) + .count(); +} + +static inline int64_t elapsed_ms(std::chrono::time_point m_begin) +{ + return std::chrono::duration_cast( + std::chrono::high_resolution_clock::now() - m_begin) + .count(); +} + +#define GEN_INVOKE_US(name, title, expr) \ + auto name = [&] { \ + std::chrono::time_point m_begin = \ + std::chrono::high_resolution_clock::now(); \ + auto result = expr; \ + std::cout << #name << "," << #title << "," << elapsed_us(m_begin) << "us" << std::endl; \ + return result; \ + }; + +#define GEN_INVOKE_MS(name, title, expr) \ + auto name = [&] { \ + std::chrono::time_point m_begin = \ + std::chrono::high_resolution_clock::now(); \ + auto result = expr; \ + std::cout << #name << "," << #title << "," << elapsed_ms(m_begin) << "ms" << std::endl; \ + return result; \ + }; + +#define GEN_INVOKE_NS(name, title, expr) \ + auto name = [&] { \ + std::chrono::time_point m_begin = \ + std::chrono::high_resolution_clock::now(); \ + auto result = expr; \ + std::cout << #name << "," << #title << "," << elapsed_ns(m_begin) << "ns" << std::endl; \ + return result; \ + }; + +#endif //!__TESTS_TIME_ELAPSED_H__ \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/traffic_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/traffic_test.cpp new file mode 100644 index 000000000..94a9b2a87 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/traffic_test.cpp @@ -0,0 +1,146 @@ +#include "traffic_controller.h" +#include "native_netd_service.h" +#include "traffic_init.h" +#include +#include +#include +#include + +TEST(traffic, getInterfaceRxTrafficTest) +{ + nmd::native_nted_service testNetdService; + std::string ifName("eth0"); + long trafficBytes1 = testNetdService.getIfaceRxBytes(ifName); + nmd::traffic_stats_parcel result = testNetdService.interfaceGetStats(ifName); + long trafficBytes2 = result.rxBytes; + std::cout << trafficBytes2 << std::endl; + ASSERT_LE(trafficBytes1, trafficBytes2); +} + +TEST(traffic, getInterfaceTxTrafficTest) +{ + nmd::native_nted_service testNetdService; + std::string ifName("eth0"); + long trafficBytes1 = testNetdService.getIfaceTxBytes(ifName); + nmd::traffic_stats_parcel result = testNetdService.interfaceGetStats(ifName); + long trafficBytes2 = result.txBytes; + std::cout << trafficBytes2 << std::endl; + ASSERT_LE(trafficBytes1, trafficBytes2); +} + +TEST(traffic, getCellularRxTraffic) +{ + nmd::native_nted_service testNetdService; + long trafficBytes = testNetdService.getCellularRxBytes(); + std::cout << trafficBytes << std::endl; +} + +TEST(traffic, getCellularTxTraffic) +{ + nmd::native_nted_service testNetdService; + long trafficBytes = testNetdService.getCellularTxBytes(); + std::cout << trafficBytes << std::endl; +} + +TEST(traffic, getAllRxTraffic) +{ + nmd::native_nted_service testNetdService; + long trafficBytes = testNetdService.getAllRxBytes(); + std::cout << trafficBytes << std::endl; +} + +TEST(traffic, getAllTxTraffic) +{ + nmd::native_nted_service testNetdService; + long trafficBytes = testNetdService.getAllTxBytes(); + std::cout << trafficBytes << std::endl; +} + +TEST(traffic, getUid0RxBytes) +{ + nmd::native_nted_service testNetdService; + nmd::traffic_init::start_traffic_account(); + sleep(2); + long trafficUidRxBytes = testNetdService.getUidRxBytes(0); + std::cout << trafficUidRxBytes << std::endl; +} + +TEST(traffic, getUid0TxBytes) +{ + nmd::native_nted_service testNetdService; + nmd::traffic_init::start_traffic_account(); + sleep(2); + long trafficUidRxBytes = testNetdService.getUidTxBytes(0); + std::cout << trafficUidRxBytes << std::endl; +} + +TEST(traffic, getTetherTxTraffic) +{ + nmd::native_nted_service nativeNetdService; + std::string cmd = "iptables -t filter -N TETHER_TRAFFIC"; + nmd::traffic_controller::execIptablesRuleMethod(cmd); + nmd::traffic_controller::startTrafficTether(); + nmd::traffic_controller::traffic_controller_log(); + long resultTx = nativeNetdService.getTetherTxBytes(); + std::cout << resultTx << std::endl; +} + +TEST(traffic, getTetherRxTraffic) +{ + nmd::native_nted_service nativeNetdService; + std::string cmd = "iptables -t filter -N TETHER_TRAFFIC"; + nmd::traffic_controller::execIptablesRuleMethod(cmd); + nmd::traffic_controller::startTrafficTether(); + nmd::traffic_controller::traffic_controller_log(); + long resultRx = nativeNetdService.getTetherRxBytes(); + std::cout << resultRx << std::endl; +} + +TEST(traffic_init, initTrafficAccoutEnv) +{ + constexpr const char *ingressBpfProg = "/sys/fs/bpf/cgroup-ingress-traffic-uid"; + constexpr const char *egressBpfProg = "/sys/fs/bpf/cgroup-egress-traffic-uid"; + constexpr const char *unixSocketTraffic = "/dev/socket/traffic"; + constexpr const char *trafficCgroupPath = "/sys/fs/cgroup/unified/cgroup-traffic-uid/cgroup.procs"; + + nmd::traffic_init::init_traffic_env(); + + int ingressBpfFile = access(ingressBpfProg, F_OK); + int egressBpfFile = access(egressBpfProg, F_OK); + int unixSocketFile = access(unixSocketTraffic, F_OK); + int cgroupPidFile = access(trafficCgroupPath, F_OK); + EXPECT_EQ(ingressBpfFile, -1); + EXPECT_EQ(egressBpfFile, -1); + EXPECT_EQ(unixSocketFile, 0); + EXPECT_EQ(cgroupPidFile, 0); +} + +TEST(traffic_init, loadTrafficBpf) +{ + nmd::traffic_init::load_traffic_bpf(); + char cmd[1024] = {0}; + char buf_ps[1024]; + FILE *ptr; + strcpy(cmd, "ps -ef | grep load-traffic-bpf | grep -v \"grep\" | wc -l"); + sleep(2); + if ((ptr = popen(cmd, "r")) != NULL) { + while (fgets(buf_ps, 1024, ptr) != NULL) { + EXPECT_NE(std::string(buf_ps), std::string("0\n")); + } + } +} + +TEST(traffic_init, loadExecveBpf) +{ + nmd::traffic_init::load_execve_bpf(); + char cmd[1024] = {0}; + char buf_ps[1024]; + FILE *ptr; + strcpy(cmd, "ps -ef | grep load-execve-bpf | grep -v \"grep\" | wc -l"); + sleep(2); + if ((ptr = popen(cmd, "r")) != NULL) { + while (fgets(buf_ps, 1024, ptr) != NULL) { + EXPECT_NE(std::string(buf_ps), std::string("0\n")); + } + } +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/unit/block_queue_unit_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/unit/block_queue_unit_test.cpp new file mode 100644 index 000000000..722818f38 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/unit/block_queue_unit_test.cpp @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "blocking_queue.h" + +TEST(blocking_queue, shoudEnqueue) +{ + nmd::blocking_queue queue(30); + EXPECT_TRUE(queue.isEmpty()); + queue.push(1); + EXPECT_EQ(queue.pop(), 1); + for (int i = 0; i < 30; i++) { + queue.push(i); + } + EXPECT_TRUE(queue.isFull()); +} diff --git a/http/services/netmanagernative/net_mgr_native/tests/unit/dnsresolv_service_unit_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/unit/dnsresolv_service_unit_test.cpp new file mode 100644 index 000000000..604c664f6 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/unit/dnsresolv_service_unit_test.cpp @@ -0,0 +1,271 @@ +#include +#include +#include "dnsresolv_service.h" +#include "socket_base.h" +#include "dnsresolv.h" +#include +namespace { +void setNameList(char *buffer, const size_t bufferSize, const std::vector namelist) +{ + if (nullptr == buffer || 0 == bufferSize || namelist.empty()) { + return; + } + + char *buffCur = buffer; + size_t buffCount(0); + for (auto &name : namelist) { + if (name.empty()) { + continue; + } + + if ((bufferSize - buffCount) < (name.length() + 1)) { + break; + } + + strcpy(buffCur, name.c_str()); + buffCur += (name.length() + 1); + buffCount += (name.length() + 1); + } +} +} // namespace + +class mock_socket : public nmd::common::socket_base { +public: + MOCK_METHOD2(sendMsg, ssize_t(const int socketFd, const msghdr &msg)); +}; + +class dnsresolv_service_unit_test : public ::testing::Test { +public: + virtual void SetUp() override {} + virtual void TearDown() override {} + +protected: + const uint16_t TEST_NETID = 65501; +}; + +TEST_F(dnsresolv_service_unit_test, jobRunBadParam) +{ + mock_socket mockSocket; + EXPECT_CALL(mockSocket, sendMsg(::testing::_, ::testing::_)).Times(0); + + auto job = std::make_shared(-1, nullptr, 0, nullptr); + ASSERT_THAT(job, ::testing::Ne(nullptr)); + job->run(); +} + +TEST_F(dnsresolv_service_unit_test, doCreateNetworkCache) +{ + nmd::dnsresolver_response_cmd cmdRep; + bzero(&cmdRep, sizeof(cmdRep)); + cmdRep.cmdID = nmd::dnsresolver_response_cmd::cmd_id::QUERY_STATE_OK; + size_t repSize = cmdRep.cmdID == nmd::dnsresolver_response_cmd::cmd_id::QUERY_SUCCESS_WITH_RESULT ? + (sizeof(cmdRep) + cmdRep.resSize) : + sizeof(cmdRep); + iovec iov[1] = {{&cmdRep, repSize}}; + + msghdr hdr; + bzero(&hdr, sizeof(hdr)); + hdr.msg_iov = iov; + hdr.msg_iovlen = 1; + mock_socket *mockSocket = new mock_socket(); + ASSERT_THAT(mockSocket, ::testing::Ne(nullptr)); + EXPECT_CALL(*mockSocket, sendMsg(1, ::testing::_)).Times(2); + + nmd::dnsresolver_request_cmd reqCmd; + bzero(&reqCmd, sizeof(reqCmd)); + reqCmd.cmdID = nmd::dnsresolver_request_cmd::cmd_id::CREATE_NETWORK_CACHE; + reqCmd.netid = TEST_NETID; + + auto job = std::make_shared(1, reinterpret_cast(&reqCmd), sizeof(reqCmd), + std::shared_ptr(mockSocket)); + ASSERT_THAT(job, ::testing::Ne(nullptr)); + job->run(); + job->run(); +} + +TEST_F(dnsresolv_service_unit_test, doDestroyNetworkCache) +{ + nmd::dnsresolver_response_cmd cmdRep; + bzero(&cmdRep, sizeof(cmdRep)); + cmdRep.cmdID = nmd::dnsresolver_response_cmd::cmd_id::QUERY_STATE_OK; + size_t repSize = cmdRep.cmdID == nmd::dnsresolver_response_cmd::cmd_id::QUERY_SUCCESS_WITH_RESULT ? + (sizeof(cmdRep) + cmdRep.resSize) : + sizeof(cmdRep); + iovec iov[1] = {{&cmdRep, repSize}}; + + msghdr hdr; + bzero(&hdr, sizeof(hdr)); + hdr.msg_iov = iov; + hdr.msg_iovlen = 1; + mock_socket *mockSocket = new mock_socket(); + ASSERT_THAT(mockSocket, ::testing::Ne(nullptr)); + EXPECT_CALL(*mockSocket, sendMsg(1, ::testing::_)).Times(1); + + nmd::dnsresolver_request_cmd reqCmd; + bzero(&reqCmd, sizeof(reqCmd)); + reqCmd.cmdID = nmd::dnsresolver_request_cmd::cmd_id::DESOTRY_NETWORK_CACHE; + reqCmd.netid = TEST_NETID; + + auto job = std::make_shared(1, reinterpret_cast(&reqCmd), sizeof(reqCmd), + std::shared_ptr(mockSocket)); + ASSERT_THAT(job, ::testing::Ne(nullptr)); + job->run(); +} + +TEST_F(dnsresolv_service_unit_test, doSetResolverConfig) +{ + nmd::dnsresolver_response_cmd cmdRep; + bzero(&cmdRep, sizeof(cmdRep)); + cmdRep.cmdID = nmd::dnsresolver_response_cmd::cmd_id::QUERY_STATE_OK; + size_t repSize = cmdRep.cmdID == nmd::dnsresolver_response_cmd::cmd_id::QUERY_SUCCESS_WITH_RESULT ? + (sizeof(cmdRep) + cmdRep.resSize) : + sizeof(cmdRep); + iovec iov[1] = {{&cmdRep, repSize}}; + + msghdr hdr; + bzero(&hdr, sizeof(hdr)); + hdr.msg_iov = iov; + hdr.msg_iovlen = 1; + mock_socket *mockSocket = new mock_socket(); + ASSERT_THAT(mockSocket, ::testing::Ne(nullptr)); + EXPECT_CALL(*mockSocket, sendMsg(1, ::testing::_)).Times(1); + const nmd::dnsresolver_params param = { + TEST_NETID, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + + nmd::dnsresolver_request_cmd reqCmd; + bzero(&reqCmd, sizeof(reqCmd)); + reqCmd.cmdID = nmd::dnsresolver_request_cmd::cmd_id::SET_RESOLVER_CONFIG; + reqCmd.netid = param.netId; + reqCmd.cmd_baseTimeoutMsec = param.baseTimeoutMsec; + reqCmd.cmd_retryCount = param.retryCount; + reqCmd.cmd_serverCount = static_cast(param.servers.size()); + reqCmd.cmd_domainCount = static_cast(param.domains.size()); + setNameList(reqCmd.cmd_servers, nmd::MAX_NAME_LIST_LEN, param.servers); + setNameList(reqCmd.cmd_domains, nmd::MAX_NAME_LIST_LEN, param.domains); + + auto job = std::make_shared(1, reinterpret_cast(&reqCmd), sizeof(reqCmd), + std::shared_ptr(mockSocket)); + ASSERT_THAT(job, ::testing::Ne(nullptr)); + job->run(); +} + +TEST_F(dnsresolv_service_unit_test, doGetAddrInfo) +{ + mock_socket *mockSocket = new mock_socket(); + ASSERT_THAT(mockSocket, ::testing::Ne(nullptr)); + EXPECT_CALL(*mockSocket, sendMsg(1, ::testing::_)).Times(1); + + nmd::dnsresolver_request_cmd reqCmd; + bzero(&reqCmd, sizeof(reqCmd)); + reqCmd.cmdID = nmd::dnsresolver_request_cmd::cmd_id::CREATE_NETWORK_CACHE; + reqCmd.netid = nmd::NETID_UNSET; + auto job = std::make_shared(1, reinterpret_cast(&reqCmd), sizeof(reqCmd), + std::shared_ptr(mockSocket)); + ASSERT_THAT(job, ::testing::Ne(nullptr)); + job->run(); + + mock_socket *mockSocket1 = new mock_socket(); + ASSERT_THAT(mockSocket1, ::testing::Ne(nullptr)); + EXPECT_CALL(*mockSocket1, sendMsg(1, ::testing::_)).Times(1); + const nmd::dnsresolver_params param = { + nmd::NETID_UNSET, 0, 1, {"8.8.8.8", "114.114.114.114"}, {"baidu.com", "google.com"}}; + + nmd::dnsresolver_request_cmd reqCmd1; + bzero(&reqCmd1, sizeof(reqCmd1)); + reqCmd1.cmdID = nmd::dnsresolver_request_cmd::cmd_id::SET_RESOLVER_CONFIG; + reqCmd1.netid = param.netId; + reqCmd1.cmd_baseTimeoutMsec = param.baseTimeoutMsec; + reqCmd1.cmd_retryCount = param.retryCount; + reqCmd1.cmd_serverCount = static_cast(param.servers.size()); + reqCmd1.cmd_domainCount = static_cast(param.domains.size()); + setNameList(reqCmd1.cmd_servers, nmd::MAX_NAME_LIST_LEN, param.servers); + setNameList(reqCmd1.cmd_domains, nmd::MAX_NAME_LIST_LEN, param.domains); + + auto job1 = std::make_shared(1, reinterpret_cast(&reqCmd1), sizeof(reqCmd1), + std::shared_ptr(mockSocket1)); + ASSERT_THAT(job1, ::testing::Ne(nullptr)); + job1->run(); + + mock_socket *mockSocket2 = new mock_socket(); + ASSERT_THAT(mockSocket2, ::testing::Ne(nullptr)); + EXPECT_CALL(*mockSocket2, sendMsg(1, ::testing::_)).Times(2); + struct addrinfo hints; + bzero(&hints, sizeof(addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + nmd::dnsresolver_request_cmd_t reqCmd2; + bzero(&reqCmd2, sizeof(reqCmd2)); + reqCmd2.cmdID = nmd::dnsresolver_request_cmd::cmd_id::GET_ADDR_INFO; + strncpy(reqCmd2.cmd_hostName, "www.baidu.com", nmd::MAX_NAME_LEN); + reqCmd2.cmd_hints = hints; + + auto job2 = std::make_shared(1, reinterpret_cast(&reqCmd2), sizeof(reqCmd2), + std::shared_ptr(mockSocket2)); + ASSERT_THAT(job2, ::testing::Ne(nullptr)); + job2->run(); +} + +TEST_F(dnsresolv_service_unit_test, doGetAddrInfoFromCache) +{ + mock_socket *mockSocket = new mock_socket(); + ASSERT_THAT(mockSocket, ::testing::Ne(nullptr)); + EXPECT_CALL(*mockSocket, sendMsg(1, ::testing::_)).Times(2); + struct addrinfo hints; + bzero(&hints, sizeof(addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + nmd::dnsresolver_request_cmd_t reqCmd; + bzero(&reqCmd, sizeof(reqCmd)); + reqCmd.cmdID = nmd::dnsresolver_request_cmd::cmd_id::GET_ADDR_INFO; + strncpy(reqCmd.cmd_hostName, "www.baidu.com", nmd::MAX_NAME_LEN); + reqCmd.cmd_hints = hints; + + auto job = std::make_shared(1, reinterpret_cast(&reqCmd), sizeof(reqCmd), + std::shared_ptr(mockSocket)); + ASSERT_THAT(job, ::testing::Ne(nullptr)); + job->run(); +} + +TEST_F(dnsresolv_service_unit_test, doGetAddrInfoFailed) +{ + mock_socket *mockSocket = new mock_socket(); + ASSERT_THAT(mockSocket, ::testing::Ne(nullptr)); + EXPECT_CALL(*mockSocket, sendMsg(1, ::testing::_)).Times(1); + struct addrinfo hints; + bzero(&hints, sizeof(addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + nmd::dnsresolver_request_cmd_t reqCmd; + bzero(&reqCmd, sizeof(reqCmd)); + reqCmd.cmdID = nmd::dnsresolver_request_cmd::cmd_id::GET_ADDR_INFO; + strncpy(reqCmd.cmd_hostName, "unknow", nmd::MAX_NAME_LEN); + reqCmd.cmd_hints = hints; + + auto job = std::make_shared(1, reinterpret_cast(&reqCmd), sizeof(reqCmd), + std::shared_ptr(mockSocket)); + ASSERT_THAT(job, ::testing::Ne(nullptr)); + job->run(); +} + +TEST_F(dnsresolv_service_unit_test, init) +{ + nmd::dnsresolv_service dnsService; + nmd::dnsresolv_callbacks callbacks; + auto ret = dnsService.init(callbacks); + EXPECT_THAT(ret, ::testing::Eq(false)); + + auto callbackFunc = [](uint16_t netid, uid_t uid, nmd::netd_net_context &netcontext) { + if (nmd::NETID_UNSET == netid || nmd::NET_CONTEXT_INVALID_UID == uid) { + netcontext.appNetId = netid; + } + }; + callbacks.getNetworkContext = callbackFunc; + ret = dnsService.init(callbacks); + EXPECT_THAT(ret, ::testing::Eq(true)); +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/unit/event_reporter_unit_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/unit/event_reporter_unit_test.cpp new file mode 100644 index 000000000..46e1e9bd6 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/unit/event_reporter_unit_test.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DISABLE_WARNING_PUSH +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_IMPLICIT_INT_CONVERSION +DISABLE_WARNING_SHORTEN_64_TO_32 +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_SIGN_COMPARE +DISABLE_WARNING_OLD_STYLE_CAST +DISABLE_WARNING_CAST_ALIGN +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_C99_EXTENSIONS + +namespace event_report_test { +void defaultOnInterfaceAddressUpdated(const std::string &addr, const std::string &ifName, int flags, int scope) +{ + std::cout << "InterfaceAddressUpdate:" << addr << "," << ifName << "," << flags << "," << scope << std::endl; +} +void defaultOnInterfaceAddressRemoved(const std::string &addr, const std::string &ifName, int flags, int scope) +{ + std::cout << "InterfaceAddressRemoved:" << addr << "," << ifName << "," << flags << "," << scope << std::endl; +} +void defaultOnInterfaceAdded(const std::string &ifName) +{ + std::cout << "InterfaceAdded:" << ifName << std::endl; +} +void defaultOnInterfaceRemoved(const std::string &ifName) +{ + std::cout << "InterfaceRemoved:" << ifName << std::endl; +} +void defaultOnInterfaceChanged(const std::string &ifName, bool up) +{ + std::cout << "InterfaceChanged:" << ifName << "," << up << std::endl; +} +void defaultOnInterfaceLinkStateChanged(const std::string &ifName, bool up) +{ + std::cout << "InterfaceLinkStateChanged:" << ifName << "," << up << std::endl; +} +void defaultOnRouteChanged( + bool updated, const std::string &route, const std::string &gateway, const std::string &ifName) +{ + std::cout << "RouteChanged:" << updated << "," << route << "," << gateway << "," << ifName << std::endl; +} +} // namespace event_report_test + +TEST(event_reporter, registerEventListener) +{ + nmd::event_reporter report; + + nmd::inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = event_report_test::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = event_report_test::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = event_report_test::defaultOnInterfaceAdded, + .onInterfaceRemoved = event_report_test::defaultOnInterfaceRemoved, + .onInterfaceChanged = event_report_test::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = event_report_test::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = event_report_test::defaultOnRouteChanged, + }; + + report.registerEventListener(glistener); +} + +DISABLE_WARNING_POP diff --git a/http/services/netmanagernative/net_mgr_native/tests/unit/get_addr_info_unit_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/unit/get_addr_info_unit_test.cpp new file mode 100644 index 000000000..e0d898cd0 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/unit/get_addr_info_unit_test.cpp @@ -0,0 +1,343 @@ + +#include +#include +#include "get_addr_info.h" +#include "dnsresolv.h" +#include + +class get_addr_info_unit_test : public ::testing::Test { +public: + virtual void SetUp() override {} + virtual void TearDown() override {} + +protected: + const uint16_t TEST_NETID = 65501; + const uint16_t TEST_MARK = 65501; + +public: + static int validateHints(const addrinfo *hints) + { + return nmd::get_addr_info::validateHints(hints); + } + + static int checkHostNameAndExplore( + const addrinfo &ai, const char *hostname, const char *servname, addrinfo *cur) + { + return nmd::get_addr_info::checkHostNameAndExplore(ai, hostname, servname, cur); + } + + static int getPort(const addrinfo *ai, const char *servname, bool matchonly) + { + return nmd::get_addr_info::getPort(ai, servname, matchonly); + } + + static int strToNumber(const char *p) + { + return nmd::get_addr_info::strToNumber(p); + } + + static int exploreNull(const addrinfo *pai, const char *servname, addrinfo **res) + { + return nmd::get_addr_info::exploreNull(pai, servname, res); + } + + static const nmd::afd *findAfd(int af) + { + return nmd::get_addr_info::findAfd(af); + } + + static addrinfo *getAi(const addrinfo *pai, const nmd::afd *pafd, const char *addr) + { + return nmd::get_addr_info::getAi(pai, pafd, addr); + } + + static int ip6StrToScopeid(const char *scope, const struct sockaddr_in6 &sin6, uint32_t &scopeid) + { + return nmd::get_addr_info::ip6StrToScopeid(scope, sin6, scopeid); + } + + static int exploreNumericScope(const addrinfo *pai, const char *hostname, const char *servname, addrinfo **res) + { + return nmd::get_addr_info::exploreNumericScope(pai, hostname, servname, res); + } + static bool haveIpv6(uint32_t mark, uid_t uid) + { + return nmd::get_addr_info::haveIpv6(mark, uid); + } + static bool haveIpv4(uint32_t mark, uid_t uid) + { + return nmd::get_addr_info::haveIpv4(mark, uid); + } + static int sendViaTcp(nmd::dns_res_state &statp, nmd::dns_res_params ¶ms, const uint8_t *buf, + const size_t buflen, uint8_t *ans, size_t anssiz, int &terrno, const size_t ns, time_t &at, int &rcode, + int &delay) + { + return nmd::get_addr_info::sendViaTcp( + statp, params, buf, buflen, ans, anssiz, terrno, ns, at, rcode, delay); + } + static int sendViaUdp(nmd::dns_res_state &statp, nmd::dns_res_params ¶ms, const uint8_t *buf, + const size_t buflen, uint8_t *ans, size_t anssiz, int &terrno, size_t &ns, bool &needTcp, + int &gotsomewhere, time_t &at, int &rcode, int &delay) + { + return nmd::get_addr_info::sendViaUdp( + statp, params, buf, buflen, ans, anssiz, terrno, ns, needTcp, gotsomewhere, at, rcode, delay); + } + + static bool sockEq(const struct sockaddr *socka, const struct sockaddr *sockb) + { + return nmd::get_addr_info::sockEq(socka, sockb); + } +}; + +TEST_F(get_addr_info_unit_test, validateHints) +{ + auto ret = get_addr_info_unit_test::validateHints(nullptr); + EXPECT_NE(ret, 0); + + addrinfo hints; + bzero(&hints, sizeof(addrinfo)); + ret = get_addr_info_unit_test::validateHints(&hints); + EXPECT_EQ(ret, 0); + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + ret = get_addr_info_unit_test::validateHints(&hints); + EXPECT_EQ(ret, 0); +} + +TEST_F(get_addr_info_unit_test, checkHostNameAndExplore) +{ + addrinfo ai = {}; + addrinfo sentinel = {}; + addrinfo *cur = &sentinel; + + auto ret = get_addr_info_unit_test::checkHostNameAndExplore(ai, nullptr, nullptr, cur); + EXPECT_EQ(ret, 0); + if (nullptr != cur->ai_next) { + freeaddrinfo(cur->ai_next); + } +} + +TEST_F(get_addr_info_unit_test, getPort) +{ + addrinfo ai = {}; + auto ret = get_addr_info_unit_test::getPort(&ai, nullptr, true); + EXPECT_EQ(ret, 0); + + ai.ai_family = AF_INET; + ai.ai_socktype = SOCK_RAW; + ret = get_addr_info_unit_test::getPort(&ai, "", true); + EXPECT_THAT(ret, ::testing::Eq(EAI_SERVICE)); + + ai.ai_socktype = SOCK_DGRAM; + ret = get_addr_info_unit_test::getPort(&ai, "", true); + EXPECT_THAT(ret, ::testing::Eq(EAI_SERVICE)); + + ai.ai_flags = AI_NUMERICSERV; + ai.ai_socktype = SOCK_DGRAM; + ret = get_addr_info_unit_test::getPort(&ai, "", true); + EXPECT_THAT(ret, ::testing::Eq(EAI_NONAME)); +} + +TEST_F(get_addr_info_unit_test, strToNumber) +{ + auto ret = get_addr_info_unit_test::strToNumber(""); + EXPECT_EQ(ret, -1); + + ret = get_addr_info_unit_test::strToNumber("53"); + EXPECT_EQ(ret, 53); + + ret = get_addr_info_unit_test::strToNumber("4294967296"); + EXPECT_EQ(ret, -1); +} + +TEST_F(get_addr_info_unit_test, exploreNull) +{ + addrinfo ai = {}; + addrinfo sentinel = {}; + addrinfo *cur = &sentinel; + + auto ret = get_addr_info_unit_test::exploreNull(&ai, nullptr, &cur); + EXPECT_EQ(ret, 0); +} + +TEST_F(get_addr_info_unit_test, findAfd) +{ + auto ret = get_addr_info_unit_test::findAfd(PF_UNSPEC); + EXPECT_THAT(ret, ::testing::Eq(nullptr)); +} + +TEST_F(get_addr_info_unit_test, getAi) +{ + addrinfo ai = {}; + ai.ai_flags = AI_CANONNAME; + ai.ai_family = AF_INET; + ai.ai_socktype = SOCK_STREAM; + ai.ai_protocol = IPPROTO_TCP; + + const nmd::afd *pafd = findAfd(ai.ai_family); + EXPECT_THAT(pafd, ::testing::Ne(nullptr)); + + uint8_t *buff[nmd::MAX_PACKET] = {}; + + auto ret = get_addr_info_unit_test::getAi(&ai, pafd, reinterpret_cast(buff)); + if (nullptr != ret) { + freeaddrinfo(ret); + } +} + +TEST_F(get_addr_info_unit_test, ip6StrToScopeid) +{ + struct sockaddr_in6 in6 = {}; + bzero(&in6, sizeof(sockaddr_in6)); + uint32_t scopeID(0); + auto ret = get_addr_info_unit_test::ip6StrToScopeid("", in6, scopeID); + EXPECT_THAT(ret, ::testing::Eq(-1)); + + in6.sin6_family = AF_INET6; + const char *ipv6Addr = "02:42:ac:11:00:02"; + inet_pton(AF_INET6, ipv6Addr, in6.sin6_addr.s6_addr); + ret = get_addr_info_unit_test::ip6StrToScopeid("10", in6, scopeID); + EXPECT_THAT(ret, ::testing::Eq(0)); + EXPECT_THAT(scopeID, ::testing::Eq(10u)); +} + +TEST_F(get_addr_info_unit_test, exploreNumericScope) +{ + struct addrinfo ai = {}; + ai.ai_family = AF_INET6; + struct addrinfo *res(nullptr); + auto ret = get_addr_info_unit_test::exploreNumericScope(&ai, "02:42:ac:11:00:02%10", nullptr, &res); + EXPECT_THAT(ret, ::testing::Eq(0)); + EXPECT_THAT(res, ::testing::Eq(nullptr)); +} + +TEST_F(get_addr_info_unit_test, haveIpv6) +{ + auto ret = get_addr_info_unit_test::haveIpv6(nmd::MARK_UNSET, nmd::NET_CONTEXT_INVALID_UID); + EXPECT_THAT(ret, ::testing::Eq(false)); +} + +TEST_F(get_addr_info_unit_test, haveIpv4) +{ + auto ret = get_addr_info_unit_test::haveIpv4(nmd::MARK_UNSET, nmd::NET_CONTEXT_INVALID_UID); + EXPECT_THAT(ret, ::testing::Eq(true)); +} + +TEST_F(get_addr_info_unit_test, sendViaTcp) +{ + nmd::netd_net_context netcontext = {}; + netcontext.appNetId = TEST_NETID; + netcontext.appMark = TEST_MARK; + netcontext.dnsNetId = TEST_NETID; + netcontext.dnsMark = TEST_MARK; + netcontext.uid = nmd::NET_CONTEXT_INVALID_UID; + netcontext.pid = nmd::NET_CONTEXT_INVALID_PID; + + nmd::dns_res_state res; + res.init(&netcontext); + res.nsaddrs = {nmd::common::net_utils::ip_sock_addr::toIPSockAddr("8.8.8.8", 53), + nmd::common::net_utils::ip_sock_addr::toIPSockAddr("114.114.114.114", 53)}; + nmd::dns_res_params params; + params.baseTimeoutMsec = 0; + params.retryCount = 1; + + uint8_t buf[] = {0xa8, 0xd2, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x63, 0x65, + 0x6e, 0x6f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01}; + std::vector answer = std::vector(nmd::MAX_PACKET, 0); // buffer to put answer + int terrno = ETIME; + int rcode = nmd::RCODE_INTERNAL_ERROR; + time_t query_time = 0; + int delay = 0; + size_t ns = 0; + int resplen = get_addr_info_unit_test::sendViaTcp( + res, params, buf, sizeof(buf), answer.data(), answer.size(), terrno, ns, query_time, rcode, delay); + EXPECT_THAT(resplen, ::testing::Ne(0)); + EXPECT_THAT(terrno, ::testing::Eq(0)); + + ns = 20; + resplen = get_addr_info_unit_test::sendViaTcp( + res, params, buf, sizeof(buf), answer.data(), answer.size(), terrno, ns, query_time, rcode, delay); + EXPECT_THAT(resplen, ::testing::Eq(-1)); + EXPECT_THAT(terrno, ::testing::Eq(EINVAL)); +} + +TEST_F(get_addr_info_unit_test, sendViaUdp) +{ + nmd::netd_net_context netcontext = {}; + netcontext.appNetId = TEST_NETID; + netcontext.appMark = TEST_MARK; + netcontext.dnsNetId = TEST_NETID; + netcontext.dnsMark = TEST_MARK; + netcontext.uid = nmd::NET_CONTEXT_INVALID_UID; + netcontext.pid = nmd::NET_CONTEXT_INVALID_PID; + + nmd::dns_res_state res; + res.init(&netcontext); + res.nsaddrs = {nmd::common::net_utils::ip_sock_addr::toIPSockAddr("8.8.8.8", 53), + nmd::common::net_utils::ip_sock_addr::toIPSockAddr("114.114.114.114", 53)}; + nmd::dns_res_params params; + params.baseTimeoutMsec = 0; + params.retryCount = 1; + + uint8_t buf[] = {0xa8, 0xd2, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x63, 0x65, + 0x6e, 0x6f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01}; + std::vector answer = std::vector(nmd::MAX_PACKET, 0); // buffer to put answer + int terrno = ETIME; + int rcode = nmd::RCODE_INTERNAL_ERROR; + time_t query_time = 0; + int delay = 0; + size_t ns = 0; + bool useTcp = false; + int gotsomewhere = 0; + + int resplen = get_addr_info_unit_test::sendViaUdp(res, params, buf, sizeof(buf), answer.data(), answer.size(), + terrno, ns, useTcp, gotsomewhere, query_time, rcode, delay); + EXPECT_THAT(resplen, ::testing::Ne(0)); + EXPECT_THAT(terrno, ::testing::Eq(0)); + + ns = 20; + resplen = get_addr_info_unit_test::sendViaUdp(res, params, buf, sizeof(buf), answer.data(), answer.size(), + terrno, ns, useTcp, gotsomewhere, query_time, rcode, delay); + EXPECT_THAT(resplen, ::testing::Eq(-1)); + EXPECT_THAT(terrno, ::testing::Eq(EINVAL)); +} + +TEST_F(get_addr_info_unit_test, sockEq) +{ + auto ret = get_addr_info_unit_test::sockEq(nullptr, nullptr); + EXPECT_THAT(ret, ::testing::Eq(false)); + + sockaddr_in addra; + bzero(&addra, sizeof(addra)); + sockaddr_in addrb; + bzero(&addrb, sizeof(addrb)); + ret = get_addr_info_unit_test::sockEq( + reinterpret_cast(&addra), reinterpret_cast(&addrb)); + EXPECT_THAT(ret, ::testing::Eq(false)); + + addra.sin_family = AF_INET, addra.sin_addr.s_addr = inet_addr("192.168.0.1"); + addrb.sin_family = AF_INET, addrb.sin_addr.s_addr = inet_addr("192.168.0.1"); + ret = get_addr_info_unit_test::sockEq( + reinterpret_cast(&addra), reinterpret_cast(&addrb)); + EXPECT_THAT(ret, ::testing::Eq(true)); + + DISABLE_WARNING_PUSH + DISABLE_WARNING_C99_EXTENSIONS + struct sockaddr_in6 sin6a = {.sin6_family = AF_INET6, + .sin6_addr.s6_addr = {// 2000:: + 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + struct sockaddr_in6 sin6b = {.sin6_family = AF_INET6, + .sin6_addr.s6_addr = {// 2000:: + 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + DISABLE_WARNING_POP + ret = get_addr_info_unit_test::sockEq( + reinterpret_cast(&sin6a), reinterpret_cast(&sin6b)); + EXPECT_THAT(ret, ::testing::Eq(true)); + + ret = get_addr_info_unit_test::sockEq( + reinterpret_cast(&addra), reinterpret_cast(&sin6b)); + EXPECT_THAT(ret, ::testing::Eq(false)); +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/unit/net_utils_unit_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/unit/net_utils_unit_test.cpp new file mode 100644 index 000000000..69f02d02b --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/unit/net_utils_unit_test.cpp @@ -0,0 +1,12 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TEST(net_utils, shouldIpAddressToString) {} diff --git a/http/services/netmanagernative/net_mgr_native/tests/unit/netlink_handler_unit_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/unit/netlink_handler_unit_test.cpp new file mode 100644 index 000000000..7d08ec462 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/unit/netlink_handler_unit_test.cpp @@ -0,0 +1,443 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DISABLE_WARNING_PUSH +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_IMPLICIT_INT_CONVERSION +DISABLE_WARNING_SHORTEN_64_TO_32 +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_SIGN_COMPARE +DISABLE_WARNING_OLD_STYLE_CAST +DISABLE_WARNING_CAST_ALIGN +DISABLE_WARNING_SIGN_CONVERSION +DISABLE_WARNING_C99_EXTENSIONS + +namespace event_handler_test { +static int defaultOnInterfaceAddressUpdatedInvokeCount = 0; +static int defaultOnInterfaceAddressRemovedInvokeCount = 0; +static int defaultOnInterfaceAddedInvokeCount = 0; +static int defaultOnInterfaceRemovedInvokeCount = 0; +static int defaultOnInterfaceChangedInvokeCount = 0; +static int defaultOnInterfaceLinkStateChangedInvokeCount = 0; +static int defaultOnRouteChangedInvokeCount = 0; + +void defaultOnInterfaceAddressUpdated(const std::string &addr, const std::string &ifName, int flags, int scope) +{ + defaultOnInterfaceAddressUpdatedInvokeCount = 1; + std::cout << "InterfaceAddressUpdate:" << addr << "," << ifName << "," << flags << "," << scope << std::endl; +} +void defaultOnInterfaceAddressRemoved(const std::string &addr, const std::string &ifName, int flags, int scope) +{ + defaultOnInterfaceAddressRemovedInvokeCount = 1; + std::cout << "InterfaceAddressRemoved:" << addr << "," << ifName << "," << flags << "," << scope << std::endl; +} +void defaultOnInterfaceAdded(const std::string &ifName) +{ + defaultOnInterfaceAddedInvokeCount = 1; + std::cout << "InterfaceAdded:" << ifName << std::endl; +} +void defaultOnInterfaceRemoved(const std::string &ifName) +{ + defaultOnInterfaceRemovedInvokeCount = 1; + std::cout << "InterfaceRemoved:" << ifName << std::endl; +} +void defaultOnInterfaceChanged(const std::string &ifName, bool up) +{ + defaultOnInterfaceChangedInvokeCount = 1; + std::cout << "InterfaceChanged:" << ifName << "," << up << std::endl; +} +void defaultOnInterfaceLinkStateChanged(const std::string &ifName, bool up) +{ + defaultOnInterfaceLinkStateChangedInvokeCount = 1; + std::cout << "InterfaceLinkStateChanged:" << ifName << "," << up << std::endl; +} +void defaultOnRouteChanged( + bool updated, const std::string &route, const std::string &gateway, const std::string &ifName) +{ + defaultOnRouteChangedInvokeCount = 1; + std::cout << "RouteChanged:" << updated << "," << route << "," << gateway << "," << ifName << std::endl; +} + +void initTest() +{ + defaultOnInterfaceAddressUpdatedInvokeCount = 0; + defaultOnInterfaceAddressRemovedInvokeCount = 0; + defaultOnInterfaceAddedInvokeCount = 0; + defaultOnInterfaceRemovedInvokeCount = 0; + defaultOnInterfaceChangedInvokeCount = 0; + defaultOnInterfaceLinkStateChangedInvokeCount = 0; + defaultOnRouteChangedInvokeCount = 0; +} +} // namespace event_handler_test + +TEST(netlink_handler, onUnknown) +{ + nmd::event_reporter report; + + nmd::inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = event_handler_test::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = event_handler_test::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = event_handler_test::defaultOnInterfaceAdded, + .onInterfaceRemoved = event_handler_test::defaultOnInterfaceRemoved, + .onInterfaceChanged = event_handler_test::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = event_handler_test::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = event_handler_test::defaultOnRouteChanged, + }; + + report.registerEventListener(glistener); + + nmd::netlink_handler handler(NETLINK_ROUTE, getpid()); + handler.setEventListener(std::make_shared(report)); + + std::shared_ptr ev = std::make_shared(); + ev->setAction(nmd::Action::Unknown); + handler.onEvent(ev); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressUpdatedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceLinkStateChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnRouteChangedInvokeCount, 0); +} + +TEST(netlink_handler, onAdd) +{ + nmd::event_reporter report; + + nmd::inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = event_handler_test::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = event_handler_test::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = event_handler_test::defaultOnInterfaceAdded, + .onInterfaceRemoved = event_handler_test::defaultOnInterfaceRemoved, + .onInterfaceChanged = event_handler_test::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = event_handler_test::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = event_handler_test::defaultOnRouteChanged, + }; + + report.registerEventListener(glistener); + nmd::netlink_handler handler(NETLINK_ROUTE, getpid()); + handler.setEventListener(std::make_shared(report)); + + event_handler_test::initTest(); + std::shared_ptr ev = std::make_shared(); + ev->setAction(nmd::Action::Add); + ev->addParam("INTERFACE", "test_INTERFACE"); + handler.onEvent(ev); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressUpdatedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddedInvokeCount, 1); + EXPECT_EQ(event_handler_test::defaultOnInterfaceRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceLinkStateChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnRouteChangedInvokeCount, 0); +} + +TEST(netlink_handler, onLinkUp) +{ + nmd::event_reporter report; + + nmd::inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = event_handler_test::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = event_handler_test::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = event_handler_test::defaultOnInterfaceAdded, + .onInterfaceRemoved = event_handler_test::defaultOnInterfaceRemoved, + .onInterfaceChanged = event_handler_test::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = event_handler_test::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = event_handler_test::defaultOnRouteChanged, + }; + + report.registerEventListener(glistener); + + nmd::netlink_handler handler(NETLINK_ROUTE, getpid()); + handler.setEventListener(std::make_shared(report)); + + event_handler_test::initTest(); + std::shared_ptr ev = std::make_shared(); + ev->addParam("INTERFACE", "test_INTERFACE"); + ev->setAction(nmd::Action::LinkUp); + handler.onEvent(ev); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressUpdatedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceLinkStateChangedInvokeCount, 1); + EXPECT_EQ(event_handler_test::defaultOnRouteChangedInvokeCount, 0); +} + +TEST(netlink_handler, onLinkDown) +{ + nmd::event_reporter report; + + nmd::inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = event_handler_test::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = event_handler_test::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = event_handler_test::defaultOnInterfaceAdded, + .onInterfaceRemoved = event_handler_test::defaultOnInterfaceRemoved, + .onInterfaceChanged = event_handler_test::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = event_handler_test::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = event_handler_test::defaultOnRouteChanged, + }; + + report.registerEventListener(glistener); + + nmd::netlink_handler handler(NETLINK_ROUTE, getpid()); + handler.setEventListener(std::make_shared(report)); + + event_handler_test::initTest(); + std::shared_ptr ev = std::make_shared(); + ev->addParam("INTERFACE", "test_INTERFACE"); + ev->setAction(nmd::Action::LinkDown); + handler.onEvent(ev); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressUpdatedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceLinkStateChangedInvokeCount, 1); + EXPECT_EQ(event_handler_test::defaultOnRouteChangedInvokeCount, 0); +} + +TEST(netlink_handler, onChange) +{ + nmd::event_reporter report; + + nmd::inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = event_handler_test::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = event_handler_test::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = event_handler_test::defaultOnInterfaceAdded, + .onInterfaceRemoved = event_handler_test::defaultOnInterfaceRemoved, + .onInterfaceChanged = event_handler_test::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = event_handler_test::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = event_handler_test::defaultOnRouteChanged, + }; + + report.registerEventListener(glistener); + + nmd::netlink_handler handler(NETLINK_ROUTE, getpid()); + handler.setEventListener(std::make_shared(report)); + + event_handler_test::initTest(); + std::shared_ptr ev = std::make_shared(); + ev->addParam("INTERFACE", "test_INTERFACE"); + ev->setAction(nmd::Action::Change); + handler.onEvent(ev); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressUpdatedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceLinkStateChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnRouteChangedInvokeCount, 0); +} + +TEST(netlink_handler, onRemove) +{ + nmd::event_reporter report; + + nmd::inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = event_handler_test::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = event_handler_test::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = event_handler_test::defaultOnInterfaceAdded, + .onInterfaceRemoved = event_handler_test::defaultOnInterfaceRemoved, + .onInterfaceChanged = event_handler_test::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = event_handler_test::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = event_handler_test::defaultOnRouteChanged, + }; + + report.registerEventListener(glistener); + + nmd::netlink_handler handler(NETLINK_ROUTE, getpid()); + handler.setEventListener(std::make_shared(report)); + + event_handler_test::initTest(); + std::shared_ptr ev = std::make_shared(); + ev->addParam("INTERFACE", "test_INTERFACE"); + ev->setAction(nmd::Action::Remove); + handler.onEvent(ev); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressUpdatedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceRemovedInvokeCount, 1); + EXPECT_EQ(event_handler_test::defaultOnInterfaceChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceLinkStateChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnRouteChangedInvokeCount, 0); +} + +TEST(netlink_handler, onRouteRemoved) +{ + nmd::event_reporter report; + + nmd::inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = event_handler_test::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = event_handler_test::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = event_handler_test::defaultOnInterfaceAdded, + .onInterfaceRemoved = event_handler_test::defaultOnInterfaceRemoved, + .onInterfaceChanged = event_handler_test::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = event_handler_test::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = event_handler_test::defaultOnRouteChanged, + }; + + report.registerEventListener(glistener); + + event_handler_test::initTest(); + nmd::netlink_handler handler(NETLINK_ROUTE, getpid()); + handler.setEventListener(std::make_shared(report)); + std::shared_ptr ev = std::make_shared(); + + ev->addParam("ROUTE", "test_ROUTE"); + ev->addParam("GATEWAY", "test_GATEWAY"); + ev->addParam("INTERFACE", "test_INTERFACE"); + ev->setAction(nmd::Action::RouteRemoved); + handler.onEvent(ev); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressUpdatedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceLinkStateChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnRouteChangedInvokeCount, 1); +} +TEST(netlink_handler, onRouteUpdated) +{ + nmd::event_reporter report; + + nmd::inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = event_handler_test::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = event_handler_test::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = event_handler_test::defaultOnInterfaceAdded, + .onInterfaceRemoved = event_handler_test::defaultOnInterfaceRemoved, + .onInterfaceChanged = event_handler_test::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = event_handler_test::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = event_handler_test::defaultOnRouteChanged, + }; + + report.registerEventListener(glistener); + + nmd::netlink_handler handler(NETLINK_ROUTE, getpid()); + handler.setEventListener(std::make_shared(report)); + + event_handler_test::initTest(); + std::shared_ptr ev = std::make_shared(); + ev->addParam("ROUTE", "test_ROUTE"); + ev->addParam("GATEWAY", "test_GATEWAY"); + ev->addParam("INTERFACE", "test_INTERFACE"); + ev->setAction(nmd::Action::RouteUpdated); + handler.onEvent(ev); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressUpdatedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceLinkStateChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnRouteChangedInvokeCount, 1); +} + +TEST(netlink_handler, onAddressRemoved) +{ + nmd::event_reporter report; + + nmd::inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = event_handler_test::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = event_handler_test::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = event_handler_test::defaultOnInterfaceAdded, + .onInterfaceRemoved = event_handler_test::defaultOnInterfaceRemoved, + .onInterfaceChanged = event_handler_test::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = event_handler_test::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = event_handler_test::defaultOnRouteChanged, + }; + + report.registerEventListener(glistener); + + nmd::netlink_handler handler(NETLINK_ROUTE, getpid()); + handler.setEventListener(std::make_shared(report)); + + event_handler_test::initTest(); + std::shared_ptr ev = std::make_shared(); + ev->setAction(nmd::Action::AddressRemoved); + handler.onEvent(ev); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressUpdatedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceLinkStateChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnRouteChangedInvokeCount, 0); +} + +TEST(netlink_handler, onAddressUpdated) +{ + nmd::event_reporter report; + + nmd::inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = event_handler_test::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = event_handler_test::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = event_handler_test::defaultOnInterfaceAdded, + .onInterfaceRemoved = event_handler_test::defaultOnInterfaceRemoved, + .onInterfaceChanged = event_handler_test::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = event_handler_test::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = event_handler_test::defaultOnRouteChanged, + }; + + report.registerEventListener(glistener); + + nmd::netlink_handler handler(NETLINK_ROUTE, getpid()); + handler.setEventListener(std::make_shared(report)); + + event_handler_test::initTest(); + std::shared_ptr ev = std::make_shared(); + ev->setAction(nmd::Action::AddressUpdated); + handler.onEvent(ev); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressUpdatedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceLinkStateChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnRouteChangedInvokeCount, 0); +} + +TEST(netlink_handler, notify) +{ + nmd::event_reporter report; + + nmd::inetd_unsolicited_event_listener glistener { + .onInterfaceAddressUpdated = event_handler_test::defaultOnInterfaceAddressUpdated, + .onInterfaceAddressRemoved = event_handler_test::defaultOnInterfaceAddressRemoved, + .onInterfaceAdded = event_handler_test::defaultOnInterfaceAdded, + .onInterfaceRemoved = event_handler_test::defaultOnInterfaceRemoved, + .onInterfaceChanged = event_handler_test::defaultOnInterfaceChanged, + .onInterfaceLinkStateChanged = event_handler_test::defaultOnInterfaceLinkStateChanged, + .onRouteChanged = event_handler_test::defaultOnRouteChanged, + }; + + report.registerEventListener(glistener); + + event_handler_test::initTest(); + nmd::netlink_handler handler(NETLINK_ROUTE, getpid()); + handler.setEventListener(std::make_shared(report)); + + handler.notifyInterfaceChanged("eth0", true); + handler.notifyAddressUpdated("192.168.12.13", "eth0", 0, 0); + handler.notifyAddressRemoved("192.168.12.13", "eth0", 0, 0); + + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressUpdatedInvokeCount, 1); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddressRemovedInvokeCount, 1); + EXPECT_EQ(event_handler_test::defaultOnInterfaceAddedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceRemovedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnInterfaceChangedInvokeCount, 1); + EXPECT_EQ(event_handler_test::defaultOnInterfaceLinkStateChangedInvokeCount, 0); + EXPECT_EQ(event_handler_test::defaultOnRouteChangedInvokeCount, 0); +} + +DISABLE_WARNING_POP diff --git a/http/services/netmanagernative/net_mgr_native/tests/unit/netlink_manager_unit_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/unit/netlink_manager_unit_test.cpp new file mode 100644 index 000000000..5f506b110 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/unit/netlink_manager_unit_test.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netlink_manager.h" +#include "netlink_listener.h" + +TEST(netlinkManager, init) +{ + nmd::netlink_manager manager(getpid()); + manager.setPid(1); + manager.getReporter()->getListener().onInterfaceAddressUpdated("128.9.12.3", "eth0", 0, 0); + manager.getReporter()->getListener().onInterfaceAddressRemoved("128.9.12.3", "eth0", 0, 0); + manager.getReporter()->getListener().onInterfaceAdded("eth0"); + manager.getReporter()->getListener().onInterfaceRemoved("eth0"); + manager.getReporter()->getListener().onInterfaceChanged("eth0", true); + manager.getReporter()->getListener().onInterfaceLinkStateChanged("eth0", true); + manager.getReporter()->getListener().onRouteChanged(true, "192.168.1.1", "192.168.1.1", "eth0"); + EXPECT_EQ(manager.getPid(), 1); +} + +TEST(netlink_listener, stopListen) +{ + int pid = getpid(); + nmd::netlink_listener nls(AF_INET, pid); + nls.stopListen(); + EXPECT_EQ(false, nls.getNetlinkListenerState()); +} diff --git a/http/services/netmanagernative/net_mgr_native/tests/unit/route_controller_unit_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/unit/route_controller_unit_test.cpp new file mode 100644 index 000000000..8af27e310 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/unit/route_controller_unit_test.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "route_controller.h" + +TEST(route_controller_test, addInterfaceToDefaultNetwork) +{ + EXPECT_NE( + nmd::route_controller::addInterfaceToDefaultNetwork("eth0", nmd::NetworkPermission::PERMISSION_NONE), -1); +} + +TEST(route_controller_test, removeInterfaceToDefaultNetwork) +{ + EXPECT_NE( + nmd::route_controller::removeInterfaceFromDefaultNetwork("eth0", nmd::NetworkPermission::PERMISSION_NONE), + -1); +} + +TEST(route_controller_test, createChildChains) +{ + EXPECT_EQ(nmd::route_controller::createChildChains("mangle", "INPUT", "test_mangle_INPUT"), 0); +} + +TEST(route_controller_test, removeInterfaceFromPhysicalNetwork) +{ + EXPECT_EQ(nmd::route_controller::removeInterfaceFromPhysicalNetwork( + 0, "eth0", nmd::NetworkPermission::PERMISSION_NONE), + 1); +} + +TEST(route_controller_test, addRoute) +{ + EXPECT_EQ(nmd::route_controller::addRoute(0, "eth0", "47.94.251.146/32", "10.205.127.254"), 1); +} + +TEST(route_controller_test, removeRoute) +{ + EXPECT_EQ(nmd::route_controller::removeRoute(0, "eth0", "47.94.251.146/32", "10.205.127.254"), 1); +} diff --git a/http/services/netmanagernative/net_mgr_native/tests/unit/traffic_controller_unit_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/unit/traffic_controller_unit_test.cpp new file mode 100644 index 000000000..a27ca9ed5 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/unit/traffic_controller_unit_test.cpp @@ -0,0 +1,11 @@ +#include +#include +#include "traffic_controller.h" + +TEST(traffic_controller_unit, getTetherClientInfo) +{ + auto tetherClientInfo = nmd::traffic_controller::getTetherClientInfo(); + for (auto iter = tetherClientInfo.begin(); iter != tetherClientInfo.end(); iter++) { + std::cout << (*iter).ipAddr << std::endl; + } +} \ No newline at end of file diff --git a/http/services/netmanagernative/net_mgr_native/tests/unit/traffic_init_unit_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/unit/traffic_init_unit_test.cpp new file mode 100644 index 000000000..4e7d3daa4 --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/unit/traffic_init_unit_test.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include "traffic_init.h" +#include "utils.h" + +class traffic_init_unit_test : public ::testing::Test { +public: + static void recursion_mkdir(const char *dir) + { + nmd::traffic_init::recursion_mkdir(dir); + } + + static void create_cgroup() + { + nmd::traffic_init::create_cgroup(); + } + + static void write_all_pid_to_cgroup() + { + nmd::traffic_init::write_all_pid_to_cgroup(); + } + + static int create_unix_socket() + { + return nmd::traffic_init::create_unix_socket(); + } + +private: +}; + +TEST_F(traffic_init_unit_test, recursionMkdir) +{ + const char *dir = "/root/test/test/"; + traffic_init_unit_test::recursion_mkdir(dir); + DIR *d = opendir(dir); + EXPECT_TRUE(d != NULL); + nmd::common::utils::removeDirectory("/root/test/"); + closedir(d); +} + +TEST_F(traffic_init_unit_test, writeAllPidToCgroup) +{ + char cmd[1024] = {0}; + char buf_ps[100]; + FILE *ptr; + + traffic_init_unit_test::create_cgroup(); + traffic_init_unit_test::write_all_pid_to_cgroup(); + strcpy(cmd, "cat /sys/fs/cgroup/unified/cgroup-traffic-uid/cgroup.procs | wc -l"); + if ((ptr = popen(cmd, "r")) != NULL) { + while (fgets(buf_ps, 100, ptr) != NULL) { + EXPECT_NE(std::string(buf_ps), std::string("0\n")); + } + } +} + +TEST_F(traffic_init_unit_test, createUnixSocket) +{ + remove("/dev/socket/traffic"); + nmd::traffic_init::traffic_init_log(); + int ret = traffic_init_unit_test::create_unix_socket(); + EXPECT_EQ(0, ret); +} diff --git a/http/services/netmanagernative/net_mgr_native/tests/unit/utils_unit_test.cpp b/http/services/netmanagernative/net_mgr_native/tests/unit/utils_unit_test.cpp new file mode 100644 index 000000000..29a8a342d --- /dev/null +++ b/http/services/netmanagernative/net_mgr_native/tests/unit/utils_unit_test.cpp @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TEST(utils, shouldGetCurrentTime) +{ + nmd::common::utils::getCurrentTime(); +} + +TEST(utils, shouldRemoveDirectory) +{ + mkdir("test_dir", 777); + mkdir("test_dir/test_dir", 777); + + nmd::common::utils::removeDirectory("test_dir"); + + DIR *d = opendir("test_dir"); + + EXPECT_TRUE(d == NULL); +} diff --git a/http/utils/BUILD.gn b/http/utils/BUILD.gn new file mode 100644 index 000000000..32734e087 --- /dev/null +++ b/http/utils/BUILD.gn @@ -0,0 +1,66 @@ +# 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/netmgr_log_wrapper.cpp" + ] + + defines = [ + "NET_MANAGER_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 += [ + "native_appdatamgr:native_preferences", + "appexecfwk_standard:libeventhandler" + ] + + part_name = "netstack" + subsystem_name = "communication" +} diff --git a/http/utils/log/include/netmgr_log_wrapper.h b/http/utils/log/include/netmgr_log_wrapper.h new file mode 100644 index 000000000..b479a83d6 --- /dev/null +++ b/http/utils/log/include/netmgr_log_wrapper.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 NETMGR_LOG_WRAPPER_H +#define NETMGR_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}; + +#define PRINT_LOG(op, fmt, ...) \ + (void)OHOS::HiviewDFX::HiLog::op(NET_MGR_LABEL, "[%{public}s-(%{public}s:%{public}d)]" fmt, __FUNCTION__, \ + __FILE__, __LINE__, ##__VA_ARGS__) + +#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 // NETMGR_LOG_WRAPPER_H \ No newline at end of file diff --git a/http/utils/log/src/netmgr_log_wrapper.cpp b/http/utils/log/src/netmgr_log_wrapper.cpp new file mode 100644 index 000000000..ecb1fc112 --- /dev/null +++ b/http/utils/log/src/netmgr_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 "netmgr_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 -- Gitee