aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-03 15:52:58 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-03 15:52:58 +0000
commitf9055633b0e8642869404f8598d6b12260bdeaaf (patch)
tree71aaa03f4550146976967c79fa0a109ad00b93ec
parent16b861c374c60830e369f58cff33a5b5349f9e5c (diff)
parent943382cf28dccd0527094011080cc6f2a8c109cc (diff)
downloadot-br-posix-android14-mainline-adbd-release.tar.gz
Snap for 10428683 from 943382cf28dccd0527094011080cc6f2a8c109cc to mainline-adbd-releaseaml_adb_340912530aml_adb_340912350aml_adb_340912200aml_adb_340912000android14-mainline-adbd-release
Change-Id: I0f803e7067276e0baf236def7a84729fbd4dc930
-rw-r--r--.github/ISSUE_TEMPLATE.md2
-rw-r--r--.github/workflows/border_router.yml66
-rw-r--r--.github/workflows/build.yml40
-rw-r--r--.github/workflows/docker.yml6
-rw-r--r--.github/workflows/macOS.yml4
-rw-r--r--.github/workflows/meshcop.yml3
-rw-r--r--Android.bp9
-rw-r--r--CMakeLists.txt13
-rw-r--r--METADATA17
-rw-r--r--NOTICE8
-rw-r--r--OWNERS6
-rw-r--r--README.md12
-rw-r--r--doc/CMakeLists.txt2
-rw-r--r--etc/cmake/options.cmake25
-rw-r--r--etc/docker/Dockerfile12
-rwxr-xr-xetc/docker/docker_entrypoint.sh27
-rw-r--r--etc/openwrt/openthread-br/Makefile1
-rw-r--r--etc/yocto/otbr_git.bb64
-rw-r--r--examples/platforms/beagleboneblack/default16
-rw-r--r--examples/platforms/nxp/linux-imx/aarch64.cmake3
-rw-r--r--examples/platforms/nxp/linux-imx/arm.cmake56
-rw-r--r--examples/platforms/raspbian/default2
-rw-r--r--examples/platforms/ubuntu/default2
-rw-r--r--script/_dhcpv6_pd2
-rw-r--r--script/_disable_services13
-rwxr-xr-xscript/_firewall73
-rw-r--r--script/_nat64132
-rw-r--r--script/_network_manager4
-rw-r--r--script/_otbr6
-rwxr-xr-xscript/bootstrap30
-rwxr-xr-xscript/console2
-rw-r--r--script/otbr-firewall109
-rwxr-xr-xscript/server4
-rwxr-xr-xscript/setup5
-rwxr-xr-xscript/test19
-rwxr-xr-xscript/update2
-rw-r--r--src/CMakeLists.txt5
-rw-r--r--src/agent/CMakeLists.txt31
-rw-r--r--src/agent/agent_instance.hpp89
-rw-r--r--src/agent/application.cpp197
-rw-r--r--src/agent/application.hpp156
-rw-r--r--src/agent/instance_params.cpp45
-rw-r--r--src/agent/instance_params.hpp99
-rw-r--r--src/agent/main.cpp231
-rw-r--r--src/agent/otbr-agent.default.in1
-rw-r--r--src/agent/otbr-agent.service.in7
-rw-r--r--src/agent/vendor.hpp2
-rw-r--r--src/backbone_router/CMakeLists.txt2
-rw-r--r--src/backbone_router/backbone_agent.cpp9
-rw-r--r--src/backbone_router/backbone_agent.hpp8
-rw-r--r--src/backbone_router/dua_routing_manager.cpp12
-rw-r--r--src/backbone_router/dua_routing_manager.hpp15
-rw-r--r--src/backbone_router/nd_proxy.cpp18
-rw-r--r--src/backbone_router/nd_proxy.hpp29
-rw-r--r--src/border_agent/CMakeLists.txt1
-rw-r--r--src/border_agent/border_agent.cpp246
-rw-r--r--src/border_agent/border_agent.hpp64
-rw-r--r--src/common/callback.hpp97
-rw-r--r--src/common/code_utils.hpp134
-rw-r--r--src/common/dns_utils.hpp4
-rw-r--r--src/common/logging.cpp31
-rw-r--r--src/common/logging.hpp70
-rw-r--r--src/common/mainloop.hpp4
-rw-r--r--src/common/mainloop_manager.hpp13
-rw-r--r--src/common/task_runner.cpp73
-rw-r--r--src/common/task_runner.hpp75
-rw-r--r--src/common/tlv.hpp10
-rw-r--r--src/common/types.hpp74
-rw-r--r--src/dbus/client/thread_api_dbus.cpp104
-rw-r--r--src/dbus/client/thread_api_dbus.hpp503
-rw-r--r--src/dbus/common/constants.hpp17
-rw-r--r--src/dbus/common/dbus_message_helper.hpp167
-rw-r--r--src/dbus/common/dbus_message_helper_openthread.cpp477
-rw-r--r--src/dbus/common/types.hpp135
-rw-r--r--src/dbus/server/dbus_agent.cpp76
-rw-r--r--src/dbus/server/dbus_agent.hpp40
-rw-r--r--src/dbus/server/dbus_object.cpp18
-rw-r--r--src/dbus/server/dbus_object.hpp70
-rw-r--r--src/dbus/server/dbus_request.hpp32
-rw-r--r--src/dbus/server/dbus_thread_object.cpp495
-rw-r--r--src/dbus/server/dbus_thread_object.hpp42
-rw-r--r--src/dbus/server/introspect.xml280
-rw-r--r--src/mdns/mdns.cpp502
-rw-r--r--src/mdns/mdns.hpp451
-rw-r--r--src/mdns/mdns_avahi.cpp1090
-rw-r--r--src/mdns/mdns_avahi.hpp459
-rw-r--r--src/mdns/mdns_mdnssd.cpp976
-rw-r--r--src/mdns/mdns_mdnssd.hpp408
-rw-r--r--src/ncp/ncp_openthread.cpp125
-rw-r--r--src/ncp/ncp_openthread.hpp67
-rw-r--r--src/openwrt/ubus/otubus.cpp4
-rw-r--r--src/openwrt/ubus/otubus.hpp651
-rw-r--r--src/openwrt/view/admin_thread/thread_scan.htm13
-rw-r--r--src/rest/connection.hpp27
-rw-r--r--src/rest/json.hpp64
-rw-r--r--src/rest/parser.hpp6
-rw-r--r--src/rest/request.hpp12
-rw-r--r--src/rest/resource.cpp8
-rw-r--r--src/rest/resource.hpp14
-rw-r--r--src/rest/response.hpp14
-rw-r--r--src/rest/rest_web_server.hpp15
-rw-r--r--src/sdp_proxy/advertising_proxy.cpp208
-rw-r--r--src/sdp_proxy/advertising_proxy.hpp27
-rw-r--r--src/sdp_proxy/discovery_proxy.cpp102
-rw-r--r--src/sdp_proxy/discovery_proxy.hpp5
-rw-r--r--src/trel_dnssd/CMakeLists.txt37
-rw-r--r--src/trel_dnssd/trel_dnssd.cpp522
-rw-r--r--src/trel_dnssd/trel_dnssd.hpp196
-rw-r--r--src/utils/CMakeLists.txt4
-rw-r--r--src/utils/crc16.hpp6
-rw-r--r--src/utils/dns_utils.cpp100
-rw-r--r--src/utils/dns_utils.hpp83
-rw-r--r--src/utils/infra_link_selector.cpp353
-rw-r--r--src/utils/infra_link_selector.hpp151
-rw-r--r--src/utils/pskc.hpp6
-rw-r--r--src/utils/socket_utils.cpp32
-rw-r--r--src/utils/socket_utils.hpp24
-rw-r--r--src/utils/steering_data.hpp10
-rw-r--r--src/utils/string_utils.cpp (renamed from src/utils/strcpy_utils.cpp)28
-rw-r--r--src/utils/string_utils.hpp (renamed from src/utils/strcpy_utils.hpp)45
-rw-r--r--src/utils/thread_helper.cpp205
-rw-r--r--src/utils/thread_helper.hpp120
-rw-r--r--src/web/web-service/frontend/index.html7
-rw-r--r--src/web/web-service/frontend/res/js/app.js18
-rw-r--r--src/web/web-service/ot_client.cpp49
-rw-r--r--src/web/web-service/ot_client.hpp19
-rw-r--r--src/web/web-service/web_server.cpp12
-rw-r--r--src/web/web-service/web_server.hpp6
-rw-r--r--src/web/web-service/wpan_service.cpp6
-rw-r--r--src/web/web-service/wpan_service.hpp16
-rw-r--r--tests/dbus/CMakeLists.txt2
-rwxr-xr-xtests/dbus/test-client153
-rw-r--r--tests/dbus/test_dbus_client.cpp156
-rw-r--r--tests/mdns/main.cpp207
-rwxr-xr-xtests/mdns/test-multiple8
-rwxr-xr-xtests/mdns/test-single4
-rwxr-xr-xtests/mdns/test-stop12
-rwxr-xr-xtests/mdns/test-update4
-rwxr-xr-xtests/rest/test-rest-server4
-rwxr-xr-xtests/scripts/auto-attach86
-rwxr-xr-xtests/scripts/bootstrap.sh7
-rwxr-xr-xtests/scripts/check-android-build6
-rwxr-xr-xtests/scripts/check-docker1
-rwxr-xr-xtests/scripts/check-scripts38
-rwxr-xr-xtests/scripts/infra-link-selector145
-rwxr-xr-xtests/scripts/meshcop24
-rw-r--r--tests/unit/CMakeLists.txt1
-rw-r--r--tests/unit/test_dbus_message.cpp4
-rw-r--r--tests/unit/test_logging.cpp2
-rw-r--r--tests/unit/test_once_callback.cpp (renamed from src/agent/agent_instance.cpp)50
-rw-r--r--tests/unit/test_task_runner.cpp56
m---------third_party/cJSON/repo0
m---------third_party/http-parser/repo0
-rw-r--r--third_party/openthread/CMakeLists.txt24
m---------third_party/openthread/repo0
-rwxr-xr-xtools/reference_device/testharness-discovery2
156 files changed, 9346 insertions, 4058 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 160bc34e..479ca7f2 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,3 +1,3 @@
GitHub Issues are for bugs and feature requests. To make bugs and feature requests more easy to find and organize, we close issues that are deemed out of scope for GitHub Issues.
-The openthread-users Google Group is the recommended place for users to discuss OpenThread and interact directly with the OpenThread community. https://groups.google.com/forum/#!forum/openthread-users
+OpenThread GitHub Discussions is the recommended place for users to discuss OpenThread and interact directly with the OpenThread community. https://github.com/openthread/openthread/discussions
diff --git a/.github/workflows/border_router.yml b/.github/workflows/border_router.yml
index fb010a9a..9f56b9f3 100644
--- a/.github/workflows/border_router.yml
+++ b/.github/workflows/border_router.yml
@@ -50,27 +50,57 @@ jobs:
runs-on: ubuntu-20.04
strategy:
+ fail-fast: false
matrix:
include:
- name: "Border Router (mDNSResponder)"
- otbr_options: "-DOT_TREL=OFF -DOT_MLR=ON -DOTBR_COVERAGE=ON -DOT_SRP_SERVER=ON -DOT_ECDSA=ON -DOT_SERVICE=ON -DOTBR_DUA_ROUTING=OFF"
+ otbr_options: "-DOT_TREL=OFF -DOT_MLR=ON -DOTBR_COVERAGE=ON -DOT_SRP_SERVER=ON -DOT_ECDSA=ON -DOT_SERVICE=ON -DOTBR_DUA_ROUTING=ON -DOT_DUA=ON -DOTBR_BORDER_ROUTING_NAT64=ON"
border_routing: 1
otbr_mdns: "mDNSResponder"
cert_scripts: ./tests/scripts/thread-cert/border_router/*.py
+ packet_verification: 1
- name: "Border Router (Avahi)"
- otbr_options: "-DOT_TREL=OFF -DOT_MLR=ON -DOTBR_COVERAGE=ON -DOT_SRP_SERVER=ON -DOT_ECDSA=ON -DOT_SERVICE=ON -DOTBR_DUA_ROUTING=OFF"
+ otbr_options: "-DOT_TREL=OFF -DOT_MLR=ON -DOTBR_COVERAGE=ON -DOT_SRP_SERVER=ON -DOT_ECDSA=ON -DOT_SERVICE=ON -DOTBR_DUA_ROUTING=ON -DOT_DUA=ON -DOTBR_BORDER_ROUTING_NAT64=ON"
border_routing: 1
otbr_mdns: "avahi"
cert_scripts: ./tests/scripts/thread-cert/border_router/*.py
+ packet_verification: 1
+ - name: "Border Router TREL (mDNSResponder)"
+ otbr_options: "-DOT_TREL=ON -DOT_MLR=ON -DOTBR_COVERAGE=ON -DOT_SRP_SERVER=ON -DOT_ECDSA=ON -DOT_SERVICE=ON -DOTBR_DUA_ROUTING=ON -DOT_DUA=ON -DOTBR_BORDER_ROUTING_NAT64=ON"
+ border_routing: 1
+ otbr_mdns: "mDNSResponder"
+ cert_scripts: ./tests/scripts/thread-cert/border_router/*.py
+ packet_verification: 2
+ - name: "Border Router TREL (Avahi)"
+ otbr_options: "-DOT_TREL=ON -DOT_MLR=ON -DOTBR_COVERAGE=ON -DOT_SRP_SERVER=ON -DOT_ECDSA=ON -DOT_SERVICE=ON -DOTBR_DUA_ROUTING=ON -DOT_DUA=ON -DOTBR_BORDER_ROUTING_NAT64=ON"
+ border_routing: 1
+ otbr_mdns: "avahi"
+ cert_scripts: ./tests/scripts/thread-cert/border_router/*.py
+ packet_verification: 2
+ - name: "Border Router MATN (mDNSResponder)"
+ otbr_options: "-DOT_TREL=OFF -DOT_MLR=ON -DOTBR_COVERAGE=ON -DOT_SRP_SERVER=ON -DOT_ECDSA=ON -DOT_SERVICE=ON -DOTBR_DUA_ROUTING=ON -DOT_DUA=ON -DOTBR_BORDER_ROUTING_NAT64=ON"
+ border_routing: 1
+ otbr_mdns: "mDNSResponder"
+ cert_scripts: ./tests/scripts/thread-cert/border_router/MATN/*.py
+ packet_verification: 1
+ - name: "Border Router NAT64 (mDNSResponder)"
+ otbr_options: "-DOT_TREL=OFF -DOT_MLR=ON -DOTBR_COVERAGE=ON -DOT_SRP_SERVER=ON -DOT_ECDSA=ON -DOT_SERVICE=ON -DOTBR_DUA_ROUTING=ON -DOT_DUA=ON -DOTBR_BORDER_ROUTING_NAT64=ON"
+ border_routing: 1
+ otbr_mdns: "mDNSResponder"
+ cert_scripts: ./tests/scripts/thread-cert/border_router/nat64/*.py
+ packet_verification: 1
- name: "Backbone Router"
otbr_options: "-DOT_TREL=OFF -DOT_DUA=ON -DOT_MLR=ON -DOTBR_COVERAGE=ON -DOT_SRP_SERVER=ON -DOT_ECDSA=ON -DOT_SERVICE=ON -DOTBR_DUA_ROUTING=ON"
border_routing: 0
+ otbr_mdns: "mDNSResponder"
cert_scripts: ./tests/scripts/thread-cert/backbone/*.py
+ packet_verification: 1
+
name: ${{ matrix.name }}
env:
- PACKET_VERIFICATION: 1
- THREAD_VERSION: 1.2
+ PACKET_VERIFICATION: ${{ matrix.packet_verification }}
+ THREAD_VERSION: 1.3
VIRTUAL_TIME: 0
PYTHONUNBUFFERED: 1
REFERENCE_DEVICE: 1
@@ -79,11 +109,24 @@ jobs:
INTER_OP: 0
INTER_OP_BBR: 0
BORDER_ROUTING: ${{ matrix.border_routing }}
+ MAX_JOBS: 3
steps:
- uses: actions/checkout@v2
with:
submodules: true
+ - name: Get Border Router Test ID
+ id: unique_action_id
+ run: |
+ echo ::set-output name=id::"${GITHUB_WORKFLOW}-${GITHUB_JOB}-${GITHUB_RUN_ID}-${{matrix.name}}"
+ - name: Check cached result
+ id: check_cache_result
+ uses: actions/cache@v2
+ with:
+ path: |
+ _test_complete_
+ key: "_test_complete_${{ steps.unique_action_id.outputs.id }}"
- name: Build OTBR Docker Image
+ if: ${{ success() && steps.check_cache_result.outputs.cache-hit != 'true' }}
run: |
# We need the `-DOT_SRP_SERVER=ON` option because the `bbr_5_11_01.py` script is referring SRP server.
# This should be fixed by enhancing the test script to handle SRP server situations properly.
@@ -99,28 +142,37 @@ jobs:
--build-arg MDNS="${{ matrix.otbr_mdns }}" \
--build-arg OTBR_OPTIONS="${otbr_options} -DCMAKE_CXX_FLAGS='-DOPENTHREAD_CONFIG_DNSSD_SERVER_BIND_UNSPECIFIED_NETIF=1'"
- name: Bootstrap OpenThread Test
+ if: ${{ success() && steps.check_cache_result.outputs.cache-hit != 'true' }}
run: |
sudo rm /etc/apt/sources.list.d/* && sudo apt-get update
sudo apt-get --no-install-recommends install -y python3-setuptools python3-wheel ninja-build socat nodejs npm
python3 -m pip install -r third_party/openthread/repo/tests/scripts/thread-cert/requirements.txt
- name: Build OpenThread
+ if: ${{ success() && steps.check_cache_result.outputs.cache-hit != 'true' }}
run: |
(cd third_party/openthread/repo && ./script/test build)
- name: Get Thread-Wireshark
+ if: ${{ success() && steps.check_cache_result.outputs.cache-hit != 'true' }}
run: |
(cd third_party/openthread/repo && ./script/test get_thread_wireshark)
- name: Run Test
+ if: ${{ success() && steps.check_cache_result.outputs.cache-hit != 'true' }}
run: |
export CI_ENV="$(bash <(curl -s https://codecov.io/env)) -e GITHUB_ACTIONS -e OTBR_COVERAGE"
echo "CI_ENV=${CI_ENV}"
(cd third_party/openthread/repo && sudo -E ./script/test cert_suite ${{ matrix.cert_scripts }} || (sudo chmod a+r *.log *.json *.pcap && false))
- uses: actions/upload-artifact@v2
- if: ${{ failure() }}
+ if: ${{ failure() && steps.check_cache_result.outputs.cache-hit != 'true' }}
with:
- name: thread-1-2-backbone-results
+ name: thread-1-3-backbone-results
path: |
third_party/openthread/repo/*.pcap
third_party/openthread/repo/*.json
third_party/openthread/repo/*.log
- name: Codecov
- uses: codecov/codecov-action@v1
+ if: ${{ success() && steps.check_cache_result.outputs.cache-hit != 'true' }}
+ uses: codecov/codecov-action@v2
+ - name: Cache test result
+ if: ${{ success() && steps.check_cache_result.outputs.cache-hit != 'true' }}
+ run: |
+ mkdir _test_complete_
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index be616303..783a1a31 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -57,29 +57,28 @@ jobs:
android-check:
runs-on: ubuntu-20.04
- strategy:
- matrix:
- mdns: ["mDNSResponder", ""]
steps:
- uses: actions/checkout@v2
with:
submodules: true
- - name: Check
- env:
- OTBR_MDNS: ${{ matrix.mdns }}
+ - name: Check (Border Agent with mDNSResponder)
run: >
- docker run --rm --env OTBR_MDNS=$OTBR_MDNS -v $PWD:/build/ot-br-posix -v $PWD/third_party/openthread/repo:/build/external/openthread openthread/android-trusty bash -c
+ docker run --rm --env OTBR_MDNS=mDNSResponder -v $PWD:/build/ot-br-posix -v $PWD/third_party/openthread/repo:/build/external/openthread openthread/android-trusty bash -c
"BUILD_TARGET=android-check ot-br-posix/tests/scripts/bootstrap.sh && \
ot-br-posix/tests/scripts/check-android-build"
check:
runs-on: ubuntu-20.04
strategy:
+ fail-fast: false
matrix:
+ build_type: ["Debug", "Release"]
mdns: ["mDNSResponder", "avahi"]
env:
BUILD_TARGET: check
+ OTBR_BUILD_TYPE: ${{ matrix.build_type }}
OTBR_MDNS: ${{ matrix.mdns }}
+ OTBR_OPTIONS: "-DOTBR_SRP_ADVERTISING_PROXY=ON"
OTBR_COVERAGE: 1
steps:
- uses: actions/checkout@v2
@@ -90,16 +89,19 @@ jobs:
- name: Run
run: script/test build check
- name: Codecov
- uses: codecov/codecov-action@v1
+ uses: codecov/codecov-action@v2
rest-check:
runs-on: ubuntu-18.04
strategy:
+ fail-fast: false
matrix:
rest: ["rest-off", ""]
env:
BUILD_TARGET: check
OTBR_REST: ${{ matrix.rest }}
+ OTBR_MDNS: mDNSResponder
+ OTBR_OPTIONS: "-DOTBR_SRP_ADVERTISING_PROXY=ON -DOTBR_DNSSD_DISCOVERY_PROXY=ON"
OTBR_COVERAGE: 1
steps:
- uses: actions/checkout@v2
@@ -110,7 +112,7 @@ jobs:
- name: Run
run: script/test build check
- name: Codecov
- uses: codecov/codecov-action@v1
+ uses: codecov/codecov-action@v2
script-check:
runs-on: ubuntu-20.04
@@ -126,7 +128,7 @@ jobs:
- name: Run
run: tests/scripts/check-scripts
- name: Codecov
- uses: codecov/codecov-action@v1
+ uses: codecov/codecov-action@v2
scan-build:
runs-on: ubuntu-20.04
@@ -158,3 +160,21 @@ jobs:
cmake --version | grep 3.10.3
- name: Build
run: script/test package
+
+ simulation:
+ runs-on: ubuntu-latest
+ env:
+ BUILD_TARGET: check
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ submodules: true
+ - name: Bootstrap
+ run: tests/scripts/bootstrap.sh
+ - name: Build
+ run: |
+ script/bootstrap
+ script/test build
+ - name: Run
+ run: |
+ script/test simulation
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 7fb08211..1fc1303e 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -49,6 +49,7 @@ jobs:
docker-check:
runs-on: ubuntu-latest
strategy:
+ fail-fast: false
matrix:
rcp_bus: ["UART", "SPI"]
env:
@@ -69,6 +70,7 @@ jobs:
buildx:
runs-on: ubuntu-20.04
strategy:
+ fail-fast: false
matrix:
include:
- image_tag: "latest"
@@ -81,8 +83,8 @@ jobs:
build_args: ""
platforms: "linux/amd64,linux/arm64"
push: yes
- - image_tag: "hirsute"
- base_image: "ubuntu:hirsute"
+ - image_tag: "jammy"
+ base_image: "ubuntu:jammy"
build_args: ""
platforms: "linux/amd64,linux/arm64"
push: yes
diff --git a/.github/workflows/macOS.yml b/.github/workflows/macOS.yml
index d4197d38..32d2a1e3 100644
--- a/.github/workflows/macOS.yml
+++ b/.github/workflows/macOS.yml
@@ -47,7 +47,7 @@ jobs:
if: "github.ref != 'refs/heads/main'"
build-check:
- runs-on: macos-10.15
+ runs-on: macos-12
steps:
- uses: actions/checkout@v2
with:
@@ -59,4 +59,4 @@ jobs:
brew reinstall boost cmake cpputest dbus jsoncpp ninja
- name: Build
run: |
- OTBR_OPTIONS='-DOTBR_MDNS=OFF' ./script/test build
+ OTBR_OPTIONS='-DOTBR_BORDER_AGENT=OFF -DOTBR_MDNS=OFF -DOT_FIREWALL=OFF -DOTBR_DBUS=OFF' ./script/test build
diff --git a/.github/workflows/meshcop.yml b/.github/workflows/meshcop.yml
index a038358c..d015fe88 100644
--- a/.github/workflows/meshcop.yml
+++ b/.github/workflows/meshcop.yml
@@ -49,6 +49,7 @@ jobs:
meshcop:
runs-on: ubuntu-latest
strategy:
+ fail-fast: false
matrix:
mdns: ["mDNSResponder", "avahi"]
steps:
@@ -83,4 +84,4 @@ jobs:
OTBR_USE_WEB_COMMISSIONER: 1
run: script/test meshcop
- name: Codecov
- uses: codecov/codecov-action@v1
+ uses: codecov/codecov-action@v2
diff --git a/Android.bp b/Android.bp
index e47a6e5b..8c90fb67 100644
--- a/Android.bp
+++ b/Android.bp
@@ -102,8 +102,7 @@ cc_binary {
],
srcs: [
- "src/agent/agent_instance.cpp",
- "src/agent/instance_params.cpp",
+ "src/agent/application.cpp",
"src/agent/main.cpp",
"src/border_agent/border_agent.cpp",
"src/ncp/ncp_openthread.cpp",
@@ -118,8 +117,11 @@ cc_binary {
"src/common/mainloop_manager.cpp",
"src/mdns/mdns.cpp",
"src/mdns/mdns_mdnssd.cpp",
+ "src/utils/dns_utils.cpp",
"src/utils/hex.cpp",
- "src/utils/strcpy_utils.cpp",
+ "src/utils/infra_link_selector.cpp",
+ "src/utils/socket_utils.cpp",
+ "src/utils/string_utils.cpp",
],
shared_libs: [
@@ -132,6 +134,7 @@ cc_binary {
static_libs: [
"libopenthread-cli",
"ot-core",
+ "openthread-tcplp",
],
host_ldlibs: ["-lutil"],
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ff9c6e17..59a567e7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,6 +29,7 @@
cmake_minimum_required(VERSION 3.10.2)
project(openthread-br VERSION 0.3.0)
+add_compile_options(-Wall -Wextra -Werror -Wfatal-errors -Wuninitialized -Wno-missing-braces)
add_library(otbr-config INTERFACE)
@@ -36,7 +37,9 @@ set(OTBR_INFRA_IF_NAME "wlan0" CACHE STRING "The infrastructure interface name")
set(OTBR_VENDOR_NAME "OpenThread" CACHE STRING "The vendor name")
set(OTBR_PRODUCT_NAME "BorderRouter" CACHE STRING "The product name")
set(OTBR_NAME "${OTBR_VENDOR_NAME}_${OTBR_PRODUCT_NAME}" CACHE STRING "The package name")
-set(OTBR_MDNS "avahi" CACHE STRING "mDNS service provider")
+set(OTBR_MESHCOP_SERVICE_INSTANCE_NAME "${OTBR_VENDOR_NAME} ${OTBR_PRODUCT_NAME}" CACHE STRING "The OTBR MeshCoP service instance name")
+set(OTBR_MDNS "avahi" CACHE STRING "mDNS publisher provider")
+set(OTBR_SYSLOG_FACILITY_ID LOG_USER CACHE STRING "Syslog logging facility")
set_property(CACHE OTBR_MDNS PROPERTY STRINGS "avahi" "mDNSResponder")
@@ -60,8 +63,6 @@ if (OTBR_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_link_libraries(otbr-config INTERFACE --coverage)
endif()
-add_compile_options(-Wall -Wextra -Werror -Wfatal-errors -Wno-missing-braces)
-
message(STATUS "OTBR package name: ${OTBR_NAME}")
if(NOT OTBR_VERSION)
@@ -89,6 +90,8 @@ target_compile_definitions(otbr-config INTERFACE
"OTBR_PRODUCT_NAME=\"${OTBR_PRODUCT_NAME}\""
"OTBR_PACKAGE_NAME=\"${OTBR_NAME}\""
"OTBR_PACKAGE_VERSION=\"${OTBR_VERSION}\""
+ "OTBR_MESHCOP_SERVICE_INSTANCE_NAME=\"${OTBR_MESHCOP_SERVICE_INSTANCE_NAME}\""
+ "OTBR_SYSLOG_FACILITY_ID=${OTBR_SYSLOG_FACILITY_ID}"
)
if(BUILD_SHARED_LIBS)
@@ -118,8 +121,8 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
endif()
set(CPACK_GENERATOR "DEB")
- set(CPACK_DEBIAN_PACKAGE_MAINTAINER "OpenThread Authors <openthread-users@googlegroups.com")
- set(CPACK_PACKAGE_CONTACT "OpenThread Authors <openthread-users@googlegroups.com")
+ set(CPACK_DEBIAN_PACKAGE_MAINTAINER "OpenThread Authors (https://github.com/openthread/openthread)")
+ set(CPACK_PACKAGE_CONTACT "OpenThread Authors (https://github.com/openthread/openthread)")
include(CPack)
endif()
diff --git a/METADATA b/METADATA
new file mode 100644
index 00000000..830cabe7
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,17 @@
+name: "ot-br-posix"
+description:
+ "ot-br-posix is an open-source implementation of the Thread Border Router."
+
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://github.com/openthread/ot-br-posix"
+ }
+ url {
+ type: GIT
+ value: "https://github.com/openthread/ot-br-posix.git"
+ }
+ version: "c75203a9c7d0df0188527360e556d17e940a945f"
+ last_upgrade_date { year: 2022 month: 11 day: 15 }
+ license_type: NOTICE
+}
diff --git a/NOTICE b/NOTICE
index 962490e5..94a2d719 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
-OpenThread is an open source implementation of the Thread 1.1.1 Final Specification.
-The Thread 1.1.1 Final Specification is promulgated by the Thread Group. The Thread
+OpenThread is an open source implementation of the Thread 1.2.0 Final Specification.
+The Thread 1.2.0 Final Specification is promulgated by the Thread Group. The Thread
Group is a non-profit organization formed for the purposes of defining one or
more specifications, best practices, reference architectures, implementation
guidelines and certification programs to promote the availability of compliant
@@ -7,10 +7,10 @@ implementations of the Thread protocol. Information on becoming a Member, includ
information about the benefits thereof, can be found at http://threadgroup.org.
OpenThread is not affiliated with or endorsed by the Thread Group. Implementation
-of this OpenThread code does not assure compliance with the Thread 1.1.1 Final
+of this OpenThread code does not assure compliance with the Thread 1.2.0 Final
Specification and does not convey the right to identify any final product as Thread
certified. Members of the Thread Group may hold patents and other intellectual
-property rights relating to the Thread 1.1.1 Final Specification, ownership and
+property rights relating to the Thread 1.2.0 Final Specification, ownership and
licenses of which are subject to the Thread Group’s IP Policies, and not this license.
The included copyright to the OpenThread code is subject to the license in the
diff --git a/OWNERS b/OWNERS
index 26f38df9..31c558eb 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,5 @@
-xyk@google.com
+# Bug component: 1203089
+
+include platform/packages/modules/ThreadNetwork:/OWNERS
+
jinran@google.com
-zhanglongxia@google.com
diff --git a/README.md b/README.md
index a542e7d6..deace2c6 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
# OpenThread Border Router
-Per the [Thread 1.1.1 Specification](http://threadgroup.org/ThreadSpec), a Thread Border Router connects a Thread network to other IP-based networks, such as Wi-Fi or Ethernet. A Thread network requires a Border Router to connect to other networks.
+Per the [Thread Specification](http://threadgroup.org/ThreadSpec), a Thread Border Router connects a Thread network to other IP-based networks, such as Wi-Fi or Ethernet. A Thread network requires a Border Router to connect to other networks.
A Thread Border Router minimally supports the following functions:
@@ -67,13 +67,11 @@ Please only use the OpenThread name and marks when accurately referencing this s
# Need help?
-There are numerous avenues for OpenThread support:
+OpenThread support is available on GitHub:
-- Bugs and feature requests — [submit to the Issue Tracker](https://github.com/openthread/ot-br-posix/issues)
-- Stack Overflow — [post questions using the `openthread` tag](http://stackoverflow.com/questions/tagged/openthread)
-- Google Groups — [discussion and announcements at openthread-users](https://groups.google.com/forum/#!forum/openthread-users)
-
-The openthread-users Google Group is the recommended place for users to discuss OpenThread and interact directly with the OpenThread team.
+- Bugs and feature requests pertaining to the OpenThread Border Router — [submit to the openthread/ot-br-posix Issue Tracker](https://github.com/openthread/ot-br-posix/issues)
+- OpenThread bugs and feature requests — [submit to the OpenThread Issue Tracker](https://github.com/openthread/openthread/issues)
+- Community Discussion - [ask questions, share ideas, and engage with other community members](https://github.com/openthread/openthread/discussions)
## OpenThread
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index 86ccb0a3..edd64537 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -51,7 +51,7 @@ if (DOXYGEN_FOUND)
COMMAND cp ${DBUS_DOC_SRC} ${DBUS_DOC_TARGET}
VERBATIM
)
- add_dependencies(otbr-dbus-server-doc-copy otbr-dbus-server-doc)
+ add_dependencies(otbr-dbus-server-doc-copy doxygen otbr-dbus-server-doc)
add_dependencies(otbr-doc otbr-dbus-server-doc-copy)
endif()
else()
diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake
index d4e74e26..a4d244d0 100644
--- a/etc/cmake/options.cmake
+++ b/etc/cmake/options.cmake
@@ -30,6 +30,11 @@ find_package(PkgConfig)
option(OTBR_DOC "Build documentation" OFF)
+option(OTBR_BORDER_AGENT "Enable Border Agent" ON)
+if (OTBR_BORDER_AGENT)
+ target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_BORDER_AGENT=1)
+endif()
+
option(OTBR_BACKBONE_ROUTER "Enable Backbone Router" OFF)
if (OTBR_BACKBONE_ROUTER)
target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_BACKBONE_ROUTER=1)
@@ -37,6 +42,8 @@ endif()
option(OTBR_BORDER_ROUTING "Enable Border Routing Manager" OFF)
+option(OTBR_BORDER_ROUTING_NAT64 "Enable NAT64 support in Border Routing Manager" OFF)
+
option(OTBR_DBUS "Enable DBus support" OFF)
if(OTBR_DBUS)
pkg_check_modules(DBUS REQUIRED dbus-1)
@@ -74,4 +81,22 @@ if(OTBR_UNSECURE_JOIN)
target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_UNSECURE_JOIN=1)
endif()
+option(OTBR_TREL "Enable TREL link support." OFF)
+if(OTBR_TREL)
+ target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_TREL=1)
+endif()
+
+
option(OTBR_WEB "Enable Web GUI" OFF)
+
+option(OTBR_NOTIFY_UPSTART "Notify upstart when ready." ON)
+if(OTBR_NOTIFY_UPSTART)
+ target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_NOTIFY_UPSTART=1)
+endif()
+
+option(OTBR_VENDOR_INFRA_LINK_SELECT "Enable Vendor-specific infrastructure link selection rules" OFF)
+if(OTBR_VENDOR_INFRA_LINK_SELECT)
+ target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_VENDOR_INFRA_LINK_SELECT=1)
+else()
+ target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_VENDOR_INFRA_LINK_SELECT=0)
+endif()
diff --git a/etc/docker/Dockerfile b/etc/docker/Dockerfile
index 7975b73b..adee8612 100644
--- a/etc/docker/Dockerfile
+++ b/etc/docker/Dockerfile
@@ -35,6 +35,7 @@ ARG OT_BACKBONE_CI
ARG OTBR_OPTIONS
ARG DNS64
ARG NAT64
+ARG NAT64_SERVICE
ARG REFERENCE_DEVICE
ARG RELEASE
ARG REST_API
@@ -52,7 +53,8 @@ ENV PLATFORM ubuntu
ENV REFERENCE_DEVICE=${REFERENCE_DEVICE:-0}
ENV RELEASE=${RELEASE:-1}
ENV NAT64=${NAT64:-1}
-ENV DNS64=${DNS64:-1}
+ENV NAT64_SERVICE=${NAT64_SERVICE:-tayga}
+ENV DNS64=${DNS64:-0}
ENV WEB_GUI=${WEB_GUI:-1}
ENV REST_API=${REST_API:-1}
ENV DOCKER 1
@@ -63,7 +65,7 @@ COPY . /app
WORKDIR /app
# Required during build or run
-ENV OTBR_DOCKER_REQS sudo
+ENV OTBR_DOCKER_REQS sudo python3
# Required during build, could be removed
ENV OTBR_DOCKER_DEPS git ca-certificates
@@ -79,9 +81,7 @@ ENV OTBR_OT_BACKBONE_CI_DEPS curl lcov wget build-essential
# Required and installed during build (script/bootstrap) when RELEASE=1, could be removed
ENV OTBR_NORELEASE_DEPS \
- cmake \
- cpputest \
- doxygen
+ cpputest-dev
RUN apt-get update \
&& apt-get install --no-install-recommends -y $OTBR_DOCKER_REQS $OTBR_DOCKER_DEPS \
@@ -89,7 +89,7 @@ RUN apt-get update \
&& ln -fs /usr/share/zoneinfo/UTC /etc/localtime \
&& ./script/bootstrap \
&& ./script/setup \
- && chmod 644 /etc/bind/named.conf.options \
+ && ([ "${DNS64}" = "0" ] || chmod 644 /etc/bind/named.conf.options) \
&& ([ "${OT_BACKBONE_CI}" = "1" ] || ( \
mv ./script /tmp \
&& mv ./etc /tmp \
diff --git a/etc/docker/docker_entrypoint.sh b/etc/docker/docker_entrypoint.sh
index 3cc1d029..b71fad32 100755
--- a/etc/docker/docker_entrypoint.sh
+++ b/etc/docker/docker_entrypoint.sh
@@ -38,6 +38,11 @@ function parse_args()
shift
shift
;;
+ --trel-url)
+ TREL_URL="$2"
+ shift
+ shift
+ ;;
--interface | -I)
TUN_INTERFACE_NAME=$2
shift
@@ -53,14 +58,6 @@ function parse_args()
shift
shift
;;
- --disable-default-prefix-route)
- AUTO_PREFIX_ROUTE=false
- shift
- ;;
- --disable-default-prefix-slaac)
- AUTO_PREFIX_SLAAC=false
- shift
- ;;
*)
shift
;;
@@ -71,26 +68,26 @@ function parse_args()
parse_args "$@"
[ -n "$RADIO_URL" ] || RADIO_URL="spinel+hdlc+uart:///dev/ttyUSB0"
+[ -n "$TREL_URL" ] || TREL_URL=""
[ -n "$TUN_INTERFACE_NAME" ] || TUN_INTERFACE_NAME="wpan0"
[ -n "$BACKBONE_INTERFACE" ] || BACKBONE_INTERFACE="eth0"
-[ -n "$AUTO_PREFIX_ROUTE" ] || AUTO_PREFIX_ROUTE=true
-[ -n "$AUTO_PREFIX_SLAAC" ] || AUTO_PREFIX_SLAAC=true
[ -n "$NAT64_PREFIX" ] || NAT64_PREFIX="64:ff9b::/96"
echo "RADIO_URL:" $RADIO_URL
+echo "TREL_URL:" $TREL_URL
echo "TUN_INTERFACE_NAME:" $TUN_INTERFACE_NAME
echo "BACKBONE_INTERFACE: $BACKBONE_INTERFACE"
echo "NAT64_PREFIX:" $NAT64_PREFIX
-echo "AUTO_PREFIX_ROUTE:" $AUTO_PREFIX_ROUTE
-echo "AUTO_PREFIX_SLAAC:" $AUTO_PREFIX_SLAAC
NAT64_PREFIX=${NAT64_PREFIX/\//\\\/}
+TAYGA_CONF=/etc/tayga.conf
+BIND_CONF_OPTIONS=/etc/bind/named.conf.options
-sed -i "s/^prefix.*$/prefix $NAT64_PREFIX/" /etc/tayga.conf
-sed -i "s/dns64.*$/dns64 $NAT64_PREFIX {};/" /etc/bind/named.conf.options
+! test -f $TAYGA_CONF || sed -i "s/^prefix.*$/prefix $NAT64_PREFIX/" $TAYGA_CONF
+! test -f $BIND_CONF_OPTIONS || sed -i "s/dns64.*$/dns64 $NAT64_PREFIX {};/" $BIND_CONF_OPTIONS
sed -i "s/$INFRA_IF_NAME/$BACKBONE_INTERFACE/" /etc/sysctl.d/60-otbr-accept-ra.conf
-echo "OTBR_AGENT_OPTS=\"-I $TUN_INTERFACE_NAME -B $BACKBONE_INTERFACE -d7 $RADIO_URL\"" >/etc/default/otbr-agent
+echo "OTBR_AGENT_OPTS=\"-I $TUN_INTERFACE_NAME -B $BACKBONE_INTERFACE -d7 $RADIO_URL $TREL_URL\"" >/etc/default/otbr-agent
echo "OTBR_WEB_OPTS=\"-I $TUN_INTERFACE_NAME -d7 -p 80\"" >/etc/default/otbr-web
/app/script/server
diff --git a/etc/openwrt/openthread-br/Makefile b/etc/openwrt/openthread-br/Makefile
index 158b5b76..eb724bdf 100644
--- a/etc/openwrt/openthread-br/Makefile
+++ b/etc/openwrt/openthread-br/Makefile
@@ -43,6 +43,7 @@ CMAKE_SOURCE_DIR=$(LOCAL_SOURCE_DIR)
CMAKE_OPTIONS+= \
-DBUILD_TESTING=OFF \
-DCMAKE_INSTALL_PREFIX=/usr \
+ -DOTBR_BORDER_AGENT=OFF \
-DOTBR_MDNS=OFF \
-DOT_READLINE=OFF \
-DOTBR_OPENWRT=ON
diff --git a/etc/yocto/otbr_git.bb b/etc/yocto/otbr_git.bb
new file mode 100644
index 00000000..a36f54ac
--- /dev/null
+++ b/etc/yocto/otbr_git.bb
@@ -0,0 +1,64 @@
+#
+# Copyright (c) 2021, The OpenThread Authors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the copyright holder nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# Sample Yocto recipe to build OTBR
+
+DESCRIPTION = "OpenThread Border Router Agent"
+HOMEPAGE = "https://github.com/openthread/ot-br-posix"
+
+LICENSE = "BSD-3-Clause"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=87109e44b2fda96a8991f27684a7349c"
+
+SRC_URI = "gitsm://git@github.com/openthread/ot-br-posix.git;branch=main;protocol=ssh"
+
+ICECC_DISABLED = "1"
+
+S = "${WORKDIR}/git"
+SRCREV = "${AUTOREV}"
+PV_append = "+${SRCPV}"
+
+DEPENDS += "avahi boost dbus iproute2 jsoncpp ncurses"
+
+inherit autotools cmake
+
+EXTRA_OECMAKE += " \
+ -GNinja \
+ -Werror=n \
+ -DBUILD_TESTING=OFF \
+ -DCMAKE_BUILD_TYPE="Release" \
+ -DOTBR_BACKBONE_ROUTER=OFF \
+ -DOTBR_BORDER_ROUTING=ON \
+ -DOTBR_COVERAGE=OFF \
+ -DOTBR_MDNS=avahi \
+ -DOTBR_SRP_ADVERTISING_PROXY=ON \
+ -DOTBR_VENDOR_NAME="OpenThread" \
+ -DOTBR_PRODUCT_NAME="Border Router" \
+ -DOTBR_MESHCOP_SERVICE_INSTANCE_NAME="OpenThread Border Router" \
+ -DOT_DUA=OFF \
+ -DOT_POSIX_SETTINGS_PATH='"/tmp/"' \
+ -DOT_MLR=OFF \
+"
diff --git a/examples/platforms/beagleboneblack/default b/examples/platforms/beagleboneblack/default
index e92e238e..0f32d414 100644
--- a/examples/platforms/beagleboneblack/default
+++ b/examples/platforms/beagleboneblack/default
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2017, The OpenThread Authors.
+# Copyright (c) 2017-2021, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -28,17 +28,11 @@
#
# shellcheck disable=SC2034
-SUDO_EXTEND_TIME=false
-
-SWAP_REQUIRED=false
-
NAT64=1
-DNS64=1
+DNS64=0
DHCPV6_PD=0
-NETWORK_MANAGER=1
-# disabled unless specifically added for the device
-NETWORK_MANAGER_WIFI=0
-BACKBONE_ROUTER=0
-BORDER_ROUTING=0
+NETWORK_MANAGER=0
+BACKBONE_ROUTER=1
+BORDER_ROUTING=1
WEB_GUI=1
REST_API=1
diff --git a/examples/platforms/nxp/linux-imx/aarch64.cmake b/examples/platforms/nxp/linux-imx/aarch64.cmake
index be0264fb..7d2e23f9 100644
--- a/examples/platforms/nxp/linux-imx/aarch64.cmake
+++ b/examples/platforms/nxp/linux-imx/aarch64.cmake
@@ -39,7 +39,7 @@ set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Additional CFLAGS for release
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Additional CXXFLAGS for release")
set(CMAKE_ASM_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Additional ASM FLAGS for release")
set(CMAKE_C_LINK_FLAGS " -mcpu=cortex-a53 -march=armv8-a+crc+crypto -fstack-protector-strong -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=$ENV{SDKTARGETSYSROOT} -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -Wl,-z,relro,-z,now" CACHE STRING "LDFLAGS")
-set(CMAKE_CXX_LINK_FLAGS " -mcpu=cortex-a53 -march=armv8-a+crc+crypto -fstack-protector-strong -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=$ENV{SDKTARGETSYSROOT} -O2 -pipe -g -feliminate-unused-debug-types -Wno-error -fvisibility-inlines-hidden -mcpu=cortex-a53 -march=armv8-a+crc+crypto -fstack-protector-strong -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -Wl,-z,relro,-z,now" CACHE STRING "LDFLAGS")
+set(CMAKE_CXX_LINK_FLAGS " -mcpu=cortex-a53 -march=armv8-a+crc+crypto -fstack-protector-strong -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=$ENV{SDKTARGETSYSROOT} -O2 -pipe -g -feliminate-unused-debug-types -Wno-error -fvisibility-inlines-hidden -mcpu=cortex-a53 -march=armv8-a+crc+crypto -fstack-protector-strong -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -Wl,-z,relro,-z,now -L$ENV{SDKTARGETSYSROOT}/usr/lib" CACHE STRING "LDFLAGS")
set(CMAKE_FIND_ROOT_PATH $ENV{OECORE_NATIVE_SYSROOT} $ENV{SDKTARGETSYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
@@ -52,3 +52,4 @@ list(APPEND CMAKE_MODULE_PATH "$ENV{SDKTARGETSYSROOT}/usr/share/cmake/Modules/")
set(CMAKE_LIBRARY_PATH /usr/lib /lib)
list(APPEND CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES /usr/include)
list(APPEND CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES /usr/include)
+set(READLINE "$ENV{SDKTARGETSYSROOT}/usr/lib/libreadline.so")
diff --git a/examples/platforms/nxp/linux-imx/arm.cmake b/examples/platforms/nxp/linux-imx/arm.cmake
new file mode 100644
index 00000000..b7f5f4c2
--- /dev/null
+++ b/examples/platforms/nxp/linux-imx/arm.cmake
@@ -0,0 +1,56 @@
+# Copyright (c) 2022, The OpenThread Authors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the copyright holder nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR arm)
+set(CMAKE_C_COMPILER arm-poky-linux-gnueabi-gcc)
+set(CMAKE_CXX_COMPILER arm-poky-linux-gnueabi-g++)
+set(CMAKE_C_COMPILER_LAUNCHER)
+set(CMAKE_CXX_COMPILER_LAUNCHER)
+set(CMAKE_ASM_COMPILER arm-poky-linux-gnueabi-gcc)
+find_program(CMAKE_AR arm-poky-linux-gnueabi-gcc-ar DOC "Archiver" REQUIRED)
+set(CMAKE_C_FLAGS " -mthumb -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7 -fstack-protector-strong -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=$ENV{SDKTARGETSYSROOT} -O2 -pipe -g -feliminate-unused-debug-types " CACHE STRING "CFLAGS")
+set(CMAKE_CXX_FLAGS " -mthumb -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7 -fstack-protector-strong --sysroot=$ENV{SDKTARGETSYSROOT} -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security -fvisibility-inlines-hidden" CACHE STRING "CXXFLAGS")
+set(CMAKE_ASM_FLAGS " -mthumb -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7 -fstack-protector-strong --sysroot=$ENV{SDKTARGETSYSROOT} -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security " CACHE STRING "ASM FLAGS")
+set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Additional CFLAGS for release")
+set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Additional CXXFLAGS for release")
+set(CMAKE_ASM_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Additional ASM FLAGS for release")
+set(CMAKE_C_LINK_FLAGS " -mthumb -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7 -fstack-protector-strong --sysroot=$ENV{SDKTARGETSYSROOT} -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security -Wl,-z,relro,-z,now" CACHE STRING "LDFLAGS")
+set(CMAKE_CXX_LINK_FLAGS " -mthumb -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7 -fstack-protector-strong --sysroot=$ENV{SDKTARGETSYSROOT} -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security -fvisibility-inlines-hidden -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -Wl,-z,relro,-z,now -L$ENV{SDKTARGETSYSROOT}/usr/lib " CACHE STRING "LDFLAGS")
+set(CMAKE_FIND_ROOT_PATH $ENV{OECORE_NATIVE_SYSROOT} $ENV{SDKTARGETSYSROOT})
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_PROGRAM_PATH "/")
+set(CMAKE_INSTALL_RPATH)
+set(CMAKE_BUILD_RPATH_USE_ORIGIN ON)
+list(APPEND CMAKE_MODULE_PATH "$ENV{SDKTARGETSYSROOT}/usr/share/cmake/Modules/")
+set(CMAKE_LIBRARY_PATH /usr/lib /lib)
+list(APPEND CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES /usr/include)
+list(APPEND CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES /usr/include)
+set(READLINE "$ENV{SDKTARGETSYSROOT}/usr/lib/libreadline.so")
diff --git a/examples/platforms/raspbian/default b/examples/platforms/raspbian/default
index 29df9cfa..f5bb3f07 100644
--- a/examples/platforms/raspbian/default
+++ b/examples/platforms/raspbian/default
@@ -29,7 +29,7 @@
# shellcheck disable=SC2034
NAT64=1
-DNS64=1
+DNS64=0
DHCPV6_PD=0
NETWORK_MANAGER=0
BACKBONE_ROUTER=1
diff --git a/examples/platforms/ubuntu/default b/examples/platforms/ubuntu/default
index 29df9cfa..f5bb3f07 100644
--- a/examples/platforms/ubuntu/default
+++ b/examples/platforms/ubuntu/default
@@ -29,7 +29,7 @@
# shellcheck disable=SC2034
NAT64=1
-DNS64=1
+DNS64=0
DHCPV6_PD=0
NETWORK_MANAGER=0
BACKBONE_ROUTER=1
diff --git a/script/_dhcpv6_pd b/script/_dhcpv6_pd
index 95e9ae2f..b2e9e920 100644
--- a/script/_dhcpv6_pd
+++ b/script/_dhcpv6_pd
@@ -160,6 +160,8 @@ create_ncp_state_notifier_script()
# This script notifies about NCP state changes.
#
+set -euxo pipefail
+
PID=\$\$
NAME="ncp_state_notifier"
diff --git a/script/_disable_services b/script/_disable_services
index 4e598f48..130c70e7 100644
--- a/script/_disable_services
+++ b/script/_disable_services
@@ -36,9 +36,13 @@ bbb_disable_services()
SERVICE_LIST=""
SERVICE_LIST="${SERVICE_LIST} apache2 " # Debian jessie
SERVICE_LIST="${SERVICE_LIST} nginx " # Debian stretch
+ SERVICE_LIST="${SERVICE_LIST} bonescript-autorun.service"
SERVICE_LIST="${SERVICE_LIST} bonescript.socket"
SERVICE_LIST="${SERVICE_LIST} bonescript.service"
- SERVICE_LIST="${SERVICE_LIST} bonescript-autorun.service"
+ SERVICE_LIST="${SERVICE_LIST} cloud9.socket"
+ SERVICE_LIST="${SERVICE_LIST} cloud9.service"
+ SERVICE_LIST="${SERVICE_LIST} nodered.service"
+ SERVICE_LIST="${SERVICE_LIST} dnsmasq.service" # Disable well before bind9
for service in $SERVICE_LIST; do
if [ "$(sudo systemctl is-active "$service")" != "inactive" ]; then
@@ -47,6 +51,13 @@ bbb_disable_services()
done
fi
done
+
+ # stop avahi from advertising for cloud9 and nodered
+ sudo rm -rf /etc/avahi/services
+ # default dnsmasq configuration for connman tether conflicts with bind9
+ # removing the directory stops the startup script from creating
+ # /etc/dnsmasq.d/SoftAp0
+ sudo rm -rf /etc/dnsmasq.d
}
disable_services()
diff --git a/script/_firewall b/script/_firewall
new file mode 100755
index 00000000..0a29c369
--- /dev/null
+++ b/script/_firewall
@@ -0,0 +1,73 @@
+#!/bin/bash
+#
+# Copyright (c) 2021, The OpenThread Authors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the copyright holder nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+FIREWALL_SERVICE=/etc/init.d/otbr-firewall
+
+sudo modprobe ip6table_filter || true
+
+firewall_uninstall()
+{
+ firewall_stop
+ if have systemctl; then
+ sudo systemctl disable otbr-firewall || true
+ fi
+ # systemctl disable doesn't remove sym-links
+ if have update-rc.d; then
+ sudo update-rc.d otbr-firewall remove || true
+ fi
+ test ! -f $FIREWALL_SERVICE || sudo rm $FIREWALL_SERVICE
+}
+
+firewall_install()
+{
+ sudo cp script/otbr-firewall $FIREWALL_SERVICE
+ sudo chmod a+x $FIREWALL_SERVICE
+ if have systemctl; then
+ sudo systemctl enable otbr-firewall || die 'Failed to enable firewall service!'
+ sudo systemctl start otbr-firewall || die 'Failed to start firewall service!'
+ fi
+}
+
+firewall_start()
+{
+ if with DOCKER; then
+ service otbr-firewall start || die 'Failed to start firewall service'
+ elif have systemctl; then
+ sudo systemctl start otbr-firewall || die 'Failed to start firewall service'
+ fi
+}
+
+firewall_stop()
+{
+ if with DOCKER; then
+ service otbr-firewall stop || true
+ elif have systemctl; then
+ sudo systemctl stop otbr-firewall || true
+ fi
+}
diff --git a/script/_nat64 b/script/_nat64
index a1db0dc1..c8efe1a6 100644
--- a/script/_nat64
+++ b/script/_nat64
@@ -30,29 +30,79 @@
# This script manipulates nat64 configuration.
#
+NAT64_SERVICE="${NAT64_SERVICE:-tayga}"
TAYGA_DEFAULT=/etc/default/tayga
TAYGA_CONF=/etc/tayga.conf
TAYGA_IPV4_ADDR=192.168.255.1
TAYGA_IPV6_ADDR=fdaa:bb:1::1
TAYGA_TUN_V6_ADDR=fdaa:bb:1::2
+NAT64_PREFIX=64:ff9b::/96
+DYNAMIC_POOL="${NAT64_DYNAMIC_POOL:-192.168.255.0/24}"
NAT44_SERVICE=/etc/init.d/otbr-nat44
-WLAN_IFNAMES=eth0
+WLAN_IFNAMES="${INFRA_IF_NAME:-eth0}"
# Currently solution was verified only on raspbian and ubuntu.
#
#without NAT64 || test $PLATFORM = ubuntu || test $PLATFORM = raspbian || die "nat64 is not tested under $PLATFORM."
-nat64_install()
+tayga_install()
{
- with NAT64 || return 0
-
test -f $TAYGA_DEFAULT -a -f $TAYGA_CONF || die 'Cannot find tayga configuration file!'
sudo sed -i 's/^RUN="no"/RUN="yes"/' $TAYGA_DEFAULT
sudo sed -i 's/^IPV4_TUN_ADDR=""/IPV4_TUN_ADDR="'$TAYGA_IPV4_ADDR'"/' $TAYGA_DEFAULT
sudo sed -i 's/^IPV6_TUN_ADDR=""/IPV6_TUN_ADDR="'$TAYGA_TUN_V6_ADDR'"/' $TAYGA_DEFAULT
sudo sed -i 's/^prefix /##prefix /' $TAYGA_CONF
- sudo sed -i 's/^# prefix 64:ff9b::\/96/prefix 64:ff9b::\/96/' $TAYGA_CONF
+ sudo sed -i '/^##prefix /a prefix '$NAT64_PREFIX $TAYGA_CONF
sudo sed -i '/^#ipv6-addr/a ipv6-addr '$TAYGA_IPV6_ADDR $TAYGA_CONF
+ sudo sed -i 's/^dynamic-pool /##dynamic-pool /' $TAYGA_CONF
+ sudo sed -i '/^##dynamic-pool /a dynamic-pool '"$DYNAMIC_POOL" $TAYGA_CONF
+
+ if have systemctl; then
+ sudo systemctl restart tayga || die 'Unable to restart taga service!'
+ sudo systemctl enable tayga || die 'Unable to enable taga service!'
+ fi
+}
+
+tayga_uninstall()
+{
+ sudo sed -i 's/^RUN="yes"/RUN="no"/' $TAYGA_DEFAULT
+ sudo sed -i 's/^IPV4_TUN_ADDR="'$TAYGA_IPV4_ADDR'"/IPV4_TUN_ADDR=""/' $TAYGA_DEFAULT
+ sudo sed -i '/^prefix /d' $TAYGA_CONF
+ if grep "##prefix " $TAYGA_CONF; then
+ sudo sed -i 's/^##prefix /prefix /' $TAYGA_CONF
+ else
+ sudo sed -i 's/^# prefix /prefix /' $TAYGA_CONF
+ fi
+ sudo sed -i '/^ipv6-addr '$TAYGA_IPV6_ADDR'/d' $TAYGA_CONF
+ if grep "##dynamic-pool " $TAYGA_CONF; then
+ sudo sed -i '/^dynamic-pool /d' $TAYGA_CONF
+ sudo sed -i 's/^##dynamic-pool /dynamic-pool /' $TAYGA_CONF
+ fi
+}
+
+tayga_start()
+{
+ if with DOCKER; then
+ service tayga start || die 'Failed to start tayga'
+ elif have systemctl; then
+ sudo systemctl start tayga || die 'Failed to start tayga!'
+ sudo systemctl enable tayga || die 'Failed to enable tayga!'
+ fi
+}
+
+tayga_stop()
+{
+ if with DOCKER; then
+ service tayga stop || true
+ elif have systemctl; then
+ sudo systemctl stop tayga || true
+ fi
+}
+
+# Although Tayga also configures a NAT44 iptables route, this NAT44 service is used with Tayga
+# due to some history reason. It might be removed when native NAT64 service is ready.
+nat44_install()
+{
sudo tee $NAT44_SERVICE <<EOF
#! /bin/sh
#
@@ -121,23 +171,12 @@ esac
EOF
sudo chmod a+x $NAT44_SERVICE
if have systemctl; then
- sudo systemctl restart tayga || die 'Unable to restart taga service!'
- sudo systemctl enable tayga || die 'Unable to enable taga service!'
sudo systemctl enable otbr-nat44 || die 'Unable to enable nat44 service!'
fi
}
-nat64_uninstall()
+nat44_uninstall()
{
- with NAT64 || return 0
-
- nat64_stop
- sudo sed -i 's/^RUN="yes"/RUN="no"/' $TAYGA_DEFAULT
- sudo sed -i 's/^IPV4_TUN_ADDR="'$TAYGA_IPV4_ADDR'"/IPV4_TUN_ADDR=""/' $TAYGA_DEFAULT
- sudo sed -i 's/^prefix 64:ff9b::\/96/# prefix 64:ff9b::\/96/' $TAYGA_CONF
- sudo sed -i 's/^##prefix /prefix /' $TAYGA_CONF
- sudo sed -i '/^ipv6-addr '$TAYGA_IPV6_ADDR'/d' $TAYGA_CONF
-
if have systemctl; then
sudo systemctl disable otbr-nat44 || true
fi
@@ -149,27 +188,64 @@ nat64_uninstall()
test ! -f $NAT44_SERVICE || sudo rm $NAT44_SERVICE
}
+nat44_start()
+{
+ if [ "$NAT64_SERVICE" = tayga ] && have systemctl; then
+ sudo systemctl start otbr-nat44 || die 'Failed to start NAT44!'
+ else
+ sudo iptables -t nat -A POSTROUTING -s "$DYNAMIC_POOL" -j MASQUERADE || die 'Failed to start NAT44!'
+ fi
+}
+
+nat44_stop()
+{
+ if [ "$NAT64_SERVICE" = tayga ] && have systemctl; then
+ sudo systemctl stop otbr-nat44 || true
+ else
+ sudo iptables -t nat -D POSTROUTING -s "$DYNAMIC_POOL" -j MASQUERADE || true
+ fi
+}
+
+nat64_install()
+{
+ with NAT64 || return 0
+
+ if [ "$NAT64_SERVICE" = tayga ]; then
+ tayga_install
+ nat44_install
+ fi
+}
+
+nat64_uninstall()
+{
+ with NAT64 || return 0
+
+ nat64_stop
+
+ if [ "$NAT64_SERVICE" = tayga ]; then
+ tayga_uninstall
+ nat44_uninstall
+ fi
+}
+
nat64_start()
{
with NAT64 || return 0
- if with DOCKER; then
- service tayga start || die 'Failed to start tayga'
- elif have systemctl; then
- sudo systemctl start tayga || die 'Failed to start tayga!'
- sudo systemctl enable tayga || die 'Failed to enable tayga!'
- sudo systemctl start otbr-nat44 || die 'Failed to start NAT44!'
+ if [ "$NAT64_SERVICE" = tayga ]; then
+ tayga_start
fi
+
+ nat44_start
}
nat64_stop()
{
with NAT64 || return 0
- if with DOCKER; then
- service tayga stop || true
- elif have systemctl; then
- sudo systemctl stop tayga || true
- sudo systemctl stop otbr-nat44 || true
+ if [ "$NAT64_SERVICE" = tayga ]; then
+ tayga_stop
fi
+
+ nat44_stop
}
diff --git a/script/_network_manager b/script/_network_manager
index 6dff8973..1bbdc5b9 100644
--- a/script/_network_manager
+++ b/script/_network_manager
@@ -84,6 +84,8 @@ create_ap_helper_script()
# POSSIBILITY OF SUCH DAMAGE.
#
+set -euxo pipefail
+
NAME="ap-helper"
IFNAME=\$1
@@ -216,6 +218,8 @@ create_dhcpv6_helper_script()
# This script manipulates DHCPv6-PD configuration.
#
+set -euxo pipefail
+
NAME="dhcpv6-helper"
IFNAME=\$1
diff --git a/script/_otbr b/script/_otbr
index 536b19a1..0def833a 100644
--- a/script/_otbr
+++ b/script/_otbr
@@ -91,10 +91,16 @@ otbr_install()
otbr_options+=(
"-DOTBR_BACKBONE_ROUTER=ON"
)
+ if [[ ${REFERENCE_DEVICE} == "1" ]]; then
+ otbr_options+=(
+ "-DOTBR_DUA_ROUTING=ON"
+ )
+ fi
fi
if [[ ${REFERENCE_DEVICE} == "1" ]]; then
otbr_options+=(
+ "-DOTBR_NO_AUTO_ATTACH=1"
"-DOT_REFERENCE_DEVICE=ON"
"-DOT_DHCP6_CLIENT=ON"
"-DOT_DHCP6_SERVER=ON"
diff --git a/script/bootstrap b/script/bootstrap
index c2beb230..51e120a5 100755
--- a/script/bootstrap
+++ b/script/bootstrap
@@ -33,6 +33,8 @@
# shellcheck source=script/_initrc
. "$(dirname "$0")"/_initrc
+NAT64_SERVICE="${NAT64_SERVICE:-tayga}"
+
install_packages_apt()
{
sudo apt-get update
@@ -54,21 +56,32 @@ install_packages_apt()
# mDNS
sudo apt-get install --no-install-recommends -y libavahi-client3 libavahi-common-dev libavahi-client-dev avahi-daemon
- (MDNS_RESPONDER_SOURCE_NAME=mDNSResponder-878.30.4 \
+ (MDNS_RESPONDER_SOURCE_NAME=mDNSResponder-1310.80.1 \
&& cd /tmp \
&& wget -4 --no-check-certificate https://opensource.apple.com/tarballs/mDNSResponder/$MDNS_RESPONDER_SOURCE_NAME.tar.gz \
&& tar xvf $MDNS_RESPONDER_SOURCE_NAME.tar.gz \
- && cd $MDNS_RESPONDER_SOURCE_NAME/mDNSPosix \
+ && cd /tmp/$MDNS_RESPONDER_SOURCE_NAME/Clients \
+ && sed -i '/#include <ctype.h>/a #include <stdarg.h>' dns-sd.c \
+ && sed -i '/#include <ctype.h>/a #include <sys/param.h>' dns-sd.c \
+ && cd /tmp/$MDNS_RESPONDER_SOURCE_NAME/mDNSPosix \
&& make os=linux && sudo make install os=linux)
# Boost
sudo apt-get install --no-install-recommends -y libboost-dev libboost-filesystem-dev libboost-system-dev
# nat64
- without NAT64 || sudo apt-get install --no-install-recommends -y tayga iptables
+ without NAT64 || {
+ "$NAT64_SERVICE" != "tayga" || sudo apt-get install --no-install-recommends -y tayga
+ sudo apt-get install --no-install-recommends -y iptables
+ }
# dns64
without DNS64 || {
+ if [ "$PLATFORM" = "beagleboneblack" ]; then
+ # dnsmasq needs to be stopped before bind9 is installed
+ sudo systemctl disable dnsmasq
+ sudo systemctl stop dnsmasq
+ fi
sudo apt-get install --no-install-recommends -y bind9
# Resolvconf cannot be installed inside docker environment
if without DOCKER; then
@@ -89,10 +102,13 @@ install_packages_apt()
without REFERENCE_DEVICE || sudo apt-get install --no-install-recommends -y radvd dnsutils
# backbone-router
- without BACKBONE_ROUTER || sudo apt-get install --no-install-recommends -y iptables libnetfilter-queue1 libnetfilter-queue-dev
+ without BACKBONE_ROUTER || sudo apt-get install --no-install-recommends -y libnetfilter-queue1 libnetfilter-queue-dev
# web dependencies
- without WEB_GUI || command -v npm || sudo apt-get install -y nodejs npm
+ without WEB_GUI || command -v npm || sudo apt-get install --no-install-recommends -y nodejs npm
+
+ # firewall
+ sudo apt-get install -y iptables ipset
}
install_packages_opkg()
@@ -111,9 +127,9 @@ install_packages_rpm()
with RELEASE || sudo $PM install -y cmake ninja-build
sudo $PM install -y dbus-devel
sudo $PM install -y avahi avahi-devel
- sudo $PM install -y doxygen
sudo $PM install -y boost-devel boost-filesystem boost-system
- sudo $PM install -y tayga iptables
+ "$NAT64_SERVICE" != "tayga" || sudo $PM install -y tayga
+ sudo $PM install -y iptables
sudo $PM install -y jsoncpp-devel
sudo $PM install -y wget
}
diff --git a/script/console b/script/console
index 912c1637..47e08911 100755
--- a/script/console
+++ b/script/console
@@ -49,11 +49,13 @@ killall_services()
on_exit()
{
killall_services
+ # shellcheck source=/dev/null
. "$AFTER_HOOK"
}
main()
{
+ # shellcheck source=/dev/null
. "$BEFORE_HOOK"
if have systemctl; then
sudo systemctl stop otbr-web otbr-agent || true
diff --git a/script/otbr-firewall b/script/otbr-firewall
new file mode 100644
index 00000000..52cef42d
--- /dev/null
+++ b/script/otbr-firewall
@@ -0,0 +1,109 @@
+#!/bin/bash
+#
+# Copyright (c) 2021, The OpenThread Authors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the copyright holder nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+### BEGIN INIT INFO
+# Provides: otbr-firewall
+# Required-Start:
+# Required-Stop:
+# Should-Start:
+# Should-Stop:
+# Default-Start: 2 3 4 5
+# Default-Stop:
+# Short-Description: OTBR firewall
+# Description: This service sets up firewall for OTBR.
+### END INIT INFO
+
+THREAD_IF="wpan0"
+OTBR_FORWARD_INGRESS_CHAIN="OTBR_FORWARD_INGRESS"
+
+. /lib/lsb/init-functions
+. /lib/init/vars.sh
+
+set -euxo pipefail
+
+ipset_destroy_if_exist()
+{
+ if ipset list "$1"; then
+ ipset destroy "$1"
+ fi
+}
+
+firewall_start()
+{
+ firewall_stop
+ ipset create -exist otbr-ingress-deny-src hash:net family inet6
+ ipset create -exist otbr-ingress-deny-src-swap hash:net family inet6
+ ipset create -exist otbr-ingress-allow-dst hash:net family inet6
+ ipset create -exist otbr-ingress-allow-dst-swap hash:net family inet6
+
+ ip6tables -N $OTBR_FORWARD_INGRESS_CHAIN
+ ip6tables -I FORWARD 1 -o $THREAD_IF -j $OTBR_FORWARD_INGRESS_CHAIN
+
+ ip6tables -A $OTBR_FORWARD_INGRESS_CHAIN -m pkttype --pkt-type unicast -i $THREAD_IF -j DROP
+ ip6tables -A $OTBR_FORWARD_INGRESS_CHAIN -m set --match-set otbr-ingress-deny-src src -j DROP
+ ip6tables -A $OTBR_FORWARD_INGRESS_CHAIN -m set --match-set otbr-ingress-allow-dst dst -j ACCEPT
+ ip6tables -A $OTBR_FORWARD_INGRESS_CHAIN -m pkttype --pkt-type unicast -j DROP
+ ip6tables -A $OTBR_FORWARD_INGRESS_CHAIN -j ACCEPT
+}
+
+firewall_stop()
+{
+ while ip6tables -C FORWARD -o $THREAD_IF -j $OTBR_FORWARD_INGRESS_CHAIN; do
+ ip6tables -D FORWARD -o $THREAD_IF -j $OTBR_FORWARD_INGRESS_CHAIN
+ done
+
+ if ip6tables -L $OTBR_FORWARD_INGRESS_CHAIN; then
+ ip6tables -w -F $OTBR_FORWARD_INGRESS_CHAIN
+ ip6tables -w -X $OTBR_FORWARD_INGRESS_CHAIN
+ fi
+
+ ipset_destroy_if_exist otbr-ingress-deny-src
+ ipset_destroy_if_exist otbr-ingress-deny-src-swap
+ ipset_destroy_if_exist otbr-ingress-allow-dst
+ ipset_destroy_if_exist otbr-ingress-allow-dst-swap
+}
+
+case "$1" in
+ start)
+ firewall_start
+ ;;
+ restart | reload | force-reload)
+ echo "Error: argument '$1' not supported" >&2
+ exit 3
+ ;;
+ stop)
+ firewall_stop
+ ;;
+ status)
+ # No-op
+ ;;
+ *)
+ echo "Usage: $0 start|stop" >&2
+ exit 3
+ ;;
+esac
diff --git a/script/server b/script/server
index 6efe6364..ce7a9817 100755
--- a/script/server
+++ b/script/server
@@ -34,13 +34,16 @@
. "$(dirname "$0")"/_initrc
. script/_nat64
. script/_dns64
+. script/_firewall
main()
{
+ # shellcheck source=/dev/null
. "$BEFORE_HOOK"
sudo sysctl --system
nat64_start || die 'Failed to start NAT64!'
dns64_start || die 'Failed to start DNS64!'
+ firewall_start || die 'Failed to start firewall'
if have systemctl; then
systemctl is-active rsyslog || sudo systemctl start rsyslog || die 'Failed to start rsyslog!'
systemctl is-active dbus || sudo systemctl start dbus || die 'Failed to start dbus!'
@@ -58,6 +61,7 @@ main()
else
die 'Unable to find service manager. Try script/console to start in console mode!'
fi
+ # shellcheck source=/dev/null
. "$AFTER_HOOK"
}
diff --git a/script/setup b/script/setup
index 6c61f63f..8262be89 100755
--- a/script/setup
+++ b/script/setup
@@ -43,9 +43,11 @@
. script/_swapfile
. script/_sudo_extend
. script/_disable_services
+. script/_firewall
main()
{
+ # shellcheck source=/dev/null
. "$BEFORE_HOOK"
extend_sudo_timeout
setup_swapfile
@@ -58,7 +60,9 @@ main()
dns64_uninstall
rt_tables_uninstall
ipforward_uninstall
+ firewall_uninstall
+ firewall_install
ipforward_install
rt_tables_install
nat64_install
@@ -67,6 +71,7 @@ main()
dhcpv6_pd_install
border_routing_install
otbr_install
+ # shellcheck source=/dev/null
. "$AFTER_HOOK"
}
diff --git a/script/test b/script/test
index 4c89b9ac..5a7b9113 100755
--- a/script/test
+++ b/script/test
@@ -38,6 +38,7 @@ readonly OTBR_COLOR_FAIL='\033[0;31m'
readonly OTBR_COLOR_NONE='\033[0m'
readonly QUIET=${QUIET:-1}
+readonly OTBR_BUILD_TYPE="${OTBR_BUILD_TYPE:-Debug}"
readonly OTBR_COVERAGE="${OTBR_COVERAGE:-0}"
readonly OTBR_MDNS="${OTBR_MDNS:-}"
readonly OTBR_REST="${OTBR_REST:-}"
@@ -105,11 +106,13 @@ EOF
do_build()
{
otbr_options=(
- "-DCMAKE_BUILD_TYPE=Debug"
+ "-DCMAKE_BUILD_TYPE=${OTBR_BUILD_TYPE}"
"-DCMAKE_INSTALL_PREFIX=/usr"
+ "-DOT_THREAD_VERSION=1.3"
"-DOTBR_DBUS=ON"
"-DOTBR_WEB=ON"
"-DOTBR_UNSECURE_JOIN=ON"
+ "-DOTBR_TREL=ON"
${otbr_options[@]+"${otbr_options[@]}"}
)
@@ -125,6 +128,7 @@ do_clean()
do_check()
{
(cd "${OTBR_TOP_BUILDDIR}" \
+ && sudo ninja install \
&& CTEST_OUTPUT_ON_FAILURE=1 ninja test)
}
@@ -173,6 +177,14 @@ do_package()
OTBR_TARGET="package" ./script/cmake-build "${otbr_options[@]}"
}
+do_simulation()
+{
+ export top_builddir="${OTBR_TOP_BUILDDIR}"
+
+ print_result tests/scripts/auto-attach
+ print_result tests/scripts/infra-link-selector
+}
+
main()
{
if [[ $# == 0 ]]; then
@@ -201,11 +213,12 @@ main()
meshcop)
top_builddir="${OTBR_TOP_BUILDDIR}" print_result ./tests/scripts/meshcop
;;
-
openwrt)
print_result ./tests/scripts/openwrt
;;
-
+ simulation)
+ do_simulation
+ ;;
package)
do_package
;;
diff --git a/script/update b/script/update
index 4c566b45..daa859a4 100755
--- a/script/update
+++ b/script/update
@@ -44,6 +44,7 @@ main()
{
./script/bootstrap
+ # shellcheck source=/dev/null
. "$BEFORE_HOOK"
otbr_uninstall
dhcpv6_pd_uninstall
@@ -58,6 +59,7 @@ main()
dns64_install
dhcpv6_pd_install
otbr_update
+ # shellcheck source=/dev/null
. "$AFTER_HOOK"
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3cf2d45a..26f3b17a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -27,10 +27,13 @@
#
add_subdirectory(agent)
-add_subdirectory(border_agent)
+if(OTBR_BORDER_AGENT)
+ add_subdirectory(border_agent)
+endif()
add_subdirectory(common)
add_subdirectory(ncp)
add_subdirectory(sdp_proxy)
+add_subdirectory(trel_dnssd)
if(OTBR_DBUS)
add_subdirectory(dbus)
diff --git a/src/agent/CMakeLists.txt b/src/agent/CMakeLists.txt
index 097e6737..c16a5e5e 100644
--- a/src/agent/CMakeLists.txt
+++ b/src/agent/CMakeLists.txt
@@ -27,34 +27,35 @@
#
add_executable(otbr-agent
- agent_instance.cpp
- agent_instance.hpp
+ application.cpp
main.cpp
uris.hpp
- instance_params.cpp
- instance_params.hpp
vendor.hpp
)
target_link_libraries(otbr-agent PRIVATE
+ $<$<BOOL:${OTBR_BORDER_AGENT}>:otbr-border-agent>
+ $<$<BOOL:${OTBR_BACKBONE_ROUTER}>:otbr-backbone-router>
$<$<BOOL:${OTBR_DBUS}>:otbr-dbus-server>
$<$<BOOL:${OTBR_MDNS}>:otbr-mdns>
$<$<BOOL:${OTBR_OPENWRT}>:otbr-ubus>
$<$<BOOL:${OTBR_REST}>:otbr-rest>
- $<$<BOOL:${OTBR_BACKBONE_ROUTER}>:otbr-backbone-router>
openthread-posix
openthread-cli-ftd
openthread-ftd
openthread-spinel-rcp
openthread-hdlc
- otbr-border-agent
otbr-sdp-proxy
otbr-ncp
otbr-common
otbr-utils
)
-add_dependencies(otbr-agent ot-ctl print-ot-config otbr-border-agent otbr-sdp-proxy otbr-utils otbr-ncp)
+add_dependencies(otbr-agent ot-ctl print-ot-config otbr-sdp-proxy otbr-utils otbr-ncp)
+if (OTBR_BORDER_AGENT)
+ add_dependencies(otbr-agent otbr-border-agent)
+endif()
+
install(TARGETS otbr-agent DESTINATION sbin)
if(CMAKE_VERSION VERSION_LESS 3.13)
@@ -66,6 +67,14 @@ endif()
set(OTBR_AGENT_USER "root" CACHE STRING "set the username running otbr-agent service")
set(OTBR_AGENT_GROUP "root" CACHE STRING "set the group using otbr-agent client")
+if(OTBR_MDNS STREQUAL "mDNSResponder")
+ set(EXEC_START_PRE "ExecStartPre=service mdns start\n")
+elseif(OTBR_MDNS STREQUAL "avahi")
+ set(EXEC_START_PRE "ExecStartPre=service avahi-daemon start\n")
+else()
+ message(WARNING "OTBR_MDNS=\"${OTBR_MDNS}\" is not supported")
+endif()
+
if(OTBR_DBUS)
configure_file(otbr-agent.conf.in otbr-agent.conf)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/otbr-agent.conf
@@ -84,8 +93,16 @@ elseif(NOT OTBR_OPENWRT)
RENAME otbr-agent)
endif()
+set(OTBR_NO_AUTO_ATTACH "0" CACHE STRING "Set to 1 to disable auto Thread attach")
+
configure_file(otbr-agent.default.in otbr-agent.default)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/otbr-agent.default
DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/default
RENAME otbr-agent
)
+
+pkg_check_modules(LIBSYSTEMD libsystemd)
+if(LIBSYSTEMD_FOUND)
+ target_compile_definitions(otbr-config INTERFACE "HAVE_LIBSYSTEMD=1")
+ target_link_libraries(otbr-agent PUBLIC ${LIBSYSTEMD_LIBRARIES})
+endif()
diff --git a/src/agent/agent_instance.hpp b/src/agent/agent_instance.hpp
deleted file mode 100644
index 8d9b3f2d..00000000
--- a/src/agent/agent_instance.hpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2017, The OpenThread Authors.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @file
- * This file includes definition for Thread border router agent instance.
- */
-
-#ifndef OTBR_AGENT_AGENT_INSTANCE_HPP_
-#define OTBR_AGENT_AGENT_INSTANCE_HPP_
-
-#include "openthread-br/config.h"
-
-#include <stdarg.h>
-#include <stdint.h>
-#include <sys/select.h>
-#include <sys/types.h>
-
-#include "agent/instance_params.hpp"
-#include "border_agent/border_agent.hpp"
-#include "ncp/ncp_openthread.hpp"
-
-namespace otbr {
-
-/**
- * This class implements an instance to host services used by border router.
- *
- */
-class AgentInstance
-{
-public:
- /**
- * The constructor to initialize the Thread border router agent instance.
- *
- * @param[in] aNcp A reference to the NCP controller.
- *
- */
- AgentInstance(Ncp::ControllerOpenThread &aNcp);
-
- /**
- * This method initialize the agent.
- *
- * @retval OTBR_ERROR_NONE Agent initialized successfully.
- * @retval OTBR_ERROR_ERRNO Failed due to error indicated in errno.
- *
- */
- otbrError Init(void);
-
- /**
- * This method returns the NCP controller.
- *
- * @retval the pointer of the NCP controller.
- *
- */
- otbr::Ncp::ControllerOpenThread &GetNcp(void) { return mNcp; }
-
-private:
- otbr::Ncp::ControllerOpenThread &mNcp;
- BorderAgent mBorderAgent;
-};
-
-} // namespace otbr
-
-#endif // OTBR_AGENT_AGENT_INSTANCE_HPP_
diff --git a/src/agent/application.cpp b/src/agent/application.cpp
new file mode 100644
index 00000000..eed641e3
--- /dev/null
+++ b/src/agent/application.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2021, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * The file implements the OTBR Agent.
+ */
+
+#define OTBR_LOG_TAG "APP"
+
+#ifdef HAVE_LIBSYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
+
+#include "agent/application.hpp"
+#include "common/code_utils.hpp"
+#include "common/mainloop_manager.hpp"
+#include "utils/infra_link_selector.hpp"
+
+namespace otbr {
+
+std::atomic_bool Application::sShouldTerminate(false);
+const struct timeval Application::kPollTimeout = {10, 0};
+
+Application::Application(const std::string & aInterfaceName,
+ const std::vector<const char *> &aBackboneInterfaceNames,
+ const std::vector<const char *> &aRadioUrls,
+ bool aEnableAutoAttach)
+ : mInterfaceName(aInterfaceName)
+#if __linux__
+ , mInfraLinkSelector(aBackboneInterfaceNames)
+ , mBackboneInterfaceName(mInfraLinkSelector.Select())
+#else
+ , mBackboneInterfaceName(aBackboneInterfaceNames.empty() ? "" : aBackboneInterfaceNames.front())
+#endif
+ , mNcp(mInterfaceName.c_str(), aRadioUrls, mBackboneInterfaceName, /* aDryRun */ false, aEnableAutoAttach)
+#if OTBR_ENABLE_BORDER_AGENT
+ , mBorderAgent(mNcp)
+#endif
+#if OTBR_ENABLE_BACKBONE_ROUTER
+ , mBackboneAgent(mNcp, aInterfaceName, mBackboneInterfaceName)
+#endif
+#if OTBR_ENABLE_OPENWRT
+ , mUbusAgent(mNcp)
+#endif
+#if OTBR_ENABLE_REST_SERVER
+ , mRestWebServer(mNcp)
+#endif
+#if OTBR_ENABLE_DBUS_SERVER && OTBR_ENABLE_BORDER_AGENT
+ , mDBusAgent(mNcp, mBorderAgent.GetPublisher())
+#endif
+#if OTBR_ENABLE_VENDOR_SERVER
+ , mVendorServer(mNcp)
+#endif
+{
+}
+
+void Application::Init(void)
+{
+ mNcp.Init();
+
+#if OTBR_ENABLE_BORDER_AGENT
+ mBorderAgent.Init();
+#endif
+#if OTBR_ENABLE_BACKBONE_ROUTER
+ mBackboneAgent.Init();
+#endif
+#if OTBR_ENABLE_OPENWRT
+ mUbusAgent.Init();
+#endif
+#if OTBR_ENABLE_REST_SERVER
+ mRestWebServer.Init();
+#endif
+#if OTBR_ENABLE_DBUS_SERVER
+ mDBusAgent.Init();
+#endif
+#if OTBR_ENABLE_VENDOR_SERVER
+ mVendorServer.Init();
+#endif
+}
+
+void Application::Deinit(void)
+{
+#if OTBR_ENABLE_BORDER_AGENT
+ mBorderAgent.Deinit();
+#endif
+
+ mNcp.Deinit();
+}
+
+otbrError Application::Run(void)
+{
+ otbrError error = OTBR_ERROR_NONE;
+
+ otbrLogInfo("Thread Border Router started on AIL %s.", mBackboneInterfaceName);
+
+#ifdef HAVE_LIBSYSTEMD
+ if (getenv("SYSTEMD_EXEC_PID") != nullptr)
+ {
+ otbrLogInfo("Notify systemd the service is ready.");
+
+ // Ignored return value as systemd recommends.
+ // See https://www.freedesktop.org/software/systemd/man/sd_notify.html
+ sd_notify(0, "READY=1");
+ }
+#endif
+
+#if OTBR_ENABLE_NOTIFY_UPSTART
+ if (getenv("UPSTART_JOB") != nullptr)
+ {
+ otbrLogInfo("Notify Upstart the service is ready.");
+ if (raise(SIGSTOP))
+ {
+ otbrLogWarning("Failed to notify Upstart.");
+ }
+ }
+#endif
+
+ // allow quitting elegantly
+ signal(SIGTERM, HandleSignal);
+
+ while (!sShouldTerminate)
+ {
+ otbr::MainloopContext mainloop;
+ int rval;
+
+ mainloop.mMaxFd = -1;
+ mainloop.mTimeout = kPollTimeout;
+
+ FD_ZERO(&mainloop.mReadFdSet);
+ FD_ZERO(&mainloop.mWriteFdSet);
+ FD_ZERO(&mainloop.mErrorFdSet);
+
+ MainloopManager::GetInstance().Update(mainloop);
+
+ rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet,
+ &mainloop.mTimeout);
+
+ if (rval >= 0)
+ {
+ MainloopManager::GetInstance().Process(mainloop);
+
+#if __linux__
+ {
+ const char *newInfraLink = mInfraLinkSelector.Select();
+
+ if (mBackboneInterfaceName != newInfraLink)
+ {
+ error = OTBR_ERROR_INFRA_LINK_CHANGED;
+ break;
+ }
+ }
+#endif
+ }
+ else if (errno != EINTR)
+ {
+ error = OTBR_ERROR_ERRNO;
+ otbrLogErr("select() failed: %s", strerror(errno));
+ break;
+ }
+ }
+
+ return error;
+}
+
+void Application::HandleSignal(int aSignal)
+{
+ sShouldTerminate = true;
+ signal(aSignal, SIG_DFL);
+}
+
+} // namespace otbr
diff --git a/src/agent/application.hpp b/src/agent/application.hpp
new file mode 100644
index 00000000..d12ed154
--- /dev/null
+++ b/src/agent/application.hpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2021, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes definition for OTBR Agent.
+ */
+
+#ifndef OTBR_AGENT_APPLICATION_HPP_
+#define OTBR_AGENT_APPLICATION_HPP_
+
+#include <atomic>
+#include <signal.h>
+#include <stdint.h>
+#include <vector>
+
+#if OTBR_ENABLE_BORDER_AGENT
+#include "border_agent/border_agent.hpp"
+#endif
+#include "ncp/ncp_openthread.hpp"
+#if OTBR_ENABLE_BACKBONE_ROUTER
+#include "backbone_router/backbone_agent.hpp"
+#endif
+#if OTBR_ENABLE_REST_SERVER
+#include "rest/rest_web_server.hpp"
+#endif
+#if OTBR_ENABLE_DBUS_SERVER
+#include "dbus/server/dbus_agent.hpp"
+#endif
+#if OTBR_ENABLE_OPENWRT
+#include "openwrt/ubus/otubus.hpp"
+#endif
+#if OTBR_ENABLE_VENDOR_SERVER
+#include "agent/vendor.hpp"
+#endif
+#include "utils/infra_link_selector.hpp"
+
+namespace otbr {
+
+/**
+ * @addtogroup border-router-agent
+ *
+ * @brief
+ * This module includes definition for OTBR application.
+ *
+ * @{
+ */
+
+/**
+ * This class implements OTBR application management.
+ *
+ */
+class Application : private NonCopyable
+{
+public:
+ /**
+ * This constructor initializes the Application instance.
+ *
+ * @param[in] aInterfaceName Name of the Thread network interface.
+ * @param[in] aBackboneInterfaceName Name of the backbone network interface.
+ * @param[in] aRadioUrls The radio URLs (can be IEEE802.15.4 or TREL radio).
+ * @param[in] aEnableAutoAttach Whether or not to automatically attach to the saved network.
+ *
+ */
+ explicit Application(const std::string & aInterfaceName,
+ const std::vector<const char *> &aBackboneInterfaceNames,
+ const std::vector<const char *> &aRadioUrls,
+ bool aEnableAutoAttach);
+
+ /**
+ * This method initializes the Application instance.
+ *
+ */
+ void Init(void);
+
+ /**
+ * This method de-initializes the Application instance.
+ *
+ */
+ void Deinit(void);
+
+ /**
+ * This method runs the application until exit.
+ *
+ * @retval OTBR_ERROR_NONE The application exited without any error.
+ * @retval OTBR_ERROR_ERRNO The application exited with some system error.
+ *
+ */
+ otbrError Run(void);
+
+private:
+ // Default poll timeout.
+ static const struct timeval kPollTimeout;
+
+ static void HandleSignal(int aSignal);
+
+ std::string mInterfaceName;
+#if __linux__
+ otbr::Utils::InfraLinkSelector mInfraLinkSelector;
+#endif
+ const char * mBackboneInterfaceName;
+ Ncp::ControllerOpenThread mNcp;
+#if OTBR_ENABLE_BORDER_AGENT
+ BorderAgent mBorderAgent;
+#endif
+#if OTBR_ENABLE_BACKBONE_ROUTER
+ BackboneRouter::BackboneAgent mBackboneAgent;
+#endif
+#if OTBR_ENABLE_OPENWRT
+ ubus::UBusAgent mUbusAgent;
+#endif
+#if OTBR_ENABLE_REST_SERVER
+ rest::RestWebServer mRestWebServer;
+#endif
+#if OTBR_ENABLE_DBUS_SERVER
+ DBus::DBusAgent mDBusAgent;
+#endif
+#if OTBR_ENABLE_VENDOR_SERVER
+ vendor::VendorServer mVendorServer;
+#endif
+
+ static std::atomic_bool sShouldTerminate;
+};
+
+/**
+ * @}
+ */
+
+} // namespace otbr
+
+#endif // OTBR_AGENT_APPLICATION_HPP_
diff --git a/src/agent/instance_params.cpp b/src/agent/instance_params.cpp
deleted file mode 100644
index 776193b6..00000000
--- a/src/agent/instance_params.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2020, The OpenThread Authors.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @file
- * The file implements the agent instance parameters.
- */
-
-#include "agent/instance_params.hpp"
-
-namespace otbr {
-
-InstanceParams &InstanceParams::Get(void)
-{
- static InstanceParams sInstanceParams;
-
- return sInstanceParams;
-}
-
-} // namespace otbr
diff --git a/src/agent/instance_params.hpp b/src/agent/instance_params.hpp
deleted file mode 100644
index 107bd61e..00000000
--- a/src/agent/instance_params.hpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2020, The OpenThread Authors.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @file
- * This file includes definition for Thread border router agent instance parameters.
- */
-
-#ifndef OTBR_AGENT_INSATNCE_PARAMS_HPP_
-#define OTBR_AGENT_INSATNCE_PARAMS_HPP_
-
-namespace otbr {
-
-/**
- * This class represents the agent instance parameters.
- *
- */
-class InstanceParams
-{
-public:
- /**
- * This method gets the single `InstanceParams` instance.
- *
- * @returns The single `InstanceParams` instance.
- *
- */
- static InstanceParams &Get(void);
-
- /**
- * This method sets the Thread network interface name.
- *
- * @param[in] aName The Thread network interface name.
- *
- */
- void SetThreadIfName(const char *aName) { mThreadIfName = aName; }
-
- /**
- * This method gets the Thread network interface name.
- *
- * @returns The Thread network interface name.
- *
- */
- const char *GetThreadIfName(void) const { return mThreadIfName; }
-
- /**
- * This method sets the Backbone network interface name.
- *
- * @param[in] aName The Backbone network interface name.
- *
- */
- void SetBackboneIfName(const char *aName) { mBackboneIfName = aName; }
-
- /**
- * This method gets the Backbone network interface name.
- *
- * @returns The Backbone network interface name.
- *
- */
- const char *GetBackboneIfName(void) const { return mBackboneIfName; }
-
-private:
- InstanceParams()
- : mThreadIfName(nullptr)
- , mBackboneIfName(nullptr)
- {
- }
-
- const char *mThreadIfName;
- const char *mBackboneIfName;
-};
-
-} // namespace otbr
-
-#endif // OTBR_AGENT_INSATNCE_PARAMS_HPP_
diff --git a/src/agent/main.cpp b/src/agent/main.cpp
index 05b9fa84..14c33cba 100644
--- a/src/agent/main.cpp
+++ b/src/agent/main.cpp
@@ -26,22 +26,24 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#define OTBR_LOG_TAG "AGENT"
+
#include <openthread-br/config.h>
+#include <algorithm>
#include <fstream>
#include <mutex>
#include <sstream>
-#include <thread>
+#include <string>
+#include <vector>
-#include <errno.h>
+#include <assert.h>
#include <getopt.h>
-#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <assert.h>
#include <openthread/logging.h>
#include <openthread/platform/radio.h>
@@ -49,29 +51,12 @@
#include <cutils/properties.h>
#endif
-#include "agent/agent_instance.hpp"
+#include "agent/application.hpp"
#include "common/code_utils.hpp"
#include "common/logging.hpp"
#include "common/mainloop.hpp"
-#include "common/mainloop_manager.hpp"
#include "common/types.hpp"
#include "ncp/ncp_openthread.hpp"
-#if OTBR_ENABLE_REST_SERVER
-#include "rest/rest_web_server.hpp"
-using otbr::rest::RestWebServer;
-#endif
-#if OTBR_ENABLE_DBUS_SERVER
-#include "dbus/server/dbus_agent.hpp"
-using otbr::DBus::DBusAgent;
-#endif
-#if OTBR_ENABLE_OPENWRT
-#include "openwrt/ubus/otubus.hpp"
-using otbr::ubus::UBusAgent;
-#endif
-#if OTBR_ENABLE_VENDOR_SERVER
-#include "agent/vendor.hpp"
-using otbr::vendor::VendorServer;
-#endif
static const char kSyslogIdent[] = "otbr-agent";
static const char kDefaultInterfaceName[] = "wpan0";
@@ -86,18 +71,14 @@ enum
OTBR_OPT_VERSION = 'V',
OTBR_OPT_SHORTMAX = 128,
OTBR_OPT_RADIO_VERSION,
+ OTBR_OPT_AUTO_ATTACH,
};
-using otbr::MainloopManager;
+static jmp_buf sResetJump;
+static otbr::Application *gApp = nullptr;
-static jmp_buf sResetJump;
-static bool sShouldTerminate = false;
-
-void __gcov_flush();
-
-// Default poll timeout.
-static const struct timeval kPollTimeout = {10, 0};
-static const struct option kOptions[] = {
+void __gcov_flush();
+static const struct option kOptions[] = {
{"backbone-ifname", required_argument, nullptr, OTBR_OPT_BACKBONE_INTERFACE_NAME},
{"debug-level", required_argument, nullptr, OTBR_OPT_DEBUG_LEVEL},
{"help", no_argument, nullptr, OTBR_OPT_HELP},
@@ -105,79 +86,51 @@ static const struct option kOptions[] = {
{"verbose", no_argument, nullptr, OTBR_OPT_VERBOSE},
{"version", no_argument, nullptr, OTBR_OPT_VERSION},
{"radio-version", no_argument, nullptr, OTBR_OPT_RADIO_VERSION},
+ {"auto-attach", optional_argument, nullptr, OTBR_OPT_AUTO_ATTACH},
{0, 0, 0, 0}};
-static void HandleSignal(int aSignal)
+static bool ParseInteger(const char *aStr, long &aOutResult)
{
- sShouldTerminate = true;
- signal(aSignal, SIG_DFL);
-}
+ bool successful = true;
+ char *strEnd;
+ long result;
-static int Mainloop(otbr::AgentInstance &aInstance)
-{
- int error = EXIT_SUCCESS;
+ VerifyOrExit(aStr != nullptr, successful = false);
+ errno = 0;
+ result = strtol(aStr, &strEnd, 0);
+ VerifyOrExit(errno != ERANGE, successful = false);
+ VerifyOrExit(aStr != strEnd, successful = false);
- OTBR_UNUSED_VARIABLE(aInstance);
+ aOutResult = result;
-#if OTBR_ENABLE_OPENWRT
- UBusAgent ubusAgent{aInstance.GetNcp()};
- ubusAgent.Init();
-#endif
-
-#if OTBR_ENABLE_REST_SERVER
- RestWebServer restWebServer{aInstance.GetNcp()};
- restWebServer.Init();
-#endif
-
-#if OTBR_ENABLE_DBUS_SERVER
- DBusAgent dbusAgent{aInstance.GetNcp()};
- dbusAgent.Init();
-#endif
-
-#if OTBR_ENABLE_VENDOR_SERVER
- VendorServer vendorServer{aInstance.GetNcp()};
- vendorServer.Init();
-#endif
-
- otbrLogInfo("Border router agent started.");
- // allow quitting elegantly
- signal(SIGTERM, HandleSignal);
-
- while (!sShouldTerminate)
- {
- otbr::MainloopContext mainloop;
- int rval;
-
- mainloop.mMaxFd = -1;
- mainloop.mTimeout = kPollTimeout;
-
- FD_ZERO(&mainloop.mReadFdSet);
- FD_ZERO(&mainloop.mWriteFdSet);
- FD_ZERO(&mainloop.mErrorFdSet);
+exit:
+ return successful;
+}
- MainloopManager::GetInstance().Update(mainloop);
+static constexpr char kAutoAttachDisableArg[] = "--auto-attach=0";
+static char sAutoAttachDisableArgStorage[sizeof(kAutoAttachDisableArg)];
- rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet,
- &mainloop.mTimeout);
+static std::vector<char *> AppendAutoAttachDisableArg(int argc, char *argv[])
+{
+ std::vector<char *> args(argv, argv + argc);
- if (rval >= 0)
- {
- MainloopManager::GetInstance().Process(mainloop);
- }
- else if (errno != EINTR)
- {
- error = OTBR_ERROR_ERRNO;
- otbrLogErr("select() failed: %s", strerror(errno));
- break;
- }
- }
+ args.erase(std::remove_if(
+ args.begin(), args.end(),
+ [](const char *arg) { return arg != nullptr && std::string(arg).rfind("--auto-attach", 0) == 0; }),
+ args.end());
+ strcpy(sAutoAttachDisableArgStorage, kAutoAttachDisableArg);
+ args.push_back(sAutoAttachDisableArgStorage);
+ args.push_back(nullptr);
- return error;
+ return args;
}
static void PrintHelp(const char *aProgramName)
{
- fprintf(stderr, "Usage: %s [-I interfaceName] [-B backboneIfName] [-d DEBUG_LEVEL] [-v] RADIO_URL [RADIO_URL]\n",
+ fprintf(stderr,
+ "Usage: %s [-I interfaceName] [-B backboneIfName] [-d DEBUG_LEVEL] [-v] [--auto-attach[=0/1]] RADIO_URL "
+ "[RADIO_URL]\n"
+ " --auto-attach defaults to 1\n",
aProgramName);
fprintf(stderr, "%s", otSysGetRadioUrlHelpString());
}
@@ -187,11 +140,6 @@ static void PrintVersion(void)
printf("%s\n", OTBR_PACKAGE_VERSION);
}
-static void PrintRadioVersion(otInstance *aInstance)
-{
- printf("%s\n", otPlatRadioGetVersionString(aInstance));
-}
-
static void OnAllocateFailed(void)
{
otbrLogCrit("Allocate failure, exiting...");
@@ -215,16 +163,35 @@ static otbrLogLevel GetDefaultLogLevel(void)
return level;
}
+static void PrintRadioVersionAndExit(const std::vector<const char *> &aRadioUrls)
+{
+ otbr::Ncp::ControllerOpenThread ncpOpenThread{/* aInterfaceName */ "", aRadioUrls, /* aBackboneInterfaceName */ "",
+ /* aDryRun */ true, /* aEnableAutoAttach */ false};
+ const char * radioVersion;
+
+ ncpOpenThread.Init();
+
+ radioVersion = otPlatRadioGetVersionString(ncpOpenThread.GetInstance());
+ otbrLogNotice("Radio version: %s", radioVersion);
+ printf("%s\n", radioVersion);
+
+ ncpOpenThread.Deinit();
+
+ exit(EXIT_SUCCESS);
+}
+
static int realmain(int argc, char *argv[])
{
otbrLogLevel logLevel = GetDefaultLogLevel();
int opt;
- int ret = EXIT_SUCCESS;
- const char * interfaceName = kDefaultInterfaceName;
- const char * backboneInterfaceName = "";
- bool verbose = false;
- bool printRadioVersion = false;
+ int ret = EXIT_SUCCESS;
+ const char * interfaceName = kDefaultInterfaceName;
+ bool verbose = false;
+ bool printRadioVersion = false;
+ bool enableAutoAttach = true;
std::vector<const char *> radioUrls;
+ std::vector<const char *> backboneInterfaceNames;
+ long parseResult;
std::set_new_handler(OnAllocateFailed);
@@ -233,12 +200,14 @@ static int realmain(int argc, char *argv[])
switch (opt)
{
case OTBR_OPT_BACKBONE_INTERFACE_NAME:
- backboneInterfaceName = optarg;
+ backboneInterfaceNames.push_back(optarg);
+ otbrLogNotice("Backbone interface: %s", optarg);
break;
case OTBR_OPT_DEBUG_LEVEL:
- logLevel = static_cast<otbrLogLevel>(atoi(optarg));
- VerifyOrExit(logLevel >= OTBR_LOG_EMERG && logLevel <= OTBR_LOG_DEBUG, ret = EXIT_FAILURE);
+ VerifyOrExit(ParseInteger(optarg, parseResult), ret = EXIT_FAILURE);
+ VerifyOrExit(OTBR_LOG_EMERG <= parseResult && parseResult <= OTBR_LOG_DEBUG, ret = EXIT_FAILURE);
+ logLevel = static_cast<otbrLogLevel>(parseResult);
break;
case OTBR_OPT_INTERFACE_NAME:
@@ -263,6 +232,18 @@ static int realmain(int argc, char *argv[])
printRadioVersion = true;
break;
+ case OTBR_OPT_AUTO_ATTACH:
+ if (optarg == nullptr)
+ {
+ enableAutoAttach = true;
+ }
+ else
+ {
+ VerifyOrExit(ParseInteger(optarg, parseResult), ret = EXIT_FAILURE);
+ enableAutoAttach = parseResult;
+ }
+ break;
+
default:
PrintHelp(argv[0]);
ExitNow(ret = EXIT_FAILURE);
@@ -271,33 +252,36 @@ static int realmain(int argc, char *argv[])
}
otbrLogInit(kSyslogIdent, logLevel, verbose);
- otbrLogInfo("Running %s", OTBR_PACKAGE_VERSION);
- otbrLogInfo("Thread version: %s", otbr::Ncp::ControllerOpenThread::GetThreadVersion());
- otbrLogInfo("Thread interface: %s", interfaceName);
- otbrLogInfo("Backbone interface: %s", backboneInterfaceName);
+ otbrLogNotice("Running %s", OTBR_PACKAGE_VERSION);
+ otbrLogNotice("Thread version: %s", otbr::Ncp::ControllerOpenThread::GetThreadVersion());
+ otbrLogNotice("Thread interface: %s", interfaceName);
+
+ if (backboneInterfaceNames.empty())
+ {
+ otbrLogNotice("Backbone interface is not specified");
+ }
for (int i = optind; i < argc; i++)
{
- otbrLogInfo("Radio URL: %s", argv[i]);
+ otbrLogNotice("Radio URL: %s", argv[i]);
radioUrls.push_back(argv[i]);
}
+ if (printRadioVersion)
{
- otbr::Ncp::ControllerOpenThread ncpOpenThread{interfaceName, radioUrls, backboneInterfaceName};
- otbr::AgentInstance instance(ncpOpenThread);
+ PrintRadioVersionAndExit(radioUrls);
+ assert(false);
+ }
- otbr::InstanceParams::Get().SetThreadIfName(interfaceName);
- otbr::InstanceParams::Get().SetBackboneIfName(backboneInterfaceName);
+ {
+ otbr::Application app(interfaceName, backboneInterfaceNames, radioUrls, enableAutoAttach);
- SuccessOrExit(ret = instance.Init());
+ gApp = &app;
+ app.Init();
- if (printRadioVersion)
- {
- PrintRadioVersion(ncpOpenThread.GetInstance());
- ExitNow(ret = EXIT_SUCCESS);
- }
+ ret = app.Run();
- SuccessOrExit(ret = Mainloop(instance));
+ app.Deinit();
}
otbrLogDeinit();
@@ -312,7 +296,9 @@ void otPlatReset(otInstance *aInstance)
gPlatResetReason = OT_PLAT_RESET_REASON_SOFTWARE;
- otSysDeinit();
+ VerifyOrDie(gApp != nullptr, "gApp is null");
+ gApp->Deinit();
+ gApp = nullptr;
longjmp(sResetJump, 1);
assert(false);
@@ -322,11 +308,14 @@ int main(int argc, char *argv[])
{
if (setjmp(sResetJump))
{
+ std::vector<char *> args = AppendAutoAttachDisableArg(argc, argv);
+
alarm(0);
#if OPENTHREAD_ENABLE_COVERAGE
__gcov_flush();
#endif
- execvp(argv[0], argv);
+
+ execvp(args[0], args.data());
}
return realmain(argc, argv);
diff --git a/src/agent/otbr-agent.default.in b/src/agent/otbr-agent.default.in
index a353d84d..049686f1 100644
--- a/src/agent/otbr-agent.default.in
+++ b/src/agent/otbr-agent.default.in
@@ -2,3 +2,4 @@
# Options to pass to otbr-agent
OTBR_AGENT_OPTS="-I wpan0 -B @OTBR_INFRA_IF_NAME@ spinel+hdlc+uart:///dev/ttyACM0 trel://@OTBR_INFRA_IF_NAME@"
+OTBR_NO_AUTO_ATTACH=@OTBR_NO_AUTO_ATTACH@
diff --git a/src/agent/otbr-agent.service.in b/src/agent/otbr-agent.service.in
index 266af0db..83141213 100644
--- a/src/agent/otbr-agent.service.in
+++ b/src/agent/otbr-agent.service.in
@@ -1,10 +1,13 @@
[Unit]
-Description=Border Router Agent
+Description=OpenThread Border Router Agent
ConditionPathExists=@CMAKE_INSTALL_FULL_SBINDIR@/otbr-agent
+Requires=dbus.socket
+After=dbus.socket
[Service]
EnvironmentFile=-@CMAKE_INSTALL_FULL_SYSCONFDIR@/default/otbr-agent
-ExecStart=@CMAKE_INSTALL_FULL_SBINDIR@/otbr-agent $OTBR_AGENT_OPTS
+@EXEC_START_PRE@ExecStart=@CMAKE_INSTALL_FULL_SBINDIR@/otbr-agent $OTBR_AGENT_OPTS
+KillMode=mixed
Restart=on-failure
RestartSec=5
RestartPreventExitStatus=SIGKILL
diff --git a/src/agent/vendor.hpp b/src/agent/vendor.hpp
index 67b90275..9d9501bb 100644
--- a/src/agent/vendor.hpp
+++ b/src/agent/vendor.hpp
@@ -45,7 +45,7 @@ public:
/**
* The constructor of vendor server.
*
- * @param[in] aNcp A reference to the NCP controller.
+ * @param[in] aNcp A reference to the NCP controller.
*
*/
VendorServer(otbr::Ncp::ControllerOpenThread &aNcp);
diff --git a/src/backbone_router/CMakeLists.txt b/src/backbone_router/CMakeLists.txt
index e4c7361f..911cf261 100644
--- a/src/backbone_router/CMakeLists.txt
+++ b/src/backbone_router/CMakeLists.txt
@@ -35,5 +35,5 @@ add_library(otbr-backbone-router
target_link_libraries(otbr-backbone-router PRIVATE
otbr-common
otbr-utils
- netfilter_queue
+ $<$<BOOL:${OTBR_DUA_ROUTING}>:netfilter_queue>
)
diff --git a/src/backbone_router/backbone_agent.cpp b/src/backbone_router/backbone_agent.cpp
index ab867a18..40ae8cdd 100644
--- a/src/backbone_router/backbone_agent.cpp
+++ b/src/backbone_router/backbone_agent.cpp
@@ -47,13 +47,18 @@
namespace otbr {
namespace BackboneRouter {
-BackboneAgent::BackboneAgent(otbr::Ncp::ControllerOpenThread &aNcp)
+BackboneAgent::BackboneAgent(otbr::Ncp::ControllerOpenThread &aNcp,
+ std::string aInterfaceName,
+ std::string aBackboneInterfaceName)
: mNcp(aNcp)
, mBackboneRouterState(OT_BACKBONE_ROUTER_STATE_DISABLED)
#if OTBR_ENABLE_DUA_ROUTING
- , mNdProxyManager(aNcp)
+ , mNdProxyManager(aNcp, aBackboneInterfaceName)
+ , mDuaRoutingManager(aInterfaceName, aBackboneInterfaceName)
#endif
{
+ OTBR_UNUSED_VARIABLE(aInterfaceName);
+ OTBR_UNUSED_VARIABLE(aBackboneInterfaceName);
}
void BackboneAgent::Init(void)
diff --git a/src/backbone_router/backbone_agent.hpp b/src/backbone_router/backbone_agent.hpp
index 121f34ae..b9e14f1d 100644
--- a/src/backbone_router/backbone_agent.hpp
+++ b/src/backbone_router/backbone_agent.hpp
@@ -38,9 +38,9 @@
#include <openthread/backbone_router_ftd.h>
-#include "agent/instance_params.hpp"
#include "backbone_router/dua_routing_manager.hpp"
#include "backbone_router/nd_proxy.hpp"
+#include "common/code_utils.hpp"
#include "ncp/ncp_openthread.hpp"
namespace otbr {
@@ -59,7 +59,7 @@ namespace BackboneRouter {
* This class implements Thread Backbone agent functionality.
*
*/
-class BackboneAgent
+class BackboneAgent : private NonCopyable
{
public:
static constexpr uint16_t kBackboneUdpPort = 61631; ///< The BBR port.
@@ -70,7 +70,9 @@ public:
* @param[in] aNcp The Thread instance.
*
*/
- BackboneAgent(otbr::Ncp::ControllerOpenThread &aNcp);
+ BackboneAgent(otbr::Ncp::ControllerOpenThread &aNcp,
+ std::string aInterfaceName,
+ std::string aBackboneInterfaceName);
/**
* This method initializes the Backbone agent.
diff --git a/src/backbone_router/dua_routing_manager.cpp b/src/backbone_router/dua_routing_manager.cpp
index 3b024fe2..4ae3cda6 100644
--- a/src/backbone_router/dua_routing_manager.cpp
+++ b/src/backbone_router/dua_routing_manager.cpp
@@ -70,28 +70,28 @@ exit:
void DuaRoutingManager::AddDefaultRouteToThread(void)
{
SystemUtils::ExecuteCommand("ip -6 route add %s dev %s proto static metric 1", mDomainPrefix.ToString().c_str(),
- InstanceParams::Get().GetThreadIfName());
+ mInterfaceName.c_str());
}
void DuaRoutingManager::DelDefaultRouteToThread(void)
{
SystemUtils::ExecuteCommand("ip -6 route del %s dev %s proto static metric 1", mDomainPrefix.ToString().c_str(),
- InstanceParams::Get().GetThreadIfName());
+ mInterfaceName.c_str());
}
void DuaRoutingManager::AddPolicyRouteToBackbone(void)
{
// Packets from Thread interface use route table "openthread"
- SystemUtils::ExecuteCommand("ip -6 rule add iif %s table openthread", InstanceParams::Get().GetThreadIfName());
+ SystemUtils::ExecuteCommand("ip -6 rule add iif %s table openthread", mInterfaceName.c_str());
SystemUtils::ExecuteCommand("ip -6 route add %s dev %s proto static table openthread",
- mDomainPrefix.ToString().c_str(), InstanceParams::Get().GetBackboneIfName());
+ mDomainPrefix.ToString().c_str(), mBackboneInterfaceName.c_str());
}
void DuaRoutingManager::DelPolicyRouteToBackbone(void)
{
- SystemUtils::ExecuteCommand("ip -6 rule del iif %s table openthread", InstanceParams::Get().GetThreadIfName());
+ SystemUtils::ExecuteCommand("ip -6 rule del iif %s table openthread", mInterfaceName.c_str());
SystemUtils::ExecuteCommand("ip -6 route del %s dev %s proto static table openthread",
- mDomainPrefix.ToString().c_str(), InstanceParams::Get().GetBackboneIfName());
+ mDomainPrefix.ToString().c_str(), mBackboneInterfaceName.c_str());
}
} // namespace BackboneRouter
diff --git a/src/backbone_router/dua_routing_manager.hpp b/src/backbone_router/dua_routing_manager.hpp
index 9f1d090c..97220ca9 100644
--- a/src/backbone_router/dua_routing_manager.hpp
+++ b/src/backbone_router/dua_routing_manager.hpp
@@ -37,9 +37,10 @@
#if OTBR_ENABLE_DUA_ROUTING
#include <set>
+#include <utility>
#include <openthread/backbone_router_ftd.h>
-#include "agent/instance_params.hpp"
+#include "common/code_utils.hpp"
#include "ncp/ncp_openthread.hpp"
#include "utils/system_utils.hpp"
@@ -59,15 +60,17 @@ namespace BackboneRouter {
* This class implements the DUA routing manager.
*
*/
-class DuaRoutingManager
+class DuaRoutingManager : private NonCopyable
{
public:
/**
* This constructor initializes a DUA routing manager instance.
*
*/
- explicit DuaRoutingManager()
+ explicit DuaRoutingManager(std::string aInterfaceName, std::string aBackboneInterfaceName)
: mEnabled(false)
+ , mInterfaceName(std::move(aInterfaceName))
+ , mBackboneInterfaceName(std::move(aBackboneInterfaceName))
{
}
@@ -89,8 +92,10 @@ private:
void AddPolicyRouteToBackbone(void);
void DelPolicyRouteToBackbone(void);
- Ip6Prefix mDomainPrefix;
- bool mEnabled : 1;
+ Ip6Prefix mDomainPrefix;
+ bool mEnabled : 1;
+ std::string mInterfaceName;
+ std::string mBackboneInterfaceName;
};
/**
diff --git a/src/backbone_router/nd_proxy.cpp b/src/backbone_router/nd_proxy.cpp
index 5d3e98f0..5a0a37b9 100644
--- a/src/backbone_router/nd_proxy.cpp
+++ b/src/backbone_router/nd_proxy.cpp
@@ -52,7 +52,6 @@
#error "Platform not supported"
#endif
-#include "agent/instance_params.hpp"
#include "backbone_router/constants.hpp"
#include "common/code_utils.hpp"
#include "common/logging.hpp"
@@ -79,7 +78,7 @@ void NdProxyManager::Enable(const Ip6Prefix &aDomainPrefix)
VerifyOrExit(SystemUtils::ExecuteCommand(
"ip6tables -t raw -A PREROUTING -6 -d %s -p icmpv6 --icmpv6-type neighbor-solicitation -i %s -j "
"NFQUEUE --queue-num 88",
- mDomainPrefix.ToString().c_str(), InstanceParams::Get().GetBackboneIfName()) == 0,
+ mDomainPrefix.ToString().c_str(), mBackboneInterfaceName.c_str()) == 0,
error = OTBR_ERROR_ERRNO);
exit:
@@ -105,7 +104,7 @@ void NdProxyManager::Disable(void)
VerifyOrExit(SystemUtils::ExecuteCommand(
"ip6tables -t raw -D PREROUTING -6 -d %s -p icmpv6 --icmpv6-type neighbor-solicitation -i %s -j "
"NFQUEUE --queue-num 88",
- mDomainPrefix.ToString().c_str(), InstanceParams::Get().GetBackboneIfName()) == 0,
+ mDomainPrefix.ToString().c_str(), mBackboneInterfaceName.c_str()) == 0,
error = OTBR_ERROR_ERRNO);
exit:
@@ -114,7 +113,7 @@ exit:
void NdProxyManager::Init(void)
{
- mBackboneIfIndex = if_nametoindex(InstanceParams::Get().GetBackboneIfName());
+ mBackboneIfIndex = if_nametoindex(mBackboneInterfaceName.c_str());
VerifyOrDie(mBackboneIfIndex > 0, "if_nametoindex failed");
}
@@ -354,7 +353,7 @@ otbrError NdProxyManager::UpdateMacAddress(void)
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, InstanceParams::Get().GetBackboneIfName(), sizeof(ifr.ifr_name) - 1);
+ strncpy(ifr.ifr_name, mBackboneInterfaceName.c_str(), sizeof(ifr.ifr_name) - 1);
VerifyOrExit(ioctl(mIcmp6RawSock, SIOCGIFHWADDR, &ifr) != -1, error = OTBR_ERROR_ERRNO);
memcpy(mMacAddress.m8, ifr.ifr_hwaddr.sa_data, sizeof(mMacAddress));
@@ -377,12 +376,13 @@ otbrError NdProxyManager::InitIcmp6RawSocket(void)
VerifyOrExit(mIcmp6RawSock >= 0, error = OTBR_ERROR_ERRNO);
#if __linux__
- VerifyOrExit(setsockopt(mIcmp6RawSock, SOL_SOCKET, SO_BINDTODEVICE, InstanceParams::Get().GetBackboneIfName(),
- strlen(InstanceParams::Get().GetBackboneIfName())) == 0,
+ VerifyOrExit(setsockopt(mIcmp6RawSock, SOL_SOCKET, SO_BINDTODEVICE, mBackboneInterfaceName.c_str(),
+ mBackboneInterfaceName.length()) == 0,
error = OTBR_ERROR_ERRNO);
#else // __NetBSD__ || __FreeBSD__ || __APPLE__
- VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IP, IP_BOUND_IF, mBackboneIfName.c_str(), mBackboneIfName.size()),
- error = OTBR_ERROR_ERRNO);
+ VerifyOrExit(
+ setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_BOUND_IF, mBackboneIfName.c_str(), mBackboneIfName.size()),
+ error = OTBR_ERROR_ERRNO);
#endif // __linux__
VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) == 0,
diff --git a/src/backbone_router/nd_proxy.hpp b/src/backbone_router/nd_proxy.hpp
index a7b70b85..4250ff8d 100644
--- a/src/backbone_router/nd_proxy.hpp
+++ b/src/backbone_router/nd_proxy.hpp
@@ -46,9 +46,11 @@
#include <netinet/in.h>
#include <set>
#include <string>
+#include <utility>
#include <openthread/backbone_router_ftd.h>
+#include "common/code_utils.hpp"
#include "common/mainloop.hpp"
#include "common/types.hpp"
#include "ncp/ncp_openthread.hpp"
@@ -69,15 +71,16 @@ namespace BackboneRouter {
* This class implements ND Proxy manager.
*
*/
-class NdProxyManager : public MainloopProcessor
+class NdProxyManager : public MainloopProcessor, private NonCopyable
{
public:
/**
* This constructor initializes a NdProxyManager instance.
*
*/
- explicit NdProxyManager(otbr::Ncp::ControllerOpenThread &aNcp)
+ explicit NdProxyManager(otbr::Ncp::ControllerOpenThread &aNcp, std::string aBackboneInterfaceName)
: mNcp(aNcp)
+ , mBackboneInterfaceName(std::move(aBackboneInterfaceName))
, mIcmp6RawSock(-1)
, mUnicastNsQueueSock(-1)
, mNfqHandler(nullptr)
@@ -105,28 +108,15 @@ public:
*/
void Disable(void);
- /**
- * This method updates the mainloop context.
- *
- * @param[inout] aMainloop A reference to the mainloop to be updated.
- *
- */
void Update(MainloopContext &aMainloop) override;
-
- /**
- * This method processes mainloop events.
- *
- * @param[in] aMainloop A reference to the mainloop context.
- *
- */
void Process(const MainloopContext &aMainloop) override;
/**
* This method handles a Backbone Router ND Proxy event.
*
- * @param[in] aEvent The Backbone Router ND Proxy event type.
- * @param[in] aDua The Domain Unicast Address of the ND Proxy, or `nullptr` if @p `aEvent` is
- * `OT_BACKBONE_ROUTER_NDPROXY_CLEARED`.
+ * @param[in] aEvent The Backbone Router ND Proxy event type.
+ * @param[in] aDua The Domain Unicast Address of the ND Proxy, or `nullptr` if @p `aEvent` is
+ * `OT_BACKBONE_ROUTER_NDPROXY_CLEARED`.
*
*/
void HandleBackboneRouterNdProxyEvent(otBackboneRouterNdProxyEvent aEvent, const otIp6Address *aDua);
@@ -134,7 +124,7 @@ public:
/**
* This method returns if the ND Proxy manager is enabled.
*
- * @returns If the ND Proxy manager is enabled;
+ * @returns If the ND Proxy manager is enabled;
*
*/
bool IsEnabled(void) const { return mIcmp6RawSock >= 0; }
@@ -162,6 +152,7 @@ private:
int HandleNetfilterQueue(struct nfq_q_handle *aNfQueueHandler, struct nfgenmsg *aNfMsg, struct nfq_data *aNfData);
otbr::Ncp::ControllerOpenThread &mNcp;
+ std::string mBackboneInterfaceName;
std::set<Ip6Address> mNdProxySet;
uint32_t mBackboneIfIndex;
int mIcmp6RawSock;
diff --git a/src/border_agent/CMakeLists.txt b/src/border_agent/CMakeLists.txt
index 9b60a6ee..c58acdbc 100644
--- a/src/border_agent/CMakeLists.txt
+++ b/src/border_agent/CMakeLists.txt
@@ -34,5 +34,6 @@ add_library(otbr-border-agent
target_link_libraries(otbr-border-agent PRIVATE
$<$<BOOL:${OTBR_MDNS}>:otbr-mdns>
$<$<BOOL:${OTBR_BACKBONE_ROUTER}>:otbr-backbone-router>
+ otbr-trel-dnssd
otbr-common
)
diff --git a/src/border_agent/border_agent.cpp b/src/border_agent/border_agent.cpp
index bfe0f5d9..b14c2f1b 100644
--- a/src/border_agent/border_agent.cpp
+++ b/src/border_agent/border_agent.cpp
@@ -31,7 +31,7 @@
* The file implements the Thread border agent.
*/
-#define OTBR_LOG_TAG "AGENT"
+#define OTBR_LOG_TAG "BA"
#include "border_agent/border_agent.hpp"
@@ -44,6 +44,10 @@
#include <string.h>
#include <unistd.h>
+#include <iomanip>
+#include <random>
+#include <sstream>
+
#include <openthread/border_agent.h>
#include <openthread/thread_ftd.h>
#include <openthread/platform/toolchain.h>
@@ -59,13 +63,15 @@
#include "common/tlv.hpp"
#include "common/types.hpp"
#include "utils/hex.hpp"
-#include "utils/strcpy_utils.hpp"
namespace otbr {
+static const char kVendorName[] = OTBR_VENDOR_NAME;
+static const char kProductName[] = OTBR_PRODUCT_NAME;
static const char kBorderAgentServiceType[] = "_meshcop._udp"; ///< Border agent service type of mDNS
static const char kBorderAgentServiceInstanceName[] =
OTBR_MESHCOP_SERVICE_INSTANCE_NAME; ///< Border agent service name of mDNS
+static constexpr int kBorderAgentServiceDummyPort = 49152;
/**
* Locators
@@ -92,19 +98,15 @@ uint32_t BorderAgent::StateBitmap::ToUint32(void) const
BorderAgent::BorderAgent(otbr::Ncp::ControllerOpenThread &aNcp)
: mNcp(aNcp)
-#if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
- , mPublisher(Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, HandleMdnsState, this))
+ , mPublisher(Mdns::Publisher::Create([this](Mdns::Publisher::State aNewState) { HandleMdnsState(aNewState); }))
#if OTBR_ENABLE_SRP_ADVERTISING_PROXY
, mAdvertisingProxy(aNcp, *mPublisher)
#endif
-#else
- , mPublisher(nullptr)
-#endif
#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
, mDiscoveryProxy(aNcp, *mPublisher)
#endif
-#if OTBR_ENABLE_BACKBONE_ROUTER
- , mBackboneAgent(aNcp)
+#if OTBR_ENABLE_TREL
+ , mTrelDnssd(aNcp, *mPublisher)
#endif
{
}
@@ -113,52 +115,47 @@ void BorderAgent::Init(void)
{
mNcp.AddThreadStateChangedCallback([this](otChangedFlags aFlags) { HandleThreadStateChanged(aFlags); });
-#if OTBR_ENABLE_BACKBONE_ROUTER
- mBackboneAgent.Init();
+#if OTBR_ENABLE_DBUS_SERVER
+ mNcp.GetThreadHelper()->SetUpdateMeshCopTxtHandler([this](std::map<std::string, std::vector<uint8_t>> aUpdate) {
+ HandleUpdateVendorMeshCoPTxtEntries(std::move(aUpdate));
+ });
+ mNcp.RegisterResetHandler([this]() {
+ mNcp.GetThreadHelper()->SetUpdateMeshCopTxtHandler([this](std::map<std::string, std::vector<uint8_t>> aUpdate) {
+ HandleUpdateVendorMeshCoPTxtEntries(std::move(aUpdate));
+ });
+ });
#endif
- if (IsThreadStarted())
- {
- Start();
- }
- else
- {
- Stop();
- }
+ mServiceInstanceName = BaseServiceInstanceName();
+
+ Start();
}
-otbrError BorderAgent::Start(void)
+void BorderAgent::Deinit(void)
{
- otbrError error = OTBR_ERROR_NONE;
-
- VerifyOrExit(IsThreadStarted(), errno = EAGAIN, error = OTBR_ERROR_ERRNO);
-
- // In case we didn't receive Thread down event.
Stop();
+}
-#if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
+void BorderAgent::Start(void)
+{
+ otbrError error = OTBR_ERROR_NONE;
+
+ SuccessOrExit(error = mPublisher->Start());
#if OTBR_ENABLE_SRP_ADVERTISING_PROXY
mAdvertisingProxy.Start();
#endif
- UpdateMeshCopService();
-
#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
mDiscoveryProxy.Start();
#endif
-#endif // OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
-
exit:
otbrLogResult(error, "Start Thread Border Agent");
- return error;
}
void BorderAgent::Stop(void)
{
otbrLogInfo("Stop Thread Border Agent");
-#if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
- mPublisher->Stop();
#if OTBR_ENABLE_SRP_ADVERTISING_PROXY
mAdvertisingProxy.Stop();
#endif
@@ -167,18 +164,12 @@ void BorderAgent::Stop(void)
mDiscoveryProxy.Stop();
#endif
-#endif
-}
-
-void BorderAgent::HandleMdnsState(void *aContext, Mdns::Publisher::State aState)
-{
- static_cast<BorderAgent *>(aContext)->HandleMdnsState(aState);
+ UnpublishMeshCopService();
+ mPublisher->Stop();
}
BorderAgent::~BorderAgent(void)
{
- Stop();
-
if (mPublisher != nullptr)
{
delete mPublisher;
@@ -195,13 +186,25 @@ void BorderAgent::HandleMdnsState(Mdns::Publisher::State aState)
#if OTBR_ENABLE_SRP_ADVERTISING_PROXY
mAdvertisingProxy.PublishAllHostsAndServices();
#endif
+#if OTBR_ENABLE_TREL
+ mTrelDnssd.OnMdnsPublisherReady();
+#endif
break;
default:
- otbrLogWarning("mDNS service not available!");
+ otbrLogWarning("mDNS publisher not available!");
break;
}
}
+static uint64_t ConvertTimestampToUint64(const otTimestamp &aTimestamp)
+{
+ // 64 bits Timestamp fields layout
+ //-----48 bits------//-----15 bits-----//-------1 bit-------//
+ // Seconds // Ticks // Authoritative //
+ return (aTimestamp.mSeconds << 16) | static_cast<uint64_t>(aTimestamp.mTicks << 1) |
+ static_cast<uint64_t>(aTimestamp.mAuthoritative);
+}
+
void BorderAgent::PublishMeshCopService(void)
{
StateBitmap state;
@@ -211,16 +214,18 @@ void BorderAgent::PublishMeshCopService(void)
const otExtAddress * extAddr = otLinkGetExtendedAddress(instance);
const char * networkName = otThreadGetNetworkName(instance);
Mdns::Publisher::TxtList txtList{{"rv", "1"}};
+ int port;
- otbrLogInfo("Publish meshcop service %s.%s.local.", kBorderAgentServiceInstanceName, kBorderAgentServiceType);
+ otbrLogInfo("Publish meshcop service %s.%s.local.", mServiceInstanceName.c_str(), kBorderAgentServiceType);
+ txtList.emplace_back("vn", kVendorName);
+ txtList.emplace_back("mn", kProductName);
txtList.emplace_back("nn", networkName);
txtList.emplace_back("xp", extPanId->m8, sizeof(extPanId->m8));
txtList.emplace_back("tv", mNcp.GetThreadVersion());
- // "dd" represents for device discriminator which
- // should always be the IEEE 802.15.4 extended address.
- txtList.emplace_back("dd", extAddr->m8, sizeof(extAddr->m8));
+ // "xa" stands for Extended MAC Address (64-bit) of the Thread Interface of the Border Agent.
+ txtList.emplace_back("xa", extAddr->m8, sizeof(extAddr->m8));
state.mConnectionMode = kConnectionModePskc;
state.mAvailability = kAvailabilityHigh;
@@ -247,7 +252,6 @@ void BorderAgent::PublishMeshCopService(void)
{
otError error;
otOperationalDataset activeDataset;
- uint64_t activeTimestamp;
uint32_t partitionId;
if ((error = otDatasetGetActive(instance, &activeDataset)) != OT_ERROR_NONE)
@@ -256,8 +260,11 @@ void BorderAgent::PublishMeshCopService(void)
}
else
{
- activeTimestamp = htobe64(activeDataset.mActiveTimestamp);
- txtList.emplace_back("at", reinterpret_cast<uint8_t *>(&activeTimestamp), sizeof(activeTimestamp));
+ uint64_t activeTimestampValue = ConvertTimestampToUint64(activeDataset.mActiveTimestamp);
+
+ activeTimestampValue = htobe64(activeTimestampValue);
+ txtList.emplace_back("at", reinterpret_cast<uint8_t *>(&activeTimestampValue),
+ sizeof(activeTimestampValue));
}
partitionId = otThreadGetPartitionId(instance);
@@ -277,41 +284,95 @@ void BorderAgent::PublishMeshCopService(void)
txtList.emplace_back("dn", otThreadGetDomainName(instance));
#endif
+ if (otBorderAgentGetState(instance) != OT_BORDER_AGENT_STATE_STOPPED)
+ {
+ port = otBorderAgentGetUdpPort(instance);
+ }
+ else
+ {
+ // When thread interface is not active, the border agent is not started, thus it's not listening to any port and
+ // not handling requests. In such situation, we use a dummy port number for publishing the MeshCoP service to
+ // advertise the status of the border router. One can learn the thread interface status from `sb` entry so it
+ // doesn't have to send requests to the dummy port when border agent is not running.
+ port = kBorderAgentServiceDummyPort;
+ }
+
+#if OTBR_ENABLE_DBUS_SERVER
+ for (const auto &entry : mMeshCopTxtUpdate)
+ {
+ const std::string & key = entry.first;
+ const std::vector<uint8_t> &value = entry.second;
+ bool found = false;
+
+ for (auto &addedEntry : txtList)
+ {
+ if (addedEntry.mName == key)
+ {
+ addedEntry.mValue = value;
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ txtList.emplace_back(key.c_str(), value.data(), value.size());
+ }
+ }
+#endif
- mPublisher->PublishService(/* aHostName */ nullptr, otBorderAgentGetUdpPort(instance),
- kBorderAgentServiceInstanceName, kBorderAgentServiceType, Mdns::Publisher::SubTypeList{},
- txtList);
+ mPublisher->PublishService(/* aHostName */ "", mServiceInstanceName, kBorderAgentServiceType,
+ Mdns::Publisher::SubTypeList{}, port, txtList, [this](otbrError aError) {
+ if (aError == OTBR_ERROR_ABORTED)
+ {
+ // OTBR_ERROR_ABORTED is thrown when an ongoing service registration is
+ // cancelled. This can happen when the meshcop service is being updated
+ // frequently. To avoid false alarms, it should not be logged like a real error.
+ otbrLogInfo("Cancelled previous publishing meshcop service %s.%s.local",
+ mServiceInstanceName.c_str(), kBorderAgentServiceType);
+ }
+ else
+ {
+ otbrLogResult(aError, "Result of publish meshcop service %s.%s.local",
+ mServiceInstanceName.c_str(), kBorderAgentServiceType);
+ }
+ if (aError == OTBR_ERROR_DUPLICATED)
+ {
+ // Try to unpublish current service in case we are trying to register
+ // multiple new services simultaneously when the original service name
+ // is conflicted.
+ UnpublishMeshCopService();
+ mServiceInstanceName = GetAlternativeServiceInstanceName();
+ PublishMeshCopService();
+ }
+ });
}
void BorderAgent::UnpublishMeshCopService(void)
{
- assert(IsThreadStarted());
- VerifyOrExit(!mNetworkName.empty());
-
- otbrLogInfo("Unpublish meshcop service %s.%s.local.", kBorderAgentServiceInstanceName, kBorderAgentServiceType);
+ otbrLogInfo("Unpublish meshcop service %s.%s.local", mServiceInstanceName.c_str(), kBorderAgentServiceType);
- mPublisher->UnpublishService(kBorderAgentServiceInstanceName, kBorderAgentServiceType);
-
-exit:
- return;
+ mPublisher->UnpublishService(mServiceInstanceName, kBorderAgentServiceType, [this](otbrError aError) {
+ otbrLogResult(aError, "Result of unpublish meshcop service %s.%s.local", mServiceInstanceName.c_str(),
+ kBorderAgentServiceType);
+ });
}
void BorderAgent::UpdateMeshCopService(void)
{
- assert(IsThreadStarted());
-
- const char *networkName = otThreadGetNetworkName(mNcp.GetInstance());
-
VerifyOrExit(mPublisher->IsStarted(), mPublisher->Start());
- VerifyOrExit(IsPskcInitialized(), UnpublishMeshCopService());
-
PublishMeshCopService();
- mNetworkName = networkName;
-
exit:
return;
}
+#if OTBR_ENABLE_DBUS_SERVER
+void BorderAgent::HandleUpdateVendorMeshCoPTxtEntries(std::map<std::string, std::vector<uint8_t>> aUpdate)
+{
+ mMeshCopTxtUpdate = std::move(aUpdate);
+ UpdateMeshCopService();
+}
+#endif
+
void BorderAgent::HandleThreadStateChanged(otChangedFlags aFlags)
{
VerifyOrExit(mPublisher != nullptr);
@@ -322,21 +383,13 @@ void BorderAgent::HandleThreadStateChanged(otChangedFlags aFlags)
if (aFlags & OT_CHANGED_THREAD_ROLE)
{
otbrLogInfo("Thread is %s", (IsThreadStarted() ? "up" : "down"));
-
- if (IsThreadStarted())
- {
- Start();
- }
- else
- {
- Stop();
- }
}
- else if (IsThreadStarted())
+
+ if (aFlags & (OT_CHANGED_THREAD_ROLE | OT_CHANGED_THREAD_EXT_PANID | OT_CHANGED_THREAD_NETWORK_NAME |
+ OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE))
{
UpdateMeshCopService();
}
-
exit:
return;
}
@@ -348,23 +401,28 @@ bool BorderAgent::IsThreadStarted(void) const
return role == OT_DEVICE_ROLE_CHILD || role == OT_DEVICE_ROLE_ROUTER || role == OT_DEVICE_ROLE_LEADER;
}
-bool BorderAgent::IsPskcInitialized(void) const
+std::string BorderAgent::BaseServiceInstanceName() const
{
- bool initialized = false;
- otPskc pskc;
-
- otThreadGetPskc(mNcp.GetInstance(), &pskc);
-
- for (uint8_t byte : pskc.m8)
- {
- if (byte != 0x00)
- {
- initialized = true;
- break;
- }
- }
+ const otExtAddress *extAddress = otLinkGetExtendedAddress(mNcp.GetInstance());
+ std::stringstream ss;
+
+ ss << kBorderAgentServiceInstanceName << " #";
+ ss << std::uppercase << std::hex << std::setfill('0');
+ ss << std::setw(2) << static_cast<int>(extAddress->m8[6]);
+ ss << std::setw(2) << static_cast<int>(extAddress->m8[7]);
+ return ss.str();
+}
- return initialized;
+std::string BorderAgent::GetAlternativeServiceInstanceName() const
+{
+ std::random_device r;
+ std::default_random_engine engine(r());
+ std::uniform_int_distribution<uint16_t> uniform_dist(1, 0xFFFF);
+ uint16_t rand = uniform_dist(engine);
+ std::stringstream ss;
+
+ ss << BaseServiceInstanceName() << " (" << rand << ")";
+ return ss.str();
}
} // namespace otbr
diff --git a/src/border_agent/border_agent.hpp b/src/border_agent/border_agent.hpp
index c363569a..580ff0a0 100644
--- a/src/border_agent/border_agent.hpp
+++ b/src/border_agent/border_agent.hpp
@@ -34,20 +34,22 @@
#ifndef OTBR_AGENT_BORDER_AGENT_HPP_
#define OTBR_AGENT_BORDER_AGENT_HPP_
+#if !(OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO)
+#error "Border Agent feature requires at least one `OTBR_MDNS` implementation"
+#endif
+
#include <vector>
#include <stdint.h>
-#include "agent/instance_params.hpp"
+#include "backbone_router/backbone_agent.hpp"
+#include "common/code_utils.hpp"
#include "common/mainloop.hpp"
#include "mdns/mdns.hpp"
#include "ncp/ncp_openthread.hpp"
#include "sdp_proxy/advertising_proxy.hpp"
#include "sdp_proxy/discovery_proxy.hpp"
-
-#if OTBR_ENABLE_BACKBONE_ROUTER
-#include "backbone_router/backbone_agent.hpp"
-#endif
+#include "trel_dnssd/trel_dnssd.hpp"
#ifndef OTBR_VENDOR_NAME
#define OTBR_VENDOR_NAME "OpenThread"
@@ -58,7 +60,7 @@
#endif
#ifndef OTBR_MESHCOP_SERVICE_INSTANCE_NAME
-#define OTBR_MESHCOP_SERVICE_INSTANCE_NAME OTBR_VENDOR_NAME "_" OTBR_PRODUCT_NAME
+#define OTBR_MESHCOP_SERVICE_INSTANCE_NAME OTBR_VENDOR_NAME " " OTBR_PRODUCT_NAME
#endif
namespace otbr {
@@ -76,13 +78,13 @@ namespace otbr {
* This class implements Thread border agent functionality.
*
*/
-class BorderAgent
+class BorderAgent : private NonCopyable
{
public:
/**
* The constructor to initialize the Thread border agent.
*
- * @param[in] aNcp A reference to the NCP controller.
+ * @param[in] aNcp A reference to the NCP controller.
*
*/
BorderAgent(otbr::Ncp::ControllerOpenThread &aNcp);
@@ -95,6 +97,20 @@ public:
*/
void Init(void);
+ /**
+ * This method de-initializes border agent service.
+ *
+ */
+ void Deinit(void);
+
+ /**
+ * This method returns the Publisher the border agent is using.
+ *
+ * @returns A reference to the mPublisher.
+ *
+ */
+ Mdns::Publisher &GetPublisher() { return *mPublisher; }
+
private:
enum : uint8_t
{
@@ -138,22 +154,28 @@ private:
uint32_t ToUint32(void) const;
};
- otbrError Start(void);
- void Stop(void);
- static void HandleMdnsState(void *aContext, Mdns::Publisher::State aState);
- void HandleMdnsState(Mdns::Publisher::State aState);
- void PublishMeshCopService(void);
- void UnpublishMeshCopService(void);
- void UpdateMeshCopService(void);
+ void Start(void);
+ void Stop(void);
+ void HandleMdnsState(Mdns::Publisher::State aState);
+ void PublishMeshCopService(void);
+ void UpdateMeshCopService(void);
+ void UnpublishMeshCopService(void);
+#if OTBR_ENABLE_DBUS_SERVER
+ void HandleUpdateVendorMeshCoPTxtEntries(std::map<std::string, std::vector<uint8_t>> aUpdate);
+#endif
void HandleThreadStateChanged(otChangedFlags aFlags);
- bool IsThreadStarted(void) const;
- bool IsPskcInitialized(void) const;
+ bool IsThreadStarted(void) const;
+ std::string BaseServiceInstanceName() const;
+ std::string GetAlternativeServiceInstanceName() const;
otbr::Ncp::ControllerOpenThread &mNcp;
Mdns::Publisher * mPublisher;
- std::string mNetworkName;
+
+#if OTBR_ENABLE_DBUS_SERVER
+ std::map<std::string, std::vector<uint8_t>> mMeshCopTxtUpdate;
+#endif
#if OTBR_ENABLE_SRP_ADVERTISING_PROXY
AdvertisingProxy mAdvertisingProxy;
@@ -161,9 +183,11 @@ private:
#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
Dnssd::DiscoveryProxy mDiscoveryProxy;
#endif
-#if OTBR_ENABLE_BACKBONE_ROUTER
- BackboneRouter::BackboneAgent mBackboneAgent;
+#if OTBR_ENABLE_TREL
+ TrelDnssd::TrelDnssd mTrelDnssd;
#endif
+
+ std::string mServiceInstanceName;
};
/**
diff --git a/src/common/callback.hpp b/src/common/callback.hpp
new file mode 100644
index 00000000..ac5ff1c5
--- /dev/null
+++ b/src/common/callback.hpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2021, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OTBR_COMMON_CALLBACK_HPP_
+#define OTBR_COMMON_CALLBACK_HPP_
+
+#include <functional>
+#include <type_traits>
+
+namespace otbr {
+
+template <class T> class OnceCallback;
+
+/**
+ * A callback which can be invoked at most once.
+ *
+ * IsNull is guaranteed to return true once the callback has been invoked.
+ *
+ * Example usage:
+ * OnceCallback<int(int)> square([](int x) { return x * x; });
+ * std::move(square)(5); // Returns 25.
+ * std::move(square)(6); // Crashes since `square` has already run.
+ * square(7); // Compiling error.
+ *
+ * Inspired by Chromium base::OnceCallback
+ * (https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/base/callback.h).
+ *
+ */
+template <typename R, typename... Args> class OnceCallback<R(Args...)>
+{
+public:
+ // Constructs a new `OnceCallback` instance with a callable.
+ //
+ // This constructor is for matching std::function<> and lambda and the
+ // `std::enable_if_t` check is only required for working around gcc 4.x
+ // compiling issue which trying to instantiate this template constructor
+ // for use cases like `::mOnceCallback(aOnceCallback)`.
+ template <typename T, typename = typename std::enable_if<!std::is_same<OnceCallback, T>::value>::type>
+ OnceCallback(T &&func)
+ : mFunc(std::forward<T>(func))
+ {
+ }
+
+ OnceCallback(const OnceCallback &) = delete;
+ OnceCallback &operator=(const OnceCallback &) = delete;
+ OnceCallback(OnceCallback &&) = default;
+ OnceCallback &operator=(OnceCallback &&) = default;
+
+ R operator()(Args...) const &
+ {
+ static_assert(!sizeof(*this), "OnceCallback::() can only be invoked on a non-const "
+ "rvalue, i.e. std::move(callback)().");
+ }
+
+ R operator()(Args... args) &&
+ {
+ // Move `this` to a local variable to clear internal state
+ // before invoking the callback function.
+ OnceCallback cb = std::move(*this);
+
+ return cb.mFunc(std::forward<Args>(args)...);
+ }
+
+ bool IsNull() const { return mFunc == nullptr; }
+
+private:
+ std::function<R(Args...)> mFunc;
+};
+
+} // namespace otbr
+
+#endif // OTBR_COMMON_CALLBACK_HPP_
diff --git a/src/common/code_utils.hpp b/src/common/code_utils.hpp
index 682ab484..eda76683 100644
--- a/src/common/code_utils.hpp
+++ b/src/common/code_utils.hpp
@@ -37,6 +37,8 @@
#define OTBR_LOG_TAG "UTILS"
#endif
+#include <assert.h>
+#include <memory>
#include <stdlib.h>
#include "common/logging.hpp"
@@ -44,10 +46,10 @@
/**
* This aligns the pointer to @p aAlignType.
*
- * @param[in] aMem A pointer to arbitrary memory.
- * @param[in] aAlignType The type to align with and convert the pointer to this type.
+ * @param[in] aMem A pointer to arbitrary memory.
+ * @param[in] aAlignType The type to align with and convert the pointer to this type.
*
- * @returns A @aAlignType pointer to aligned memory.
+ * @returns A pointer to aligned memory.
*
*/
#define OTBR_ALIGNED(aMem, aAlignType) \
@@ -65,7 +67,7 @@
* commonly be successful, and branches to the local label 'exit' if
* the status is unsuccessful.
*
- * @param[in] aStatus A scalar status to be evaluated against zero (0).
+ * @param[in] aStatus A scalar status to be evaluated against zero (0).
*
*/
#define SuccessOrExit(aStatus) \
@@ -81,18 +83,18 @@
* This macro verifies a given error status to be successful (compared against value zero (0)), otherwise, it emits a
* given error messages and exits the program.
*
- * @param[in] aStatus A scalar error status to be evaluated against zero (0).
- * @param[in] aMessage A message (text string) to print on failure.
+ * @param[in] aStatus A scalar error status to be evaluated against zero (0).
+ * @param[in] aMessage A message (text string) to print on failure.
*
*/
-#define SuccessOrDie(aStatus, aMessage) \
- do \
- { \
- if ((aStatus) != 0) \
- { \
- otbrLogEmerg("FAILED %s:%d - %s", __FUNCTION__, __LINE__, aMessage); \
- exit(-1); \
- } \
+#define SuccessOrDie(aStatus, aMessage) \
+ do \
+ { \
+ if ((aStatus) != 0) \
+ { \
+ otbrLogEmerg("FAILED %s:%d - %s", __FILE__, __LINE__, aMessage); \
+ exit(-1); \
+ } \
} while (false)
/**
@@ -100,9 +102,9 @@
* commonly be true, and both executes @a ... and branches to the
* local label 'exit' if the condition is false.
*
- * @param[in] aCondition A Boolean expression to be evaluated.
- * @param[in] ... An expression or block to execute when the
- * assertion fails.
+ * @param[in] aCondition A Boolean expression to be evaluated.
+ * @param[in] ... An expression or block to execute when the
+ * assertion fails.
*
*/
#define VerifyOrExit(aCondition, ...) \
@@ -119,18 +121,18 @@
* This macro checks for the specified condition, which is expected to commonly be true,
* and both prints the message and terminates the program if the condition is false.
*
- * @param[in] aCondition The condition to verify
- * @param[in] aMessage A message (text string) to print on failure.
+ * @param[in] aCondition The condition to verify
+ * @param[in] aMessage A message (text string) to print on failure.
*
*/
-#define VerifyOrDie(aCondition, aMessage) \
- do \
- { \
- if (!(aCondition)) \
- { \
- otbrLogEmerg("FAILED %s:%d - %s", __FUNCTION__, __LINE__, aMessage); \
- exit(-1); \
- } \
+#define VerifyOrDie(aCondition, aMessage) \
+ do \
+ { \
+ if (!(aCondition)) \
+ { \
+ otbrLogEmerg("FAILED %s:%d - %s", __FILE__, __LINE__, aMessage); \
+ exit(-1); \
+ } \
} while (false)
/**
@@ -141,8 +143,8 @@
* failure for the overall exit status of the enclosing
* function body.
*
- * @param[in] ... An optional expression or block to execute
- * when the assertion fails.
+ * @param[in] ... An optional expression or block to execute
+ * when the assertion fails.
*
*/
#define ExitNow(...) \
@@ -155,4 +157,78 @@
#define OTBR_NOOP
#define OTBR_UNUSED_VARIABLE(variable) ((void)(variable))
+template <typename T, typename... Args> std::unique_ptr<T> MakeUnique(Args &&... args)
+{
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+/**
+ * This class makes any class that derives from it non-copyable. It is intended to be used as a private base class.
+ *
+ */
+class NonCopyable
+{
+public:
+ NonCopyable(const NonCopyable &) = delete;
+ NonCopyable &operator=(const NonCopyable &) = delete;
+
+protected:
+ NonCopyable(void) = default;
+};
+
+template <typename T> class Optional
+{
+public:
+ constexpr Optional(void) = default;
+
+ Optional(T aValue) { SetValue(aValue); }
+
+ ~Optional(void) { ClearValue(); }
+
+ Optional(const Optional &aOther) { AssignFrom(aOther); }
+
+ Optional &operator=(const Optional &aOther) { AssignFrom(aOther); }
+
+ constexpr const T *operator->(void)const { return &GetValue(); }
+
+ constexpr const T &operator*(void)const { return GetValue(); }
+
+ constexpr bool HasValue(void) const { return mHasValue; }
+
+private:
+ T &GetValue(void) const
+ {
+ assert(mHasValue);
+ return *const_cast<T *>(reinterpret_cast<const T *>(&mStorage));
+ }
+
+ void ClearValue(void)
+ {
+ if (mHasValue)
+ {
+ GetValue().~T();
+ mHasValue = false;
+ }
+ }
+
+ void SetValue(const T &aValue)
+ {
+ ClearValue();
+ new (&mStorage) T(aValue);
+ mHasValue = true;
+ }
+
+ void AssignFrom(const Optional &aOther)
+ {
+ ClearValue();
+ if (aOther.mHasValue)
+ {
+ SetValue(aOther.GetValue());
+ }
+ }
+
+ alignas(T) unsigned char mStorage[sizeof(T)];
+ bool mHasValue = false;
+};
+
#endif // OTBR_COMMON_CODE_UTILS_HPP_
diff --git a/src/common/dns_utils.hpp b/src/common/dns_utils.hpp
index 477294ad..0add7871 100644
--- a/src/common/dns_utils.hpp
+++ b/src/common/dns_utils.hpp
@@ -77,9 +77,9 @@ struct DnsNameInfo
/**
* This method splits a full DNS name into name components.
*
- * @param[in] aName The full DNS name to dissect.
+ * @param[in] aName The full DNS name to dissect.
*
- * @returns A `DnsNameInfo` structure containing DNS name information.
+ * @returns A `DnsNameInfo` structure containing DNS name information.
*
* @sa DnsNameInfo
*
diff --git a/src/common/logging.cpp b/src/common/logging.cpp
index 7e08172f..cde74339 100644
--- a/src/common/logging.cpp
+++ b/src/common/logging.cpp
@@ -28,6 +28,10 @@
#define OTBR_LOG_TAG "LOG"
+#ifndef OTBR_SYSLOG_FACILITY_ID
+#define OTBR_SYSLOG_FACILITY_ID LOG_USER
+#endif
+
#include "common/logging.hpp"
#include <assert.h>
@@ -56,13 +60,22 @@ otbrLogLevel otbrLogGetLevel(void)
return sLevel;
}
+/**
+ * Set current log level.
+ */
+void otbrLogSetLevel(otbrLogLevel aLevel)
+{
+ assert(aLevel >= OTBR_LOG_EMERG && aLevel <= OTBR_LOG_DEBUG);
+ sLevel = aLevel;
+}
+
/** Initialize logging */
void otbrLogInit(const char *aIdent, otbrLogLevel aLevel, bool aPrintStderr)
{
assert(aIdent);
assert(aLevel >= OTBR_LOG_EMERG && aLevel <= OTBR_LOG_DEBUG);
- openlog(aIdent, (LOG_CONS | LOG_PID) | (aPrintStderr ? LOG_PERROR : 0), LOG_USER);
+ openlog(aIdent, (LOG_CONS | LOG_PID) | (aPrintStderr ? LOG_PERROR : 0), OTBR_SYSLOG_FACILITY_ID);
sLevel = aLevel;
}
@@ -127,7 +140,7 @@ void otbrLogvNoFilter(otbrLogLevel aLevel, const char *aFormat, va_list aArgList
}
/** Hex dump data to the log */
-void otbrDump(otbrLogLevel aLevel, const char *aPrefix, const void *aMemory, size_t aSize)
+void otbrDump(otbrLogLevel aLevel, const char *aLogTag, const char *aPrefix, const void *aMemory, size_t aSize)
{
static const char kHexChars[] = "0123456789abcdef";
assert(aPrefix && (aMemory || aSize == 0));
@@ -173,7 +186,7 @@ void otbrDump(otbrLogLevel aLevel, const char *aPrefix, const void *aMemory, siz
}
*ch = 0;
- syslog(static_cast<int>(aLevel), "%s: %04x: %s", aPrefix, addr, hex);
+ otbrLog(aLevel, aLogTag, "%s: %04x: %s", aPrefix, addr, hex);
}
}
@@ -219,6 +232,18 @@ const char *otbrErrorString(otbrError aError)
error = "Invalid arguments";
break;
+ case OTBR_ERROR_DUPLICATED:
+ error = "Duplicated";
+ break;
+
+ case OTBR_ERROR_ABORTED:
+ error = "Aborted";
+ break;
+
+ case OTBR_ERROR_INVALID_STATE:
+ error = "Invalid state";
+ break;
+
default:
error = "Unknown";
}
diff --git a/src/common/logging.hpp b/src/common/logging.hpp
index a10ac0e7..0e4a50e8 100644
--- a/src/common/logging.hpp
+++ b/src/common/logging.hpp
@@ -50,25 +50,30 @@
*/
typedef enum
{
- OTBR_LOG_EMERG, /* system is unusable */
- OTBR_LOG_ALERT, /* action must be taken immediately */
- OTBR_LOG_CRIT, /* critical conditions */
- OTBR_LOG_ERR, /* error conditions */
- OTBR_LOG_WARNING, /* warning conditions */
- OTBR_LOG_NOTICE, /* normal but significant condition */
- OTBR_LOG_INFO, /* informational */
- OTBR_LOG_DEBUG, /* debug-level messages */
+ OTBR_LOG_EMERG, ///< System is unusable
+ OTBR_LOG_ALERT, ///< Action must be taken immediately
+ OTBR_LOG_CRIT, ///< Critical conditions
+ OTBR_LOG_ERR, ///< Error conditions
+ OTBR_LOG_WARNING, ///< Warning conditions
+ OTBR_LOG_NOTICE, ///< Normal but significant condition
+ OTBR_LOG_INFO, ///< Informational
+ OTBR_LOG_DEBUG, ///< Debug level messages
} otbrLogLevel;
/**
- * Get current log level
+ * Get current log level.
*/
otbrLogLevel otbrLogGetLevel(void);
/**
- * Control log to syslog
+ * Set current log level.
+ */
+void otbrLogSetLevel(otbrLogLevel aLevel);
+
+/**
+ * Control log to syslog.
*
- * @param[in] enable true to log to/via syslog
+ * @param[in] enable True to log to/via syslog.
*
*/
void otbrLogEnableSyslog(bool aEnabled);
@@ -76,9 +81,9 @@ void otbrLogEnableSyslog(bool aEnabled);
/**
* This function initialize the logging service.
*
- * @param[in] aIdent Identity of the logger.
- * @param[in] aLevel Log level of the logger.
- * @param[in] aPrintStderr Whether to log to stderr.
+ * @param[in] aIdent Identity of the logger.
+ * @param[in] aLevel Log level of the logger.
+ * @param[in] aPrintStderr Whether to log to stderr.
*
*/
void otbrLogInit(const char *aIdent, otbrLogLevel aLevel, bool aPrintStderr);
@@ -86,9 +91,9 @@ void otbrLogInit(const char *aIdent, otbrLogLevel aLevel, bool aPrintStderr);
/**
* This function log at level @p aLevel.
*
- * @param[in] aLevel Log level of the logger.
- * @param[in] aLogTag Log tag.
- * @param[in] aFormat Format string as in printf.
+ * @param[in] aLevel Log level of the logger.
+ * @param[in] aLogTag Log tag.
+ * @param[in] aFormat Format string as in printf.
*
*/
void otbrLog(otbrLogLevel aLevel, const char *aLogTag, const char *aFormat, ...);
@@ -96,9 +101,9 @@ void otbrLog(otbrLogLevel aLevel, const char *aLogTag, const char *aFormat, ...)
/**
* This function log at level @p aLevel.
*
- * @param[in] aLevel Log level of the logger.
- * @param[in] aFormat Format string as in printf.
- * @param[in] aArgList The variable-length arguments list.
+ * @param[in] aLevel Log level of the logger.
+ * @param[in] aFormat Format string as in printf.
+ * @param[in] aArgList The variable-length arguments list.
*
*/
void otbrLogv(otbrLogLevel aLevel, const char *aFormat, va_list aArgList);
@@ -106,9 +111,9 @@ void otbrLogv(otbrLogLevel aLevel, const char *aFormat, va_list aArgList);
/**
* This function writes logs without filtering with the log level.
*
- * @param[in] aLevel Log level of the logger.
- * @param[in] aFormat Format string as in printf.
- * @param[in] aArgList The variable-length arguments list.
+ * @param[in] aLevel Log level of the logger.
+ * @param[in] aFormat Format string as in printf.
+ * @param[in] aArgList The variable-length arguments list.
*
*/
void otbrLogvNoFilter(otbrLogLevel aLevel, const char *aFormat, va_list aArgList);
@@ -116,18 +121,19 @@ void otbrLogvNoFilter(otbrLogLevel aLevel, const char *aFormat, va_list aArgList
/**
* This function dump memory as hex string at level @p aLevel.
*
- * @param[in] aLevel Log level of the logger.
- * @param[in] aPrefix String before dumping memory.
- * @param[in] aMemory The pointer to the memory to be dumped.
- * @param[in] aSize The size of memory in bytes to be dumped.
+ * @param[in] aLevel Log level of the logger.
+ * @param[in] aLogTag Log tag.
+ * @param[in] aPrefix String before dumping memory.
+ * @param[in] aMemory The pointer to the memory to be dumped.
+ * @param[in] aSize The size of memory in bytes to be dumped.
*
*/
-void otbrDump(otbrLogLevel aLevel, const char *aPrefix, const void *aMemory, size_t aSize);
+void otbrDump(otbrLogLevel aLevel, const char *aLogTag, const char *aPrefix, const void *aMemory, size_t aSize);
/**
* This function converts error code to string.
*
- * @param[in] aError The error code.
+ * @param[in] aError The error code.
*
* @returns The string information of error.
*
@@ -146,9 +152,9 @@ void otbrLogDeinit(void);
* If @p aError is OTBR_ERROR_NONE, the log level will be OTBR_LOG_INFO,
* otherwise OTBR_LOG_WARNING.
*
- * @param[in] aError The action result.
- * @param[in] aFormat Format string as in printf.
- * @param[in] ... Arguments for the format specification.
+ * @param[in] aError The action result.
+ * @param[in] aFormat Format string as in printf.
+ * @param[in] ... Arguments for the format specification.
*
*/
#define otbrLogResult(aError, aFormat, ...) \
diff --git a/src/common/mainloop.hpp b/src/common/mainloop.hpp
index 4e2ba9ca..91ccb589 100644
--- a/src/common/mainloop.hpp
+++ b/src/common/mainloop.hpp
@@ -61,7 +61,7 @@ public:
/**
* This method updates the mainloop context.
*
- * @param[inout] aMainloop A reference to the mainloop to be updated.
+ * @param[in,out] aMainloop A reference to the mainloop to be updated.
*
*/
virtual void Update(MainloopContext &aMainloop) = 0;
@@ -69,7 +69,7 @@ public:
/**
* This method processes mainloop events.
*
- * @param[in] aMainloop A reference to the mainloop context.
+ * @param[in] aMainloop A reference to the mainloop context.
*
*/
virtual void Process(const MainloopContext &aMainloop) = 0;
diff --git a/src/common/mainloop_manager.hpp b/src/common/mainloop_manager.hpp
index cbb722ba..381ebfb5 100644
--- a/src/common/mainloop_manager.hpp
+++ b/src/common/mainloop_manager.hpp
@@ -40,6 +40,7 @@
#include <list>
+#include "common/code_utils.hpp"
#include "common/mainloop.hpp"
#include "ncp/ncp_openthread.hpp"
@@ -49,7 +50,7 @@ namespace otbr {
* This class implements the mainloop manager.
*
*/
-class MainloopManager
+class MainloopManager : private NonCopyable
{
public:
/**
@@ -61,8 +62,6 @@ public:
/**
* This method returns the singleton instance of the mainloop manager.
*
- * @retval A reference to the mainloop manager.
- *
*/
static MainloopManager &GetInstance(void)
{
@@ -73,7 +72,7 @@ public:
/**
* This method adds a mainloop processors to the mainloop managger.
*
- * @param[in] aMainloopProcessor A pointer to the mainloop processor.
+ * @param[in] aMainloopProcessor A pointer to the mainloop processor.
*
*/
void AddMainloopProcessor(MainloopProcessor *aMainloopProcessor);
@@ -81,7 +80,7 @@ public:
/**
* This method removes a mainloop processors from the mainloop managger.
*
- * @param[in] aMainloopProcessor A pointer to the mainloop processor.
+ * @param[in] aMainloopProcessor A pointer to the mainloop processor.
*
*/
void RemoveMainloopProcessor(MainloopProcessor *aMainloopProcessor);
@@ -89,7 +88,7 @@ public:
/**
* This method updates the mainloop context of all mainloop processors.
*
- * @param[inout] aMainloop A reference to the mainloop to be updated.
+ * @param[in,out] aMainloop A reference to the mainloop to be updated.
*
*/
void Update(MainloopContext &aMainloop);
@@ -97,7 +96,7 @@ public:
/**
* This method processes mainloop events of all mainloop processors.
*
- * @param[in] aMainloop A reference to the mainloop context.
+ * @param[in] aMainloop A reference to the mainloop context.
*
*/
void Process(const MainloopContext &aMainloop);
diff --git a/src/common/task_runner.cpp b/src/common/task_runner.cpp
index 91924512..9a7f154d 100644
--- a/src/common/task_runner.cpp
+++ b/src/common/task_runner.cpp
@@ -70,14 +70,14 @@ TaskRunner::~TaskRunner(void)
}
}
-void TaskRunner::Post(const Task<void> aTask)
+void TaskRunner::Post(Task<void> aTask)
{
Post(Milliseconds::zero(), std::move(aTask));
}
-void TaskRunner::Post(Milliseconds aDelay, const Task<void> aTask)
+TaskRunner::TaskId TaskRunner::Post(Milliseconds aDelay, Task<void> aTask)
{
- PushTask(aDelay, std::move(aTask));
+ return PushTask(aDelay, std::move(aTask));
}
void TaskRunner::Update(MainloopContext &aMainloop)
@@ -85,22 +85,26 @@ void TaskRunner::Update(MainloopContext &aMainloop)
FD_SET(mEventFd[kRead], &aMainloop.mReadFdSet);
aMainloop.mMaxFd = std::max(mEventFd[kRead], aMainloop.mMaxFd);
- if (!mTaskQueue.empty())
{
- auto now = Clock::now();
- auto &task = mTaskQueue.top();
- auto delay = std::chrono::duration_cast<Microseconds>(task.GetTimeExecute() - now);
- auto timeout = FromTimeval<Microseconds>(aMainloop.mTimeout);
+ std::lock_guard<std::mutex> _(mTaskQueueMutex);
- if (task.GetTimeExecute() < now)
+ if (!mTaskQueue.empty())
{
- delay = Microseconds::zero();
- }
+ auto now = Clock::now();
+ auto &task = mTaskQueue.top();
+ auto delay = std::chrono::duration_cast<Microseconds>(task.GetTimeExecute() - now);
+ auto timeout = FromTimeval<Microseconds>(aMainloop.mTimeout);
- if (delay <= timeout)
- {
- aMainloop.mTimeout.tv_sec = delay.count() / 1000000;
- aMainloop.mTimeout.tv_usec = delay.count() % 1000000;
+ if (task.GetTimeExecute() < now)
+ {
+ delay = Microseconds::zero();
+ }
+
+ if (delay <= timeout)
+ {
+ aMainloop.mTimeout.tv_sec = delay.count() / 1000000;
+ aMainloop.mTimeout.tv_usec = delay.count() % 1000000;
+ }
}
}
}
@@ -125,13 +129,21 @@ void TaskRunner::Process(const MainloopContext &aMainloop)
PopTasks();
}
-void TaskRunner::PushTask(Milliseconds aDelay, const Task<void> aTask)
+TaskRunner::TaskId TaskRunner::PushTask(Milliseconds aDelay, Task<void> aTask)
{
- ssize_t rval;
- const uint8_t kOne = 1;
- std::lock_guard<std::mutex> _(mTaskQueueMutex);
+ ssize_t rval;
+ const uint8_t kOne = 1;
+ TaskId taskId;
+
+ {
+ std::lock_guard<std::mutex> _(mTaskQueueMutex);
+
+ taskId = mNextTaskId++;
+
+ mActiveTaskIds.insert(taskId);
+ mTaskQueue.emplace(taskId, aDelay, std::move(aTask));
+ }
- mTaskQueue.emplace(aDelay, std::move(aTask));
do
{
rval = write(mEventFd[kWrite], &kOne, sizeof(kOne));
@@ -147,7 +159,14 @@ void TaskRunner::PushTask(Milliseconds aDelay, const Task<void> aTask)
otbrLogWarning("Failed to write fd %d: %s", mEventFd[kWrite], strerror(errno));
exit:
- return;
+ return taskId;
+}
+
+void TaskRunner::Cancel(TaskRunner::TaskId aTaskId)
+{
+ std::lock_guard<std::mutex> _(mTaskQueueMutex);
+
+ mActiveTaskIds.erase(aTaskId);
}
void TaskRunner::PopTasks(void)
@@ -155,6 +174,7 @@ void TaskRunner::PopTasks(void)
while (true)
{
Task<void> task;
+ bool canceled;
// The braces here are necessary for auto-releasing of the mutex.
{
@@ -162,8 +182,12 @@ void TaskRunner::PopTasks(void)
if (!mTaskQueue.empty() && mTaskQueue.top().GetTimeExecute() <= Clock::now())
{
- task = std::move(mTaskQueue.top().mTask);
+ const DelayedTask &top = mTaskQueue.top();
+ TaskId taskId = top.mTaskId;
+
+ task = std::move(top.mTask);
mTaskQueue.pop();
+ canceled = (mActiveTaskIds.erase(taskId) == 0);
}
else
{
@@ -171,7 +195,10 @@ void TaskRunner::PopTasks(void)
}
}
- task();
+ if (!canceled)
+ {
+ task();
+ }
}
}
diff --git a/src/common/task_runner.hpp b/src/common/task_runner.hpp
index 3aad74a2..1e72e807 100644
--- a/src/common/task_runner.hpp
+++ b/src/common/task_runner.hpp
@@ -41,7 +41,9 @@
#include <future>
#include <mutex>
#include <queue>
+#include <set>
+#include "common/code_utils.hpp"
#include "common/mainloop.hpp"
#include "common/time.hpp"
@@ -52,7 +54,7 @@ namespace otbr {
* tasks on the mainloop.
*
*/
-class TaskRunner : public MainloopProcessor
+class TaskRunner : public MainloopProcessor, private NonCopyable
{
public:
/**
@@ -62,6 +64,14 @@ public:
template <class T> using Task = std::function<T(void)>;
/**
+ * This type represents a unique task ID to an delayed task.
+ *
+ * Note: A valid task ID is never zero.
+ *
+ */
+ typedef uint64_t TaskId;
+
+ /**
* This constructor initializes the Task Runner instance.
*
*/
@@ -79,21 +89,33 @@ public:
* Tasks are executed sequentially and follow the First-Come-First-Serve rule.
* It is safe to call this method in different threads concurrently.
*
- * @param[in] aTask The task to be executed.
+ * @param[in] aTask The task to be executed.
*
*/
- void Post(const Task<void> aTask);
+ void Post(Task<void> aTask);
/**
* This method posts a task to the task runner and returns immediately.
*
* The task will be executed on the mainloop after `aDelay` milliseconds from now.
+ * It is safe to call this method in different threads concurrently.
*
- * @param[in] aDelay The delay before executing the task (in milliseconds).
- * @param[in] aTask The task to be executed.
+ * @param[in] aDelay The delay before executing the task (in milliseconds).
+ * @param[in] aTask The task to be executed.
+ *
+ * @returns The unique task ID of the delayed task.
*
*/
- void Post(Milliseconds aDelay, const Task<void> aTask);
+ TaskId Post(Milliseconds aDelay, Task<void> aTask);
+
+ /**
+ * This method cancels a delayed task from the task runner.
+ * It is safe to call this method in different threads concurrently.
+ *
+ * @param[in] aTaskId The unique task ID of the delayed task to cancel.
+ *
+ */
+ void Cancel(TaskId aTaskId);
/**
* This method posts a task and waits for the completion of the task.
@@ -102,32 +124,19 @@ public:
* This method must be called in a thread other than the mainloop thread. Otherwise,
* the caller will be blocked forever.
*
- * @returns The result returned by the task @p aTask.
+ * @returns The result returned by the task @p aTask.
*
*/
template <class T> T PostAndWait(const Task<T> &aTask)
{
std::promise<T> pro;
- Post([&]() { pro.set_value(aTask()); });
+ Post([&pro, &aTask]() { pro.set_value(aTask()); });
return pro.get_future().get();
}
- /**
- * This method updates the mainloop context.
- *
- * @param[inout] aMainloop A reference to the mainloop to be updated.
- *
- */
void Update(MainloopContext &aMainloop) override;
-
- /**
- * This method processes mainloop events.
- *
- * @param[in] aMainloop A reference to the mainloop context.
- *
- */
void Process(const MainloopContext &aMainloop) override;
private:
@@ -146,28 +155,27 @@ private:
bool operator()(const DelayedTask &aLhs, const DelayedTask &aRhs) const { return aRhs < aLhs; }
};
- DelayedTask(Milliseconds aDelay, Task<void> aTask)
- : mTimeCreated(Clock::now())
- , mDelay(aDelay)
+ DelayedTask(TaskId aTaskId, Milliseconds aDelay, Task<void> aTask)
+ : mTaskId(aTaskId)
+ , mDeadline(Clock::now() + aDelay)
, mTask(std::move(aTask))
{
}
bool operator<(const DelayedTask &aOther) const
{
- return GetTimeExecute() <= aOther.GetTimeExecute() ||
- (GetTimeExecute() == aOther.GetTimeExecute() && mTimeCreated < aOther.mTimeCreated);
+ return mDeadline <= aOther.mDeadline || (mDeadline == aOther.mDeadline && mTaskId < aOther.mTaskId);
}
- Timepoint GetTimeExecute(void) const { return mTimeCreated + mDelay; }
+ Timepoint GetTimeExecute(void) const { return mDeadline; }
- Timepoint mTimeCreated;
- Milliseconds mDelay;
- Task<void> mTask;
+ TaskId mTaskId;
+ Timepoint mDeadline;
+ Task<void> mTask;
};
- void PushTask(Milliseconds aDelay, const Task<void> aTask);
- void PopTasks(void);
+ TaskId PushTask(Milliseconds aDelay, Task<void> aTask);
+ void PopTasks(void);
// The event fds which are used to wakeup the mainloop
// when there are pending tasks in the task queue.
@@ -175,6 +183,9 @@ private:
std::priority_queue<DelayedTask, std::vector<DelayedTask>, DelayedTask::Comparator> mTaskQueue;
+ std::set<TaskId> mActiveTaskIds;
+ TaskId mNextTaskId = 1;
+
// The mutex which protects the `mTaskQueue` from being
// simultaneously accessed by multiple threads.
std::mutex mTaskQueueMutex;
diff --git a/src/common/tlv.hpp b/src/common/tlv.hpp
index f94d41a7..16bc00ad 100644
--- a/src/common/tlv.hpp
+++ b/src/common/tlv.hpp
@@ -131,7 +131,7 @@ public:
/**
* This method sets a uint64_t as the value.
*
- * @param[in] aValue The uint64_t value.
+ * @param[in] aValue The uint64_t value.
*
*/
void SetValue(uint64_t aValue)
@@ -149,7 +149,7 @@ public:
/**
* This method sets a uint32_t as the value.
*
- * @param[in] aValue The uint32_t value.
+ * @param[in] aValue The uint32_t value.
*
*/
void SetValue(uint32_t aValue)
@@ -167,7 +167,7 @@ public:
/**
* This method sets uint16_t as the value.
*
- * @param[in] aValue uint16_t value
+ * @param[in] aValue The uint16_t value.
*
*/
void SetValue(uint16_t aValue)
@@ -183,7 +183,7 @@ public:
/**
* This method sets uint8_t as the value.
*
- * @param[in] aValue uint8_t value
+ * @param[in] aValue The uint8_t value.
*
*/
void SetValue(uint8_t aValue)
@@ -195,7 +195,7 @@ public:
/**
* This method sets int8_t as the value.
*
- * @param[in] aValue int8_t value
+ * @param[in] aValue The int8_t value.
*
*/
void SetValue(int8_t aValue)
diff --git a/src/common/types.hpp b/src/common/types.hpp
index f7085ade..6035c1cb 100644
--- a/src/common/types.hpp
+++ b/src/common/types.hpp
@@ -54,6 +54,7 @@
#define OTBR_IP6_ADDRESS_SIZE 16
#define OTBR_IP6_PREFIX_SIZE 8
+#define OTBR_IP4_ADDRESS_SIZE 4
#define OTBR_NETWORK_KEY_SIZE 16
#define OTBR_PSKC_SIZE 16
@@ -70,17 +71,20 @@ enum otbrError
{
OTBR_ERROR_NONE = 0, ///< No error.
- OTBR_ERROR_ERRNO = -1, ///< Error defined by errno.
- OTBR_ERROR_DBUS = -2, ///< DBus error.
- OTBR_ERROR_MDNS = -3, ///< mDNS error.
- OTBR_ERROR_OPENTHREAD = -4, ///< OpenThread error.
- OTBR_ERROR_REST = -5, ///< Rest Server error.
- OTBR_ERROR_SMCROUTE = -6, ///< SMCRoute error.
- OTBR_ERROR_NOT_FOUND = -7, ///< Not found.
- OTBR_ERROR_PARSE = -8, ///< Parse error.
- OTBR_ERROR_NOT_IMPLEMENTED = -9, ///< Not implemented error.
- OTBR_ERROR_INVALID_ARGS = -10, ///< Invalid arguments error.
- OTBR_ERROR_DUPLICATED = -11, ///< Duplicated operation, resource or name.
+ OTBR_ERROR_ERRNO = -1, ///< Error defined by errno.
+ OTBR_ERROR_DBUS = -2, ///< DBus error.
+ OTBR_ERROR_MDNS = -3, ///< mDNS error.
+ OTBR_ERROR_OPENTHREAD = -4, ///< OpenThread error.
+ OTBR_ERROR_REST = -5, ///< Rest Server error.
+ OTBR_ERROR_SMCROUTE = -6, ///< SMCRoute error.
+ OTBR_ERROR_NOT_FOUND = -7, ///< Not found.
+ OTBR_ERROR_PARSE = -8, ///< Parse error.
+ OTBR_ERROR_NOT_IMPLEMENTED = -9, ///< Not implemented error.
+ OTBR_ERROR_INVALID_ARGS = -10, ///< Invalid arguments error.
+ OTBR_ERROR_DUPLICATED = -11, ///< Duplicated operation, resource or name.
+ OTBR_ERROR_ABORTED = -12, ///< The operation is aborted.
+ OTBR_ERROR_INVALID_STATE = -13, ///< The target isn't in a valid state.
+ OTBR_ERROR_INFRA_LINK_CHANGED = -14, ///< The infrastructure link is changed.
};
namespace otbr {
@@ -117,7 +121,7 @@ public:
/**
* Constructor with an 16-bit Thread locator.
*
- * @param[in] aLocator 16-bit Thread locator, RLOC or ALOC.
+ * @param[in] aLocator The 16-bit Thread locator, RLOC or ALOC.
*
*/
Ip6Address(uint16_t aLocator)
@@ -132,7 +136,7 @@ public:
/**
* Constructor with an Ip6 address.
*
- * @param[in] aAddress The Ip6 address.
+ * @param[in] aAddress The Ip6 address.
*
*/
Ip6Address(const uint8_t (&aAddress)[16]);
@@ -142,7 +146,7 @@ public:
*
* @param[in] aOther The other Ip6 address to compare with.
*
- * @returns Whether the Ip6 address is smaller than the other address.
+ * @returns Whether the Ip6 address is smaller than the other address.
*
*/
bool operator<(const Ip6Address &aOther) const { return memcmp(this, &aOther, sizeof(Ip6Address)) < 0; }
@@ -152,7 +156,7 @@ public:
*
* @param[in] aOther The other Ip6 address to compare with.
*
- * @returns Whether the Ip6 address is equal to the other address.
+ * @returns Whether the Ip6 address is equal to the other address.
*
*/
bool operator==(const Ip6Address &aOther) const { return m64[0] == aOther.m64[0] && m64[1] == aOther.m64[1]; }
@@ -193,7 +197,7 @@ public:
/**
* This method returns if the Ip6 address is a multicast address.
*
- * @returns Whether the Ip6 address is a multicast address.
+ * @returns Whether the Ip6 address is a multicast address.
*
*/
bool IsMulticast(void) const { return m8[0] == 0xff; }
@@ -201,7 +205,7 @@ public:
/**
* This method returns if the Ip6 address is a link-local address.
*
- * @returns Whether the Ip6 address is a link-local address.
+ * @returns Whether the Ip6 address is a link-local address.
*
*/
bool IsLinkLocal(void) const { return (m16[0] & bswap_16(0xffc0)) == bswap_16(0xfe80); }
@@ -244,8 +248,8 @@ public:
/**
* This function converts Ip6 addresses from text to `Ip6Address`.
*
- * @param[in] aStr The Ip6 address text.
- * @param[out] aAddr A reference to `Ip6Address` to output the Ip6 address.
+ * @param[in] aStr The Ip6 address text.
+ * @param[out] aAddr A reference to `Ip6Address` to output the Ip6 address.
*
* @retval OTBR_ERROR_NONE If the Ip6 address was successfully converted.
* @retval OTBR_ERROR_INVALID_ARGS If @p `aStr` is not a valid string representing of Ip6 address.
@@ -335,7 +339,7 @@ public:
/**
* This method returns if the Ip6 prefix is valid.
*
- * @returns If the Ip6 prefix is valid.
+ * @returns If the Ip6 prefix is valid.
*
*/
bool IsValid(void) const { return mLength > 0 && mLength <= 128; }
@@ -376,6 +380,36 @@ public:
};
};
+struct MdnsResponseCounters
+{
+ uint32_t mSuccess; ///< The number of successful responses
+ uint32_t mNotFound; ///< The number of 'not found' responses
+ uint32_t mInvalidArgs; ///< The number of 'invalid arg' responses
+ uint32_t mDuplicated; ///< The number of 'duplicated' responses
+ uint32_t mNotImplemented; ///< The number of 'not implemented' responses
+ uint32_t mUnknownError; ///< The number of unknown error responses
+};
+
+struct MdnsTelemetryInfo
+{
+ static constexpr uint32_t kEmaFactorNumerator = 1;
+ static constexpr uint32_t kEmaFactorDenominator = 2;
+
+ static_assert(kEmaFactorNumerator > 0, "kEmaFactorNumerator must be greater than 0");
+ static_assert(kEmaFactorDenominator > kEmaFactorNumerator,
+ "kEmaFactorDenominator must be greater than kEmaFactorNumerator");
+
+ MdnsResponseCounters mHostRegistrations;
+ MdnsResponseCounters mServiceRegistrations;
+ MdnsResponseCounters mHostResolutions;
+ MdnsResponseCounters mServiceResolutions;
+
+ uint32_t mHostRegistrationEmaLatency; ///< The EMA latency of host registrations in milliseconds
+ uint32_t mServiceRegistrationEmaLatency; ///< The EMA latency of service registrations in milliseconds
+ uint32_t mHostResolutionEmaLatency; ///< The EMA latency of host resolutions in milliseconds
+ uint32_t mServiceResolutionEmaLatency; ///< The EMA latency of service resolutions in milliseconds
+};
+
} // namespace otbr
#endif // OTBR_COMMON_TYPES_HPP_
diff --git a/src/dbus/client/thread_api_dbus.cpp b/src/dbus/client/thread_api_dbus.cpp
index 57ffed34..cc9bb2be 100644
--- a/src/dbus/client/thread_api_dbus.cpp
+++ b/src/dbus/client/thread_api_dbus.cpp
@@ -123,6 +123,7 @@ DBusHandlerResult ThreadApiDBus::sDBusMessageFilter(DBusConnection *aConnection,
DBusHandlerResult ThreadApiDBus::DBusMessageFilter(DBusConnection *aConnection, DBusMessage *aMessage)
{
+ DBusHandlerResult handled = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
OTBR_UNUSED_VARIABLE(aConnection);
DBusMessageIter iter, subIter, dictEntryIter, valIter;
@@ -150,9 +151,10 @@ DBusHandlerResult ThreadApiDBus::DBusMessageFilter(DBusConnection *aConnection,
{
f(role);
}
+ handled = DBUS_HANDLER_RESULT_HANDLED;
exit:
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ return handled;
}
void ThreadApiDBus::AddDeviceRoleHandler(const DeviceRoleHandler &aHandler)
@@ -192,6 +194,39 @@ void ThreadApiDBus::ScanPendingCallHandler(DBusPendingCall *aPending)
mScanHandler = nullptr;
}
+ClientError ThreadApiDBus::EnergyScan(uint32_t aScanDuration, const EnergyScanHandler &aHandler)
+{
+ ClientError error = ClientError::ERROR_NONE;
+ const auto args = std::tie(aScanDuration);
+
+ VerifyOrExit(mEnergyScanHandler == nullptr, error = ClientError::OT_ERROR_INVALID_STATE);
+ mEnergyScanHandler = aHandler;
+
+ error = CallDBusMethodAsync(OTBR_DBUS_ENERGY_SCAN_METHOD, args,
+ &ThreadApiDBus::sHandleDBusPendingCall<&ThreadApiDBus::EnergyScanPendingCallHandler>);
+ if (error != ClientError::ERROR_NONE)
+ {
+ mEnergyScanHandler = nullptr;
+ }
+exit:
+ return error;
+}
+
+void ThreadApiDBus::EnergyScanPendingCallHandler(DBusPendingCall *aPending)
+{
+ std::vector<EnergyScanResult> results;
+ UniqueDBusMessage message(dbus_pending_call_steal_reply(aPending));
+ auto args = std::tie(results);
+
+ if (message != nullptr)
+ {
+ DBusMessageToTuple(*message, args);
+ }
+
+ mEnergyScanHandler(results);
+ mEnergyScanHandler = nullptr;
+}
+
ClientError ThreadApiDBus::PermitUnsecureJoin(uint16_t aPort, uint32_t aSeconds)
{
return CallDBusMethodSync(OTBR_DBUS_PERMIT_UNSECURE_JOIN_METHOD, std::tie(aPort, aSeconds));
@@ -267,6 +302,45 @@ void ThreadApiDBus::AttachPendingCallHandler(DBusPendingCall *aPending)
handler(ret);
}
+ClientError ThreadApiDBus::Detach(const OtResultHandler &aHandler)
+{
+ ClientError error = ClientError::ERROR_NONE;
+
+ VerifyOrExit(mDetachHandler == nullptr && mJoinerHandler == nullptr, error = ClientError::OT_ERROR_INVALID_STATE);
+ mDetachHandler = aHandler;
+
+ if (aHandler)
+ {
+ error = CallDBusMethodAsync(OTBR_DBUS_DETACH_METHOD,
+ &ThreadApiDBus::sHandleDBusPendingCall<&ThreadApiDBus::DetachPendingCallHandler>);
+ }
+ else
+ {
+ error = CallDBusMethodSync(OTBR_DBUS_DETACH_METHOD);
+ }
+ if (error != ClientError::ERROR_NONE)
+ {
+ mDetachHandler = nullptr;
+ }
+exit:
+ return error;
+}
+
+void ThreadApiDBus::DetachPendingCallHandler(DBusPendingCall *aPending)
+{
+ ClientError ret = ClientError::OT_ERROR_FAILED;
+ UniqueDBusMessage message(dbus_pending_call_steal_reply(aPending));
+ auto handler = mDetachHandler;
+
+ if (message != nullptr)
+ {
+ ret = CheckErrorMessage(message.get());
+ }
+
+ mDetachHandler = nullptr;
+ handler(ret);
+}
+
ClientError ThreadApiDBus::FactoryReset(const OtResultHandler &aHandler)
{
ClientError error = ClientError::ERROR_NONE;
@@ -544,6 +618,11 @@ ClientError ThreadApiDBus::GetExternalRoutes(std::vector<ExternalRoute> &aExtern
return GetProperty(OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES, aExternalRoutes);
}
+ClientError ThreadApiDBus::GetOnMeshPrefixes(std::vector<OnMeshPrefix> &aOnMeshPrefixes)
+{
+ return GetProperty(OTBR_DBUS_PROPERTY_ON_MESH_PREFIXES, aOnMeshPrefixes);
+}
+
ClientError ThreadApiDBus::GetActiveDatasetTlvs(std::vector<uint8_t> &aDataset)
{
return GetProperty(OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, aDataset);
@@ -554,6 +633,23 @@ ClientError ThreadApiDBus::GetRadioRegion(std::string &aRadioRegion)
return GetProperty(OTBR_DBUS_PROPERTY_RADIO_REGION, aRadioRegion);
}
+ClientError ThreadApiDBus::GetSrpServerInfo(SrpServerInfo &aSrpServerInfo)
+{
+ return GetProperty(OTBR_DBUS_PROPERTY_SRP_SERVER_INFO, aSrpServerInfo);
+}
+
+ClientError ThreadApiDBus::GetMdnsTelemetryInfo(MdnsTelemetryInfo &aMdnsTelemetryInfo)
+{
+ return GetProperty(OTBR_DBUS_PROPERTY_MDNS_TELEMETRY_INFO, aMdnsTelemetryInfo);
+}
+
+#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
+ClientError ThreadApiDBus::GetDnssdCounters(DnssdCounters &aDnssdCounters)
+{
+ return GetProperty(OTBR_DBUS_PROPERTY_DNSSD_COUNTERS, aDnssdCounters);
+}
+#endif
+
std::string ThreadApiDBus::GetInterfaceName(void)
{
return mInterfaceName;
@@ -719,5 +815,11 @@ ClientError ThreadApiDBus::AttachAllNodesTo(const std::vector<uint8_t> &aDataset
return CallDBusMethodSync(OTBR_DBUS_ATTACH_ALL_NODES_TO_METHOD, args);
}
+ClientError ThreadApiDBus::UpdateVendorMeshCopTxtEntries(std::vector<TxtEntry> &aUpdate)
+{
+ auto args = std::tie(aUpdate);
+ return CallDBusMethodSync(OTBR_DBUS_UPDATE_VENDOR_MESHCOP_TXT_METHOD, args);
+}
+
} // namespace DBus
} // namespace otbr
diff --git a/src/dbus/client/thread_api_dbus.hpp b/src/dbus/client/thread_api_dbus.hpp
index 006dbca6..8ab2bcaf 100644
--- a/src/dbus/client/thread_api_dbus.hpp
+++ b/src/dbus/client/thread_api_dbus.hpp
@@ -53,6 +53,7 @@ class ThreadApiDBus
public:
using DeviceRoleHandler = std::function<void(DeviceRole)>;
using ScanHandler = std::function<void(const std::vector<ActiveScanResult> &)>;
+ using EnergyScanHandler = std::function<void(const std::vector<EnergyScanResult> &)>;
using OtResultHandler = std::function<void(ClientError)>;
/**
@@ -60,7 +61,7 @@ public:
*
* Will use the default interfacename
*
- * @param[in] aConnection The dbus connection.
+ * @param[in] aConnection The dbus connection.
*
*/
ThreadApiDBus(DBusConnection *aConnection);
@@ -68,8 +69,8 @@ public:
/**
* The constructor of a d-bus object.
*
- * @param[in] aConnection The dbus connection.
- * @param[in] aInterfaceName The network interface name.
+ * @param[in] aConnection The dbus connection.
+ * @param[in] aInterfaceName The network interface name.
*
*/
ThreadApiDBus(DBusConnection *aConnection, const std::string &aInterfaceName);
@@ -77,7 +78,7 @@ public:
/**
* This method adds a callback for device role change.
*
- * @param[in] aHandler The device role handler.
+ * @param[in] aHandler The device role handler.
*
*/
void AddDeviceRoleHandler(const DeviceRoleHandler &aHandler);
@@ -85,12 +86,12 @@ public:
/**
* This method permits unsecure join on port.
*
- * @param[in] aPort The port number.
- * @param[in] aSeconds The timeout to close the port, 0 for never close.
+ * @param[in] aPort The port number.
+ * @param[in] aSeconds The timeout to close the port, 0 for never close.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError PermitUnsecureJoin(uint16_t aPort, uint32_t aSeconds);
@@ -98,28 +99,43 @@ public:
/**
* This method performs a Thread network scan.
*
- * @param[in] aHandler The scan result handler.
+ * @param[in] aHandler The scan result handler.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError Scan(const ScanHandler &aHandler);
/**
+ * This method performs an IEEE 802.15.4 Energy Scan.
+ *
+ * @param[in] aScanDuration The duration for the scan for each channel, in milliseconds. Note that maximum value
+ * for the duration is currently 65535. If it's the duration is larger than that, the
+ * handler will get an INVALID_ARGS error code.
+ * @param[in] aHandler The energy scan result handler.
+ *
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
+ *
+ */
+ ClientError EnergyScan(uint32_t aScanDuration, const EnergyScanHandler &aHandler);
+
+ /**
* This method attaches the device to the Thread network.
- * @param[in] aNetworkName The network name.
- * @param[in] aPanId The pan id, UINT16_MAX for random.
- * @param[in] aExtPanId The extended pan id, UINT64_MAX for random.
- * @param[in] aNetworkKey The network key, empty for random.
- * @param[in] aPSKc The pre-shared commissioner key, empty for random.
- * @param[in] aChannelMask A bitmask for valid channels, will random select one.
- * @param[in] aHandler The attach result handler.
+ * @param[in] aNetworkName The network name.
+ * @param[in] aPanId The pan id, UINT16_MAX for random.
+ * @param[in] aExtPanId The extended pan id, UINT64_MAX for random.
+ * @param[in] aNetworkKey The network key, empty for random.
+ * @param[in] aPSKc The pre-shared commissioner key, empty for random.
+ * @param[in] aChannelMask A bitmask for valid channels, will random select one.
+ * @param[in] aHandler The attach result handler.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError Attach(const std::string & aNetworkName,
@@ -136,22 +152,32 @@ public:
* The network parameters will be set with the active dataset under this
* circumstance.
*
- * @param[in] aHandler The attach result handler.
+ * @param[in] aHandler The attach result handler.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError Attach(const OtResultHandler &aHandler);
/**
+ * This method detaches the device from the Thread network.
+ *
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
+ *
+ */
+ ClientError Detach(const OtResultHandler &aHandler);
+
+ /**
* This method attaches the device to the specified Thread network.
*
* If the device has already attached to a network, send a request to migrate the existing network.
*
- * @param[in] aDataset The Operational Dataset that contains parameter values of the Thread network to attach
- * to. It must have a valid Delay Timer and Pending Timestamp.
+ * @param[in] aDataset The Operational Dataset that contains parameter values of the Thread network to attach
+ * to. It must have a valid Delay Timer and Pending Timestamp.
*
* @retval ERROR_NONE Successfully requested the Thread network migration.
* @retval ERROR_DBUS D-Bus encode/decode error.
@@ -167,11 +193,11 @@ public:
/**
* This method performs a factory reset.
*
- * @param[in] aHandler The reset result handler.
+ * @param[in] aHandler The reset result handler.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError FactoryReset(const OtResultHandler &aHandler);
@@ -179,9 +205,9 @@ public:
/**
* This method performs a soft reset.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError Reset(void);
@@ -191,17 +217,17 @@ public:
*
* @note The joiner start and the attach proccesses are exclusive
*
- * @param[in] aPskd The pre-shared key for device.
- * @param[in] aProvisioningUrl The provision url.
- * @param[in] aVendorName The vendor name.
- * @param[in] aVendorModel The vendor model.
- * @param[in] aVendorSwVersion The vendor software version.
- * @param[in] aVendorData The vendor custom data.
- * @param[in] aHandler The join result handler.
+ * @param[in] aPskd The pre-shared key for device.
+ * @param[in] aProvisioningUrl The provision url.
+ * @param[in] aVendorName The vendor name.
+ * @param[in] aVendorModel The vendor model.
+ * @param[in] aVendorSwVersion The vendor software version.
+ * @param[in] aVendorData The vendor custom data.
+ * @param[in] aHandler The join result handler.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError JoinerStart(const std::string & aPskd,
@@ -215,9 +241,9 @@ public:
/**
* This method stops the joiner process
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError JoinerStop(void);
@@ -225,11 +251,11 @@ public:
/**
* This method adds a on-mesh address prefix.
*
- * @param[in] aPrefix The address prefix.
+ * @param[in] aPrefix The address prefix.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError AddOnMeshPrefix(const OnMeshPrefix &aPrefix);
@@ -237,11 +263,11 @@ public:
/**
* This method removes a on-mesh address prefix.
*
- * @param[in] aPrefix The address prefix.
+ * @param[in] aPrefix The address prefix.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError RemoveOnMeshPrefix(const Ip6Prefix &aPrefix);
@@ -249,11 +275,11 @@ public:
/**
* This method adds an external route.
*
- * @param[in] aExternalroute The external route config
+ * @param[in] aExternalroute The external route config
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError AddExternalRoute(const ExternalRoute &aExternalRoute);
@@ -261,11 +287,11 @@ public:
/**
* This method removes an external route.
*
- * @param[in] aPrefix The route prefix.
+ * @param[in] aPrefix The route prefix.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError RemoveExternalRoute(const Ip6Prefix &aPrefix);
@@ -273,11 +299,11 @@ public:
/**
* This method sets the mesh-local prefix.
*
- * @param[in] aPrefix The address prefix.
+ * @param[in] aPrefix The address prefix.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError SetMeshLocalPrefix(const std::array<uint8_t, OTBR_IP6_PREFIX_SIZE> &aPrefix);
@@ -285,11 +311,11 @@ public:
/**
* This method sets the legacy prefix of ConnectIP.
*
- * @param[in] aPrefix The address prefix.
+ * @param[in] aPrefix The address prefix.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError SetLegacyUlaPrefix(const std::array<uint8_t, OTBR_IP6_PREFIX_SIZE> &aPrefix);
@@ -297,11 +323,11 @@ public:
/**
* This method sets the active operational dataset.
*
- * @param[out] aDataset The active operational dataset
+ * @param[out] aDataset The active operational dataset
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError SetActiveDatasetTlvs(const std::vector<uint8_t> &aDataset);
@@ -309,11 +335,11 @@ public:
/**
* This method sets the link operating mode.
*
- * @param[in] aConfig The operating mode config.
+ * @param[in] aConfig The operating mode config.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError SetLinkMode(const LinkModeConfig &aConfig);
@@ -321,11 +347,11 @@ public:
/**
* This method sets the radio region.
*
- * @param[in] aRadioRegion The radio region.
+ * @param[in] aRadioRegion The radio region.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError SetRadioRegion(const std::string &aRadioRegion);
@@ -333,11 +359,11 @@ public:
/**
* This method gets the link operating mode.
*
- * @param[out] aConfig The operating mode config.
+ * @param[out] aConfig The operating mode config.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetLinkMode(LinkModeConfig &aConfig);
@@ -345,11 +371,11 @@ public:
/**
* This method gets the current device role.
*
- * @param[out] aDeviceRole The device role
+ * @param[out] aDeviceRole The device role
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetDeviceRole(DeviceRole &aDeviceRole);
@@ -357,11 +383,11 @@ public:
/**
* This method gets the network name.
*
- * @param[out] aName The network name.
+ * @param[out] aName The network name.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetNetworkName(std::string &aName);
@@ -369,11 +395,11 @@ public:
/**
* This method gets the network pan id.
*
- * @param[out] aPanId The pan id.
+ * @param[out] aPanId The pan id.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetPanId(uint16_t &aPanId);
@@ -381,11 +407,11 @@ public:
/**
* This method gets the extended pan id.
*
- * @param[out] aExtPanId The extended pan id.
+ * @param[out] aExtPanId The extended pan id.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetExtPanId(uint64_t &aExtPanId);
@@ -393,11 +419,11 @@ public:
/**
* This method gets the extended pan id.
*
- * @param[out] aChannel The extended pan id.
+ * @param[out] aChannel The extended pan id.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetChannel(uint16_t &aChannel);
@@ -405,11 +431,11 @@ public:
/**
* This method gets the network network key.
*
- * @param[out] aNetworkKey The network network key.
+ * @param[out] aNetworkKey The network network key.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetNetworkKey(std::vector<uint8_t> &aNetworkKey);
@@ -417,11 +443,11 @@ public:
/**
* This method gets the Clear Channel Assessment failure rate.
*
- * @param[out] aFailureRate The failure rate.
+ * @param[out] aFailureRate The failure rate.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetCcaFailureRate(uint16_t &aFailureRate);
@@ -429,11 +455,11 @@ public:
/**
* This method gets the mac level statistics counters.
*
- * @param[out] aCounters The statistic counters.
+ * @param[out] aCounters The statistic counters.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetLinkCounters(MacCounters &aCounters); // For telemetry
@@ -441,11 +467,11 @@ public:
/**
* This method gets the ip level statistics counters.
*
- * @param[out] aCounters The statistic counters.
+ * @param[out] aCounters The statistic counters.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetIp6Counters(IpCounters &aCounters); // For telemetry
@@ -453,11 +479,11 @@ public:
/**
* This method gets the supported channel mask.
*
- * @param[out] aChannelMask The channel mask.
+ * @param[out] aChannelMask The channel mask.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetSupportedChannelMask(uint32_t &aChannelMask);
@@ -465,11 +491,11 @@ public:
/**
* This method gets the Thread routing locator
*
- * @param[out] aRloc16 The routing locator
+ * @param[out] aRloc16 The routing locator
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetRloc16(uint16_t &aRloc16);
@@ -477,11 +503,11 @@ public:
/**
* This method gets 802.15.4 extended address
*
- * @param[out] aExtendedAddress The extended address
+ * @param[out] aExtendedAddress The extended address
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetExtendedAddress(uint64_t &aExtendedAddress);
@@ -489,12 +515,12 @@ public:
/**
* This method gets the node's router id.
*
- * @param[out] aRouterId The router id.
+ * @param[out] aRouterId The router id.
*
- * @retval ERROR_NONE Successfully performed the dbus function call.
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval OT_ERROR_INVALID_STATE The node is not a router.
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call.
+ * @retval ERROR_DBUS dbus encode/decode error.
+ * @retval OT_ERROR_INVALID_STATE The node is not a router.
+ * @retval ... OpenThread defined error value otherwise.
*
*/
ClientError GetRouterId(uint8_t &aRouterId);
@@ -502,11 +528,11 @@ public:
/**
* This method gets the network's leader data.
*
- * @param[out] aLeaderData The leader data.
+ * @param[out] aLeaderData The leader data.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetLeaderData(LeaderData &aLeaderData);
@@ -514,11 +540,11 @@ public:
/**
* This method gets the network data.
*
- * @param[out] aNetworkData The network data.
+ * @param[out] aNetworkData The network data.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetNetworkData(std::vector<uint8_t> &aNetworkData);
@@ -526,11 +552,11 @@ public:
/**
* This method gets the stable network data.
*
- * @param[out] aNetworkData The stable network data.
+ * @param[out] aNetworkData The stable network data.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetStableNetworkData(std::vector<uint8_t> &aNetworkData);
@@ -538,11 +564,11 @@ public:
/**
* This method gets the node's local leader weight.
*
- * @param[out] aWeight The local leader weight.
+ * @param[out] aWeight The local leader weight.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetLocalLeaderWeight(uint8_t &aWeight);
@@ -550,11 +576,11 @@ public:
/**
* This method gets the channel monitor sample count.
*
- * @param[out] aSampleCount The channel monitor sample count.
+ * @param[out] aSampleCount The channel monitor sample count.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetChannelMonitorSampleCount(uint32_t &aSampleCount);
@@ -562,11 +588,11 @@ public:
/**
* This method gets the channel qualities
*
- * @param[out] aChannelQualities The channel qualities.
+ * @param[out] aChannelQualities The channel qualities.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetChannelMonitorAllChannelQualities(std::vector<ChannelQuality> &aChannelQualities);
@@ -574,11 +600,11 @@ public:
/**
* This method gets the child table.
*
- * @param[out] aChildTable The child table.
+ * @param[out] aChildTable The child table.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetChildTable(std::vector<ChildInfo> &aChildTable);
@@ -586,11 +612,11 @@ public:
/**
* This method gets the neighbor table.
*
- * @param[out] aNeighborTable The neighbor table.
+ * @param[out] aNeighborTable The neighbor table.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetNeighborTable(std::vector<NeighborInfo> &aNeighborTable);
@@ -598,11 +624,11 @@ public:
/**
* This method gets the network's parition id.
*
- * @param[out] aPartitionId The partition id.
+ * @param[out] aPartitionId The partition id.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetPartitionId(uint32_t &aPartitionId);
@@ -610,11 +636,11 @@ public:
/**
* This method gets the rssi of the latest packet.
*
- * @param[out] aRssi The rssi of the latest packet.
+ * @param[out] aRssi The rssi of the latest packet.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetInstantRssi(int8_t &aRssi);
@@ -622,11 +648,11 @@ public:
/**
* This method gets the radio transmit power.
*
- * @param[out] aTxPower The radio transmit power.
+ * @param[out] aTxPower The radio transmit power.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetRadioTxPower(int8_t &aTxPower);
@@ -634,23 +660,35 @@ public:
/**
* This method gets the external route table
*
- * @param[out] aExternalRoutes The external route table
+ * @param[out] aExternalRoutes The external route table
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetExternalRoutes(std::vector<ExternalRoute> &aExternalRoutes);
/**
+ * This method gets the on-mesh prefixes
+ *
+ * @param[out] aOnMeshPrefixes The on-mesh prefixes
+ *
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
+ *
+ */
+ ClientError GetOnMeshPrefixes(std::vector<OnMeshPrefix> &aOnMeshPrefixes);
+
+ /**
* This method gets the active operational dataset
*
- * @param[out] aDataset The active operational dataset
+ * @param[out] aDataset The active operational dataset
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetActiveDatasetTlvs(std::vector<uint8_t> &aDataset);
@@ -658,16 +696,54 @@ public:
/**
* This method gets the radio region.
*
- * @param[out] aRadioRegion The radio region.
+ * @param[out] aRadioRegion The radio region.
*
- * @retval ERROR_NONE successfully performed the dbus function call
- * @retval ERROR_DBUS dbus encode/decode error
- * @retval ... OpenThread defined error value otherwise
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
*
*/
ClientError GetRadioRegion(std::string &aRadioRegion);
/**
+ * This method gets the SRP server information.
+ *
+ * @param[out] aSrpServerInfo The SRP server information.
+ *
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
+ *
+ */
+ ClientError GetSrpServerInfo(SrpServerInfo &aSrpServerInfo);
+
+ /**
+ * This method gets the MDNS telemetry information.
+ *
+ * @param[out] aMdnsTelemetryInfo The MDNS telemetry information.
+ *
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
+ *
+ */
+ ClientError GetMdnsTelemetryInfo(MdnsTelemetryInfo &aMdnsTelemetryInfo);
+
+#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
+ /**
+ * This method gets the DNS-SD counters.
+ *
+ * @param[out] aDnssdCounters The DNS-SD counters.
+ *
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
+ *
+ */
+ ClientError GetDnssdCounters(DnssdCounters &aDnssdCounters);
+#endif
+
+ /**
* This method returns the network interface name the client is bound to.
*
* @returns The network interface name.
@@ -675,6 +751,25 @@ public:
*/
std::string GetInterfaceName(void);
+ /**
+ * This method sets multiple vendor-specific entries for the TXT record of the MeshCoP service.
+ *
+ * @note
+ * - The @p aUpdate must contain all vendor-specific TXT entries you want to update. The latest call will supersede
+ * previous calls.
+ * - If @p aUpdate contains thread-specific entries like 'nn', 'at', the whole update will be rejected.
+ * - If @p aUpdate contains a key which is already published in TXT record, it will be updated according to @p
+ * aUpdate.
+ *
+ * @param[in] aUpdate The updated key-value entries.
+ *
+ * @retval ERROR_NONE Successfully performed the dbus function call
+ * @retval ERROR_DBUS dbus encode/decode error
+ * @retval ... OpenThread defined error value otherwise
+ *
+ */
+ ClientError UpdateVendorMeshCopTxtEntries(std::vector<TxtEntry> &aUpdate);
+
private:
ClientError CallDBusMethodSync(const std::string &aMethodName);
ClientError CallDBusMethodAsync(const std::string &aMethodName, DBusPendingCallNotifyFunction aFunction);
@@ -698,10 +793,12 @@ private:
static void sHandleDBusPendingCall(DBusPendingCall *aPending, void *aThreadApiDBus);
void AttachPendingCallHandler(DBusPendingCall *aPending);
+ void DetachPendingCallHandler(DBusPendingCall *aPending);
void FactoryResetPendingCallHandler(DBusPendingCall *aPending);
void JoinerStartPendingCallHandler(DBusPendingCall *aPending);
static void sScanPendingCallHandler(DBusPendingCall *aPending, void *aThreadApiDBus);
void ScanPendingCallHandler(DBusPendingCall *aPending);
+ void EnergyScanPendingCallHandler(DBusPendingCall *aPending);
static void EmptyFree(void *) {}
@@ -709,10 +806,12 @@ private:
DBusConnection *mConnection;
- ScanHandler mScanHandler;
- OtResultHandler mAttachHandler;
- OtResultHandler mFactoryResetHandler;
- OtResultHandler mJoinerHandler;
+ ScanHandler mScanHandler;
+ EnergyScanHandler mEnergyScanHandler;
+ OtResultHandler mAttachHandler;
+ OtResultHandler mDetachHandler;
+ OtResultHandler mFactoryResetHandler;
+ OtResultHandler mJoinerHandler;
std::vector<DeviceRoleHandler> mDeviceRoleHandlers;
};
diff --git a/src/dbus/common/constants.hpp b/src/dbus/common/constants.hpp
index 2004f0a9..ce2e1a7f 100644
--- a/src/dbus/common/constants.hpp
+++ b/src/dbus/common/constants.hpp
@@ -45,6 +45,7 @@
#define OTBR_DBUS_OBJECT_PREFIX "/io/openthread/BorderRouter/"
#define OTBR_DBUS_SCAN_METHOD "Scan"
+#define OTBR_DBUS_ENERGY_SCAN_METHOD "EnergyScan"
#define OTBR_DBUS_ATTACH_METHOD "Attach"
#define OTBR_DBUS_DETACH_METHOD "Detach"
#define OTBR_DBUS_FACTORY_RESET_METHOD "FactoryReset"
@@ -57,6 +58,8 @@
#define OTBR_DBUS_ADD_EXTERNAL_ROUTE_METHOD "AddExternalRoute"
#define OTBR_DBUS_REMOVE_EXTERNAL_ROUTE_METHOD "RemoveExternalRoute"
#define OTBR_DBUS_ATTACH_ALL_NODES_TO_METHOD "AttachAllNodesTo"
+#define OTBR_DBUS_UPDATE_VENDOR_MESHCOP_TXT_METHOD "UpdateVendorMeshCopTxtEntries"
+#define OTBR_DBUS_GET_PROPERTIES_METHOD "GetProperties"
#define OTBR_DBUS_PROPERTY_MESH_LOCAL_PREFIX "MeshLocalPrefix"
#define OTBR_DBUS_PROPERTY_LEGACY_ULA_PREFIX "LegacyULAPrefix"
@@ -86,8 +89,20 @@
#define OTBR_DBUS_PROPERTY_INSTANT_RSSI "InstantRssi"
#define OTBR_DBUS_PROPERTY_RADIO_TX_POWER "RadioTxPower"
#define OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES "ExternalRoutes"
+#define OTBR_DBUS_PROPERTY_ON_MESH_PREFIXES "OnMeshPrefixes"
#define OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS "ActiveDatasetTlvs"
#define OTBR_DBUS_PROPERTY_RADIO_REGION "RadioRegion"
+#define OTBR_DBUS_PROPERTY_SRP_SERVER_INFO "SrpServerInfo"
+#define OTBR_DBUS_PROPERTY_DNSSD_COUNTERS "DnssdCounters"
+#define OTBR_DBUS_PROPERTY_OT_HOST_VERSION "OtHostVersion"
+#define OTBR_DBUS_PROPERTY_OT_RCP_VERSION "OtRcpVersion"
+#define OTBR_DBUS_PROPERTY_THREAD_VERSION "ThreadVersion"
+#define OTBR_DBUS_PROPERTY_EUI64 "Eui64"
+#define OTBR_DBUS_PROPERTY_MDNS_TELEMETRY_INFO "MdnsTelemetryInfo"
+#define OTBR_DBUS_PROPERTY_RADIO_SPINEL_METRICS "RadioSpinelMetrics"
+#define OTBR_DBUS_PROPERTY_RCP_INTERFACE_METRICS "RcpInterfaceMetrics"
+#define OTBR_DBUS_PROPERTY_UPTIME "Uptime"
+#define OTBR_DBUS_PROPERTY_RADIO_COEX_METRICS "RadioCoexMetrics"
#define OTBR_ROLE_NAME_DISABLED "disabled"
#define OTBR_ROLE_NAME_DETACHED "detached"
@@ -95,4 +110,6 @@
#define OTBR_ROLE_NAME_ROUTER "router"
#define OTBR_ROLE_NAME_LEADER "leader"
+#define OTBR_DBUS_SIGNAL_READY "Ready"
+
#endif // OTBR_DBUS_CONSTANTS_HPP_
diff --git a/src/dbus/common/dbus_message_helper.hpp b/src/dbus/common/dbus_message_helper.hpp
index e7240f6b..ccc81192 100644
--- a/src/dbus/common/dbus_message_helper.hpp
+++ b/src/dbus/common/dbus_message_helper.hpp
@@ -53,6 +53,8 @@ otbrError DBusMessageEncode(DBusMessageIter *aIter, const otbrError &aError);
otbrError DBusMessageExtract(DBusMessageIter *aIter, otbrError &aError);
otbrError DBusMessageEncode(DBusMessageIter *aIter, const ActiveScanResult &aScanResult);
otbrError DBusMessageExtract(DBusMessageIter *aIter, ActiveScanResult &aScanResult);
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const EnergyScanResult &aResult);
+otbrError DBusMessageExtract(DBusMessageIter *aIter, EnergyScanResult &aResult);
otbrError DBusMessageEncode(DBusMessageIter *aIter, const LinkModeConfig &aConfig);
otbrError DBusMessageExtract(DBusMessageIter *aIter, LinkModeConfig &aConfig);
otbrError DBusMessageEncode(DBusMessageIter *aIter, const Ip6Prefix &aPrefix);
@@ -73,6 +75,26 @@ otbrError DBusMessageEncode(DBusMessageIter *aIter, const LeaderData &aLeaderDat
otbrError DBusMessageExtract(DBusMessageIter *aIter, LeaderData &aLeaderData);
otbrError DBusMessageEncode(DBusMessageIter *aIter, const ChannelQuality &aQuality);
otbrError DBusMessageExtract(DBusMessageIter *aIter, ChannelQuality &aQuality);
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const TxtEntry &aTxtEntry);
+otbrError DBusMessageExtract(DBusMessageIter *aIter, TxtEntry &aTxtEntry);
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const SrpServerInfo::Registration &aRegistration);
+otbrError DBusMessageExtract(DBusMessageIter *aIter, SrpServerInfo::Registration &aRegistration);
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const SrpServerInfo::ResponseCounters &aResponseCounters);
+otbrError DBusMessageExtract(DBusMessageIter *aIter, SrpServerInfo::ResponseCounters &aResponseCounters);
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const SrpServerInfo &aSrpServerInfo);
+otbrError DBusMessageExtract(DBusMessageIter *aIter, SrpServerInfo &aSrpServerInfo);
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const MdnsResponseCounters &aMdnsResponseCounters);
+otbrError DBusMessageExtract(DBusMessageIter *aIter, MdnsResponseCounters &aMdnsResponseCounters);
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const MdnsTelemetryInfo &aMdnsTelemetryInfo);
+otbrError DBusMessageExtract(DBusMessageIter *aIter, MdnsTelemetryInfo &aMdnsTelemetryInfo);
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const DnssdCounters &aDnssdCounters);
+otbrError DBusMessageExtract(DBusMessageIter *aIter, DnssdCounters &aDnssdCounters);
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const RadioSpinelMetrics &aRadioSpinelMetrics);
+otbrError DBusMessageExtract(DBusMessageIter *aIter, RadioSpinelMetrics &RadioSpinelMetrics);
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const RcpInterfaceMetrics &aRcpInterfaceMetrics);
+otbrError DBusMessageExtract(DBusMessageIter *aIter, RcpInterfaceMetrics &aRcpInterfaceMetrics);
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const RadioCoexMetrics &aRadioCoexMetrics);
+otbrError DBusMessageExtract(DBusMessageIter *aIter, RadioCoexMetrics &aRadioCoexMetrics);
template <typename T> struct DBusTypeTrait;
@@ -124,6 +146,18 @@ template <> struct DBusTypeTrait<std::vector<ExternalRoute>>
static constexpr const char *TYPE_AS_STRING = "a((ayy)qybb)";
};
+template <> struct DBusTypeTrait<OnMeshPrefix>
+{
+ // struct of {{array of bytes, byte}, uint16, byte, bool, bool, bool, bool, bool, bool, bool, bool, bool}
+ static constexpr const char *TYPE_AS_STRING = "((ayy)qybbbbbbbbb)";
+};
+
+template <> struct DBusTypeTrait<std::vector<OnMeshPrefix>>
+{
+ // array of {{array of bytes, byte}, uint16, byte, bool, bool, bool, bool, bool, bool, bool, bool, bool}
+ static constexpr const char *TYPE_AS_STRING = "a((ayy)qybbbbbbbbb)";
+};
+
template <> struct DBusTypeTrait<LeaderData>
{
// struct of { uint32, byte, byte, byte, byte }
@@ -164,6 +198,12 @@ template <> struct DBusTypeTrait<ActiveScanResult>
static constexpr const char *TYPE_AS_STRING = "(tstayqqyyyybb)";
};
+template <> struct DBusTypeTrait<EnergyScanResult>
+{
+ // struct of { uint8, int8_t }
+ static constexpr const char *TYPE_AS_STRING = "(yy)";
+};
+
template <> struct DBusTypeTrait<ChannelQuality>
{
// struct of { uint8, uint16}
@@ -177,6 +217,75 @@ template <> struct DBusTypeTrait<std::vector<ChildInfo>>
static constexpr const char *TYPE_AS_STRING = "a(tuuqqyyyyqqbbbb)";
};
+template <> struct DBusTypeTrait<TxtEntry>
+{
+ // struct of { string, array<uint8> }
+ static constexpr const char *TYPE_AS_STRING = "(say)";
+};
+
+template <> struct DBusTypeTrait<std::vector<TxtEntry>>
+{
+ // array of struct of { string, array<uint8> }
+ static constexpr const char *TYPE_AS_STRING = "a(say)";
+};
+
+template <> struct DBusTypeTrait<SrpServerState>
+{
+ static constexpr int TYPE = DBUS_TYPE_BYTE;
+ static constexpr const char *TYPE_AS_STRING = DBUS_TYPE_BYTE_AS_STRING;
+};
+
+template <> struct DBusTypeTrait<SrpServerAddressMode>
+{
+ static constexpr int TYPE = DBUS_TYPE_BYTE;
+ static constexpr const char *TYPE_AS_STRING = DBUS_TYPE_BYTE_AS_STRING;
+};
+
+template <> struct DBusTypeTrait<SrpServerInfo>
+{
+ // struct of { uint8, uint16, uint8,
+ // struct of { uint32, uint32, uint64, uint64, uint64, uint64 },
+ // struct of { uint32, uint32, uint64, uint64, uint64, uint64 },
+ // struct of { uint32, uint32, uint32, uint32, uint32, uint32} }
+ static constexpr const char *TYPE_AS_STRING = "(yqy(uutttt)(uutttt)(uuuuuu))";
+};
+
+template <> struct DBusTypeTrait<MdnsTelemetryInfo>
+{
+ // struct of { struct of { uint32, uint32, uint32, uint32, uint32, uint32 },
+ // struct of { uint32, uint32, uint32, uint32, uint32, uint32 },
+ // struct of { uint32, uint32, uint32, uint32, uint32, uint32 },
+ // struct of { uint32, uint32, uint32, uint32, uint32, uint32 },
+ // uint32, uint32, uint32, uint32 }
+ static constexpr const char *TYPE_AS_STRING = "((uuuuuu)(uuuuuu)(uuuuuu)(uuuuuu)uuuu)";
+};
+
+template <> struct DBusTypeTrait<DnssdCounters>
+{
+ // struct of { uint32, uint32, uint32, uint32, uint32, uint32, uint32 }
+ static constexpr const char *TYPE_AS_STRING = "(uuuuuuu)";
+};
+
+template <> struct DBusTypeTrait<RadioSpinelMetrics>
+{
+ // struct of { uint32, uint32, uint32, uint32 }
+ static constexpr const char *TYPE_AS_STRING = "(uuuu)";
+};
+
+template <> struct DBusTypeTrait<RcpInterfaceMetrics>
+{
+ // struct of { uint8, uint64, uint64, uint64, uint64, uint64, uint64, uint64 }
+ static constexpr const char *TYPE_AS_STRING = "(yttttttt)";
+};
+
+template <> struct DBusTypeTrait<RadioCoexMetrics>
+{
+ // struct of { uint32, uint32, uint32, uint32, uint32, uint32, uint32, uint32,
+ // uint32, uint32, uint32, uint32, uint32, uint32, uint32, uint32,
+ // uint32, uint32, bool }
+ static constexpr const char *TYPE_AS_STRING = "(uuuuuuuuuuuuuuuuuub)";
+};
+
template <> struct DBusTypeTrait<int8_t>
{
static constexpr int TYPE = DBUS_TYPE_BYTE;
@@ -449,6 +558,24 @@ public:
}
};
+template <> class DBusMessageIterFor<0, 0>
+{
+public:
+ static otbrError ConvertToTuple(DBusMessageIter *aIter, std::tuple<> &aValues)
+ {
+ OTBR_UNUSED_VARIABLE(aIter);
+ OTBR_UNUSED_VARIABLE(aValues);
+ return OTBR_ERROR_NONE;
+ }
+
+ static otbrError ConvertToDBusMessage(DBusMessageIter *aIter, const std::tuple<> &aValues)
+ {
+ OTBR_UNUSED_VARIABLE(aIter);
+ OTBR_UNUSED_VARIABLE(aValues);
+ return OTBR_ERROR_NONE;
+ }
+};
+
template <size_t N, typename... FieldTypes> class DBusMessageIterFor<1, N, FieldTypes...>
{
public:
@@ -486,11 +613,11 @@ constexpr otbrError ConvertToTuple(DBusMessageIter *aIter, std::tuple<FieldTypes
/**
* This function converts a value to a d-bus variant.
*
- * @param[out] aIter The message iterator pointing to the variant.
- * @param[in] aValue The value input.
+ * @param[out] aIter The message iterator pointing to the variant.
+ * @param[in] aValue The value input.
*
- * @retval OTBR_ERROR_NONE Successfully encoded to the variant.
- * @retval OTBR_ERROR_DBUS Failed to encode to the variant.
+ * @retval OTBR_ERROR_NONE Successfully encoded to the variant.
+ * @retval OTBR_ERROR_DBUS Failed to encode to the variant.
*/
template <typename ValueType> otbrError DBusMessageEncodeToVariant(DBusMessageIter *aIter, const ValueType &aValue)
{
@@ -512,11 +639,11 @@ exit:
/**
* This function converts a d-bus variant to a value.
*
- * @param[in] aIter The message iterator pointing to the variant.
- * @param[out] aValue The value output.
+ * @param[in] aIter The message iterator pointing to the variant.
+ * @param[out] aValue The value output.
*
- * @retval OTBR_ERROR_NONE Successfully decoded the variant.
- * @retval OTBR_ERROR_DBUS Failed to decode the variant.
+ * @retval OTBR_ERROR_NONE Successfully decoded the variant.
+ * @retval OTBR_ERROR_DBUS Failed to decode the variant.
*/
template <typename ValueType> otbrError DBusMessageExtractFromVariant(DBusMessageIter *aIter, ValueType &aValue)
{
@@ -535,11 +662,11 @@ exit:
/**
* This function converts a d-bus message to a tuple of C++ types.
*
- * @param[in] aMessage The dbus message to decode.
- * @param[out] aValues The tuple output.
+ * @param[in] aMessage The dbus message to decode.
+ * @param[out] aValues The tuple output.
*
- * @retval OTBR_ERROR_NONE Successfully decoded the message.
- * @retval OTBR_ERROR_DBUS Failed to decode the message.
+ * @retval OTBR_ERROR_NONE Successfully decoded the message.
+ * @retval OTBR_ERROR_DBUS Failed to decode the message.
*/
template <typename... FieldTypes>
otbrError DBusMessageToTuple(DBusMessage &aMessage, std::tuple<FieldTypes...> &aValues)
@@ -558,11 +685,11 @@ exit:
/**
* This function converts a tuple of C++ types to a d-bus message.
*
- * @param[out] aMessage The dbus message output.
- * @param[in] aValues The tuple to encode.
+ * @param[out] aMessage The dbus message output.
+ * @param[in] aValues The tuple to encode.
*
- * @retval OTBR_ERROR_NONE Successfully encoded the message.
- * @retval OTBR_ERROR_DBUS Failed to encode the message.
+ * @retval OTBR_ERROR_NONE Successfully encoded the message.
+ * @retval OTBR_ERROR_DBUS Failed to encode the message.
*/
template <typename... FieldTypes>
otbrError TupleToDBusMessage(DBusMessage &aMessage, const std::tuple<FieldTypes...> &aValues)
@@ -576,11 +703,11 @@ otbrError TupleToDBusMessage(DBusMessage &aMessage, const std::tuple<FieldTypes.
/**
* This function converts a d-bus message to a tuple of C++ types.
*
- * @param[in] aMessage The dbus message to decode.
- * @param[out] aValues The tuple output.
+ * @param[in] aMessage The dbus message to decode.
+ * @param[out] aValues The tuple output.
*
- * @retval OTBR_ERROR_NONE Successfully decoded the message.
- * @retval OTBR_ERROR_DBUS Failed to decode the message.
+ * @retval OTBR_ERROR_NONE Successfully decoded the message.
+ * @retval OTBR_ERROR_DBUS Failed to decode the message.
*/
template <typename... FieldTypes>
otbrError DBusMessageToTuple(UniqueDBusMessage const &aMessage, std::tuple<FieldTypes...> &aValues)
diff --git a/src/dbus/common/dbus_message_helper_openthread.cpp b/src/dbus/common/dbus_message_helper_openthread.cpp
index 7193f4d4..b91c5479 100644
--- a/src/dbus/common/dbus_message_helper_openthread.cpp
+++ b/src/dbus/common/dbus_message_helper_openthread.cpp
@@ -68,7 +68,7 @@ otbrError DBusMessageExtract(DBusMessageIter *aIter, ActiveScanResult &aScanResu
SuccessOrExit(error = DBusMessageExtract(&sub, aScanResult.mLqi));
SuccessOrExit(error = DBusMessageExtract(&sub, aScanResult.mVersion));
SuccessOrExit(error = DBusMessageExtract(&sub, aScanResult.mIsNative));
- SuccessOrExit(error = DBusMessageExtract(&sub, aScanResult.mIsJoinable));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aScanResult.mDiscover));
dbus_message_iter_next(aIter);
error = OTBR_ERROR_NONE;
@@ -93,7 +93,7 @@ otbrError DBusMessageEncode(DBusMessageIter *aIter, const ActiveScanResult &aSca
SuccessOrExit(error = DBusMessageEncode(&sub, aScanResult.mLqi));
SuccessOrExit(error = DBusMessageEncode(&sub, aScanResult.mVersion));
SuccessOrExit(error = DBusMessageEncode(&sub, aScanResult.mIsNative));
- SuccessOrExit(error = DBusMessageEncode(&sub, aScanResult.mIsJoinable));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aScanResult.mDiscover));
VerifyOrExit(dbus_message_iter_close_container(aIter, &sub), error = OTBR_ERROR_DBUS);
error = OTBR_ERROR_NONE;
@@ -101,6 +101,38 @@ exit:
return error;
}
+otbrError DBusMessageExtract(DBusMessageIter *aIter, EnergyScanResult &aResult)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ VerifyOrExit(dbus_message_iter_get_arg_type(aIter) == DBUS_TYPE_STRUCT, error = OTBR_ERROR_DBUS);
+ dbus_message_iter_recurse(aIter, &sub);
+
+ SuccessOrExit(error = DBusMessageExtract(&sub, aResult.mChannel));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aResult.mMaxRssi));
+
+ dbus_message_iter_next(aIter);
+exit:
+ return error;
+}
+
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const EnergyScanResult &aResult)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ VerifyOrExit(dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT, nullptr, &sub), error = OTBR_ERROR_DBUS);
+
+ SuccessOrExit(error = DBusMessageEncode(&sub, aResult.mChannel));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aResult.mMaxRssi));
+
+ VerifyOrExit(dbus_message_iter_close_container(aIter, &sub), error = OTBR_ERROR_DBUS);
+
+exit:
+ return error;
+}
+
otbrError DBusMessageEncode(DBusMessageIter *aIter, const LinkModeConfig &aConfig)
{
otbrError error = OTBR_ERROR_NONE;
@@ -208,36 +240,51 @@ exit:
otbrError DBusMessageEncode(DBusMessageIter *aIter, const OnMeshPrefix &aPrefix)
{
- DBusMessageIter sub, flagsSub;
- auto args = std::tie(aPrefix.mPreferred, aPrefix.mSlaac, aPrefix.mDhcp, aPrefix.mConfigure, aPrefix.mDefaultRoute,
- aPrefix.mOnMesh, aPrefix.mStable);
- otbrError error = OTBR_ERROR_NONE;
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
VerifyOrExit(dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT, nullptr, &sub), error = OTBR_ERROR_DBUS);
- SuccessOrExit(error = ConvertToDBusMessage(&sub, std::tie(aPrefix.mPrefix, aPrefix.mPreference)));
- VerifyOrExit(dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, nullptr, &flagsSub), error = OTBR_ERROR_DBUS);
- SuccessOrExit(error = ConvertToDBusMessage(&flagsSub, args));
- VerifyOrExit(dbus_message_iter_close_container(&sub, &flagsSub) == true, error = OTBR_ERROR_DBUS);
- VerifyOrExit(dbus_message_iter_close_container(aIter, &sub) == true, error = OTBR_ERROR_DBUS);
+
+ SuccessOrExit(error = DBusMessageEncode(&sub, aPrefix.mPrefix));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aPrefix.mRloc16));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aPrefix.mPreference));
+
+ SuccessOrExit(error = DBusMessageEncode(&sub, aPrefix.mPreferred));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aPrefix.mSlaac));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aPrefix.mDhcp));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aPrefix.mConfigure));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aPrefix.mDefaultRoute));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aPrefix.mOnMesh));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aPrefix.mStable));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aPrefix.mNdDns));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aPrefix.mDp));
+ VerifyOrExit(dbus_message_iter_close_container(aIter, &sub), error = OTBR_ERROR_DBUS);
+
exit:
return error;
}
otbrError DBusMessageExtract(DBusMessageIter *aIter, OnMeshPrefix &aPrefix)
{
- DBusMessageIter sub, flagsSub;
- auto args = std::tie(aPrefix.mPrefix, aPrefix.mPreference);
- auto flagArgs = std::tie(aPrefix.mPreferred, aPrefix.mSlaac, aPrefix.mDhcp, aPrefix.mConfigure,
- aPrefix.mDefaultRoute, aPrefix.mOnMesh, aPrefix.mStable);
- otbrError error = OTBR_ERROR_NONE;
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
- VerifyOrExit(dbus_message_iter_get_arg_type(aIter) == DBUS_TYPE_STRUCT, error = OTBR_ERROR_DBUS);
dbus_message_iter_recurse(aIter, &sub);
- SuccessOrExit(error = ConvertToTuple(&sub, args));
- VerifyOrExit(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT, error = OTBR_ERROR_DBUS);
- dbus_message_iter_recurse(&sub, &flagsSub);
- SuccessOrExit(error = ConvertToTuple(&flagsSub, flagArgs));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aPrefix.mPrefix));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aPrefix.mRloc16));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aPrefix.mPreference));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aPrefix.mPreferred));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aPrefix.mSlaac));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aPrefix.mDhcp));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aPrefix.mConfigure));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aPrefix.mDefaultRoute));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aPrefix.mOnMesh));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aPrefix.mStable));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aPrefix.mNdDns));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aPrefix.mDp));
+
dbus_message_iter_next(aIter);
+
exit:
return error;
}
@@ -438,5 +485,393 @@ exit:
return error;
}
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const TxtEntry &aTxtEntry)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+ auto args = std::tie(aTxtEntry.mKey, aTxtEntry.mValue);
+
+ VerifyOrExit(dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT, nullptr, &sub));
+ SuccessOrExit(error = ConvertToDBusMessage(&sub, args));
+ VerifyOrExit(dbus_message_iter_close_container(aIter, &sub) == true, error = OTBR_ERROR_DBUS);
+exit:
+ return error;
+}
+
+otbrError DBusMessageExtract(DBusMessageIter *aIter, TxtEntry &aTxtEntry)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+ auto args = std::tie(aTxtEntry.mKey, aTxtEntry.mValue);
+
+ VerifyOrExit(dbus_message_iter_get_arg_type(aIter) == DBUS_TYPE_STRUCT, error = OTBR_ERROR_DBUS);
+ dbus_message_iter_recurse(aIter, &sub);
+ SuccessOrExit(error = ConvertToTuple(&sub, args));
+ dbus_message_iter_next(aIter);
+exit:
+ return error;
+}
+
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const SrpServerInfo::Registration &aRegistration)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+ auto args = std::tie(aRegistration.mFreshCount, aRegistration.mDeletedCount, aRegistration.mLeaseTimeTotal,
+ aRegistration.mKeyLeaseTimeTotal, aRegistration.mRemainingLeaseTimeTotal,
+ aRegistration.mRemainingKeyLeaseTimeTotal);
+
+ VerifyOrExit(dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT, nullptr, &sub), error = OTBR_ERROR_DBUS);
+ SuccessOrExit(error = ConvertToDBusMessage(&sub, args));
+ VerifyOrExit(dbus_message_iter_close_container(aIter, &sub) == true, error = OTBR_ERROR_DBUS);
+exit:
+ return error;
+}
+
+otbrError DBusMessageExtract(DBusMessageIter *aIter, SrpServerInfo::Registration &aRegistration)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+ auto args = std::tie(aRegistration.mFreshCount, aRegistration.mDeletedCount, aRegistration.mLeaseTimeTotal,
+ aRegistration.mKeyLeaseTimeTotal, aRegistration.mRemainingLeaseTimeTotal,
+ aRegistration.mRemainingKeyLeaseTimeTotal);
+
+ VerifyOrExit(dbus_message_iter_get_arg_type(aIter) == DBUS_TYPE_STRUCT, error = OTBR_ERROR_DBUS);
+ dbus_message_iter_recurse(aIter, &sub);
+ SuccessOrExit(error = ConvertToTuple(&sub, args));
+ dbus_message_iter_next(aIter);
+exit:
+ return error;
+}
+
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const SrpServerInfo::ResponseCounters &aResponseCounters)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+ auto args = std::tie(aResponseCounters.mSuccess, aResponseCounters.mServerFailure, aResponseCounters.mFormatError,
+ aResponseCounters.mNameExists, aResponseCounters.mRefused, aResponseCounters.mOther);
+
+ VerifyOrExit(dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT, nullptr, &sub), error = OTBR_ERROR_DBUS);
+ SuccessOrExit(error = ConvertToDBusMessage(&sub, args));
+ VerifyOrExit(dbus_message_iter_close_container(aIter, &sub) == true, error = OTBR_ERROR_DBUS);
+exit:
+ return error;
+}
+
+otbrError DBusMessageExtract(DBusMessageIter *aIter, SrpServerInfo::ResponseCounters &aResponseCounters)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+ auto args = std::tie(aResponseCounters.mSuccess, aResponseCounters.mServerFailure, aResponseCounters.mFormatError,
+ aResponseCounters.mNameExists, aResponseCounters.mRefused, aResponseCounters.mOther);
+
+ VerifyOrExit(dbus_message_iter_get_arg_type(aIter) == DBUS_TYPE_STRUCT, error = OTBR_ERROR_DBUS);
+ dbus_message_iter_recurse(aIter, &sub);
+ SuccessOrExit(error = ConvertToTuple(&sub, args));
+ dbus_message_iter_next(aIter);
+exit:
+ return error;
+}
+
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const SrpServerInfo &aSrpServerInfo)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ VerifyOrExit(dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT, nullptr, &sub), error = OTBR_ERROR_DBUS);
+
+ SuccessOrExit(error = DBusMessageEncode(&sub, aSrpServerInfo.mState));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aSrpServerInfo.mPort));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aSrpServerInfo.mAddressMode));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aSrpServerInfo.mHosts));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aSrpServerInfo.mServices));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aSrpServerInfo.mResponseCounters));
+
+ VerifyOrExit(dbus_message_iter_close_container(aIter, &sub), error = OTBR_ERROR_DBUS);
+exit:
+ return error;
+}
+
+otbrError DBusMessageExtract(DBusMessageIter *aIter, SrpServerInfo &aSrpServerInfo)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ dbus_message_iter_recurse(aIter, &sub);
+ SuccessOrExit(error = DBusMessageExtract(&sub, aSrpServerInfo.mState));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aSrpServerInfo.mPort));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aSrpServerInfo.mAddressMode));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aSrpServerInfo.mHosts));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aSrpServerInfo.mServices));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aSrpServerInfo.mResponseCounters));
+
+ dbus_message_iter_next(aIter);
+exit:
+ return error;
+}
+
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const DnssdCounters &aDnssdCounters)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ VerifyOrExit(dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT, nullptr, &sub), error = OTBR_ERROR_DBUS);
+
+ SuccessOrExit(error = DBusMessageEncode(&sub, aDnssdCounters.mSuccessResponse));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aDnssdCounters.mServerFailureResponse));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aDnssdCounters.mFormatErrorResponse));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aDnssdCounters.mNameErrorResponse));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aDnssdCounters.mNotImplementedResponse));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aDnssdCounters.mOtherResponse));
+
+ SuccessOrExit(error = DBusMessageEncode(&sub, aDnssdCounters.mResolvedBySrp));
+
+ VerifyOrExit(dbus_message_iter_close_container(aIter, &sub), error = OTBR_ERROR_DBUS);
+exit:
+ return error;
+}
+
+otbrError DBusMessageExtract(DBusMessageIter *aIter, DnssdCounters &aDnssdCounters)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ dbus_message_iter_recurse(aIter, &sub);
+
+ SuccessOrExit(error = DBusMessageExtract(&sub, aDnssdCounters.mSuccessResponse));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aDnssdCounters.mServerFailureResponse));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aDnssdCounters.mFormatErrorResponse));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aDnssdCounters.mNameErrorResponse));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aDnssdCounters.mNotImplementedResponse));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aDnssdCounters.mOtherResponse));
+
+ SuccessOrExit(error = DBusMessageExtract(&sub, aDnssdCounters.mResolvedBySrp));
+
+ dbus_message_iter_next(aIter);
+exit:
+ return error;
+}
+
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const MdnsResponseCounters &aMdnsResponseCounters)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ VerifyOrExit(dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT, nullptr, &sub), error = OTBR_ERROR_DBUS);
+
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsResponseCounters.mSuccess));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsResponseCounters.mNotFound));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsResponseCounters.mInvalidArgs));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsResponseCounters.mDuplicated));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsResponseCounters.mNotImplemented));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsResponseCounters.mUnknownError));
+
+ VerifyOrExit(dbus_message_iter_close_container(aIter, &sub), error = OTBR_ERROR_DBUS);
+exit:
+ return error;
+}
+
+otbrError DBusMessageExtract(DBusMessageIter *aIter, MdnsResponseCounters &aMdnsResponseCounters)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ dbus_message_iter_recurse(aIter, &sub);
+
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsResponseCounters.mSuccess));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsResponseCounters.mNotFound));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsResponseCounters.mInvalidArgs));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsResponseCounters.mDuplicated));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsResponseCounters.mNotImplemented));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsResponseCounters.mUnknownError));
+
+ dbus_message_iter_next(aIter);
+exit:
+ return error;
+}
+
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const MdnsTelemetryInfo &aMdnsTelemetryInfo)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ VerifyOrExit(dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT, nullptr, &sub), error = OTBR_ERROR_DBUS);
+
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsTelemetryInfo.mHostRegistrations));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsTelemetryInfo.mServiceRegistrations));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsTelemetryInfo.mHostResolutions));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsTelemetryInfo.mServiceResolutions));
+
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsTelemetryInfo.mHostRegistrationEmaLatency));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsTelemetryInfo.mServiceRegistrationEmaLatency));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsTelemetryInfo.mHostResolutionEmaLatency));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aMdnsTelemetryInfo.mServiceResolutionEmaLatency));
+
+ VerifyOrExit(dbus_message_iter_close_container(aIter, &sub), error = OTBR_ERROR_DBUS);
+exit:
+ return error;
+}
+
+otbrError DBusMessageExtract(DBusMessageIter *aIter, MdnsTelemetryInfo &aMdnsTelemetryInfo)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ dbus_message_iter_recurse(aIter, &sub);
+
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsTelemetryInfo.mHostRegistrations));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsTelemetryInfo.mServiceRegistrations));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsTelemetryInfo.mHostResolutions));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsTelemetryInfo.mServiceResolutions));
+
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsTelemetryInfo.mHostRegistrationEmaLatency));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsTelemetryInfo.mServiceRegistrationEmaLatency));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsTelemetryInfo.mHostResolutionEmaLatency));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aMdnsTelemetryInfo.mServiceResolutionEmaLatency));
+
+ dbus_message_iter_next(aIter);
+exit:
+ return error;
+}
+
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const RadioSpinelMetrics &aRadioSpinelMetrics)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ VerifyOrExit(dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT, nullptr, &sub), error = OTBR_ERROR_DBUS);
+
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioSpinelMetrics.mRcpTimeoutCount));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioSpinelMetrics.mRcpUnexpectedResetCount));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioSpinelMetrics.mRcpRestorationCount));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioSpinelMetrics.mSpinelParseErrorCount));
+
+ VerifyOrExit(dbus_message_iter_close_container(aIter, &sub), error = OTBR_ERROR_DBUS);
+exit:
+ return error;
+}
+
+otbrError DBusMessageExtract(DBusMessageIter *aIter, RadioSpinelMetrics &aRadioSpinelMetrics)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ dbus_message_iter_recurse(aIter, &sub);
+
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioSpinelMetrics.mRcpTimeoutCount));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioSpinelMetrics.mRcpUnexpectedResetCount));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioSpinelMetrics.mRcpRestorationCount));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioSpinelMetrics.mSpinelParseErrorCount));
+
+ dbus_message_iter_next(aIter);
+exit:
+ return error;
+}
+
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const RcpInterfaceMetrics &aRcpInterfaceMetrics)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ VerifyOrExit(dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT, nullptr, &sub), error = OTBR_ERROR_DBUS);
+
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRcpInterfaceMetrics.mRcpInterfaceType));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRcpInterfaceMetrics.mTransferredFrameCount));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRcpInterfaceMetrics.mTransferredValidFrameCount));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRcpInterfaceMetrics.mTransferredGarbageFrameCount));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRcpInterfaceMetrics.mRxFrameCount));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRcpInterfaceMetrics.mRxFrameByteCount));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRcpInterfaceMetrics.mTxFrameCount));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRcpInterfaceMetrics.mTxFrameByteCount));
+
+ VerifyOrExit(dbus_message_iter_close_container(aIter, &sub), error = OTBR_ERROR_DBUS);
+exit:
+ return error;
+}
+
+otbrError DBusMessageExtract(DBusMessageIter *aIter, RcpInterfaceMetrics &aRcpInterfaceMetrics)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ dbus_message_iter_recurse(aIter, &sub);
+
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRcpInterfaceMetrics.mRcpInterfaceType));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRcpInterfaceMetrics.mTransferredFrameCount));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRcpInterfaceMetrics.mTransferredValidFrameCount));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRcpInterfaceMetrics.mTransferredGarbageFrameCount));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRcpInterfaceMetrics.mRxFrameCount));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRcpInterfaceMetrics.mRxFrameByteCount));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRcpInterfaceMetrics.mTxFrameCount));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRcpInterfaceMetrics.mTxFrameByteCount));
+
+ dbus_message_iter_next(aIter);
+exit:
+ return error;
+}
+
+otbrError DBusMessageEncode(DBusMessageIter *aIter, const RadioCoexMetrics &aRadioCoexMetrics)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ VerifyOrExit(dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT, nullptr, &sub), error = OTBR_ERROR_DBUS);
+
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumGrantGlitch));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumTxRequest));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumTxGrantImmediate));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumTxGrantWait));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumTxGrantWaitActivated));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumTxGrantWaitTimeout));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumTxGrantDeactivatedDuringRequest));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumTxDelayedGrant));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mAvgTxRequestToGrantTime));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumRxRequest));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumRxGrantImmediate));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumRxGrantWait));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumRxGrantWaitActivated));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumRxGrantWaitTimeout));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumRxGrantDeactivatedDuringRequest));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumRxDelayedGrant));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mAvgRxRequestToGrantTime));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mNumRxGrantNone));
+ SuccessOrExit(error = DBusMessageEncode(&sub, aRadioCoexMetrics.mStopped));
+
+ VerifyOrExit(dbus_message_iter_close_container(aIter, &sub), error = OTBR_ERROR_DBUS);
+exit:
+ return error;
+}
+
+otbrError DBusMessageExtract(DBusMessageIter *aIter, RadioCoexMetrics &aRadioCoexMetrics)
+{
+ DBusMessageIter sub;
+ otbrError error = OTBR_ERROR_NONE;
+
+ dbus_message_iter_recurse(aIter, &sub);
+
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumGrantGlitch));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumTxRequest));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumTxGrantImmediate));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumTxGrantWait));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumTxGrantWaitActivated));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumTxGrantWaitTimeout));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumTxGrantDeactivatedDuringRequest));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumTxDelayedGrant));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mAvgTxRequestToGrantTime));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumRxRequest));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumRxGrantImmediate));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumRxGrantWait));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumRxGrantWaitActivated));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumRxGrantWaitTimeout));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumRxGrantDeactivatedDuringRequest));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumRxDelayedGrant));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mAvgRxRequestToGrantTime));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mNumRxGrantNone));
+ SuccessOrExit(error = DBusMessageExtract(&sub, aRadioCoexMetrics.mStopped));
+
+ dbus_message_iter_next(aIter);
+exit:
+ return error;
+}
+
} // namespace DBus
} // namespace otbr
diff --git a/src/dbus/common/types.hpp b/src/dbus/common/types.hpp
index 08811c81..76c41034 100644
--- a/src/dbus/common/types.hpp
+++ b/src/dbus/common/types.hpp
@@ -66,7 +66,13 @@ struct ActiveScanResult
uint8_t mLqi; ///< LQI
uint8_t mVersion; ///< Version
bool mIsNative; ///< Native Commissioner flag
- bool mIsJoinable; ///< Joining Permitted flag
+ bool mDiscover; ///< Result from MLE Discovery
+};
+
+struct EnergyScanResult
+{
+ uint8_t mChannel; ///< IEEE 802.15.4 Channel
+ int8_t mMaxRssi; ///< The max RSSI (dBm)
};
struct LinkModeConfig
@@ -91,6 +97,11 @@ struct OnMeshPrefix
Ip6Prefix mPrefix;
/**
+ * The Rloc associated with the Border Router prefix.
+ */
+ uint16_t mRloc16;
+
+ /**
* A 2-bit signed integer indicating router preference as defined in RFC 4191.
*/
int8_t mPreference;
@@ -121,14 +132,24 @@ struct OnMeshPrefix
bool mDefaultRoute;
/**
- * TRUE, if this prefix is considered on-mesh. FALSE, otherwise.
+ * TRUE if this prefix is considered on-mesh. FALSE otherwise.
*/
bool mOnMesh;
/**
- * TRUE, if this configuration is considered Stable Network Data. FALSE, otherwise.
+ * TRUE if this configuration is considered Stable Network Data. FALSE otherwise.
*/
bool mStable;
+
+ /**
+ * TRUE if this border router can supply DNS information via ND. FALSE otherwise.
+ */
+ bool mNdDns;
+
+ /**
+ * TRUE if this prefix is a Thread Domain Prefix. FALSE otherwise.
+ */
+ bool mDp;
};
struct ExternalRoute
@@ -490,6 +511,114 @@ struct LeaderData
uint8_t mLeaderRouterId; ///< Leader Router ID
};
+struct TxtEntry
+{
+ std::string mKey;
+ std::vector<uint8_t> mValue;
+};
+
+enum SrpServerState : uint8_t
+{
+ OTBR_SRP_SERVER_STATE_DISABLED = 0, ///< The SRP server is disabled.
+ OTBR_SRP_SERVER_STATE_RUNNING = 1, ///< The SRP server is running.
+ OTBR_SRP_SERVER_STATE_STOPPED = 2, ///< The SRP server is stopped.
+};
+
+enum SrpServerAddressMode : uint8_t
+{
+ OTBR_SRP_SERVER_ADDRESS_MODE_UNICAST = 0, ///< Unicast address mode.
+ OTBR_SRP_SERVER_ADDRESS_MODE_ANYCAST = 1, ///< Anycast address mode.
+};
+
+struct SrpServerInfo
+{
+ struct Registration
+ {
+ uint32_t mFreshCount; ///< The number of active hosts/services registered on the SRP server
+ uint32_t mDeletedCount; ///< The number of hosts/services in 'Deleted' state on the SRP server
+ uint64_t mLeaseTimeTotal; ///< The sum of lease time in milliseconds of all active hosts/services
+ ///< on the SRP server
+ uint64_t mKeyLeaseTimeTotal; ///< The sum of key lease time in milliseconds of all active hosts/services on the
+ ///< SRP server
+ uint64_t mRemainingLeaseTimeTotal; ///< The sum of remaining lease time in milliseconds of all active
+ ///< hosts/services on the SRP server
+ uint64_t mRemainingKeyLeaseTimeTotal; ///< The sum of remaining key lease time in milliseconds of all active
+ ///< hosts/services on the SRP server
+ };
+
+ struct ResponseCounters
+ {
+ uint32_t mSuccess; ///< The number of successful responses
+ uint32_t mServerFailure; ///< The number of server failure responses
+ uint32_t mFormatError; ///< The number of format error responses
+ uint32_t mNameExists; ///< The number of 'name exists' responses
+ uint32_t mRefused; ///< The number of refused responses
+ uint32_t mOther; ///< The number of other responses
+ };
+
+ SrpServerState mState; ///< The state of the SRP server
+ uint16_t mPort; ///< The listening port number
+ SrpServerAddressMode mAddressMode; ///< The address mode {unicast, anycast} of the SRP server
+ Registration mHosts; ///< The registration information of hosts on the SRP server
+ Registration mServices; ///< The registration information of services on the SRP server
+ ResponseCounters mResponseCounters; ///< The counters of response codes sent by the SRP server
+};
+
+struct DnssdCounters
+{
+ uint32_t mSuccessResponse; ///< The number of successful responses
+ uint32_t mServerFailureResponse; ///< The number of server failure responses
+ uint32_t mFormatErrorResponse; ///< The number of format error responses
+ uint32_t mNameErrorResponse; ///< The number of name error responses
+ uint32_t mNotImplementedResponse; ///< The number of 'not implemented' responses
+ uint32_t mOtherResponse; ///< The number of other responses
+
+ uint32_t mResolvedBySrp; ///< The number of queries completely resolved by the local SRP server
+};
+
+struct RadioSpinelMetrics
+{
+ uint32_t mRcpTimeoutCount; ///< The number of RCP timeouts.
+ uint32_t mRcpUnexpectedResetCount; ///< The number of RCP unexcepted resets.
+ uint32_t mRcpRestorationCount; ///< The number of RCP restorations.
+ uint32_t mSpinelParseErrorCount; ///< The number of spinel frame parse errors.
+};
+
+struct RcpInterfaceMetrics
+{
+ uint8_t mRcpInterfaceType; ///< The RCP interface type.
+ uint64_t mTransferredFrameCount; ///< The number of transferred frames.
+ uint64_t mTransferredValidFrameCount; ///< The number of transferred valid frames.
+ uint64_t mTransferredGarbageFrameCount; ///< The number of transferred garbage frames.
+ uint64_t mRxFrameCount; ///< The number of received frames.
+ uint64_t mRxFrameByteCount; ///< The number of received bytes.
+ uint64_t mTxFrameCount; ///< The number of transmitted frames.
+ uint64_t mTxFrameByteCount; ///< The number of transmitted bytes.
+};
+
+struct RadioCoexMetrics
+{
+ uint32_t mNumGrantGlitch; ///< Number of grant glitches.
+ uint32_t mNumTxRequest; ///< Number of tx requests.
+ uint32_t mNumTxGrantImmediate; ///< Number of tx requests while grant was active.
+ uint32_t mNumTxGrantWait; ///< Number of tx requests while grant was inactive.
+ uint32_t mNumTxGrantWaitActivated; ///< Number of tx requests while grant was inactive that were ultimately granted.
+ uint32_t mNumTxGrantWaitTimeout; ///< Number of tx requests while grant was inactive that timed out.
+ uint32_t mNumTxGrantDeactivatedDuringRequest; ///< Number of tx that were in progress when grant was deactivated.
+ uint32_t mNumTxDelayedGrant; ///< Number of tx requests that were not granted within 50us.
+ uint32_t mAvgTxRequestToGrantTime; ///< Average time in usec from tx request to grant.
+ uint32_t mNumRxRequest; ///< Number of rx requests.
+ uint32_t mNumRxGrantImmediate; ///< Number of rx requests while grant was active.
+ uint32_t mNumRxGrantWait; ///< Number of rx requests while grant was inactive.
+ uint32_t mNumRxGrantWaitActivated; ///< Number of rx requests while grant was inactive that were ultimately granted.
+ uint32_t mNumRxGrantWaitTimeout; ///< Number of rx requests while grant was inactive that timed out.
+ uint32_t mNumRxGrantDeactivatedDuringRequest; ///< Number of rx that were in progress when grant was deactivated.
+ uint32_t mNumRxDelayedGrant; ///< Number of rx requests that were not granted within 50us.
+ uint32_t mAvgRxRequestToGrantTime; ///< Average time in usec from rx request to grant.
+ uint32_t mNumRxGrantNone; ///< Number of rx requests that completed without receiving grant.
+ bool mStopped; ///< Stats collection stopped due to saturation.
+};
+
} // namespace DBus
} // namespace otbr
diff --git a/src/dbus/server/dbus_agent.cpp b/src/dbus/server/dbus_agent.cpp
index b0aaaee9..de94927d 100644
--- a/src/dbus/server/dbus_agent.cpp
+++ b/src/dbus/server/dbus_agent.cpp
@@ -30,49 +30,81 @@
#include "dbus/server/dbus_agent.hpp"
+#include <chrono>
+#include <thread>
+#include <unistd.h>
+
#include "common/logging.hpp"
#include "dbus/common/constants.hpp"
+#include "mdns/mdns.hpp"
namespace otbr {
namespace DBus {
-const struct timeval DBusAgent::kPollTimeout = {0, 0};
+const struct timeval DBusAgent::kPollTimeout = {0, 0};
+constexpr std::chrono::seconds DBusAgent::kDBusWaitAllowance;
-DBusAgent::DBusAgent(otbr::Ncp::ControllerOpenThread &aNcp)
+DBusAgent::DBusAgent(otbr::Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher)
: mInterfaceName(aNcp.GetInterfaceName())
, mNcp(aNcp)
+ , mPublisher(aPublisher)
{
}
-otbrError DBusAgent::Init(void)
+void DBusAgent::Init(void)
+{
+ otbrError error = OTBR_ERROR_NONE;
+
+ auto connection_deadline = Clock::now() + kDBusWaitAllowance;
+
+ while ((mConnection = PrepareDBusConnection()) == nullptr && Clock::now() < connection_deadline)
+ {
+ otbrLogWarning("Failed to setup DBus connection, will retry after 1 second");
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ }
+
+ VerifyOrDie(mConnection != nullptr, "Failed to get DBus connection");
+
+ mThreadObject =
+ std::unique_ptr<DBusThreadObject>(new DBusThreadObject(mConnection.get(), mInterfaceName, &mNcp, &mPublisher));
+ error = mThreadObject->Init();
+ VerifyOrDie(error == OTBR_ERROR_NONE, "Failed to initialize DBus Agent");
+}
+
+DBusAgent::UniqueDBusConnection DBusAgent::PrepareDBusConnection(void)
{
- DBusError dbusError;
- otbrError error = OTBR_ERROR_NONE;
- int requestReply;
- std::string serverName = OTBR_DBUS_SERVER_PREFIX + mInterfaceName;
+ DBusError dbusError;
+ DBusConnection * conn = nullptr;
+ UniqueDBusConnection uniqueConn;
+ int requestReply;
+ std::string serverName = OTBR_DBUS_SERVER_PREFIX + mInterfaceName;
dbus_error_init(&dbusError);
- DBusConnection *conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbusError);
- mConnection = std::unique_ptr<DBusConnection, std::function<void(DBusConnection *)>>(
- conn, [](DBusConnection *aConnection) { dbus_connection_unref(aConnection); });
- VerifyOrExit(mConnection != nullptr, error = OTBR_ERROR_DBUS);
- dbus_bus_register(mConnection.get(), &dbusError);
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbusError);
+
+ uniqueConn = UniqueDBusConnection(conn, [](DBusConnection *aConnection) { dbus_connection_unref(aConnection); });
+
+ VerifyOrExit(uniqueConn != nullptr,
+ otbrLogWarning("Failed to get DBus connection: %s: %s", dbusError.name, dbusError.message));
+ dbus_bus_register(uniqueConn.get(), &dbusError);
+
requestReply =
- dbus_bus_request_name(mConnection.get(), serverName.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING, &dbusError);
+ dbus_bus_request_name(uniqueConn.get(), serverName.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING, &dbusError);
VerifyOrExit(requestReply == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ||
requestReply == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER,
- error = OTBR_ERROR_DBUS);
+ {
+ otbrLogWarning("Failed to request DBus name: %s: %s", dbusError.name, dbusError.message);
+ uniqueConn = nullptr;
+ });
VerifyOrExit(
- dbus_connection_set_watch_functions(mConnection.get(), AddDBusWatch, RemoveDBusWatch, nullptr, this, nullptr));
- mThreadObject = std::unique_ptr<DBusThreadObject>(new DBusThreadObject(mConnection.get(), mInterfaceName, &mNcp));
- error = mThreadObject->Init();
+ dbus_connection_set_watch_functions(uniqueConn.get(), AddDBusWatch, RemoveDBusWatch, nullptr, this, nullptr),
+ uniqueConn = nullptr);
+
exit:
- if (error != OTBR_ERROR_NONE)
- {
- otbrLogErr("Dbus error %s: %s", dbusError.name, dbusError.message);
- }
dbus_error_free(&dbusError);
- return error;
+
+ return uniqueConn;
}
dbus_bool_t DBusAgent::AddDBusWatch(struct DBusWatch *aWatch, void *aContext)
diff --git a/src/dbus/server/dbus_agent.hpp b/src/dbus/server/dbus_agent.hpp
index 4e349d9a..d334a965 100644
--- a/src/dbus/server/dbus_agent.hpp
+++ b/src/dbus/server/dbus_agent.hpp
@@ -39,6 +39,7 @@
#include <string>
#include <sys/select.h>
+#include "common/code_utils.hpp"
#include "common/mainloop.hpp"
#include "dbus/common/dbus_message_helper.hpp"
#include "dbus/common/dbus_resources.hpp"
@@ -50,52 +51,43 @@
namespace otbr {
namespace DBus {
-class DBusAgent : public MainloopProcessor
+class DBusAgent : public MainloopProcessor, private NonCopyable
{
public:
/**
* The constructor of dbus agent.
*
- * @param[in] aNcp A reference to the NCP controller.
+ * @param[in] aNcp A reference to the NCP controller.
*
*/
- DBusAgent(otbr::Ncp::ControllerOpenThread &aNcp);
+ DBusAgent(otbr::Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher);
/**
* This method initializes the dbus agent.
*
- * @returns The intialization error.
- *
*/
- otbrError Init(void);
+ void Init(void);
- /**
- * This method updates the mainloop context.
- *
- * @param[inout] aMainloop A reference to the mainloop to be updated.
- *
- */
void Update(MainloopContext &aMainloop) override;
-
- /**
- * This method processes mainloop events.
- *
- * @param[in] aMainloop A reference to the mainloop context.
- *
- */
void Process(const MainloopContext &aMainloop) override;
private:
- static dbus_bool_t AddDBusWatch(struct DBusWatch *aWatch, void *aContext);
- static void RemoveDBusWatch(struct DBusWatch *aWatch, void *aContext);
+ using Clock = std::chrono::steady_clock;
+ constexpr static std::chrono::seconds kDBusWaitAllowance = std::chrono::seconds(30);
+
+ using UniqueDBusConnection = std::unique_ptr<DBusConnection, std::function<void(DBusConnection *)>>;
+
+ static dbus_bool_t AddDBusWatch(struct DBusWatch *aWatch, void *aContext);
+ static void RemoveDBusWatch(struct DBusWatch *aWatch, void *aContext);
+ UniqueDBusConnection PrepareDBusConnection(void);
static const struct timeval kPollTimeout;
std::string mInterfaceName;
std::unique_ptr<DBusThreadObject> mThreadObject;
- using UniqueDBusConnection = std::unique_ptr<DBusConnection, std::function<void(DBusConnection *)>>;
- UniqueDBusConnection mConnection;
- otbr::Ncp::ControllerOpenThread &mNcp;
+ UniqueDBusConnection mConnection;
+ otbr::Ncp::ControllerOpenThread & mNcp;
+ Mdns::Publisher & mPublisher;
/**
* This map is used to track DBusWatch-es.
diff --git a/src/dbus/server/dbus_object.cpp b/src/dbus/server/dbus_object.cpp
index 7965d4eb..b33e8886 100644
--- a/src/dbus/server/dbus_object.cpp
+++ b/src/dbus/server/dbus_object.cpp
@@ -134,7 +134,8 @@ void DBusObject::GetPropertyMethodHandler(DBusRequest &aRequest)
DBusMessageIter iter;
std::string interfaceName;
std::string propertyName;
- otError error = OT_ERROR_NONE;
+ otError error = OT_ERROR_NONE;
+ otError replyError = OT_ERROR_NONE;
VerifyOrExit(reply != nullptr, error = OT_ERROR_NO_BUFS);
VerifyOrExit(dbus_message_iter_init(aRequest.GetMessage(), &iter), error = OT_ERROR_FAILED);
@@ -152,11 +153,11 @@ void DBusObject::GetPropertyMethodHandler(DBusRequest &aRequest)
VerifyOrExit(interfaceIter != interfaceHandlers.end(), error = OT_ERROR_NOT_FOUND);
dbus_message_iter_init_append(reply.get(), &replyIter);
- SuccessOrExit(error = interfaceIter->second(replyIter));
+ SuccessOrExit(replyError = interfaceIter->second(replyIter));
}
}
exit:
- if (error == OT_ERROR_NONE)
+ if (error == OT_ERROR_NONE && replyError == OT_ERROR_NONE)
{
if (otbrLogGetLevel() >= OTBR_LOG_DEBUG)
{
@@ -166,6 +167,12 @@ exit:
dbus_connection_send(aRequest.GetConnection(), reply.get(), nullptr);
}
+ else if (error == OT_ERROR_NONE)
+ {
+ otbrLogInfo("GetProperty %s.%s reply:%s", interfaceName.c_str(), propertyName.c_str(),
+ ConvertToDBusErrorName(replyError));
+ aRequest.ReplyOtResult(replyError);
+ }
else
{
otbrLogWarning("GetProperty %s.%s error:%s", interfaceName.c_str(), propertyName.c_str(),
@@ -249,5 +256,10 @@ DBusObject::~DBusObject(void)
{
}
+UniqueDBusMessage DBusObject::NewSignalMessage(const std::string &aInterfaceName, const std::string &aSignalName)
+{
+ return UniqueDBusMessage(dbus_message_new_signal(mObjectPath.c_str(), aInterfaceName.c_str(), aSignalName.c_str()));
+}
+
} // namespace DBus
} // namespace otbr
diff --git a/src/dbus/server/dbus_object.hpp b/src/dbus/server/dbus_object.hpp
index 5d601833..69a5c0c3 100644
--- a/src/dbus/server/dbus_object.hpp
+++ b/src/dbus/server/dbus_object.hpp
@@ -60,7 +60,7 @@ namespace DBus {
* This class is a base class for implementing a d-bus object.
*
*/
-class DBusObject
+class DBusObject : private NonCopyable
{
public:
using MethodHandlerType = std::function<void(DBusRequest &)>;
@@ -70,8 +70,8 @@ public:
/**
* The constructor of a d-bus object.
*
- * @param[in] aConnection The dbus-connection the object bounds to.
- * @param[in] aObjectPath The path of the object.
+ * @param[in] aConnection The dbus-connection the object bounds to.
+ * @param[in] aObjectPath The path of the object.
*
*/
DBusObject(DBusConnection *aConnection, const std::string &aObjectPath);
@@ -81,8 +81,8 @@ public:
*
* This method will register the object to the d-bus library.
*
- * @retval OTBR_ERROR_NONE Successfully registered the object.
- * @retval OTBR_ERROR_DBUS Failed to ragister an object.
+ * @retval OTBR_ERROR_NONE Successfully registered the object.
+ * @retval OTBR_ERROR_DBUS Failed to ragister an object.
*
*/
virtual otbrError Init(void);
@@ -90,9 +90,9 @@ public:
/**
* This method registers the method handler.
*
- * @param[in] aInterfaceName The interface name.
- * @param[in] aMethodName The method name.
- * @param[in] aHandler The method handler.
+ * @param[in] aInterfaceName The interface name.
+ * @param[in] aMethodName The method name.
+ * @param[in] aHandler The method handler.
*
*/
void RegisterMethod(const std::string & aInterfaceName,
@@ -102,33 +102,33 @@ public:
/**
* This method registers the get handler for a property.
*
- * @param[in] aInterfaceName The interface name.
- * @param[in] aMethodName The method name.
- * @param[in] aHandler The method handler.
+ * @param[in] aInterfaceName The interface name.
+ * @param[in] aPropertyName The property name.
+ * @param[in] aHandler The method handler.
*
*/
- void RegisterGetPropertyHandler(const std::string & aInterfaceName,
- const std::string & aMethodName,
- const PropertyHandlerType &aHandler);
+ virtual void RegisterGetPropertyHandler(const std::string & aInterfaceName,
+ const std::string & aPropertyName,
+ const PropertyHandlerType &aHandler);
/**
* This method registers the set handler for a property.
*
- * @param[in] aInterfaceName The interface name.
- * @param[in] aMethodName The method name.
- * @param[in] aHandler The method handler.
+ * @param[in] aInterfaceName The interface name.
+ * @param[in] aPropertyName The property name.
+ * @param[in] aHandler The method handler.
*
*/
- void RegisterSetPropertyHandler(const std::string & aInterfaceName,
- const std::string & aPropertyName,
- const PropertyHandlerType &aHandler);
+ virtual void RegisterSetPropertyHandler(const std::string & aInterfaceName,
+ const std::string & aPropertyName,
+ const PropertyHandlerType &aHandler);
/**
* This method sends a signal.
*
- * @param[in] aInterfaceName The interface name.
- * @param[in] aSignalName The signal name.
- * @param[in] aArgs The tuple to be encoded into the signal.
+ * @param[in] aInterfaceName The interface name.
+ * @param[in] aSignalName The signal name.
+ * @param[in] aArgs The tuple to be encoded into the signal.
*
* @retval OTBR_ERROR_NONE Signal successfully sent.
* @retval OTBR_ERROR_DBUS Failed to send the signal.
@@ -139,12 +139,11 @@ public:
const std::string & aSignalName,
const std::tuple<FieldTypes...> &aArgs)
{
- UniqueDBusMessage signalMsg{
- dbus_message_new_signal(mObjectPath.c_str(), aInterfaceName.c_str(), aSignalName.c_str())};
- otbrError error = OTBR_ERROR_NONE;
+ UniqueDBusMessage signalMsg = NewSignalMessage(aInterfaceName, aSignalName);
+ otbrError error = OTBR_ERROR_NONE;
VerifyOrExit(signalMsg != nullptr, error = OTBR_ERROR_DBUS);
- VerifyOrExit(error = otbr::DBus::TupleToDBusMessage(*signalMsg, aArgs));
+ SuccessOrExit(error = otbr::DBus::TupleToDBusMessage(*signalMsg, aArgs));
VerifyOrExit(dbus_connection_send(mConnection, signalMsg.get(), nullptr), error = OTBR_ERROR_DBUS);
@@ -155,9 +154,9 @@ public:
/**
* This method sends a property changed signal.
*
- * @param[in] aInterfaceName The interface name.
- * @param[in] aPropertyName The property name.
- * @param[in] aValue New value of the property.
+ * @param[in] aInterfaceName The interface name.
+ * @param[in] aPropertyName The property name.
+ * @param[in] aValue New value of the property.
*
* @retval OTBR_ERROR_NONE Signal successfully sent.
* @retval OTBR_ERROR_DBUS Failed to send the signal.
@@ -168,10 +167,9 @@ public:
const std::string &aPropertyName,
const ValueType & aValue)
{
- UniqueDBusMessage signalMsg{
- dbus_message_new_signal(mObjectPath.c_str(), DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTIES_CHANGED_SIGNAL)};
- DBusMessageIter iter, subIter, dictEntryIter;
- otbrError error = OTBR_ERROR_NONE;
+ UniqueDBusMessage signalMsg = NewSignalMessage(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTIES_CHANGED_SIGNAL);
+ DBusMessageIter iter, subIter, dictEntryIter;
+ otbrError error = OTBR_ERROR_NONE;
VerifyOrExit(signalMsg != nullptr, error = OTBR_ERROR_DBUS);
dbus_message_iter_init_append(signalMsg.get(), &iter);
@@ -216,14 +214,14 @@ public:
private:
void GetAllPropertiesMethodHandler(DBusRequest &aRequest);
-
void GetPropertyMethodHandler(DBusRequest &aRequest);
-
void SetPropertyMethodHandler(DBusRequest &aRequest);
static DBusHandlerResult sMessageHandler(DBusConnection *aConnection, DBusMessage *aMessage, void *aData);
DBusHandlerResult MessageHandler(DBusConnection *aConnection, DBusMessage *aMessage);
+ UniqueDBusMessage NewSignalMessage(const std::string &aInterfaceName, const std::string &aSignalName);
+
std::unordered_map<std::string, MethodHandlerType> mMethodHandlers;
std::unordered_map<std::string, std::unordered_map<std::string, PropertyHandlerType>> mGetPropertyHandlers;
std::unordered_map<std::string, PropertyHandlerType> mSetPropertyHandlers;
diff --git a/src/dbus/server/dbus_request.hpp b/src/dbus/server/dbus_request.hpp
index 7126cd5b..9c89bfd0 100644
--- a/src/dbus/server/dbus_request.hpp
+++ b/src/dbus/server/dbus_request.hpp
@@ -35,6 +35,7 @@
#define OTBR_LOG_TAG "DBUS"
#endif
+#include "common/code_utils.hpp"
#include "common/logging.hpp"
#include "dbus/common/dbus_message_dump.hpp"
@@ -55,8 +56,8 @@ public:
/**
* The constructor of dbus request.
*
- * @param[in] aConnection The dbus connection.
- * @param[in] aMessage The incoming dbus message.
+ * @param[in] aConnection The dbus connection.
+ * @param[in] aMessage The incoming dbus message.
*
*/
DBusRequest(DBusConnection *aConnection, DBusMessage *aMessage)
@@ -70,7 +71,7 @@ public:
/**
* The copy constructor of dbus request.
*
- * @param[in] aOther The object to be copied from.
+ * @param[in] aOther The object to be copied from.
*
*/
DBusRequest(const DBusRequest &aOther)
@@ -83,7 +84,7 @@ public:
/**
* The assignment operator of dbus request.
*
- * @param[in] aOther The object to be copied from.
+ * @param[in] aOther The object to be copied from.
*
*/
DBusRequest &operator=(const DBusRequest &aOther)
@@ -95,7 +96,7 @@ public:
/**
* This method returns the message sent to call the d-bus method.
*
- * @returns The dbus message.
+ * @returns The dbus message.
*
*/
DBusMessage *GetMessage(void) { return mMessage; }
@@ -103,7 +104,7 @@ public:
/**
* This method returns underlying d-bus connection.
*
- * @returns The dbus connection.
+ * @returns The dbus connection.
*
*/
DBusConnection *GetConnection(void) { return mConnection; }
@@ -136,9 +137,11 @@ public:
* This method replies an otError to the d-bus method call.
*
* @param[in] aError The error to be sent.
+ * @param[in] aResult The return value of the method call, if any.
*
*/
- void ReplyOtResult(otError aError)
+ template <typename ResultType = int>
+ void ReplyOtResult(otError aError, Optional<ResultType> aResult = Optional<ResultType>())
{
UniqueDBusMessage reply{nullptr};
@@ -161,12 +164,19 @@ public:
{
reply = UniqueDBusMessage(dbus_message_new_error(mMessage, ConvertToDBusErrorName(aError), nullptr));
}
+ VerifyOrDie(reply != nullptr, "Failed to allocate message");
- VerifyOrExit(reply != nullptr);
- dbus_connection_send(mConnection, reply.get(), nullptr);
+ if (aResult.HasValue())
+ {
+ DBusMessageIter replyIter;
+ otbrError error;
- exit:
- return;
+ dbus_message_iter_init_append(reply.get(), &replyIter);
+ error = DBusMessageEncode(&replyIter, *aResult);
+ VerifyOrDie(error == OTBR_ERROR_NONE, "Failed to encode result");
+ }
+
+ dbus_connection_send(mConnection, reply.get(), nullptr);
}
/**
diff --git a/src/dbus/server/dbus_thread_object.cpp b/src/dbus/server/dbus_thread_object.cpp
index ea1cce44..b5b99f85 100644
--- a/src/dbus/server/dbus_thread_object.cpp
+++ b/src/dbus/server/dbus_thread_object.cpp
@@ -31,11 +31,13 @@
#include <openthread/border_router.h>
#include <openthread/channel_monitor.h>
+#include <openthread/dnssd_server.h>
#include <openthread/instance.h>
#include <openthread/joiner.h>
#include <openthread/link_raw.h>
#include <openthread/ncp.h>
#include <openthread/netdata.h>
+#include <openthread/srp_server.h>
#include <openthread/thread_ftd.h>
#include <openthread/platform/radio.h>
@@ -93,22 +95,29 @@ namespace DBus {
DBusThreadObject::DBusThreadObject(DBusConnection * aConnection,
const std::string & aInterfaceName,
- otbr::Ncp::ControllerOpenThread *aNcp)
+ otbr::Ncp::ControllerOpenThread *aNcp,
+ Mdns::Publisher * aPublisher)
: DBusObject(aConnection, OTBR_DBUS_OBJECT_PREFIX + aInterfaceName)
, mNcp(aNcp)
+ , mPublisher(aPublisher)
{
}
otbrError DBusThreadObject::Init(void)
{
- otbrError error = DBusObject::Init();
+ otbrError error = OTBR_ERROR_NONE;
auto threadHelper = mNcp->GetThreadHelper();
+ SuccessOrExit(error = DBusObject::Init());
+
threadHelper->AddDeviceRoleHandler(std::bind(&DBusThreadObject::DeviceRoleHandler, this, _1));
+ threadHelper->AddActiveDatasetChangeHandler(std::bind(&DBusThreadObject::ActiveDatasetChangeHandler, this, _1));
mNcp->RegisterResetHandler(std::bind(&DBusThreadObject::NcpResetHandler, this));
RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_SCAN_METHOD,
std::bind(&DBusThreadObject::ScanHandler, this, _1));
+ RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_ENERGY_SCAN_METHOD,
+ std::bind(&DBusThreadObject::EnergyScanHandler, this, _1));
RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_ATTACH_METHOD,
std::bind(&DBusThreadObject::AttachHandler, this, _1));
RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_DETACH_METHOD,
@@ -133,6 +142,10 @@ otbrError DBusThreadObject::Init(void)
std::bind(&DBusThreadObject::RemoveExternalRouteHandler, this, _1));
RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_ATTACH_ALL_NODES_TO_METHOD,
std::bind(&DBusThreadObject::AttachAllNodesToHandler, this, _1));
+ RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_UPDATE_VENDOR_MESHCOP_TXT_METHOD,
+ std::bind(&DBusThreadObject::UpdateMeshCopTxtHandler, this, _1));
+ RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_GET_PROPERTIES_METHOD,
+ std::bind(&DBusThreadObject::GetPropertiesHandler, this, _1));
RegisterMethod(DBUS_INTERFACE_INTROSPECTABLE, DBUS_INTROSPECT_METHOD,
std::bind(&DBusThreadObject::IntrospectHandler, this, _1));
@@ -159,6 +172,8 @@ otbrError DBusThreadObject::Init(void)
std::bind(&DBusThreadObject::GetPanIdHandler, this, _1));
RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_EXTPANID,
std::bind(&DBusThreadObject::GetExtPanIdHandler, this, _1));
+ RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_EUI64,
+ std::bind(&DBusThreadObject::GetEui64Handler, this, _1));
RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_CHANNEL,
std::bind(&DBusThreadObject::GetChannelHandler, this, _1));
RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_NETWORK_KEY,
@@ -203,11 +218,36 @@ otbrError DBusThreadObject::Init(void)
std::bind(&DBusThreadObject::GetRadioTxPowerHandler, this, _1));
RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES,
std::bind(&DBusThreadObject::GetExternalRoutesHandler, this, _1));
+ RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_ON_MESH_PREFIXES,
+ std::bind(&DBusThreadObject::GetOnMeshPrefixesHandler, this, _1));
RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS,
std::bind(&DBusThreadObject::GetActiveDatasetTlvsHandler, this, _1));
RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RADIO_REGION,
std::bind(&DBusThreadObject::GetRadioRegionHandler, this, _1));
+ RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_SRP_SERVER_INFO,
+ std::bind(&DBusThreadObject::GetSrpServerInfoHandler, this, _1));
+ RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_MDNS_TELEMETRY_INFO,
+ std::bind(&DBusThreadObject::GetMdnsTelemetryInfoHandler, this, _1));
+ RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DNSSD_COUNTERS,
+ std::bind(&DBusThreadObject::GetDnssdCountersHandler, this, _1));
+ RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_OT_HOST_VERSION,
+ std::bind(&DBusThreadObject::GetOtHostVersionHandler, this, _1));
+ RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_OT_RCP_VERSION,
+ std::bind(&DBusThreadObject::GetOtRcpVersionHandler, this, _1));
+ RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_THREAD_VERSION,
+ std::bind(&DBusThreadObject::GetThreadVersionHandler, this, _1));
+ RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RADIO_SPINEL_METRICS,
+ std::bind(&DBusThreadObject::GetRadioSpinelMetricsHandler, this, _1));
+ RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RCP_INTERFACE_METRICS,
+ std::bind(&DBusThreadObject::GetRcpInterfaceMetricsHandler, this, _1));
+ RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_UPTIME,
+ std::bind(&DBusThreadObject::GetUptimeHandler, this, _1));
+ RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RADIO_COEX_METRICS,
+ std::bind(&DBusThreadObject::GetRadioCoexMetrics, this, _1));
+
+ SuccessOrExit(error = Signal(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_SIGNAL_READY, std::make_tuple()));
+exit:
return error;
}
@@ -219,6 +259,8 @@ void DBusThreadObject::DeviceRoleHandler(otDeviceRole aDeviceRole)
void DBusThreadObject::NcpResetHandler(void)
{
mNcp->GetThreadHelper()->AddDeviceRoleHandler(std::bind(&DBusThreadObject::DeviceRoleHandler, this, _1));
+ mNcp->GetThreadHelper()->AddActiveDatasetChangeHandler(
+ std::bind(&DBusThreadObject::ActiveDatasetChangeHandler, this, _1));
SignalPropertyChanged(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DEVICE_ROLE,
GetDeviceRoleName(OT_DEVICE_ROLE_DISABLED));
}
@@ -245,19 +287,55 @@ void DBusThreadObject::ReplyScanResult(DBusRequest & aR
{
ActiveScanResult result;
- result.mExtAddress = ConvertOpenThreadUint64(r.mExtAddress.m8);
- result.mExtendedPanId = ConvertOpenThreadUint64(r.mExtendedPanId.m8);
- result.mNetworkName = r.mNetworkName.m8;
- result.mSteeringData =
- std::vector<uint8_t>(r.mSteeringData.m8, r.mSteeringData.m8 + r.mSteeringData.mLength);
- result.mPanId = r.mPanId;
- result.mJoinerUdpPort = r.mJoinerUdpPort;
- result.mChannel = r.mChannel;
- result.mRssi = r.mRssi;
- result.mLqi = r.mLqi;
- result.mVersion = r.mVersion;
- result.mIsNative = r.mIsNative;
- result.mIsJoinable = r.mIsJoinable;
+ result.mExtAddress = ConvertOpenThreadUint64(r.mExtAddress.m8);
+ result.mPanId = r.mPanId;
+ result.mChannel = r.mChannel;
+ result.mRssi = r.mRssi;
+ result.mLqi = r.mLqi;
+
+ results.emplace_back(result);
+ }
+
+ aRequest.Reply(std::tie(results));
+ }
+}
+
+void DBusThreadObject::EnergyScanHandler(DBusRequest &aRequest)
+{
+ otError error = OT_ERROR_NONE;
+ auto threadHelper = mNcp->GetThreadHelper();
+ uint32_t scanDuration;
+
+ auto args = std::tie(scanDuration);
+
+ VerifyOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS);
+ threadHelper->EnergyScan(scanDuration, std::bind(&DBusThreadObject::ReplyEnergyScanResult, this, aRequest, _1, _2));
+
+exit:
+ if (error != OT_ERROR_NONE)
+ {
+ aRequest.ReplyOtResult(error);
+ }
+}
+
+void DBusThreadObject::ReplyEnergyScanResult(DBusRequest & aRequest,
+ otError aError,
+ const std::vector<otEnergyScanResult> &aResult)
+{
+ std::vector<EnergyScanResult> results;
+
+ if (aError != OT_ERROR_NONE)
+ {
+ aRequest.ReplyOtResult(aError);
+ }
+ else
+ {
+ for (const auto &r : aResult)
+ {
+ EnergyScanResult result;
+
+ result.mChannel = r.mChannel;
+ result.mMaxRssi = r.mMaxRssi;
results.emplace_back(result);
}
@@ -280,7 +358,11 @@ void DBusThreadObject::AttachHandler(DBusRequest &aRequest)
if (IsDBusMessageEmpty(*aRequest.GetMessage()))
{
- threadHelper->Attach([aRequest](otError aError) mutable { aRequest.ReplyOtResult(aError); });
+ threadHelper->Attach([aRequest](otError aError, int64_t aAttachDelayMs) mutable {
+ OT_UNUSED_VARIABLE(aAttachDelayMs);
+
+ aRequest.ReplyOtResult(aError);
+ });
}
else if (DBusMessageToTuple(*aRequest.GetMessage(), args) != OTBR_ERROR_NONE)
{
@@ -289,7 +371,11 @@ void DBusThreadObject::AttachHandler(DBusRequest &aRequest)
else
{
threadHelper->Attach(name, panid, extPanId, networkKey, pskc, channelMask,
- [aRequest](otError aError) mutable { aRequest.ReplyOtResult(aError); });
+ [aRequest](otError aError, int64_t aAttachDelayMs) mutable {
+ OT_UNUSED_VARIABLE(aAttachDelayMs);
+
+ aRequest.ReplyOtResult(aError);
+ });
}
}
@@ -302,8 +388,9 @@ void DBusThreadObject::AttachAllNodesToHandler(DBusRequest &aRequest)
VerifyOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS);
- mNcp->GetThreadHelper()->AttachAllNodesTo(dataset,
- [aRequest](otError error) mutable { aRequest.ReplyOtResult(error); });
+ mNcp->GetThreadHelper()->AttachAllNodesTo(dataset, [aRequest](otError error, int64_t aAttachDelayMs) mutable {
+ aRequest.ReplyOtResult<int64_t>(error, aAttachDelayMs);
+ });
exit:
if (error != OT_ERROR_NONE)
@@ -1009,6 +1096,40 @@ exit:
return error;
}
+otError DBusThreadObject::GetOnMeshPrefixesHandler(DBusMessageIter &aIter)
+{
+ auto threadHelper = mNcp->GetThreadHelper();
+ otError error = OT_ERROR_NONE;
+ otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT;
+ otBorderRouterConfig config;
+ std::vector<OnMeshPrefix> onMeshPrefixes;
+
+ while (otNetDataGetNextOnMeshPrefix(threadHelper->GetInstance(), &iter, &config) == OT_ERROR_NONE)
+ {
+ OnMeshPrefix prefix;
+
+ prefix.mPrefix.mPrefix = std::vector<uint8_t>(&config.mPrefix.mPrefix.mFields.m8[0],
+ &config.mPrefix.mPrefix.mFields.m8[OTBR_IP6_PREFIX_SIZE]);
+ prefix.mPrefix.mLength = config.mPrefix.mLength;
+ prefix.mRloc16 = config.mRloc16;
+ prefix.mPreference = config.mPreference;
+ prefix.mPreferred = config.mPreferred;
+ prefix.mSlaac = config.mSlaac;
+ prefix.mDhcp = config.mDhcp;
+ prefix.mConfigure = config.mConfigure;
+ prefix.mDefaultRoute = config.mDefaultRoute;
+ prefix.mOnMesh = config.mOnMesh;
+ prefix.mStable = config.mStable;
+ prefix.mNdDns = config.mNdDns;
+ prefix.mDp = config.mDp;
+ onMeshPrefixes.push_back(prefix);
+ }
+ VerifyOrExit(DBusMessageEncodeToVariant(&aIter, onMeshPrefixes) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS);
+
+exit:
+ return error;
+}
+
otError DBusThreadObject::SetActiveDatasetTlvsHandler(DBusMessageIter &aIter)
{
auto threadHelper = mNcp->GetThreadHelper();
@@ -1059,6 +1180,29 @@ exit:
return error;
}
+void DBusThreadObject::UpdateMeshCopTxtHandler(DBusRequest &aRequest)
+{
+ auto threadHelper = mNcp->GetThreadHelper();
+ otError error = OT_ERROR_NONE;
+ std::map<std::string, std::vector<uint8_t>> update;
+ std::vector<TxtEntry> updatedTxtEntries;
+ auto args = std::tie(updatedTxtEntries);
+
+ VerifyOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS);
+ for (const auto &entry : updatedTxtEntries)
+ {
+ update[entry.mKey] = entry.mValue;
+ }
+ for (const auto reservedKey : {"rv", "tv", "sb", "nn", "xp", "at", "pt", "dn", "sq", "bb", "omr"})
+ {
+ VerifyOrExit(!update.count(reservedKey), error = OT_ERROR_INVALID_ARGS);
+ }
+ threadHelper->OnUpdateMeshCopTxt(std::move(update));
+
+exit:
+ aRequest.ReplyOtResult(error);
+}
+
otError DBusThreadObject::GetRadioRegionHandler(DBusMessageIter &aIter)
{
auto threadHelper = mNcp->GetThreadHelper();
@@ -1077,5 +1221,318 @@ exit:
return error;
}
+otError DBusThreadObject::GetSrpServerInfoHandler(DBusMessageIter &aIter)
+{
+#if OTBR_ENABLE_SRP_ADVERTISING_PROXY
+ auto threadHelper = mNcp->GetThreadHelper();
+ auto instance = threadHelper->GetInstance();
+ otError error = OT_ERROR_NONE;
+ SrpServerInfo srpServerInfo{};
+ otSrpServerLeaseInfo leaseInfo;
+ const otSrpServerHost * host = nullptr;
+ const otSrpServerResponseCounters *responseCounters = otSrpServerGetResponseCounters(instance);
+
+ srpServerInfo.mState = SrpServerState(static_cast<uint8_t>(otSrpServerGetState(instance)));
+ srpServerInfo.mPort = otSrpServerGetPort(instance);
+ srpServerInfo.mAddressMode = SrpServerAddressMode(static_cast<uint8_t>(otSrpServerGetAddressMode(instance)));
+
+ while ((host = otSrpServerGetNextHost(instance, host)))
+ {
+ const otSrpServerService *service = nullptr;
+
+ if (otSrpServerHostIsDeleted(host))
+ {
+ ++srpServerInfo.mHosts.mDeletedCount;
+ }
+ else
+ {
+ ++srpServerInfo.mHosts.mFreshCount;
+ otSrpServerHostGetLeaseInfo(host, &leaseInfo);
+ srpServerInfo.mHosts.mLeaseTimeTotal += leaseInfo.mLease;
+ srpServerInfo.mHosts.mKeyLeaseTimeTotal += leaseInfo.mKeyLease;
+ srpServerInfo.mHosts.mRemainingLeaseTimeTotal += leaseInfo.mRemainingLease;
+ srpServerInfo.mHosts.mRemainingKeyLeaseTimeTotal += leaseInfo.mRemainingKeyLease;
+ }
+
+ while ((service = otSrpServerHostGetNextService(host, service)))
+ {
+ if (otSrpServerServiceIsDeleted(service))
+ {
+ ++srpServerInfo.mServices.mDeletedCount;
+ }
+ else
+ {
+ ++srpServerInfo.mServices.mFreshCount;
+ otSrpServerServiceGetLeaseInfo(service, &leaseInfo);
+ srpServerInfo.mServices.mLeaseTimeTotal += leaseInfo.mLease;
+ srpServerInfo.mServices.mKeyLeaseTimeTotal += leaseInfo.mKeyLease;
+ srpServerInfo.mServices.mRemainingLeaseTimeTotal += leaseInfo.mRemainingLease;
+ srpServerInfo.mServices.mRemainingKeyLeaseTimeTotal += leaseInfo.mRemainingKeyLease;
+ }
+ }
+ }
+
+ srpServerInfo.mResponseCounters.mSuccess = responseCounters->mSuccess;
+ srpServerInfo.mResponseCounters.mServerFailure = responseCounters->mServerFailure;
+ srpServerInfo.mResponseCounters.mFormatError = responseCounters->mFormatError;
+ srpServerInfo.mResponseCounters.mNameExists = responseCounters->mNameExists;
+ srpServerInfo.mResponseCounters.mRefused = responseCounters->mRefused;
+ srpServerInfo.mResponseCounters.mOther = responseCounters->mOther;
+
+ VerifyOrExit(DBusMessageEncodeToVariant(&aIter, srpServerInfo) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS);
+
+exit:
+ return error;
+#else // OTBR_ENABLE_SRP_ADVERTISING_PROXY
+ OTBR_UNUSED_VARIABLE(aIter);
+
+ return OT_ERROR_NOT_IMPLEMENTED;
+#endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY
+}
+
+otError DBusThreadObject::GetMdnsTelemetryInfoHandler(DBusMessageIter &aIter)
+{
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(DBusMessageEncodeToVariant(&aIter, mPublisher->GetMdnsTelemetryInfo()) == OTBR_ERROR_NONE,
+ error = OT_ERROR_INVALID_ARGS);
+exit:
+ return error;
+}
+
+otError DBusThreadObject::GetDnssdCountersHandler(DBusMessageIter &aIter)
+{
+#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
+ auto threadHelper = mNcp->GetThreadHelper();
+ auto instance = threadHelper->GetInstance();
+ otError error = OT_ERROR_NONE;
+ DnssdCounters dnssdCounters;
+ otDnssdCounters otDnssdCounters = *otDnssdGetCounters(instance);
+
+ dnssdCounters.mSuccessResponse = otDnssdCounters.mSuccessResponse;
+ dnssdCounters.mServerFailureResponse = otDnssdCounters.mServerFailureResponse;
+ dnssdCounters.mFormatErrorResponse = otDnssdCounters.mFormatErrorResponse;
+ dnssdCounters.mNameErrorResponse = otDnssdCounters.mNameErrorResponse;
+ dnssdCounters.mNotImplementedResponse = otDnssdCounters.mNotImplementedResponse;
+ dnssdCounters.mOtherResponse = otDnssdCounters.mOtherResponse;
+
+ dnssdCounters.mResolvedBySrp = otDnssdCounters.mResolvedBySrp;
+
+ VerifyOrExit(DBusMessageEncodeToVariant(&aIter, dnssdCounters) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS);
+
+exit:
+ return error;
+#else // OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
+ OTBR_UNUSED_VARIABLE(aIter);
+
+ return OT_ERROR_NOT_IMPLEMENTED;
+#endif // OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
+}
+
+void DBusThreadObject::GetPropertiesHandler(DBusRequest &aRequest)
+{
+ UniqueDBusMessage reply(dbus_message_new_method_return(aRequest.GetMessage()));
+ DBusMessageIter iter;
+ DBusMessageIter replyIter;
+ DBusMessageIter replySubIter;
+ std::vector<std::string> propertyNames;
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(reply != nullptr, error = OT_ERROR_NO_BUFS);
+ VerifyOrExit(dbus_message_iter_init(aRequest.GetMessage(), &iter), error = OT_ERROR_FAILED);
+ VerifyOrExit(DBusMessageExtract(&iter, propertyNames) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
+
+ dbus_message_iter_init_append(reply.get(), &replyIter);
+ VerifyOrExit(
+ dbus_message_iter_open_container(&replyIter, DBUS_TYPE_ARRAY, DBUS_TYPE_VARIANT_AS_STRING, &replySubIter),
+ error = OT_ERROR_NO_BUFS);
+
+ for (const std::string &propertyName : propertyNames)
+ {
+ auto handlerIter = mGetPropertyHandlers.find(propertyName);
+
+ otbrLogInfo("GetPropertiesHandler getting property: %s", propertyName.c_str());
+ VerifyOrExit(handlerIter != mGetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND);
+
+ SuccessOrExit(error = handlerIter->second(replySubIter));
+ }
+
+ VerifyOrExit(dbus_message_iter_close_container(&replyIter, &replySubIter), error = OT_ERROR_NO_BUFS);
+
+exit:
+ if (error == OT_ERROR_NONE)
+ {
+ dbus_connection_send(aRequest.GetConnection(), reply.get(), nullptr);
+ }
+ else
+ {
+ aRequest.ReplyOtResult(error);
+ }
+}
+
+void DBusThreadObject::RegisterGetPropertyHandler(const std::string & aInterfaceName,
+ const std::string & aPropertyName,
+ const PropertyHandlerType &aHandler)
+{
+ DBusObject::RegisterGetPropertyHandler(aInterfaceName, aPropertyName, aHandler);
+ mGetPropertyHandlers[aPropertyName] = aHandler;
+}
+
+otError DBusThreadObject::GetOtHostVersionHandler(DBusMessageIter &aIter)
+{
+ otError error = OT_ERROR_NONE;
+ std::string version = otGetVersionString();
+
+ VerifyOrExit(DBusMessageEncodeToVariant(&aIter, version) == OTBR_ERROR_NONE, error = OT_ERROR_FAILED);
+
+exit:
+ return error;
+}
+
+otError DBusThreadObject::GetEui64Handler(DBusMessageIter &aIter)
+{
+ auto threadHelper = mNcp->GetThreadHelper();
+ otError error = OT_ERROR_NONE;
+ otExtAddress extAddr;
+ uint64_t eui64;
+
+ otLinkGetFactoryAssignedIeeeEui64(threadHelper->GetInstance(), &extAddr);
+
+ eui64 = ConvertOpenThreadUint64(extAddr.m8);
+
+ VerifyOrExit(DBusMessageEncodeToVariant(&aIter, eui64) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS);
+
+exit:
+ return error;
+}
+
+otError DBusThreadObject::GetOtRcpVersionHandler(DBusMessageIter &aIter)
+{
+ auto threadHelper = mNcp->GetThreadHelper();
+ otError error = OT_ERROR_NONE;
+ std::string version = otGetRadioVersionString(threadHelper->GetInstance());
+
+ VerifyOrExit(DBusMessageEncodeToVariant(&aIter, version) == OTBR_ERROR_NONE, error = OT_ERROR_FAILED);
+
+exit:
+ return error;
+}
+
+otError DBusThreadObject::GetThreadVersionHandler(DBusMessageIter &aIter)
+{
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(DBusMessageEncodeToVariant(&aIter, otThreadGetVersion()) == OTBR_ERROR_NONE, error = OT_ERROR_FAILED);
+
+exit:
+ return error;
+}
+
+otError DBusThreadObject::GetRadioSpinelMetricsHandler(DBusMessageIter &aIter)
+{
+ otError error = OT_ERROR_NONE;
+ RadioSpinelMetrics radioSpinelMetrics;
+ otRadioSpinelMetrics otRadioSpinelMetrics = *otSysGetRadioSpinelMetrics();
+
+ radioSpinelMetrics.mRcpTimeoutCount = otRadioSpinelMetrics.mRcpTimeoutCount;
+ radioSpinelMetrics.mRcpUnexpectedResetCount = otRadioSpinelMetrics.mRcpUnexpectedResetCount;
+ radioSpinelMetrics.mRcpRestorationCount = otRadioSpinelMetrics.mRcpRestorationCount;
+ radioSpinelMetrics.mSpinelParseErrorCount = otRadioSpinelMetrics.mSpinelParseErrorCount;
+
+ VerifyOrExit(DBusMessageEncodeToVariant(&aIter, radioSpinelMetrics) == OTBR_ERROR_NONE,
+ error = OT_ERROR_INVALID_ARGS);
+
+exit:
+ return error;
+}
+
+otError DBusThreadObject::GetRcpInterfaceMetricsHandler(DBusMessageIter &aIter)
+{
+ otError error = OT_ERROR_NONE;
+ RcpInterfaceMetrics rcpInterfaceMetrics;
+ otRcpInterfaceMetrics otRcpInterfaceMetrics = *otSysGetRcpInterfaceMetrics();
+
+ rcpInterfaceMetrics.mRcpInterfaceType = otRcpInterfaceMetrics.mRcpInterfaceType;
+ rcpInterfaceMetrics.mTransferredFrameCount = otRcpInterfaceMetrics.mTransferredFrameCount;
+ rcpInterfaceMetrics.mTransferredValidFrameCount = otRcpInterfaceMetrics.mTransferredValidFrameCount;
+ rcpInterfaceMetrics.mTransferredGarbageFrameCount = otRcpInterfaceMetrics.mTransferredGarbageFrameCount;
+ rcpInterfaceMetrics.mRxFrameCount = otRcpInterfaceMetrics.mRxFrameCount;
+ rcpInterfaceMetrics.mRxFrameByteCount = otRcpInterfaceMetrics.mRxFrameByteCount;
+ rcpInterfaceMetrics.mTxFrameCount = otRcpInterfaceMetrics.mTxFrameCount;
+ rcpInterfaceMetrics.mTxFrameByteCount = otRcpInterfaceMetrics.mTxFrameByteCount;
+
+ VerifyOrExit(DBusMessageEncodeToVariant(&aIter, rcpInterfaceMetrics) == OTBR_ERROR_NONE,
+ error = OT_ERROR_INVALID_ARGS);
+
+exit:
+ return error;
+}
+
+otError DBusThreadObject::GetUptimeHandler(DBusMessageIter &aIter)
+{
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(DBusMessageEncodeToVariant(&aIter, otInstanceGetUptime(mNcp->GetThreadHelper()->GetInstance())) ==
+ OTBR_ERROR_NONE,
+ error = OT_ERROR_INVALID_ARGS);
+
+exit:
+ return error;
+}
+
+otError DBusThreadObject::GetRadioCoexMetrics(DBusMessageIter &aIter)
+{
+ otError error = OT_ERROR_NONE;
+ otRadioCoexMetrics otRadioCoexMetrics;
+ RadioCoexMetrics radioCoexMetrics;
+
+ SuccessOrExit(error = otPlatRadioGetCoexMetrics(mNcp->GetInstance(), &otRadioCoexMetrics));
+
+ radioCoexMetrics.mNumGrantGlitch = otRadioCoexMetrics.mNumGrantGlitch;
+ radioCoexMetrics.mNumTxRequest = otRadioCoexMetrics.mNumTxRequest;
+ radioCoexMetrics.mNumTxGrantImmediate = otRadioCoexMetrics.mNumTxGrantImmediate;
+ radioCoexMetrics.mNumTxGrantWait = otRadioCoexMetrics.mNumTxGrantWait;
+ radioCoexMetrics.mNumTxGrantWaitActivated = otRadioCoexMetrics.mNumTxGrantWaitActivated;
+ radioCoexMetrics.mNumTxGrantWaitTimeout = otRadioCoexMetrics.mNumTxGrantWaitTimeout;
+ radioCoexMetrics.mNumTxGrantDeactivatedDuringRequest = otRadioCoexMetrics.mNumTxGrantDeactivatedDuringRequest;
+ radioCoexMetrics.mNumTxDelayedGrant = otRadioCoexMetrics.mNumTxDelayedGrant;
+ radioCoexMetrics.mAvgTxRequestToGrantTime = otRadioCoexMetrics.mAvgTxRequestToGrantTime;
+ radioCoexMetrics.mNumRxRequest = otRadioCoexMetrics.mNumRxRequest;
+ radioCoexMetrics.mNumRxGrantImmediate = otRadioCoexMetrics.mNumRxGrantImmediate;
+ radioCoexMetrics.mNumRxGrantWait = otRadioCoexMetrics.mNumRxGrantWait;
+ radioCoexMetrics.mNumRxGrantWaitActivated = otRadioCoexMetrics.mNumRxGrantWaitActivated;
+ radioCoexMetrics.mNumRxGrantWaitTimeout = otRadioCoexMetrics.mNumRxGrantWaitTimeout;
+ radioCoexMetrics.mNumRxGrantDeactivatedDuringRequest = otRadioCoexMetrics.mNumRxGrantDeactivatedDuringRequest;
+ radioCoexMetrics.mNumRxDelayedGrant = otRadioCoexMetrics.mNumRxDelayedGrant;
+ radioCoexMetrics.mAvgRxRequestToGrantTime = otRadioCoexMetrics.mAvgRxRequestToGrantTime;
+ radioCoexMetrics.mNumRxGrantNone = otRadioCoexMetrics.mNumRxGrantNone;
+ radioCoexMetrics.mStopped = otRadioCoexMetrics.mStopped;
+
+ VerifyOrExit(DBusMessageEncodeToVariant(&aIter, radioCoexMetrics) == OTBR_ERROR_NONE,
+ error = OT_ERROR_INVALID_ARGS);
+
+exit:
+ return error;
+}
+
+void DBusThreadObject::ActiveDatasetChangeHandler(const otOperationalDatasetTlvs &aDatasetTlvs)
+{
+ std::vector<uint8_t> value(aDatasetTlvs.mLength);
+ std::copy(aDatasetTlvs.mTlvs, aDatasetTlvs.mTlvs + aDatasetTlvs.mLength, value.begin());
+ SignalPropertyChanged(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, value);
+}
+
+static_assert(OTBR_SRP_SERVER_STATE_DISABLED == static_cast<uint8_t>(OT_SRP_SERVER_STATE_DISABLED),
+ "OTBR_SRP_SERVER_STATE_DISABLED value is incorrect");
+static_assert(OTBR_SRP_SERVER_STATE_RUNNING == static_cast<uint8_t>(OT_SRP_SERVER_STATE_RUNNING),
+ "OTBR_SRP_SERVER_STATE_RUNNING value is incorrect");
+static_assert(OTBR_SRP_SERVER_STATE_STOPPED == static_cast<uint8_t>(OT_SRP_SERVER_STATE_STOPPED),
+ "OTBR_SRP_SERVER_STATE_STOPPED value is incorrect");
+
+static_assert(OTBR_SRP_SERVER_ADDRESS_MODE_UNICAST == static_cast<uint8_t>(OT_SRP_SERVER_ADDRESS_MODE_UNICAST),
+ "OTBR_SRP_SERVER_ADDRESS_MODE_UNICAST value is incorrect");
+static_assert(OTBR_SRP_SERVER_ADDRESS_MODE_ANYCAST == static_cast<uint8_t>(OT_SRP_SERVER_ADDRESS_MODE_ANYCAST),
+ "OTBR_SRP_SERVER_ADDRESS_MODE_ANYCAST value is incorrect");
+
} // namespace DBus
} // namespace otbr
diff --git a/src/dbus/server/dbus_thread_object.hpp b/src/dbus/server/dbus_thread_object.hpp
index 7a86214a..91ebb77c 100644
--- a/src/dbus/server/dbus_thread_object.hpp
+++ b/src/dbus/server/dbus_thread_object.hpp
@@ -39,6 +39,7 @@
#include <openthread/link.h>
#include "dbus/server/dbus_object.hpp"
+#include "mdns/mdns.hpp"
#include "ncp/ncp_openthread.hpp"
namespace otbr {
@@ -63,28 +64,30 @@ public:
/**
* This constructor of dbus thread object.
*
- * @param[in] aConnection The dbus connection.
- * @param[in] aInterfaceName The dbus interface name.
- * @param[in] aNcp The ncp controller
+ * @param[in] aConnection The dbus connection.
+ * @param[in] aInterfaceName The dbus interface name.
+ * @param[in] aNcp The ncp controller
+ * @param[in] aPublisher The Mdns::Publisher
*
*/
DBusThreadObject(DBusConnection * aConnection,
const std::string & aInterfaceName,
- otbr::Ncp::ControllerOpenThread *aNcp);
+ otbr::Ncp::ControllerOpenThread *aNcp,
+ Mdns::Publisher * aPublisher);
- /**
- * This method initializes the dbus thread object.
- *
- * @returns The initialization error.
- *
- */
otbrError Init(void) override;
+ void RegisterGetPropertyHandler(const std::string & aInterfaceName,
+ const std::string & aPropertyName,
+ const PropertyHandlerType &aHandler) override;
+
private:
void DeviceRoleHandler(otDeviceRole aDeviceRole);
+ void ActiveDatasetChangeHandler(const otOperationalDatasetTlvs &aDatasetTlvs);
void NcpResetHandler(void);
void ScanHandler(DBusRequest &aRequest);
+ void EnergyScanHandler(DBusRequest &aRequest);
void AttachHandler(DBusRequest &aRequest);
void AttachAllNodesToHandler(DBusRequest &aRequest);
void DetachHandler(DBusRequest &aRequest);
@@ -98,6 +101,8 @@ private:
void RemoveOnMeshPrefixHandler(DBusRequest &aRequest);
void AddExternalRouteHandler(DBusRequest &aRequest);
void RemoveExternalRouteHandler(DBusRequest &aRequest);
+ void UpdateMeshCopTxtHandler(DBusRequest &aRequest);
+ void GetPropertiesHandler(DBusRequest &aRequest);
void IntrospectHandler(DBusRequest &aRequest);
@@ -112,6 +117,7 @@ private:
otError GetNetworkNameHandler(DBusMessageIter &aIter);
otError GetPanIdHandler(DBusMessageIter &aIter);
otError GetExtPanIdHandler(DBusMessageIter &aIter);
+ otError GetEui64Handler(DBusMessageIter &aIter);
otError GetChannelHandler(DBusMessageIter &aIter);
otError GetNetworkKeyHandler(DBusMessageIter &aIter);
otError GetCcaFailureRateHandler(DBusMessageIter &aIter);
@@ -133,12 +139,26 @@ private:
otError GetInstantRssiHandler(DBusMessageIter &aIter);
otError GetRadioTxPowerHandler(DBusMessageIter &aIter);
otError GetExternalRoutesHandler(DBusMessageIter &aIter);
+ otError GetOnMeshPrefixesHandler(DBusMessageIter &aIter);
otError GetActiveDatasetTlvsHandler(DBusMessageIter &aIter);
otError GetRadioRegionHandler(DBusMessageIter &aIter);
+ otError GetSrpServerInfoHandler(DBusMessageIter &aIter);
+ otError GetMdnsTelemetryInfoHandler(DBusMessageIter &aIter);
+ otError GetDnssdCountersHandler(DBusMessageIter &aIter);
+ otError GetOtHostVersionHandler(DBusMessageIter &aIter);
+ otError GetOtRcpVersionHandler(DBusMessageIter &aIter);
+ otError GetThreadVersionHandler(DBusMessageIter &aIter);
+ otError GetRadioSpinelMetricsHandler(DBusMessageIter &aIter);
+ otError GetRcpInterfaceMetricsHandler(DBusMessageIter &aIter);
+ otError GetUptimeHandler(DBusMessageIter &aIter);
+ otError GetRadioCoexMetrics(DBusMessageIter &aIter);
void ReplyScanResult(DBusRequest &aRequest, otError aError, const std::vector<otActiveScanResult> &aResult);
+ void ReplyEnergyScanResult(DBusRequest &aRequest, otError aError, const std::vector<otEnergyScanResult> &aResult);
- otbr::Ncp::ControllerOpenThread *mNcp;
+ otbr::Ncp::ControllerOpenThread * mNcp;
+ std::unordered_map<std::string, PropertyHandlerType> mGetPropertyHandlers;
+ otbr::Mdns::Publisher * mPublisher;
};
} // namespace DBus
diff --git a/src/dbus/server/introspect.xml b/src/dbus/server/introspect.xml
index a3f86efb..46dfe8c3 100644
--- a/src/dbus/server/introspect.xml
+++ b/src/dbus/server/introspect.xml
@@ -9,22 +9,33 @@
<literallayout>
struct {
uint64 ext_address
- string network_name
- uint64 ext_panid
- uint8[] steering_data
uint16 panid
- uint16 joiner_udp_port
uint16 channel
uint16 rssi
uint8 lqi
- uint8 version
- bool is_native
- bool is_joinable
}
</literallayout>
-->
<method name="Scan">
- <arg name="scan_result" type="a(tstayqqqqyybb)" direction="out"/>
+ <arg name="scan_result" type="a(tqqqy)" direction="out"/>
+ </method>
+
+ <!-- Energy Scan: Perform a Thread energy scan.
+ @scanDuration: The 32-bit duration time for the scan of each channel, in milliseconds.
+
+ @result: array of energy scan results.
+
+ The result struture definition is:
+ <literallayout>
+ struct {
+ uint8 channel
+ int8_t max_rssi
+ }
+ </literallayout>
+ -->
+ <method name="EnergyScan">
+ <arg name="scanduration" type="u"/>
+ <arg name="result" type="a(yy)" direction="out"/>
</method>
<!-- Attach: Attach the current device to the Thread network.
@@ -49,9 +60,15 @@
<!-- AttachAllNodesTo: Request to attach all nodes to the specified Thread network.
@dataset: The Operational Dataset that contains parameter values of the Thread network
to attach to. It must be a full dataset.
+ @delay_ms: The delay between the method returns and the dataset takes effect, in
+ milliseconds. If this value is 0, then the node is attached to the given network
+ when this method returns. If this value is not 0, then the node is attached to
+ its existing network when this method returns, and will attach to the given
+ network after the delay.
-->
<method name="AttachAllNodesTo">
<arg name="dataset" type="ay"/>
+ <arg name="delay_ms" type="x" direction="out"/>
</method>
<!-- Detach: Detach the current device from the Thread network. -->
@@ -146,12 +163,12 @@
byte preference
struct {
boolean preferred
- boolean slaac
- boolean dhcp
- boolean configure
- boolean default_route
+ boolean slaac
+ boolean dhcp
+ boolean configure
+ boolean default_route
boolean on_mesh
- boolean stable
+ boolean stable
}
}
</literallayout>
@@ -159,7 +176,7 @@
<method name="AddOnMeshPrefix">
<arg name="prefix" type="((ayy)y(bbbbbbb))"/>
</method>
-
+
<!-- RemoveOnMeshPrefix: Remove an on-mesh prefix from the network.
@prefix: The on-mesh prefix.
@@ -175,6 +192,29 @@
<arg name="prefix" type="(ayy)"/>
</method>
+ <!-- UpdateMeshCopTxt: Update multiple entries in the TXT record.
+ @key: The key of the entry.
+ @value: The value of the entry.
+
+ The prefix structure is:
+ <literallayout>
+ struct {
+ string key
+ uint8[] value
+ }
+ </literallayout>
+ -->
+ <method name="UpdateVendorMeshCopTxtEntries">
+ <arg name="update" type="a(say)" direction="in"/>
+ </method>
+
+ <!-- GetProperties: Get one or more OpenThread properties.
+ @properties: Names of properties.
+ -->
+ <method name="GetProperties">
+ <arg name="properties" type="as" direction="in"/>
+ </method>
+
<!-- MeshLocalPrefix: The /64 mesh-local prefix. -->
<property name="MeshLocalPrefix" type="ay" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
@@ -449,6 +489,32 @@
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
</property>
+ <!-- OnMeshPrefixes: The list of current on-mesh prefixes.
+ on-mesh prefix structure definition:
+ <literallayout>
+ struct {
+ struct {
+ uint8[] prefix_bytes
+ uint8 prefix_length
+ }
+ uint16 rloc
+ uint8 preference
+ bool is_preferred
+ bool is_slaac
+ bool is_dhcp
+ bool is_configure
+ bool is_default_route
+ bool is_on_mesh
+ bool is_stable
+ bool is_nd_dns
+ bool is_dp
+ }
+ </literallayout>
+ -->
+ <property name="OnMeshPrefixes" type="a((ayy)qybbbbbbbbb)" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+
<!-- ActiveDatasetTlvs: The Thread active dataset tlv in binary form. -->
<property name="ActiveDatasetTlvs" type="ay" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
@@ -458,6 +524,192 @@
<property name="RadioRegion" type="s" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
</property>
+
+ <!-- SrpServerInfo: The SRP server information.
+ <literallayout>
+ struct {
+ uint8 state
+ uint16 port
+ uint8 address_mode
+ struct { // hosts
+ uint32 fresh_count
+ uint32 deleted_count
+ uint64 lease_time_total
+ uint64 key_lease_time_total
+ uint64 remaining_lease_time_total
+ uint64 remaining_key_lease_time_total
+ }
+ struct { // services
+ uint32 fresh_count
+ uint32 deleted_count
+ uint64 lease_time_total
+ uint64 key_lease_time_total
+ uint64 remaining_lease_time_total
+ uint64 remaining_key_lease_time_total
+ }
+ struct { // response counters
+ uint32 success
+ uint32 server_failure
+ uint32 format_error
+ uint32 name_exists
+ uint32 refused
+ uint32 other
+ }
+ }
+ </literallayout>
+ -->
+ <property name="SrpServerInfo" type="(yqy(uutttt)(uutttt)(uuuuuu))" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+ <!-- DnssdCounters: The DNS-SD counters
+ <literallayout>
+ struct {
+ uint32 success
+ uint32 server_failure
+ uint32 format_error
+ uint32 name_error
+ uint32 not_implemented
+ uint32 other
+ uint32 resolved_by_srp
+ }
+ </literallayout>
+ -->
+ <property name="DnssdCounters" type="(uuuuuuu)" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+
+ <!-- MdnsTelemetryInfo: The MDNS information
+ <literallayout>
+ struct {
+ struct { // host registration responses
+ uint32 success
+ uint32 not_found
+ uint32 invalid_args
+ uint32 duplicated
+ uint32 not_implemented
+ uint32 unknown_error
+ }
+ struct { // service registration responses
+ uint32 success
+ uint32 not_found
+ uint32 invalid_args
+ uint32 duplicated
+ uint32 not_implemented
+ uint32 unknown_error
+ }
+ struct { // host resolution responses
+ uint32 success
+ uint32 not_found
+ uint32 invalid_args
+ uint32 duplicated
+ uint32 not_implemented
+ uint32 unknown_error
+ }
+ struct { // service resolution responses
+ uint32 success
+ uint32 not_found
+ uint32 invalid_args
+ uint32 duplicated
+ uint32 not_implemented
+ uint32 unknown_error
+ }
+ uint32 host_registration_ema_latency
+ uint32 service_registration_ema_latency
+ uint32 host_resolution_ema_latency
+ uint32 service_resolution_ema_latency
+ }
+ </literallayout>
+ -->
+ <property name="MdnsTelemetryInfo" type="(uuuuuu)(uuuuuu)(uuuuuu)(uuuuuu)uuuu" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+
+ <!-- OtHostVersion: The version string of the host build. -->
+ <property name="OtHostVersion" type="s" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+
+ <!-- OtRcpVersion: The version string of the RCP firmware. -->
+ <property name="OtRcpVersion" type="s" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+
+ <!-- ThreadVersion: The Thread protocol version. -->
+ <property name="ThreadVersion" type="q" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+
+ <!-- Eui64: The IEEE EUI-64 of this Thread interface. -->
+ <property name="Eui64" type="t" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+
+ <!-- RadioSpinelMetrics: The radio spinel metrics
+ <literallayout>
+ struct {
+ uint32_t mRcpTimeoutCount; // The number of RCP timeouts.
+ uint32_t mRcpUnexpectedResetCount; // The number of RCP unexcepted resets.
+ uint32_t mRcpRestorationCount; // The number of RCP restorations.
+ uint32_t mSpinelParseErrorCount; // The number of spinel frame parse errors.
+ }
+ </literallayout>
+ -->
+ <property name="RadioSpinelMetrics" type="(uuuu)" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+
+ <!-- RcpInterfaceMetrics: The RCP interface metrics
+ <literallayout>
+ struct {
+ uint8_t mRcpInterfaceType; // The RCP interface type.
+ uint64_t mTransferredFrameCount; // The number of transferred frames.
+ uint64_t mTransferredValidFrameCount; // The number of transferred valid frames.
+ uint64_t mTransferredGarbageFrameCount; // The number of transferred garbage frames.
+ uint64_t mRxFrameCount; // The number of received frames.
+ uint64_t mRxFrameByteCount; // The number of received bytes.
+ uint64_t mTxFrameCount; // The number of transmitted frames.
+ uint64_t mTxFrameByteCount; // The number of transmitted bytes.
+ }
+ </literallayout>
+ -->
+ <property name="RcpInterfaceMetrics" type="(yttttttt)" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+
+ <!-- Uptime: The number of milliseconds since OpenThread instance was initialized. -->
+ <property name="Uptime" type="t" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+
+ <!-- RadioCoexMetrics: The radio coexistence metrics
+ <literallayout>
+ struct {
+ uint32_t mNumGrantGlitch; // Number of grant glitches.
+ uint32_t mNumTxRequest; // Number of tx requests.
+ uint32_t mNumTxGrantImmediate; // Number of tx requests while grant was active.
+ uint32_t mNumTxGrantWait; // Number of tx requests while grant was inactive.
+ uint32_t mNumTxGrantWaitActivated; // Number of tx requests while grant was inactive that were ultimately granted.
+ uint32_t mNumTxGrantWaitTimeout; // Number of tx requests while grant was inactive that timed out.
+ uint32_t mNumTxGrantDeactivatedDuringRequest; // Number of tx that were in progress when grant was deactivated.
+ uint32_t mNumTxDelayedGrant; // Number of tx requests that were not granted within 50us.
+ uint32_t mAvgTxRequestToGrantTime; // Average time in usec from tx request to grant.
+ uint32_t mNumRxRequest; // Number of rx requests.
+ uint32_t mNumRxGrantImmediate; // Number of rx requests while grant was active.
+ uint32_t mNumRxGrantWait; // Number of rx requests while grant was inactive.
+ uint32_t mNumRxGrantWaitActivated; // Number of rx requests while grant was inactive that were ultimately granted.
+ uint32_t mNumRxGrantWaitTimeout; // Number of rx requests while grant was inactive that timed out.
+ uint32_t mNumRxGrantDeactivatedDuringRequest; // Number of rx that were in progress when grant was deactivated.
+ uint32_t mNumRxDelayedGrant; // Number of rx requests that were not granted within 50us.
+ uint32_t mAvgRxRequestToGrantTime; // Average time in usec from rx request to grant.
+ uint32_t mNumRxGrantNone; // Number of rx requests that completed without receiving grant.
+ bool mStopped; // Stats collection stopped due to saturation.
+ }
+ </literallayout>
+ -->
+ <property name="RadioCoexMetrics" type="(uuuuuuuuuuuuuuuuuub)" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+
</interface>
<interface name="org.freedesktop.DBus.Properties">
diff --git a/src/mdns/mdns.cpp b/src/mdns/mdns.cpp
index 214c427a..ff59f4a8 100644
--- a/src/mdns/mdns.cpp
+++ b/src/mdns/mdns.cpp
@@ -31,64 +31,508 @@
* This file includes implementation of mDNS publisher.
*/
+#define OTBR_LOG_TAG "MDNS"
+
#include "mdns/mdns.hpp"
+#include <assert.h>
+
+#include <algorithm>
+#include <functional>
+
#include "common/code_utils.hpp"
+#include "utils/dns_utils.hpp"
namespace otbr {
namespace Mdns {
-bool Publisher::IsServiceTypeEqual(const char *aFirstType, const char *aSecondType)
+void Publisher::PublishService(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList,
+ ResultCallback && aCallback)
+{
+ mServiceRegistrationBeginTime[std::make_pair(aName, aType)] = Clock::now();
+
+ PublishServiceImpl(aHostName, aName, aType, aSubTypeList, aPort, aTxtList, std::move(aCallback));
+}
+
+void Publisher::PublishHost(const std::string &aName, const std::vector<uint8_t> &aAddress, ResultCallback &&aCallback)
{
- size_t firstLength = strlen(aFirstType);
- size_t secondLength = strlen(aSecondType);
+ mHostRegistrationBeginTime[aName] = Clock::now();
- if (firstLength > 0 && aFirstType[firstLength - 1] == '.')
+ PublishHostImpl(aName, aAddress, std::move(aCallback));
+}
+
+void Publisher::OnServiceResolveFailed(const std::string &aType, const std::string &aInstanceName, int32_t aErrorCode)
+{
+ UpdateMdnsResponseCounters(mTelemetryInfo.mServiceResolutions, DnsErrorToOtbrError(aErrorCode));
+ UpdateServiceInstanceResolutionEmaLatency(aInstanceName, aType, DnsErrorToOtbrError(aErrorCode));
+ OnServiceResolveFailedImpl(aType, aInstanceName, aErrorCode);
+}
+
+void Publisher::OnHostResolveFailed(const std::string &aHostName, int32_t aErrorCode)
+{
+ UpdateMdnsResponseCounters(mTelemetryInfo.mHostResolutions, DnsErrorToOtbrError(aErrorCode));
+ UpdateHostResolutionEmaLatency(aHostName, DnsErrorToOtbrError(aErrorCode));
+ OnHostResolveFailedImpl(aHostName, aErrorCode);
+}
+
+otbrError Publisher::EncodeTxtData(const TxtList &aTxtList, std::vector<uint8_t> &aTxtData)
+{
+ otbrError error = OTBR_ERROR_NONE;
+
+ for (const auto &txtEntry : aTxtList)
{
- --firstLength;
+ const auto & name = txtEntry.mName;
+ const auto & value = txtEntry.mValue;
+ const size_t entryLength = name.length() + 1 + value.size();
+
+ VerifyOrExit(entryLength <= kMaxTextEntrySize, error = OTBR_ERROR_INVALID_ARGS);
+
+ aTxtData.push_back(static_cast<uint8_t>(entryLength));
+ aTxtData.insert(aTxtData.end(), name.begin(), name.end());
+ aTxtData.push_back('=');
+ aTxtData.insert(aTxtData.end(), value.begin(), value.end());
}
- if (secondLength > 0 && aSecondType[secondLength - 1] == '.')
+
+exit:
+ return error;
+}
+
+otbrError Publisher::DecodeTxtData(Publisher::TxtList &aTxtList, const uint8_t *aTxtData, uint16_t aTxtLength)
+{
+ otbrError error = OTBR_ERROR_NONE;
+
+ for (uint16_t r = 0; r < aTxtLength;)
{
- --secondLength;
+ uint16_t entrySize = aTxtData[r];
+ uint16_t keyStart = r + 1;
+ uint16_t entryEnd = keyStart + entrySize;
+ uint16_t keyEnd = keyStart;
+ uint16_t valStart;
+
+ while (keyEnd < entryEnd && aTxtData[keyEnd] != '=')
+ {
+ keyEnd++;
+ }
+
+ valStart = keyEnd;
+ if (valStart < entryEnd && aTxtData[valStart] == '=')
+ {
+ valStart++;
+ }
+
+ aTxtList.emplace_back(reinterpret_cast<const char *>(&aTxtData[keyStart]), keyEnd - keyStart,
+ &aTxtData[valStart], entryEnd - valStart);
+
+ r += entrySize + 1;
+ VerifyOrExit(r <= aTxtLength, error = OTBR_ERROR_PARSE);
}
- return firstLength == secondLength && memcmp(aFirstType, aSecondType, firstLength) == 0;
+exit:
+ return error;
}
-otbrError Publisher::EncodeTxtData(const TxtList &aTxtList, uint8_t *aTxtData, uint16_t &aTxtLength)
+void Publisher::RemoveSubscriptionCallbacks(uint64_t aSubscriberId)
{
- otbrError error = OTBR_ERROR_NONE;
- uint8_t * cur = aTxtData;
+ size_t erased;
- for (const auto &txtEntry : aTxtList)
+ OTBR_UNUSED_VARIABLE(erased);
+
+ assert(aSubscriberId > 0);
+
+ erased = mDiscoveredCallbacks.erase(aSubscriberId);
+
+ assert(erased == 1);
+}
+
+uint64_t Publisher::AddSubscriptionCallbacks(Publisher::DiscoveredServiceInstanceCallback aInstanceCallback,
+ Publisher::DiscoveredHostCallback aHostCallback)
+{
+ uint64_t subscriberId = mNextSubscriberId++;
+
+ assert(subscriberId > 0);
+
+ mDiscoveredCallbacks.emplace(subscriberId, std::make_pair(std::move(aInstanceCallback), std::move(aHostCallback)));
+ return subscriberId;
+}
+
+void Publisher::OnServiceResolved(const std::string &aType, const DiscoveredInstanceInfo &aInstanceInfo)
+{
+ otbrLogInfo("Service %s is resolved successfully: %s %s host %s addresses %zu", aType.c_str(),
+ aInstanceInfo.mRemoved ? "remove" : "add", aInstanceInfo.mName.c_str(), aInstanceInfo.mHostName.c_str(),
+ aInstanceInfo.mAddresses.size());
+
+ DnsUtils::CheckServiceNameSanity(aType);
+
+ assert(aInstanceInfo.mNetifIndex > 0);
+
+ if (!aInstanceInfo.mRemoved)
+ {
+ DnsUtils::CheckHostnameSanity(aInstanceInfo.mHostName);
+ }
+
+ UpdateMdnsResponseCounters(mTelemetryInfo.mServiceResolutions, OTBR_ERROR_NONE);
+ UpdateServiceInstanceResolutionEmaLatency(aInstanceInfo.mName, aType, OTBR_ERROR_NONE);
+
+ for (const auto &subCallback : mDiscoveredCallbacks)
{
- const char * name = txtEntry.mName.c_str();
- const size_t nameLength = txtEntry.mName.length();
- const uint8_t *value = txtEntry.mValue.data();
- const size_t valueLength = txtEntry.mValue.size();
- const size_t entryLength = nameLength + 1 + valueLength;
+ if (subCallback.second.first != nullptr)
+ {
+ subCallback.second.first(aType, aInstanceInfo);
+ }
+ }
+}
+
+void Publisher::OnServiceRemoved(uint32_t aNetifIndex, const std::string &aType, const std::string &aInstanceName)
+{
+ DiscoveredInstanceInfo instanceInfo;
+
+ otbrLogInfo("Service %s.%s is removed from netif %u.", aInstanceName.c_str(), aType.c_str(), aNetifIndex);
+
+ instanceInfo.mRemoved = true;
+ instanceInfo.mNetifIndex = aNetifIndex;
+ instanceInfo.mName = aInstanceName;
- VerifyOrExit(nameLength > 0 && nameLength <= kMaxTextEntrySize, error = OTBR_ERROR_INVALID_ARGS);
- VerifyOrExit(cur + entryLength + 1 <= aTxtData + aTxtLength, error = OTBR_ERROR_INVALID_ARGS);
+ OnServiceResolved(aType, instanceInfo);
+}
- cur[0] = static_cast<uint8_t>(entryLength);
- ++cur;
+void Publisher::OnHostResolved(const std::string &aHostName, const Publisher::DiscoveredHostInfo &aHostInfo)
+{
+ otbrLogInfo("Host %s is resolved successfully: host %s addresses %zu ttl %u", aHostName.c_str(),
+ aHostInfo.mHostName.c_str(), aHostInfo.mAddresses.size(), aHostInfo.mTtl);
- memcpy(cur, name, nameLength);
- cur += nameLength;
+ if (!aHostInfo.mHostName.empty())
+ {
+ DnsUtils::CheckHostnameSanity(aHostInfo.mHostName);
+ }
- cur[0] = '=';
- ++cur;
+ UpdateMdnsResponseCounters(mTelemetryInfo.mHostResolutions, OTBR_ERROR_NONE);
+ UpdateHostResolutionEmaLatency(aHostName, OTBR_ERROR_NONE);
- memcpy(cur, value, valueLength);
- cur += valueLength;
+ for (const auto &subCallback : mDiscoveredCallbacks)
+ {
+ if (subCallback.second.second != nullptr)
+ {
+ subCallback.second.second(aHostName, aHostInfo);
+ }
}
+}
+
+Publisher::SubTypeList Publisher::SortSubTypeList(SubTypeList aSubTypeList)
+{
+ std::sort(aSubTypeList.begin(), aSubTypeList.end());
+ return aSubTypeList;
+}
+
+Publisher::TxtList Publisher::SortTxtList(TxtList aTxtList)
+{
+ std::sort(aTxtList.begin(), aTxtList.end(),
+ [](const TxtEntry &aLhs, const TxtEntry &aRhs) { return aLhs.mName < aRhs.mName; });
+ return aTxtList;
+}
- aTxtLength = cur - aTxtData;
+std::string Publisher::MakeFullServiceName(const std::string &aName, const std::string &aType)
+{
+ return aName + "." + aType + ".local";
+}
+
+std::string Publisher::MakeFullHostName(const std::string &aName)
+{
+ return aName + ".local";
+}
+
+void Publisher::AddServiceRegistration(ServiceRegistrationPtr &&aServiceReg)
+{
+ mServiceRegistrations.emplace(MakeFullServiceName(aServiceReg->mName, aServiceReg->mType), std::move(aServiceReg));
+}
+
+void Publisher::RemoveServiceRegistration(const std::string &aName, const std::string &aType, otbrError aError)
+{
+ auto it = mServiceRegistrations.find(MakeFullServiceName(aName, aType));
+ ServiceRegistrationPtr serviceReg;
+
+ otbrLogInfo("Removing service %s.%s", aName.c_str(), aType.c_str());
+ VerifyOrExit(it != mServiceRegistrations.end());
+
+ // Keep the ServiceRegistration around before calling `Complete`
+ // to invoke the callback. This is for avoiding invalid access
+ // to the ServiceRegistration when it's freed from the callback.
+ serviceReg = std::move(it->second);
+ mServiceRegistrations.erase(it);
+ serviceReg->Complete(aError);
exit:
- return error;
+ return;
+}
+
+Publisher::ServiceRegistration *Publisher::FindServiceRegistration(const std::string &aName, const std::string &aType)
+{
+ auto it = mServiceRegistrations.find(MakeFullServiceName(aName, aType));
+
+ return it != mServiceRegistrations.end() ? it->second.get() : nullptr;
+}
+
+Publisher::ResultCallback Publisher::HandleDuplicateServiceRegistration(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList,
+ ResultCallback && aCallback)
+{
+ ServiceRegistration *serviceReg = FindServiceRegistration(aName, aType);
+
+ VerifyOrExit(serviceReg != nullptr);
+
+ if (serviceReg->IsOutdated(aHostName, aName, aType, aSubTypeList, aPort, aTxtList))
+ {
+ otbrLogInfo("Removing existing service %s.%s: outdated", aName.c_str(), aType.c_str());
+ RemoveServiceRegistration(aName, aType, OTBR_ERROR_ABORTED);
+ }
+ else if (serviceReg->IsCompleted())
+ {
+ // Returns success if the same service has already been
+ // registered with exactly the same parameters.
+ std::move(aCallback)(OTBR_ERROR_NONE);
+ }
+ else
+ {
+ // If the same service is being registered with the same parameters,
+ // let's join the waiting queue for the result.
+ serviceReg->mCallback = std::bind(
+ [](std::shared_ptr<ResultCallback> aExistingCallback, std::shared_ptr<ResultCallback> aNewCallback,
+ otbrError aError) {
+ std::move (*aExistingCallback)(aError);
+ std::move (*aNewCallback)(aError);
+ },
+ std::make_shared<ResultCallback>(std::move(serviceReg->mCallback)),
+ std::make_shared<ResultCallback>(std::move(aCallback)), std::placeholders::_1);
+ }
+
+exit:
+ return std::move(aCallback);
+}
+
+Publisher::ResultCallback Publisher::HandleDuplicateHostRegistration(const std::string & aName,
+ const std::vector<uint8_t> &aAddress,
+ ResultCallback && aCallback)
+{
+ HostRegistration *hostReg = FindHostRegistration(aName);
+
+ VerifyOrExit(hostReg != nullptr);
+
+ if (hostReg->IsOutdated(aName, aAddress))
+ {
+ otbrLogInfo("Removing existing host %s: outdated", aName.c_str());
+ RemoveHostRegistration(hostReg->mName, OTBR_ERROR_ABORTED);
+ }
+ else if (hostReg->IsCompleted())
+ {
+ // Returns success if the same service has already been
+ // registered with exactly the same parameters.
+ std::move(aCallback)(OTBR_ERROR_NONE);
+ }
+ else
+ {
+ // If the same service is being registered with the same parameters,
+ // let's join the waiting queue for the result.
+ hostReg->mCallback = std::bind(
+ [](std::shared_ptr<ResultCallback> aExistingCallback, std::shared_ptr<ResultCallback> aNewCallback,
+ otbrError aError) {
+ std::move (*aExistingCallback)(aError);
+ std::move (*aNewCallback)(aError);
+ },
+ std::make_shared<ResultCallback>(std::move(hostReg->mCallback)),
+ std::make_shared<ResultCallback>(std::move(aCallback)), std::placeholders::_1);
+ }
+
+exit:
+ return std::move(aCallback);
+}
+
+void Publisher::AddHostRegistration(HostRegistrationPtr &&aHostReg)
+{
+ mHostRegistrations.emplace(MakeFullHostName(aHostReg->mName), std::move(aHostReg));
+}
+
+void Publisher::RemoveHostRegistration(const std::string &aName, otbrError aError)
+{
+ auto it = mHostRegistrations.find(MakeFullHostName(aName));
+ HostRegistrationPtr hostReg;
+
+ otbrLogInfo("Removing host %s", aName.c_str());
+ VerifyOrExit(it != mHostRegistrations.end());
+
+ // Keep the HostRegistration around before calling `Complete`
+ // to invoke the callback. This is for avoiding invalid access
+ // to the HostRegistration when it's freed from the callback.
+ hostReg = std::move(it->second);
+ mHostRegistrations.erase(it);
+ hostReg->Complete(aError);
+
+exit:
+ return;
+}
+
+Publisher::HostRegistration *Publisher::FindHostRegistration(const std::string &aName)
+{
+ auto it = mHostRegistrations.find(MakeFullHostName(aName));
+
+ return it != mHostRegistrations.end() ? it->second.get() : nullptr;
+}
+
+Publisher::Registration::~Registration(void)
+{
+ TriggerCompleteCallback(OTBR_ERROR_ABORTED);
+}
+
+bool Publisher::ServiceRegistration::IsOutdated(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList) const
+{
+ return !(mHostName == aHostName && mName == aName && mType == aType && mSubTypeList == aSubTypeList &&
+ mPort == aPort && mTxtList == aTxtList);
+}
+
+void Publisher::ServiceRegistration::Complete(otbrError aError)
+{
+ OnComplete(aError);
+ Registration::TriggerCompleteCallback(aError);
+}
+
+void Publisher::ServiceRegistration::OnComplete(otbrError aError)
+{
+ if (!IsCompleted())
+ {
+ mPublisher->UpdateMdnsResponseCounters(mPublisher->mTelemetryInfo.mServiceRegistrations, aError);
+ mPublisher->UpdateServiceRegistrationEmaLatency(mName, mType, aError);
+ }
+}
+
+bool Publisher::HostRegistration::IsOutdated(const std::string &aName, const std::vector<uint8_t> &aAddress) const
+{
+ return !(mName == aName && mAddress == aAddress);
+}
+
+void Publisher::HostRegistration::Complete(otbrError aError)
+{
+ OnComplete(aError);
+ Registration::TriggerCompleteCallback(aError);
+}
+
+void Publisher::HostRegistration::OnComplete(otbrError aError)
+{
+ if (!IsCompleted())
+ {
+ mPublisher->UpdateMdnsResponseCounters(mPublisher->mTelemetryInfo.mHostRegistrations, aError);
+ mPublisher->UpdateHostRegistrationEmaLatency(mName, aError);
+ }
+}
+
+void Publisher::UpdateMdnsResponseCounters(otbr::MdnsResponseCounters &aCounters, otbrError aError)
+{
+ switch (aError)
+ {
+ case OTBR_ERROR_NONE:
+ ++aCounters.mSuccess;
+ break;
+ case OTBR_ERROR_NOT_FOUND:
+ ++aCounters.mNotFound;
+ break;
+ case OTBR_ERROR_INVALID_ARGS:
+ ++aCounters.mInvalidArgs;
+ break;
+ case OTBR_ERROR_DUPLICATED:
+ ++aCounters.mDuplicated;
+ break;
+ case OTBR_ERROR_NOT_IMPLEMENTED:
+ ++aCounters.mNotImplemented;
+ break;
+ case OTBR_ERROR_MDNS:
+ default:
+ ++aCounters.mUnknownError;
+ break;
+ }
+}
+
+void Publisher::UpdateEmaLatency(uint32_t &aEmaLatency, uint32_t aLatency, otbrError aError)
+{
+ VerifyOrExit(aError != OTBR_ERROR_ABORTED);
+
+ if (!aEmaLatency)
+ {
+ aEmaLatency = aLatency;
+ }
+ else
+ {
+ aEmaLatency =
+ (aLatency * MdnsTelemetryInfo::kEmaFactorNumerator +
+ aEmaLatency * (MdnsTelemetryInfo::kEmaFactorDenominator - MdnsTelemetryInfo::kEmaFactorNumerator)) /
+ MdnsTelemetryInfo::kEmaFactorDenominator;
+ }
+
+exit:
+ return;
+}
+
+void Publisher::UpdateServiceRegistrationEmaLatency(const std::string &aInstanceName,
+ const std::string &aType,
+ otbrError aError)
+{
+ auto it = mServiceRegistrationBeginTime.find(std::make_pair(aInstanceName, aType));
+
+ if (it != mServiceRegistrationBeginTime.end())
+ {
+ uint32_t latency = std::chrono::duration_cast<Milliseconds>(Clock::now() - it->second).count();
+ UpdateEmaLatency(mTelemetryInfo.mServiceRegistrationEmaLatency, latency, aError);
+ mServiceRegistrationBeginTime.erase(it);
+ }
+}
+
+void Publisher::UpdateHostRegistrationEmaLatency(const std::string &aHostName, otbrError aError)
+{
+ auto it = mHostRegistrationBeginTime.find(aHostName);
+
+ if (it != mHostRegistrationBeginTime.end())
+ {
+ uint32_t latency = std::chrono::duration_cast<Milliseconds>(Clock::now() - it->second).count();
+ UpdateEmaLatency(mTelemetryInfo.mHostRegistrationEmaLatency, latency, aError);
+ mHostRegistrationBeginTime.erase(it);
+ }
+}
+
+void Publisher::UpdateServiceInstanceResolutionEmaLatency(const std::string &aInstanceName,
+ const std::string &aType,
+ otbrError aError)
+{
+ auto it = mServiceInstanceResolutionBeginTime.find(std::make_pair(aInstanceName, aType));
+
+ if (it != mServiceInstanceResolutionBeginTime.end())
+ {
+ uint32_t latency = std::chrono::duration_cast<Milliseconds>(Clock::now() - it->second).count();
+ UpdateEmaLatency(mTelemetryInfo.mServiceResolutionEmaLatency, latency, aError);
+ mServiceInstanceResolutionBeginTime.erase(it);
+ }
+}
+
+void Publisher::UpdateHostResolutionEmaLatency(const std::string &aHostName, otbrError aError)
+{
+ auto it = mHostResolutionBeginTime.find(aHostName);
+
+ if (it != mHostResolutionBeginTime.end())
+ {
+ uint32_t latency = std::chrono::duration_cast<Milliseconds>(Clock::now() - it->second).count();
+ UpdateEmaLatency(mTelemetryInfo.mHostResolutionEmaLatency, latency, aError);
+ mHostResolutionBeginTime.erase(it);
+ }
}
} // namespace Mdns
diff --git a/src/mdns/mdns.hpp b/src/mdns/mdns.hpp
index f1145833..8307584c 100644
--- a/src/mdns/mdns.hpp
+++ b/src/mdns/mdns.hpp
@@ -35,11 +35,16 @@
#define OTBR_AGENT_MDNS_HPP_
#include <functional>
+#include <map>
+#include <memory>
#include <string>
#include <vector>
#include <sys/select.h>
+#include "common/callback.hpp"
+#include "common/code_utils.hpp"
+#include "common/time.hpp"
#include "common/types.hpp"
namespace otbr {
@@ -50,16 +55,16 @@ namespace Mdns {
* @addtogroup border-router-mdns
*
* @brief
- * This module includes definition for mDNS service.
+ * This module includes definition for mDNS publisher.
*
* @{
*/
/**
- * This interface defines the functionality of mDNS service.
+ * This interface defines the functionality of mDNS publisher.
*
*/
-class Publisher
+class Publisher : private NonCopyable
{
public:
/**
@@ -86,6 +91,8 @@ public:
, mValue(aValue, aValue + aValueLength)
{
}
+
+ bool operator==(const TxtEntry &aOther) const { return mName == aOther.mName && mValue == aOther.mValue; }
};
typedef std::vector<TxtEntry> TxtList;
@@ -97,14 +104,16 @@ public:
*/
struct DiscoveredInstanceInfo
{
- std::string mName; ///< Instance name.
- std::string mHostName; ///< Full host name.
- std::vector<Ip6Address> mAddresses; ///< IPv6 addresses.
- uint16_t mPort = 0; ///< Port.
- uint16_t mPriority = 0; ///< Service priority.
- uint16_t mWeight = 0; ///< Service weight.
- std::vector<uint8_t> mTxtData; ///< TXT RDATA bytes.
- uint32_t mTtl = 0; ///< Service TTL.
+ bool mRemoved = false; ///< The Service Instance is removed.
+ uint32_t mNetifIndex = 0; ///< Network interface.
+ std::string mName; ///< Instance name.
+ std::string mHostName; ///< Full host name.
+ std::vector<Ip6Address> mAddresses; ///< IPv6 addresses.
+ uint16_t mPort = 0; ///< Port.
+ uint16_t mPriority = 0; ///< Service priority.
+ uint16_t mWeight = 0; ///< Service weight.
+ std::vector<uint8_t> mTxtData; ///< TXT RDATA bytes.
+ uint32_t mTtl = 0; ///< Service TTL.
};
/**
@@ -142,73 +151,23 @@ public:
kReady, ///< Ready to publish service.
};
- /**
- * This function pointer is called when mDNS service state changed.
- *
- * @param[in] aContext A pointer to application-specific context.
- * @param[in] aState The new state.
- *
- */
- typedef void (*StateHandler)(void *aContext, State aState);
-
- /**
- * This method reports the result of a service publication.
- *
- * @param[in] aName The service instance name.
- * @param[in] aType The service type.
- * @param[in] aError An error that indicates whether the service publication succeeds.
- * @param[in] aContext A user context.
- *
- */
- typedef void (*PublishServiceHandler)(const char *aName, const char *aType, otbrError aError, void *aContext);
+ /** The callback for receiving mDNS publisher state changes. */
+ using StateCallback = std::function<void(State aNewState)>;
- /**
- * This method reports the result of a host publication.
- *
- * @param[in] aName The host name.
- * @param[in] aError An OTBR error that indicates whether the host publication succeeds.
- * @param[in] aContext A user context.
- *
- */
- typedef void (*PublishHostHandler)(const char *aName, otbrError aError, void *aContext);
+ /** The callback for receiving the result of a operation. */
+ using ResultCallback = OnceCallback<void(otbrError aError)>;
/**
- * This method sets the handler for service publication.
+ * This method starts the mDNS publisher.
*
- * @param[in] aHandler A handler which will be called when a service publication is finished.
- * @param[in] aContext A user context which is associated to @p aHandler.
- *
- */
- void SetPublishServiceHandler(PublishServiceHandler aHandler, void *aContext)
- {
- mServiceHandler = aHandler;
- mServiceHandlerContext = aContext;
- }
-
- /**
- * This method sets the handler for host publication.
- *
- * @param[in] aHandler A handler which will be called when a host publication is finished.
- * @param[in] aContext A user context which is associated to @p aHandler.
- *
- */
- void SetPublishHostHandler(PublishHostHandler aHandler, void *aContext)
- {
- mHostHandler = aHandler;
- mHostHandlerContext = aContext;
- }
-
- /**
- * This method starts the mDNS service.
- *
- * @retval OTBR_ERROR_NONE Successfully started mDNS service;
- * @retval OTBR_ERROR_MDNS Failed to start mDNS service.
+ * @retval OTBR_ERROR_NONE Successfully started mDNS publisher;
+ * @retval OTBR_ERROR_MDNS Failed to start mDNS publisher.
*
*/
virtual otbrError Start(void) = 0;
/**
- * This method stops the mDNS service.
+ * This method stops the mDNS publisher.
*
*/
virtual void Stop(void) = 0;
@@ -216,8 +175,8 @@ public:
/**
* This method checks if publisher has been started.
*
- * @retval true Already started.
- * @retval false Not started.
+ * @retval true Already started.
+ * @retval false Not started.
*
*/
virtual bool IsStarted(void) const = 0;
@@ -225,66 +184,65 @@ public:
/**
* This method publishes or updates a service.
*
- * @param[in] aHostName The name of the host which this service resides on. If NULL is provided,
- * this service resides on local host and it is the implementation to provide
- * specific host name. Otherwise, the caller MUST publish the host with method
- * PublishHost.
- * @param[in] aPort The port number of this service.
- * @param[in] aName The name of this service.
- * @param[in] aType The type of this service.
- * @param[in] aSubTypeList A list of service subtypes.
- * @param[in] aTxtList A list of TXT name/value pairs.
- *
- * @retval OTBR_ERROR_NONE Successfully published or updated the service.
- * @retval OTBR_ERROR_ERRNO Failed to publish or update the service.
+ * @param[in] aHostName The name of the host which this service resides on. If an empty string is
+ * provided, this service resides on local host and it is the implementation
+ * to provide specific host name. Otherwise, the caller MUST publish the host
+ * with method PublishHost.
+ * @param[in] aName The name of this service.
+ * @param[in] aType The type of this service.
+ * @param[in] aSubTypeList A list of service subtypes.
+ * @param[in] aPort The port number of this service.
+ * @param[in] aTxtList A list of TXT name/value pairs.
+ * @param[in] aCallback The callback for receiving the publishing result. `OTBR_ERROR_NONE` will be
+ * returned if the operation is successful and all other values indicate a
+ * failure. Specifically, `OTBR_ERROR_DUPLICATED` indicates that the name has
+ * already been published and the caller can re-publish with a new name if an
+ * alternative name is available/acceptable.
*
*/
- virtual otbrError PublishService(const char * aHostName,
- uint16_t aPort,
- const char * aName,
- const char * aType,
- const SubTypeList &aSubTypeList,
- const TxtList & aTxtList) = 0;
+ void PublishService(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList,
+ ResultCallback && aCallback);
/**
* This method un-publishes a service.
*
- * @param[in] aName The name of this service.
- * @param[in] aType The type of this service.
- *
- * @retval OTBR_ERROR_NONE Successfully un-published the service.
- * @retval OTBR_ERROR_ERRNO Failed to un-publish the service.
+ * @param[in] aName The name of this service.
+ * @param[in] aType The type of this service.
+ * @param[in] aCallback The callback for receiving the publishing result.
*
*/
- virtual otbrError UnpublishService(const char *aName, const char *aType) = 0;
+ virtual void UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback) = 0;
/**
* This method publishes or updates a host.
*
- * Publishing a host is advertising an A/AAAA RR for the host name. This method should be called
- * before a service with non-null host name is published.
- *
- * @param[in] aName The name of the host.
- * @param[in] aAddress The address of the host.
- * @param[in] aAddressLength The length of @p aAddress.
+ * Publishing a host is advertising an AAAA RR for the host name. This method should be called
+ * before a service with non-empty host name is published.
*
- * @retval OTBR_ERROR_NONE Successfully published or updated the host.
- * @retval OTBR_ERROR_INVALID_ARGS The arguments are not valid.
- * @retval OTBR_ERROR_ERRNO Failed to publish or update the host.
+ * @param[in] aName The name of the host.
+ * @param[in] aAddress The address of the host.
+ * @param[in] aCallback The callback for receiving the publishing result.`OTBR_ERROR_NONE` will be
+ * returned if the operation is successful and all other values indicate a
+ * failure. Specifically, `OTBR_ERROR_DUPLICATED` indicates that the name has
+ * already been published and the caller can re-publish with a new name if an
+ * alternative name is available/acceptable.
*
*/
- virtual otbrError PublishHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength) = 0;
+ void PublishHost(const std::string &aName, const std::vector<uint8_t> &aAddress, ResultCallback &&aCallback);
/**
* This method un-publishes a host.
*
- * @param[in] aName A host name.
- *
- * @retval OTBR_ERROR_NONE Successfully un-published the host.
- * @retval OTBR_ERROR_ERRNO Failed to un-publish the host.
+ * @param[in] aName A host name.
+ * @param[in] aCallback The callback for receiving the publishing result.
*
*/
- virtual otbrError UnpublishHost(const char *aName) = 0;
+ virtual void UnpublishHost(const std::string &aName, ResultCallback &&aCallback) = 0;
/**
* This method subscribes a given service or service instance.
@@ -296,8 +254,8 @@ public:
* @note Discovery Proxy implementation guarantees no duplicate subscriptions for the same service or service
* instance.
*
- * @param[in] aType The service type.
- * @param[in] aInstanceName The service instance to subscribe, or empty to subscribe the service.
+ * @param[in] aType The service type.
+ * @param[in] aInstanceName The service instance to subscribe, or empty to subscribe the service.
*
*/
virtual void SubscribeService(const std::string &aType, const std::string &aInstanceName) = 0;
@@ -310,8 +268,8 @@ public:
*
* @note Discovery Proxy implementation guarantees no redundant unsubscription for a service or service instance.
*
- * @param[in] aType The service type.
- * @param[in] aInstanceName The service instance to unsubscribe, or empty to unsubscribe the service.
+ * @param[in] aType The service type.
+ * @param[in] aInstanceName The service instance to unsubscribe, or empty to unsubscribe the service.
*
*/
virtual void UnsubscribeService(const std::string &aType, const std::string &aInstanceName) = 0;
@@ -323,7 +281,7 @@ public:
*
* @note Discovery Proxy implementation guarantees no duplicate subscriptions for the same host.
*
- * @param[in] aHostName The host name (without domain).
+ * @param[in] aHostName The host name (without domain).
*
*/
virtual void SubscribeHost(const std::string &aHostName) = 0;
@@ -333,7 +291,7 @@ public:
*
* @note Discovery Proxy implementation guarantees no redundant unsubscription for a host.
*
- * @param[in] aHostName The host name (without domain).
+ * @param[in] aHostName The host name (without domain).
*
*/
virtual void UnsubscribeHost(const std::string &aHostName) = 0;
@@ -341,86 +299,269 @@ public:
/**
* This method sets the callbacks for subscriptions.
*
- * @param[in] aInstanceCallback The callback function to receive discovered service instances.
- * @param[in] aHostCallback The callback function to receive discovered hosts.
+ * @param[in] aInstanceCallback The callback function to receive discovered service instances.
+ * @param[in] aHostCallback The callback function to receive discovered hosts.
+ *
+ * @returns The Subscriber ID for the callbacks.
*
*/
- void SetSubscriptionCallbacks(DiscoveredServiceInstanceCallback aInstanceCallback,
- DiscoveredHostCallback aHostCallback)
- {
- mDiscoveredServiceInstanceCallback = std::move(aInstanceCallback);
- mDiscoveredHostCallback = std::move(aHostCallback);
- }
+ uint64_t AddSubscriptionCallbacks(DiscoveredServiceInstanceCallback aInstanceCallback,
+ DiscoveredHostCallback aHostCallback);
+
+ /**
+ * This method cancels callbacks for subscriptions.
+ *
+ * @param[in] aSubscriberId The Subscriber ID previously returned by `AddSubscriptionCallbacks`.
+ *
+ */
+ void RemoveSubscriptionCallbacks(uint64_t aSubscriberId);
+
+ /**
+ * This method returns the mDNS statistics information of the publisher.
+ *
+ * @returns The MdnsTelemetryInfo of the publisher.
+ *
+ */
+ const MdnsTelemetryInfo &GetMdnsTelemetryInfo() const { return mTelemetryInfo; }
virtual ~Publisher(void) = default;
/**
* This function creates a mDNS publisher.
*
- * @param[in] aProtocol Protocol to use for publishing. AF_INET6, AF_INET or AF_UNSPEC.
- * @param[in] aDomain The domain to register in. Set nullptr to use default mDNS domain ("local.").
- * @param[in] aHandler The function to be called when this service state changed.
- * @param[in] aContext A pointer to application-specific context.
+ * @param[in] aCallback The callback for receiving mDNS publisher state changes.
*
* @returns A pointer to the newly created mDNS publisher.
*
*/
- static Publisher *Create(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext);
+ static Publisher *Create(StateCallback aCallback);
/**
* This function destroys the mDNS publisher.
*
- * @param[in] aPublisher A pointer to the publisher.
+ * @param[in] aPublisher A pointer to the publisher.
*
*/
static void Destroy(Publisher *aPublisher);
/**
- * This function decides if two service types (names) are equal.
+ * This function writes the TXT entry list to a TXT data buffer. The TXT entries
+ * will be sorted by their keys.
+ *
+ * The output data is in standard DNS-SD TXT data format.
+ * See RFC 6763 for details: https://tools.ietf.org/html/rfc6763#section-6.
*
- * Different implementations may or not append a dot ('.') to the service type (name)
- * and we can not compare if two service type are equal with `strcmp`. This function
- * ignores the trailing dot when comparing two service types.
+ * @param[in] aTxtList A TXT entry list.
+ * @param[out] aTxtData A TXT data buffer.
*
- * @param[in] aFirstType The first service type.
- * @param[in] aSecondType The second service type.
+ * @retval OTBR_ERROR_NONE Successfully write the TXT entry list.
+ * @retval OTBR_ERROR_INVALID_ARGS The @p aTxtList includes invalid TXT entry.
*
- * returns A boolean that indicates whether the two service types are equal.
+ * @sa DecodeTxtData
*
*/
- static bool IsServiceTypeEqual(const char *aFirstType, const char *aSecondType);
+ static otbrError EncodeTxtData(const TxtList &aTxtList, std::vector<uint8_t> &aTxtData);
/**
- * This function writes the TXT entry list to a TXT data buffer.
+ * This function decodes a TXT entry list from a TXT data buffer.
*
- * The output data is in standard DNS-SD TXT data format.
+ * The input data should be in standard DNS-SD TXT data format.
* See RFC 6763 for details: https://tools.ietf.org/html/rfc6763#section-6.
*
- * @param[in] aTxtList A TXT entry list.
- * @param[out] aTxtData A TXT data buffer.
- * @param[inout] aTxtLength As input, it is the length of the TXT data buffer;
- * As output, it is the length of the TXT data written.
+ * @param[out] aTxtList A TXT entry list.
+ * @param[in] aTxtData A pointer to TXT data.
+ * @param[in] aTxtLength The TXT data length.
+ *
+ * @retval OTBR_ERROR_NONE Successfully decoded the TXT data.
+ * @retval OTBR_ERROR_INVALID_ARGS The @p aTxtdata has invalid TXT format.
*
- * @retval OTBR_ERROR_NONE Successfully write the TXT entry list.
- * @retval OTBR_ERROR_INVALID_ARGS The input TXT data buffer cannot hold the TXT data.
+ * @sa EncodeTxtData
*
*/
- static otbrError EncodeTxtData(const TxtList &aTxtList, uint8_t *aTxtData, uint16_t &aTxtLength);
+ static otbrError DecodeTxtData(TxtList &aTxtList, const uint8_t *aTxtData, uint16_t aTxtLength);
protected:
- enum : uint8_t
+ static constexpr uint8_t kMaxTextEntrySize = 255;
+
+ class Registration
{
- kMaxTextEntrySize = 255,
+ public:
+ ResultCallback mCallback;
+ Publisher * mPublisher;
+
+ Registration(ResultCallback &&aCallback, Publisher *aPublisher)
+ : mCallback(std::move(aCallback))
+ , mPublisher(aPublisher)
+ {
+ }
+ virtual ~Registration(void);
+
+ // Tells whether the service registration has been completed (typically by calling
+ // `ServiceRegistration::Complete`).
+ bool IsCompleted() const { return mCallback.IsNull(); }
+
+ protected:
+ // Completes the service registration with given result/error.
+ void TriggerCompleteCallback(otbrError aError)
+ {
+ if (!IsCompleted())
+ {
+ std::move(mCallback)(aError);
+ }
+ }
};
- PublishServiceHandler mServiceHandler = nullptr;
- void * mServiceHandlerContext = nullptr;
+ class ServiceRegistration : public Registration
+ {
+ public:
+ std::string mHostName;
+ std::string mName;
+ std::string mType;
+ SubTypeList mSubTypeList;
+ uint16_t mPort;
+ TxtList mTxtList;
+
+ ServiceRegistration(std::string aHostName,
+ std::string aName,
+ std::string aType,
+ SubTypeList aSubTypeList,
+ uint16_t aPort,
+ TxtList aTxtList,
+ ResultCallback &&aCallback,
+ Publisher * aPublisher)
+ : Registration(std::move(aCallback), aPublisher)
+ , mHostName(std::move(aHostName))
+ , mName(std::move(aName))
+ , mType(std::move(aType))
+ , mSubTypeList(SortSubTypeList(std::move(aSubTypeList)))
+ , mPort(aPort)
+ , mTxtList(SortTxtList(std::move(aTxtList)))
+ {
+ }
+ ~ServiceRegistration(void) override { OnComplete(OTBR_ERROR_ABORTED); }
+
+ void Complete(otbrError aError);
+
+ void OnComplete(otbrError aError);
+
+ // Tells whether this `ServiceRegistration` object is outdated comparing to the given parameters.
+ bool IsOutdated(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList) const;
+ };
- PublishHostHandler mHostHandler = nullptr;
- void * mHostHandlerContext = nullptr;
+ class HostRegistration : public Registration
+ {
+ public:
+ std::string mName;
+ std::vector<uint8_t> mAddress;
+
+ HostRegistration(std::string aName,
+ std::vector<uint8_t> aAddress,
+ ResultCallback && aCallback,
+ Publisher * aPublisher)
+ : Registration(std::move(aCallback), aPublisher)
+ , mName(std::move(aName))
+ , mAddress(std::move(aAddress))
+ {
+ }
+
+ ~HostRegistration(void) { OnComplete(OTBR_ERROR_ABORTED); }
+
+ void Complete(otbrError aError);
+
+ void OnComplete(otbrError);
+
+ // Tells whether this `HostRegistration` object is outdated comparing to the given parameters.
+ bool IsOutdated(const std::string &aName, const std::vector<uint8_t> &aAddress) const;
+ };
- DiscoveredServiceInstanceCallback mDiscoveredServiceInstanceCallback = nullptr;
- DiscoveredHostCallback mDiscoveredHostCallback = nullptr;
+ using ServiceRegistrationPtr = std::unique_ptr<ServiceRegistration>;
+ using ServiceRegistrationMap = std::map<std::string, ServiceRegistrationPtr>;
+ using HostRegistrationPtr = std::unique_ptr<HostRegistration>;
+ using HostRegistrationMap = std::map<std::string, HostRegistrationPtr>;
+
+ static SubTypeList SortSubTypeList(SubTypeList aSubTypeList);
+ static TxtList SortTxtList(TxtList aTxtList);
+ static std::string MakeFullServiceName(const std::string &aName, const std::string &aType);
+ static std::string MakeFullHostName(const std::string &aName);
+
+ virtual void PublishServiceImpl(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList,
+ ResultCallback && aCallback) = 0;
+ virtual void PublishHostImpl(const std::string & aName,
+ const std::vector<uint8_t> &aAddress,
+ ResultCallback && aCallback) = 0;
+ virtual void OnServiceResolveFailedImpl(const std::string &aType,
+ const std::string &aInstanceName,
+ int32_t aErrorCode) = 0;
+ virtual void OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode) = 0;
+
+ virtual otbrError DnsErrorToOtbrError(int32_t aError) = 0;
+
+ void AddServiceRegistration(ServiceRegistrationPtr &&aServiceReg);
+ void RemoveServiceRegistration(const std::string &aName, const std::string &aType, otbrError aError);
+ ServiceRegistration *FindServiceRegistration(const std::string &aName, const std::string &aType);
+ void OnServiceResolved(const std::string &aType, const DiscoveredInstanceInfo &aInstanceInfo);
+ void OnServiceResolveFailed(const std::string &aType, const std::string &aInstanceName, int32_t aErrorCode);
+ void OnServiceRemoved(uint32_t aNetifIndex, const std::string &aType, const std::string &aInstanceName);
+ void OnHostResolved(const std::string &aHostName, const DiscoveredHostInfo &aHostInfo);
+ void OnHostResolveFailed(const std::string &aHostName, int32_t aErrorCode);
+
+ // Handles the cases that there is already a registration for the same service.
+ // If the returned callback is completed, current registration should be considered
+ // success and no further action should be performed.
+ ResultCallback HandleDuplicateServiceRegistration(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList,
+ ResultCallback && aCallback);
+
+ ResultCallback HandleDuplicateHostRegistration(const std::string & aName,
+ const std::vector<uint8_t> &aAddress,
+ ResultCallback && aCallback);
+
+ void AddHostRegistration(HostRegistrationPtr &&aHostReg);
+ void RemoveHostRegistration(const std::string &aName, otbrError aError);
+ HostRegistration *FindHostRegistration(const std::string &aName);
+
+ static void UpdateMdnsResponseCounters(otbr::MdnsResponseCounters &aCounters, otbrError aError);
+ static void UpdateEmaLatency(uint32_t &aEmaLatency, uint32_t aLatency, otbrError aError);
+
+ void UpdateServiceRegistrationEmaLatency(const std::string &aInstanceName,
+ const std::string &aType,
+ otbrError aError);
+ void UpdateHostRegistrationEmaLatency(const std::string &aHostName, otbrError aError);
+ void UpdateServiceInstanceResolutionEmaLatency(const std::string &aInstanceName,
+ const std::string &aType,
+ otbrError aError);
+ void UpdateHostResolutionEmaLatency(const std::string &aHostName, otbrError aError);
+
+ ServiceRegistrationMap mServiceRegistrations;
+ HostRegistrationMap mHostRegistrations;
+
+ uint64_t mNextSubscriberId = 1;
+
+ std::map<uint64_t, std::pair<DiscoveredServiceInstanceCallback, DiscoveredHostCallback>> mDiscoveredCallbacks;
+ // {instance name, service type} -> the timepoint to begin service registration
+ std::map<std::pair<std::string, std::string>, Timepoint> mServiceRegistrationBeginTime;
+ // host name -> the timepoint to begin host registration
+ std::map<std::string, Timepoint> mHostRegistrationBeginTime;
+ // {instance name, service type} -> the timepoint to begin service resolution
+ std::map<std::pair<std::string, std::string>, Timepoint> mServiceInstanceResolutionBeginTime;
+ // host name -> the timepoint to begin host resolution
+ std::map<std::string, Timepoint> mHostResolutionBeginTime;
+
+ otbr::MdnsTelemetryInfo mTelemetryInfo{};
};
/**
diff --git a/src/mdns/mdns_avahi.cpp b/src/mdns/mdns_avahi.cpp
index 6ae95ca1..483a8d73 100644
--- a/src/mdns/mdns_avahi.cpp
+++ b/src/mdns/mdns_avahi.cpp
@@ -28,7 +28,7 @@
/**
* @file
- * This file implements mDNS service based on avahi.
+ * This file implements mDNS publisher based on avahi.
*/
#define OTBR_LOG_TAG "MDNS"
@@ -43,6 +43,7 @@
#include <avahi-common/malloc.h>
#include <avahi-common/timeval.h>
#include <errno.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -51,31 +52,153 @@
#include "common/code_utils.hpp"
#include "common/logging.hpp"
#include "common/time.hpp"
-#include "utils/strcpy_utils.hpp"
-
-AvahiTimeout::AvahiTimeout(const struct timeval *aTimeout,
- AvahiTimeoutCallback aCallback,
- void * aContext,
- void * aPoller)
- : mCallback(aCallback)
- , mContext(aContext)
- , mPoller(aPoller)
+
+struct AvahiWatch
{
- if (aTimeout)
+ int mFd; ///< The file descriptor to watch.
+ AvahiWatchEvent mEvents; ///< The interested events.
+ int mHappened; ///< The events happened.
+ AvahiWatchCallback mCallback; ///< The function to be called when interested events happened on mFd.
+ void * mContext; ///< A pointer to application-specific context.
+ void * mPoller; ///< The poller created this watch.
+
+ /**
+ * The constructor to initialize an Avahi watch.
+ *
+ * @param[in] aFd The file descriptor to watch.
+ * @param[in] aEvents The events to watch.
+ * @param[in] aCallback The function to be called when events happend on this file descriptor.
+ * @param[in] aContext A pointer to application-specific context.
+ * @param[in] aPoller The AvahiPoller this watcher belongs to.
+ *
+ */
+ AvahiWatch(int aFd, AvahiWatchEvent aEvents, AvahiWatchCallback aCallback, void *aContext, void *aPoller)
+ : mFd(aFd)
+ , mEvents(aEvents)
+ , mCallback(aCallback)
+ , mContext(aContext)
+ , mPoller(aPoller)
{
- mTimeout = otbr::Clock::now() + otbr::FromTimeval<otbr::Microseconds>(*aTimeout);
}
- else
+};
+
+/**
+ * This structure implements the AvahiTimeout.
+ *
+ */
+struct AvahiTimeout
+{
+ otbr::Timepoint mTimeout; ///< Absolute time when this timer timeout.
+ AvahiTimeoutCallback mCallback; ///< The function to be called when timeout.
+ void * mContext; ///< The pointer to application-specific context.
+ void * mPoller; ///< The poller created this timer.
+
+ /**
+ * The constructor to initialize an AvahiTimeout.
+ *
+ * @param[in] aTimeout A pointer to the time after which the callback should be called.
+ * @param[in] aCallback The function to be called after timeout.
+ * @param[in] aContext A pointer to application-specific context.
+ * @param[in] aPoller The AvahiPoller this timeout belongs to.
+ *
+ */
+ AvahiTimeout(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext, void *aPoller)
+ : mCallback(aCallback)
+ , mContext(aContext)
+ , mPoller(aPoller)
{
- mTimeout = otbr::Timepoint::min();
+ if (aTimeout)
+ {
+ mTimeout = otbr::Clock::now() + otbr::FromTimeval<otbr::Microseconds>(*aTimeout);
+ }
+ else
+ {
+ mTimeout = otbr::Timepoint::min();
+ }
}
-}
+};
namespace otbr {
namespace Mdns {
-Poller::Poller(void)
+static otbrError DnsErrorToOtbrError(int aAvahiError)
+{
+ otbrError error;
+
+ switch (aAvahiError)
+ {
+ case AVAHI_OK:
+ case AVAHI_ERR_INVALID_ADDRESS:
+ error = OTBR_ERROR_NONE;
+ break;
+
+ case AVAHI_ERR_NOT_FOUND:
+ error = OTBR_ERROR_NOT_FOUND;
+ break;
+
+ case AVAHI_ERR_INVALID_ARGUMENT:
+ error = OTBR_ERROR_INVALID_ARGS;
+ break;
+
+ case AVAHI_ERR_COLLISION:
+ error = OTBR_ERROR_DUPLICATED;
+ break;
+
+ case AVAHI_ERR_DNS_NOTIMP:
+ case AVAHI_ERR_NOT_SUPPORTED:
+ error = OTBR_ERROR_NOT_IMPLEMENTED;
+ break;
+
+ default:
+ error = OTBR_ERROR_MDNS;
+ break;
+ }
+
+ return error;
+}
+
+class AvahiPoller : public MainloopProcessor
+{
+public:
+ AvahiPoller(void);
+
+ // Implementation of MainloopProcessor.
+
+ void Update(MainloopContext &aMainloop) override;
+ void Process(const MainloopContext &aMainloop) override;
+
+ const AvahiPoll *GetAvahiPoll(void) const { return &mAvahiPoller; }
+
+private:
+ typedef std::vector<AvahiWatch *> Watches;
+ typedef std::vector<AvahiTimeout *> Timers;
+
+ static AvahiWatch * WatchNew(const struct AvahiPoll *aPoller,
+ int aFd,
+ AvahiWatchEvent aEvent,
+ AvahiWatchCallback aCallback,
+ void * aContext);
+ AvahiWatch * WatchNew(int aFd, AvahiWatchEvent aEvent, AvahiWatchCallback aCallback, void *aContext);
+ static void WatchUpdate(AvahiWatch *aWatch, AvahiWatchEvent aEvent);
+ static AvahiWatchEvent WatchGetEvents(AvahiWatch *aWatch);
+ static void WatchFree(AvahiWatch *aWatch);
+ void WatchFree(AvahiWatch &aWatch);
+ static AvahiTimeout * TimeoutNew(const AvahiPoll * aPoller,
+ const struct timeval *aTimeout,
+ AvahiTimeoutCallback aCallback,
+ void * aContext);
+ AvahiTimeout * TimeoutNew(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext);
+ static void TimeoutUpdate(AvahiTimeout *aTimer, const struct timeval *aTimeout);
+ static void TimeoutFree(AvahiTimeout *aTimer);
+ void TimeoutFree(AvahiTimeout &aTimer);
+
+ Watches mWatches;
+ Timers mTimers;
+ AvahiPoll mAvahiPoller;
+};
+
+AvahiPoller::AvahiPoller(void)
{
mAvahiPoller.userdata = this;
mAvahiPoller.watch_new = WatchNew;
@@ -88,16 +211,16 @@ Poller::Poller(void)
mAvahiPoller.timeout_free = TimeoutFree;
}
-AvahiWatch *Poller::WatchNew(const struct AvahiPoll *aPoller,
- int aFd,
- AvahiWatchEvent aEvent,
- AvahiWatchCallback aCallback,
- void * aContext)
+AvahiWatch *AvahiPoller::WatchNew(const struct AvahiPoll *aPoller,
+ int aFd,
+ AvahiWatchEvent aEvent,
+ AvahiWatchCallback aCallback,
+ void * aContext)
{
- return reinterpret_cast<Poller *>(aPoller->userdata)->WatchNew(aFd, aEvent, aCallback, aContext);
+ return reinterpret_cast<AvahiPoller *>(aPoller->userdata)->WatchNew(aFd, aEvent, aCallback, aContext);
}
-AvahiWatch *Poller::WatchNew(int aFd, AvahiWatchEvent aEvent, AvahiWatchCallback aCallback, void *aContext)
+AvahiWatch *AvahiPoller::WatchNew(int aFd, AvahiWatchEvent aEvent, AvahiWatchCallback aCallback, void *aContext)
{
assert(aEvent && aCallback && aFd >= 0);
@@ -106,22 +229,22 @@ AvahiWatch *Poller::WatchNew(int aFd, AvahiWatchEvent aEvent, AvahiWatchCallback
return mWatches.back();
}
-void Poller::WatchUpdate(AvahiWatch *aWatch, AvahiWatchEvent aEvent)
+void AvahiPoller::WatchUpdate(AvahiWatch *aWatch, AvahiWatchEvent aEvent)
{
aWatch->mEvents = aEvent;
}
-AvahiWatchEvent Poller::WatchGetEvents(AvahiWatch *aWatch)
+AvahiWatchEvent AvahiPoller::WatchGetEvents(AvahiWatch *aWatch)
{
return static_cast<AvahiWatchEvent>(aWatch->mHappened);
}
-void Poller::WatchFree(AvahiWatch *aWatch)
+void AvahiPoller::WatchFree(AvahiWatch *aWatch)
{
- reinterpret_cast<Poller *>(aWatch->mPoller)->WatchFree(*aWatch);
+ reinterpret_cast<AvahiPoller *>(aWatch->mPoller)->WatchFree(*aWatch);
}
-void Poller::WatchFree(AvahiWatch &aWatch)
+void AvahiPoller::WatchFree(AvahiWatch &aWatch)
{
for (Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it)
{
@@ -134,22 +257,22 @@ void Poller::WatchFree(AvahiWatch &aWatch)
}
}
-AvahiTimeout *Poller::TimeoutNew(const AvahiPoll * aPoller,
- const struct timeval *aTimeout,
- AvahiTimeoutCallback aCallback,
- void * aContext)
+AvahiTimeout *AvahiPoller::TimeoutNew(const AvahiPoll * aPoller,
+ const struct timeval *aTimeout,
+ AvahiTimeoutCallback aCallback,
+ void * aContext)
{
assert(aPoller && aCallback);
- return static_cast<Poller *>(aPoller->userdata)->TimeoutNew(aTimeout, aCallback, aContext);
+ return static_cast<AvahiPoller *>(aPoller->userdata)->TimeoutNew(aTimeout, aCallback, aContext);
}
-AvahiTimeout *Poller::TimeoutNew(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext)
+AvahiTimeout *AvahiPoller::TimeoutNew(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext)
{
mTimers.push_back(new AvahiTimeout(aTimeout, aCallback, aContext, this));
return mTimers.back();
}
-void Poller::TimeoutUpdate(AvahiTimeout *aTimer, const struct timeval *aTimeout)
+void AvahiPoller::TimeoutUpdate(AvahiTimeout *aTimer, const struct timeval *aTimeout)
{
if (aTimeout == nullptr)
{
@@ -161,12 +284,12 @@ void Poller::TimeoutUpdate(AvahiTimeout *aTimer, const struct timeval *aTimeout)
}
}
-void Poller::TimeoutFree(AvahiTimeout *aTimer)
+void AvahiPoller::TimeoutFree(AvahiTimeout *aTimer)
{
- static_cast<Poller *>(aTimer->mPoller)->TimeoutFree(*aTimer);
+ static_cast<AvahiPoller *>(aTimer->mPoller)->TimeoutFree(*aTimer);
}
-void Poller::TimeoutFree(AvahiTimeout &aTimer)
+void AvahiPoller::TimeoutFree(AvahiTimeout &aTimer)
{
for (Timers::iterator it = mTimers.begin(); it != mTimers.end(); ++it)
{
@@ -179,7 +302,7 @@ void Poller::TimeoutFree(AvahiTimeout &aTimer)
}
}
-void Poller::Update(MainloopContext &aMainloop)
+void AvahiPoller::Update(MainloopContext &aMainloop)
{
Timepoint now = Clock::now();
@@ -239,7 +362,7 @@ void Poller::Update(MainloopContext &aMainloop)
}
}
-void Poller::Process(const MainloopContext &aMainloop)
+void AvahiPoller::Process(const MainloopContext &aMainloop)
{
Timepoint now = Clock::now();
std::vector<AvahiTimeout *> expired;
@@ -294,29 +417,39 @@ void Poller::Process(const MainloopContext &aMainloop)
}
}
-PublisherAvahi::PublisherAvahi(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext)
+PublisherAvahi::PublisherAvahi(StateCallback aStateCallback)
: mClient(nullptr)
- , mProtocol(aProtocol == AF_INET6 ? AVAHI_PROTO_INET6
- : aProtocol == AF_INET ? AVAHI_PROTO_INET : AVAHI_PROTO_UNSPEC)
- , mDomain(aDomain)
+ , mPoller(MakeUnique<AvahiPoller>())
, mState(State::kIdle)
- , mStateHandler(aHandler)
- , mContext(aContext)
+ , mStateCallback(std::move(aStateCallback))
{
}
PublisherAvahi::~PublisherAvahi(void)
{
+ Stop();
+}
+
+PublisherAvahi::AvahiServiceRegistration::~AvahiServiceRegistration(void)
+{
+ ReleaseGroup(mEntryGroup);
+}
+
+PublisherAvahi::AvahiHostRegistration::~AvahiHostRegistration(void)
+{
+ ReleaseGroup(mEntryGroup);
}
otbrError PublisherAvahi::Start(void)
{
otbrError error = OTBR_ERROR_NONE;
- int avahiError = 0;
+ int avahiError = AVAHI_OK;
- mClient = avahi_client_new(mPoller.GetAvahiPoll(), AVAHI_CLIENT_NO_FAIL, HandleClientState, this, &avahiError);
+ assert(mClient == nullptr);
- if (avahiError)
+ mClient = avahi_client_new(mPoller->GetAvahiPoll(), AVAHI_CLIENT_NO_FAIL, HandleClientState, this, &avahiError);
+
+ if (avahiError != AVAHI_OK)
{
otbrLogErr("Failed to create avahi client: %s!", avahi_strerror(avahiError));
error = OTBR_ERROR_MDNS;
@@ -332,15 +465,19 @@ bool PublisherAvahi::IsStarted(void) const
void PublisherAvahi::Stop(void)
{
- FreeAllGroups();
+ mServiceRegistrations.clear();
+ mHostRegistrations.clear();
+
+ mSubscribedServices.clear();
+ mSubscribedHosts.clear();
if (mClient)
{
avahi_client_free(mClient);
mClient = nullptr;
- mState = State::kIdle;
- mStateHandler(mContext, mState);
}
+
+ mState = Mdns::Publisher::State::kIdle;
}
void PublisherAvahi::HandleClientState(AvahiClient *aClient, AvahiClientState aState, void *aContext)
@@ -355,52 +492,26 @@ void PublisherAvahi::HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupSt
void PublisherAvahi::HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState)
{
- otbrLogInfo("Avahi group change to state %d.", aState);
-
- /* Called whenever the entry group state changes */
switch (aState)
{
case AVAHI_ENTRY_GROUP_ESTABLISHED:
- /* The entry group has been established successfully */
- otbrLogInfo("Group established.");
+ otbrLogInfo("Avahi group (@%p) is established", aGroup);
CallHostOrServiceCallback(aGroup, OTBR_ERROR_NONE);
break;
case AVAHI_ENTRY_GROUP_COLLISION:
- {
- otbrLogErr("Name collision!");
- Services::iterator serviceIt = FindService(aGroup);
- if (serviceIt != mServices.end())
- {
- Service & service = *serviceIt;
- const char *hostName = service.mHostName.c_str();
- char * alternativeName = nullptr;
- uint16_t port = service.mPort;
-
- ResetGroup(service.mGroup);
- if (service.mHostName == "")
- {
- hostName = nullptr;
- }
- alternativeName = avahi_alternative_service_name(service.mName.c_str());
- service.mName = alternativeName;
- avahi_free(alternativeName);
- service.mPort = 0; // To mark the service as outdated
- PublishService(hostName, port, service.mName.c_str(), service.mType.c_str(), service.mSubTypeList,
- service.mTxtList);
- }
+ otbrLogInfo("Avahi group (@%p) name conflicted", aGroup);
+ CallHostOrServiceCallback(aGroup, OTBR_ERROR_DUPLICATED);
break;
- }
case AVAHI_ENTRY_GROUP_FAILURE:
- /* Some kind of failure happened while we were registering our services */
- otbrLogErr("Group failed: %s!", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(aGroup))));
+ otbrLogErr("Avahi group (@%p) failed: %s!", aGroup,
+ avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(aGroup))));
CallHostOrServiceCallback(aGroup, OTBR_ERROR_MDNS);
break;
case AVAHI_ENTRY_GROUP_UNCOMMITED:
case AVAHI_ENTRY_GROUP_REGISTERING:
- otbrLogErr("Group ready.");
break;
default:
@@ -409,207 +520,112 @@ void PublisherAvahi::HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupSt
}
}
-void PublisherAvahi::CallHostOrServiceCallback(AvahiEntryGroup *aGroup, otbrError aError) const
+void PublisherAvahi::CallHostOrServiceCallback(AvahiEntryGroup *aGroup, otbrError aError)
{
- if (mHostHandler != nullptr)
- {
- const auto hostIt =
- std::find_if(mHosts.begin(), mHosts.end(), [aGroup](const Host &aHost) { return aHost.mGroup == aGroup; });
+ ServiceRegistration *serviceReg;
+ HostRegistration * hostReg;
- if (hostIt != mHosts.end())
+ if ((serviceReg = FindServiceRegistration(aGroup)) != nullptr)
+ {
+ if (aError == OTBR_ERROR_NONE)
+ {
+ serviceReg->Complete(aError);
+ }
+ else
{
- mHostHandler(hostIt->mHostName.c_str(), aError, mHostHandlerContext);
+ RemoveServiceRegistration(serviceReg->mName, serviceReg->mType, aError);
}
}
-
- if (mServiceHandler != nullptr)
+ else if ((hostReg = FindHostRegistration(aGroup)) != nullptr)
{
- const auto serviceIt = std::find_if(mServices.begin(), mServices.end(),
- [aGroup](const Service &aService) { return aService.mGroup == aGroup; });
-
- if (serviceIt != mServices.end())
+ if (aError == OTBR_ERROR_NONE)
+ {
+ hostReg->Complete(aError);
+ }
+ else
{
- mServiceHandler(serviceIt->mName.c_str(), serviceIt->mType.c_str(), aError, mServiceHandlerContext);
+ RemoveHostRegistration(hostReg->mName, aError);
}
}
-}
-
-PublisherAvahi::Hosts::iterator PublisherAvahi::FindHost(const char *aHostName)
-{
- assert(aHostName != nullptr);
-
- return std::find_if(mHosts.begin(), mHosts.end(),
- [aHostName](const Host &aHost) { return aHost.mHostName == aHostName; });
-}
-
-otbrError PublisherAvahi::CreateHost(AvahiClient &aClient, const char *aHostName, Hosts::iterator &aOutHostIt)
-{
- assert(aHostName != nullptr);
-
- otbrError error = OTBR_ERROR_NONE;
- Host newHost;
-
- newHost.mHostName = aHostName;
- SuccessOrExit(error = CreateGroup(aClient, newHost.mGroup));
-
- mHosts.push_back(newHost);
- aOutHostIt = mHosts.end() - 1;
-
-exit:
- return error;
-}
-
-PublisherAvahi::Services::iterator PublisherAvahi::FindService(const char *aName, const char *aType)
-{
- assert(aName != nullptr);
- assert(aType != nullptr);
-
- return std::find_if(mServices.begin(), mServices.end(), [aName, aType](const Service &aService) {
- return aService.mName == aName && aService.mType == aType;
- });
-}
-
-PublisherAvahi::Services::iterator PublisherAvahi::FindService(AvahiEntryGroup *aGroup)
-{
- return std::find_if(mServices.begin(), mServices.end(),
- [aGroup](const Service &aService) { return aService.mGroup == aGroup; });
-}
-
-otbrError PublisherAvahi::CreateService(AvahiClient & aClient,
- const char * aName,
- const char * aType,
- Services::iterator &aOutServiceIt)
-{
- assert(aName != nullptr);
- assert(aType != nullptr);
-
- otbrError error = OTBR_ERROR_NONE;
- Service newService;
-
- newService.mName = aName;
- newService.mType = aType;
- SuccessOrExit(error = CreateGroup(aClient, newService.mGroup));
-
- mServices.push_back(newService);
- aOutServiceIt = mServices.end() - 1;
-
-exit:
- return error;
-}
-
-bool PublisherAvahi::IsServiceOutdated(const Service & aService,
- const char * aNewHostName,
- uint16_t aNewPort,
- const SubTypeList &aNewSubTypeList)
-{
- return aService.mHostName != aNewHostName || aService.mPort != aNewPort || aService.mSubTypeList != aNewSubTypeList;
-}
-
-otbrError PublisherAvahi::CreateGroup(AvahiClient &aClient, AvahiEntryGroup *&aOutGroup)
-{
- otbrError error = OTBR_ERROR_NONE;
-
- assert(aOutGroup == nullptr);
-
- aOutGroup = avahi_entry_group_new(&aClient, HandleGroupState, this);
- VerifyOrExit(aOutGroup != nullptr, error = OTBR_ERROR_MDNS);
-
-exit:
- if (error == OTBR_ERROR_MDNS)
+ else
{
- otbrLogErr("Failed to create entry group for avahi error: %s", avahi_strerror(avahi_client_errno(&aClient)));
+ otbrLogWarning("No registered service or host matches avahi group @%p", aGroup);
}
-
- return error;
}
-otbrError PublisherAvahi::ResetGroup(AvahiEntryGroup *aGroup)
+AvahiEntryGroup *PublisherAvahi::CreateGroup(AvahiClient *aClient)
{
- assert(aGroup != nullptr);
-
- otbrError error = OTBR_ERROR_NONE;
- int avahiError = avahi_entry_group_reset(aGroup);
+ AvahiEntryGroup *group = avahi_entry_group_new(aClient, HandleGroupState, this);
- if (avahiError)
+ if (group == nullptr)
{
- error = OTBR_ERROR_MDNS;
- otbrLogErr("Failed to reset entry group for avahi error: %s", avahi_strerror(avahiError));
+ otbrLogErr("Failed to create entry avahi group: %s", avahi_strerror(avahi_client_errno(aClient)));
}
- return error;
+ return group;
}
-otbrError PublisherAvahi::FreeGroup(AvahiEntryGroup *aGroup)
+void PublisherAvahi::ReleaseGroup(AvahiEntryGroup *aGroup)
{
- assert(aGroup != nullptr);
-
- otbrError error = OTBR_ERROR_NONE;
- int avahiError = avahi_entry_group_free(aGroup);
+ int error;
- if (avahiError)
- {
- error = OTBR_ERROR_MDNS;
- otbrLogErr("Failed to free entry group for avahi error: %s", avahi_strerror(avahiError));
- }
+ otbrLogInfo("Releasing avahi entry group @%p", aGroup);
- return error;
-}
+ error = avahi_entry_group_reset(aGroup);
-void PublisherAvahi::FreeAllGroups(void)
-{
- for (Service &service : mServices)
+ if (error != 0)
{
- FreeGroup(service.mGroup);
+ otbrLogErr("Failed to reset entry group for avahi error: %s", avahi_strerror(error));
}
- mServices.clear();
-
- for (Host &host : mHosts)
+ error = avahi_entry_group_free(aGroup);
+ if (error != 0)
{
- FreeGroup(host.mGroup);
+ otbrLogErr("Failed to free entry group for avahi error: %s", avahi_strerror(error));
}
-
- mHosts.clear();
}
void PublisherAvahi::HandleClientState(AvahiClient *aClient, AvahiClientState aState)
{
- otbrLogInfo("Avahi client state changed to %d.", aState);
+ otbrLogInfo("Avahi client state changed to %d", aState);
+
switch (aState)
{
case AVAHI_CLIENT_S_RUNNING:
- /* The server has startup successfully and registered its host
- * name on the network, so it's time to create our services */
- otbrLogInfo("Avahi client ready.");
- mState = State::kReady;
+ // The server has startup successfully and registered its host
+ // name on the network, so it's time to create our services.
+ otbrLogInfo("Avahi client is ready");
mClient = aClient;
- mStateHandler(mContext, mState);
+ mState = State::kReady;
+ mStateCallback(mState);
break;
case AVAHI_CLIENT_FAILURE:
- otbrLogErr("Client failure: %s", avahi_strerror(avahi_client_errno(aClient)));
+ otbrLogErr("Avahi client failed to start: %s", avahi_strerror(avahi_client_errno(aClient)));
mState = State::kIdle;
- mStateHandler(mContext, mState);
+ mStateCallback(mState);
+ Stop();
+ Start();
break;
case AVAHI_CLIENT_S_COLLISION:
- /* Let's drop our registered services. When the server is back
- * in AVAHI_SERVER_RUNNING state we will register them
- * again with the new host name. */
- otbrLogErr("Client collision: %s", avahi_strerror(avahi_client_errno(aClient)));
+ // Let's drop our registered services. When the server is back
+ // in AVAHI_SERVER_RUNNING state we will register them again
+ // with the new host name.
+ otbrLogErr("Avahi client collision detected: %s", avahi_strerror(avahi_client_errno(aClient)));
// fall through
case AVAHI_CLIENT_S_REGISTERING:
- /* The server records are now being established. This
- * might be caused by a host name change. We need to wait
- * for our own records to register until the host name is
- * properly esatblished. */
- FreeAllGroups();
+ // The server records are now being established. This might be
+ // caused by a host name change. We need to wait for our own
+ // records to register until the host name is properly established.
+ mServiceRegistrations.clear();
+ mHostRegistrations.clear();
break;
case AVAHI_CLIENT_CONNECTING:
- otbrLogDebug("Connecting to avahi server");
+ otbrLogInfo("Avahi client is connecting to the server");
break;
default:
@@ -618,211 +634,149 @@ void PublisherAvahi::HandleClientState(AvahiClient *aClient, AvahiClientState aS
}
}
-otbrError PublisherAvahi::PublishService(const char * aHostName,
- uint16_t aPort,
- const char * aName,
- const char * aType,
- const SubTypeList &aSubTypeList,
- const TxtList & aTxtList)
+void PublisherAvahi::PublishServiceImpl(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList,
+ ResultCallback && aCallback)
{
- otbrError error = OTBR_ERROR_NONE;
- int avahiError = 0;
- Services::iterator serviceIt = mServices.end();
- const char * safeHostName = (aHostName != nullptr) ? aHostName : "";
- const char * logHostName = (aHostName != nullptr) ? aHostName : "localhost";
- std::string fullHostName;
- // aligned with AvahiStringList
- AvahiStringList buffer[(kMaxSizeOfTxtRecord - 1) / sizeof(AvahiStringList) + 1];
- AvahiStringList *head = nullptr;
-
- SuccessOrExit(error = TxtListToAvahiStringList(aTxtList, buffer, sizeof(buffer), head));
-
- VerifyOrExit(mState == State::kReady, errno = EAGAIN, error = OTBR_ERROR_ERRNO);
- VerifyOrExit(mClient != nullptr, errno = EAGAIN, error = OTBR_ERROR_ERRNO);
- VerifyOrExit(aName != nullptr, error = OTBR_ERROR_INVALID_ARGS);
- VerifyOrExit(aType != nullptr, error = OTBR_ERROR_INVALID_ARGS);
-
- if (aHostName != nullptr)
+ otbrError error = OTBR_ERROR_NONE;
+ int avahiError = AVAHI_OK;
+ SubTypeList sortedSubTypeList = SortSubTypeList(aSubTypeList);
+ TxtList sortedTxtList = SortTxtList(aTxtList);
+ const std::string logHostName = !aHostName.empty() ? aHostName : "localhost";
+ std::string fullHostName;
+ AvahiEntryGroup * group = nullptr;
+
+ // Aligned with AvahiStringList
+ AvahiStringList txtBuffer[(kMaxSizeOfTxtRecord - 1) / sizeof(AvahiStringList) + 1];
+ AvahiStringList *txtHead = nullptr;
+
+ VerifyOrExit(mState == State::kReady, error = OTBR_ERROR_INVALID_STATE);
+ VerifyOrExit(mClient != nullptr, error = OTBR_ERROR_INVALID_STATE);
+
+ if (!aHostName.empty())
{
- fullHostName = MakeFullName(aHostName);
- aHostName = fullHostName.c_str();
+ fullHostName = MakeFullHostName(aHostName);
}
- serviceIt = FindService(aName, aType);
+ aCallback = HandleDuplicateServiceRegistration(aHostName, aName, aType, sortedSubTypeList, aPort, sortedTxtList,
+ std::move(aCallback));
+ VerifyOrExit(!aCallback.IsNull());
- if (serviceIt == mServices.end())
- {
- SuccessOrExit(error = CreateService(*mClient, aName, aType, serviceIt));
- }
- else if (IsServiceOutdated(*serviceIt, safeHostName, aPort, aSubTypeList))
- {
- SuccessOrExit(error = ResetGroup(serviceIt->mGroup));
- }
- else
- {
- otbrLogInfo("Update service %s.%s for host %s", aName, aType, logHostName);
- avahiError = avahi_entry_group_update_service_txt_strlst(serviceIt->mGroup, AVAHI_IF_UNSPEC, mProtocol,
- AvahiPublishFlags{}, aName, aType, mDomain, head);
- if (avahiError == 0 && mServiceHandler != nullptr)
- {
- // The handler should be called even if the request can be processed synchronously
- mServiceHandler(aName, aType, OTBR_ERROR_NONE, mServiceHandlerContext);
- }
- serviceIt->mTxtList = aTxtList;
- ExitNow();
- }
-
- otbrLogInfo("Create service %s.%s for host %s", aName, aType, logHostName);
- avahiError =
- avahi_entry_group_add_service_strlst(serviceIt->mGroup, AVAHI_IF_UNSPEC, mProtocol, AvahiPublishFlags{}, aName,
- aType, mDomain, aHostName, aPort, head);
- SuccessOrExit(avahiError);
+ SuccessOrExit(error = TxtListToAvahiStringList(aTxtList, txtBuffer, sizeof(txtBuffer), txtHead));
+ VerifyOrExit((group = CreateGroup(mClient)) != nullptr, error = OTBR_ERROR_MDNS);
+ avahiError = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags{},
+ aName.c_str(), aType.c_str(),
+ /* domain */ nullptr, fullHostName.c_str(), aPort, txtHead);
+ VerifyOrExit(avahiError == AVAHI_OK);
for (const std::string &subType : aSubTypeList)
{
- otbrLogInfo("Add subtype %s for service %s.%s", subType.c_str(), aName, aType);
+ otbrLogInfo("Add subtype %s for service %s.%s", subType.c_str(), aName.c_str(), aType.c_str());
std::string fullSubType = subType + "._sub." + aType;
- avahiError =
- avahi_entry_group_add_service_subtype(serviceIt->mGroup, AVAHI_IF_UNSPEC, mProtocol, AvahiPublishFlags{},
- aName, aType, mDomain, fullSubType.c_str());
- SuccessOrExit(avahiError);
+ avahiError = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ AvahiPublishFlags{}, aName.c_str(), aType.c_str(),
+ /* domain */ nullptr, fullSubType.c_str());
+ VerifyOrExit(avahiError == AVAHI_OK);
}
- otbrLogInfo("Commit service %s.%s", aName, aType);
- avahiError = avahi_entry_group_commit(serviceIt->mGroup);
- SuccessOrExit(avahiError);
+ otbrLogInfo("Commit avahi service %s.%s", aName.c_str(), aType.c_str());
+ avahiError = avahi_entry_group_commit(group);
+ VerifyOrExit(avahiError == AVAHI_OK);
- serviceIt->mSubTypeList = aSubTypeList;
- serviceIt->mHostName = safeHostName;
- serviceIt->mPort = aPort;
- serviceIt->mTxtList = aTxtList;
+ AddServiceRegistration(std::unique_ptr<AvahiServiceRegistration>(new AvahiServiceRegistration(
+ aHostName, aName, aType, sortedSubTypeList, aPort, sortedTxtList, std::move(aCallback), group, this)));
exit:
-
- if (avahiError)
+ if (avahiError != AVAHI_OK || error != OTBR_ERROR_NONE)
{
- error = OTBR_ERROR_MDNS;
- otbrLogErr("Failed to publish service for avahi error: %s!", avahi_strerror(avahiError));
- }
- else if (error != OTBR_ERROR_NONE)
- {
- otbrLogErr("Failed to publish service: %s!", otbrErrorString(error));
- }
+ if (avahiError != AVAHI_OK)
+ {
+ error = OTBR_ERROR_MDNS;
+ otbrLogErr("Failed to publish service for avahi error: %s!", avahi_strerror(avahiError));
+ }
- if (error != OTBR_ERROR_NONE && serviceIt != mServices.end())
- {
- FreeGroup(serviceIt->mGroup);
- mServices.erase(serviceIt);
+ if (group != nullptr)
+ {
+ ReleaseGroup(group);
+ }
+ std::move(aCallback)(error);
}
-
- return error;
}
-otbrError PublisherAvahi::UnpublishService(const char *aName, const char *aType)
+void PublisherAvahi::UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback)
{
- otbrError error = OTBR_ERROR_NONE;
- Services::iterator serviceIt;
-
- VerifyOrExit(aName != nullptr, error = OTBR_ERROR_INVALID_ARGS);
- VerifyOrExit(aType != nullptr, error = OTBR_ERROR_INVALID_ARGS);
-
- serviceIt = FindService(aName, aType);
- VerifyOrExit(serviceIt != mServices.end());
+ otbrError error = OTBR_ERROR_NONE;
- otbrLogInfo("Unpublish service %s.%s", aName, aType);
- error = FreeGroup(serviceIt->mGroup);
- mServices.erase(serviceIt);
+ VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
+ RemoveServiceRegistration(aName, aType, OTBR_ERROR_ABORTED);
exit:
- return error;
+ std::move(aCallback)(error);
}
-otbrError PublisherAvahi::PublishHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength)
+void PublisherAvahi::PublishHostImpl(const std::string & aName,
+ const std::vector<uint8_t> &aAddress,
+ ResultCallback && aCallback)
{
- otbrError error = OTBR_ERROR_NONE;
- int avahiError = 0;
- Hosts::iterator hostIt = mHosts.end();
- std::string fullHostName;
- AvahiAddress address;
-
- VerifyOrExit(mState == State::kReady, errno = EAGAIN, error = OTBR_ERROR_ERRNO);
- VerifyOrExit(mClient != nullptr, errno = EAGAIN, error = OTBR_ERROR_ERRNO);
- VerifyOrExit(aName != nullptr, error = OTBR_ERROR_INVALID_ARGS);
- VerifyOrExit(aAddress != nullptr, error = OTBR_ERROR_INVALID_ARGS);
- VerifyOrExit(aAddressLength == sizeof(address.data.ipv6.address), error = OTBR_ERROR_INVALID_ARGS);
-
- fullHostName = MakeFullName(aName);
- hostIt = FindHost(aName);
-
- if (hostIt == mHosts.end())
- {
- SuccessOrExit(error = CreateHost(*mClient, aName, hostIt));
- }
- else if (memcmp(hostIt->mAddress.data.ipv6.address, aAddress, aAddressLength))
- {
- SuccessOrExit(error = ResetGroup(hostIt->mGroup));
- }
- else
- {
- if (mHostHandler != nullptr)
- {
- // The handler should be called even if the request can be processed synchronously
- mHostHandler(aName, OTBR_ERROR_NONE, mHostHandlerContext);
- }
- ExitNow();
- }
+ otbrError error = OTBR_ERROR_NONE;
+ int avahiError = AVAHI_OK;
+ std::string fullHostName;
+ AvahiAddress address;
+ AvahiEntryGroup *group = nullptr;
+
+ VerifyOrExit(mState == State::kReady, error = OTBR_ERROR_INVALID_STATE);
+ VerifyOrExit(mClient != nullptr, error = OTBR_ERROR_INVALID_STATE);
+ VerifyOrExit(aAddress.size() == sizeof(address.data.ipv6.address), error = OTBR_ERROR_INVALID_ARGS);
+
+ aCallback = HandleDuplicateHostRegistration(aName, aAddress, std::move(aCallback));
+ VerifyOrExit(!aCallback.IsNull());
address.proto = AVAHI_PROTO_INET6;
- memcpy(&address.data.ipv6.address[0], aAddress, aAddressLength);
+ memcpy(address.data.ipv6.address, aAddress.data(), aAddress.size());
+ fullHostName = MakeFullHostName(aName);
- otbrLogInfo("Create host %s", aName);
- avahiError = avahi_entry_group_add_address(hostIt->mGroup, AVAHI_IF_UNSPEC, mProtocol, AVAHI_PUBLISH_NO_REVERSE,
+ VerifyOrExit((group = CreateGroup(mClient)) != nullptr, error = OTBR_ERROR_MDNS);
+ avahiError = avahi_entry_group_add_address(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_PUBLISH_NO_REVERSE,
fullHostName.c_str(), &address);
- SuccessOrExit(avahiError);
+ VerifyOrExit(avahiError == AVAHI_OK);
- otbrLogInfo("Commit host %s", aName);
- avahiError = avahi_entry_group_commit(hostIt->mGroup);
- SuccessOrExit(avahiError);
+ otbrLogInfo("Commit avahi host %s", aName.c_str());
+ avahiError = avahi_entry_group_commit(group);
+ VerifyOrExit(avahiError == AVAHI_OK);
- hostIt->mAddress = address;
+ AddHostRegistration(std::unique_ptr<AvahiHostRegistration>(
+ new AvahiHostRegistration(aName, aAddress, std::move(aCallback), group, this)));
exit:
-
- if (avahiError)
+ if (avahiError != AVAHI_OK || error != OTBR_ERROR_NONE)
{
- error = OTBR_ERROR_MDNS;
- otbrLogErr("Failed to publish host for avahi error: %s!", avahi_strerror(avahiError));
- }
- else if (error != OTBR_ERROR_NONE)
- {
- otbrLogErr("Failed to publish host: %s!", otbrErrorString(error));
- }
+ if (avahiError != AVAHI_OK)
+ {
+ error = OTBR_ERROR_MDNS;
+ otbrLogErr("Failed to publish host for avahi error: %s!", avahi_strerror(avahiError));
+ }
- if (error != OTBR_ERROR_NONE && hostIt != mHosts.end())
- {
- FreeGroup(hostIt->mGroup);
- mHosts.erase(hostIt);
+ if (group != nullptr)
+ {
+ ReleaseGroup(group);
+ }
+ std::move(aCallback)(error);
}
-
- return error;
}
-otbrError PublisherAvahi::UnpublishHost(const char *aName)
+void PublisherAvahi::UnpublishHost(const std::string &aName, ResultCallback &&aCallback)
{
- otbrError error = OTBR_ERROR_NONE;
- Hosts::iterator hostIt;
-
- VerifyOrExit(aName != nullptr, error = OTBR_ERROR_INVALID_ARGS);
-
- hostIt = FindHost(aName);
- VerifyOrExit(hostIt != mHosts.end());
+ otbrError error = OTBR_ERROR_NONE;
- otbrLogInfo("Delete host %s", aName);
- error = FreeGroup(hostIt->mGroup);
- mHosts.erase(hostIt);
+ VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
+ RemoveHostRegistration(aName, OTBR_ERROR_ABORTED);
exit:
- return error;
+ std::move(aCallback)(error);
}
otbrError PublisherAvahi::TxtListToAvahiStringList(const TxtList & aTxtList,
@@ -845,7 +799,7 @@ otbrError PublisherAvahi::TxtListToAvahiStringList(const TxtList & aTxtList,
// +1 for the size of "=", avahi doesn't need '\0' at the end of the entry
size_t needed = sizeof(AvahiStringList) - sizeof(AvahiStringList::text) + nameLength + valueLength + 1;
- VerifyOrExit(used + needed <= aBufferSize, errno = EMSGSIZE, error = OTBR_ERROR_ERRNO);
+ VerifyOrExit(used + needed <= aBufferSize, error = OTBR_ERROR_INVALID_ARGS);
curr->next = last;
last = curr;
memcpy(curr->text, name, nameLength);
@@ -864,109 +818,150 @@ exit:
return error;
}
-std::string PublisherAvahi::MakeFullName(const char *aName)
+Publisher::ServiceRegistration *PublisherAvahi::FindServiceRegistration(const AvahiEntryGroup *aEntryGroup)
{
- assert(aName != nullptr);
+ ServiceRegistration *result = nullptr;
+
+ for (const auto &kv : mServiceRegistrations)
+ {
+ const auto &serviceReg = static_cast<const AvahiServiceRegistration &>(*kv.second);
+ if (serviceReg.GetEntryGroup() == aEntryGroup)
+ {
+ result = kv.second.get();
+ break;
+ }
+ }
- std::string fullHostName(aName);
+ return result;
+}
+
+Publisher::HostRegistration *PublisherAvahi::FindHostRegistration(const AvahiEntryGroup *aEntryGroup)
+{
+ HostRegistration *result = nullptr;
- fullHostName += '.';
- fullHostName += (mDomain == nullptr ? "local." : mDomain);
+ for (const auto &kv : mHostRegistrations)
+ {
+ const auto &hostReg = static_cast<const AvahiHostRegistration &>(*kv.second);
+ if (hostReg.GetEntryGroup() == aEntryGroup)
+ {
+ result = kv.second.get();
+ break;
+ }
+ }
- return fullHostName;
+ return result;
}
void PublisherAvahi::SubscribeService(const std::string &aType, const std::string &aInstanceName)
{
- mSubscribedServices.emplace_back(*this, aType, aInstanceName);
+ auto service = MakeUnique<ServiceSubscription>(*this, aType, aInstanceName);
- otbrLogInfo("subscribe service %s.%s (total %zu)", aInstanceName.c_str(), aType.c_str(),
+ VerifyOrExit(mState == Publisher::State::kReady);
+ mSubscribedServices.push_back(std::move(service));
+
+ otbrLogInfo("Subscribe service %s.%s (total %zu)", aInstanceName.c_str(), aType.c_str(),
mSubscribedServices.size());
if (aInstanceName.empty())
{
- mSubscribedServices.back().Browse();
+ mSubscribedServices.back()->Browse();
}
else
{
- mSubscribedServices.back().Resolve(AVAHI_IF_UNSPEC, mProtocol, aInstanceName.c_str(), aType.c_str(), "local.");
+ mSubscribedServices.back()->Resolve(AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, aInstanceName, aType);
}
+
+exit:
+ return;
}
void PublisherAvahi::UnsubscribeService(const std::string &aType, const std::string &aInstanceName)
{
- ServiceSubscriptionList::iterator it =
- std::find_if(mSubscribedServices.begin(), mSubscribedServices.end(),
- [&aType, &aInstanceName](const ServiceSubscription &aService) {
- return aService.mType == aType && aService.mInstanceName == aInstanceName;
- });
+ ServiceSubscriptionList::iterator it;
+
+ VerifyOrExit(mState == Publisher::State::kReady);
+ it = std::find_if(mSubscribedServices.begin(), mSubscribedServices.end(),
+ [&aType, &aInstanceName](const std::unique_ptr<ServiceSubscription> &aService) {
+ return aService->mType == aType && aService->mInstanceName == aInstanceName;
+ });
assert(it != mSubscribedServices.end());
- it->Release();
- mSubscribedServices.erase(it);
+ {
+ std::unique_ptr<ServiceSubscription> service = std::move(*it);
+
+ mSubscribedServices.erase(it);
+ service->Release();
+ }
- otbrLogInfo("unsubscribe service %s.%s (left %zu)", aInstanceName.c_str(), aType.c_str(),
+ otbrLogInfo("Unsubscribe service %s.%s (left %zu)", aInstanceName.c_str(), aType.c_str(),
mSubscribedServices.size());
-}
-void PublisherAvahi::OnServiceResolved(ServiceSubscription &aService)
-{
- otbrLogInfo("Service %s is resolved successfully: %s host %s addresses %zu", aService.mType.c_str(),
- aService.mInstanceInfo.mName.c_str(), aService.mInstanceInfo.mHostName.c_str(),
- aService.mInstanceInfo.mAddresses.size());
- if (mDiscoveredServiceInstanceCallback != nullptr)
- {
- mDiscoveredServiceInstanceCallback(aService.mType, aService.mInstanceInfo);
- }
+exit:
+ return;
}
-void PublisherAvahi::OnServiceResolveFailed(const ServiceSubscription &aService, int aErrorCode)
+void PublisherAvahi::OnServiceResolveFailedImpl(const std::string &aType,
+ const std::string &aInstanceName,
+ int32_t aErrorCode)
{
- otbrLogWarning("Service %s resolving failed: code=%d", aService.mType.c_str(), aErrorCode);
+ otbrLogWarning("Resolve service %s.%s failed: %s", aInstanceName.c_str(), aType.c_str(),
+ avahi_strerror(aErrorCode));
}
-void PublisherAvahi::OnHostResolved(HostSubscription &aHost)
+void PublisherAvahi::OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode)
{
- otbrLogInfo("Host %s is resolved successfully: host %s addresses %zu ttl %u", aHost.mHostName.c_str(),
- aHost.mHostInfo.mHostName.c_str(), aHost.mHostInfo.mAddresses.size(), aHost.mHostInfo.mTtl);
- if (mDiscoveredHostCallback != nullptr)
- {
- mDiscoveredHostCallback(aHost.mHostName, aHost.mHostInfo);
- }
+ otbrLogWarning("Resolve host %s failed: %s", aHostName.c_str(), avahi_strerror(aErrorCode));
}
-void PublisherAvahi::OnHostResolveFailed(const HostSubscription &aHost, int aErrorCode)
+otbrError PublisherAvahi::DnsErrorToOtbrError(int32_t aErrorCode)
{
- otbrLogWarning("Host %s resolving failed: code=%d", aHost.mHostName.c_str(), aErrorCode);
+ return otbr::Mdns::DnsErrorToOtbrError(aErrorCode);
}
void PublisherAvahi::SubscribeHost(const std::string &aHostName)
{
- mSubscribedHosts.emplace_back(*this, aHostName);
+ auto host = MakeUnique<HostSubscription>(*this, aHostName);
+
+ VerifyOrExit(mState == Publisher::State::kReady);
+
+ mSubscribedHosts.push_back(std::move(host));
- otbrLogInfo("subscribe host %s (total %zu)", aHostName.c_str(), mSubscribedHosts.size());
+ otbrLogInfo("Subscribe host %s (total %zu)", aHostName.c_str(), mSubscribedHosts.size());
- mSubscribedHosts.back().Resolve();
+ mSubscribedHosts.back()->Resolve();
+
+exit:
+ return;
}
void PublisherAvahi::UnsubscribeHost(const std::string &aHostName)
{
- HostSubscriptionList::iterator it =
- std::find_if(mSubscribedHosts.begin(), mSubscribedHosts.end(),
- [&aHostName](const HostSubscription &aHost) { return aHost.mHostName == aHostName; });
+ HostSubscriptionList::iterator it;
+
+ VerifyOrExit(mState == Publisher::State::kReady);
+ it = std::find_if(
+ mSubscribedHosts.begin(), mSubscribedHosts.end(),
+ [&aHostName](const std::unique_ptr<HostSubscription> &aHost) { return aHost->mHostName == aHostName; });
assert(it != mSubscribedHosts.end());
- it->Release();
- mSubscribedHosts.erase(it);
+ {
+ std::unique_ptr<HostSubscription> host = std::move(*it);
+
+ mSubscribedHosts.erase(it);
+ host->Release();
+ }
+
+ otbrLogInfo("Unsubscribe host %s (remaining %zu)", aHostName.c_str(), mSubscribedHosts.size());
- otbrLogInfo("unsubscribe host %s (remaining %d)", aHostName.c_str(), mSubscribedHosts.size());
+exit:
+ return;
}
-Publisher *Publisher::Create(int aFamily, const char *aDomain, StateHandler aHandler, void *aContext)
+Publisher *Publisher::Create(StateCallback aStateCallback)
{
- return new PublisherAvahi(aFamily, aDomain, aHandler, aContext);
+ return new PublisherAvahi(std::move(aStateCallback));
}
void Publisher::Destroy(Publisher *aPublisher)
@@ -978,29 +973,31 @@ void PublisherAvahi::ServiceSubscription::Browse(void)
{
assert(mPublisherAvahi->mClient != nullptr);
- otbrLogInfo("browse service %s", mType.c_str());
+ otbrLogInfo("Browse service %s", mType.c_str());
mServiceBrowser =
- avahi_service_browser_new(mPublisherAvahi->mClient, AVAHI_IF_UNSPEC, mPublisherAvahi->mProtocol, mType.c_str(),
- mPublisherAvahi->mDomain, static_cast<AvahiLookupFlags>(0), HandleBrowseResult, this);
+ avahi_service_browser_new(mPublisherAvahi->mClient, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, mType.c_str(),
+ /* domain */ nullptr, static_cast<AvahiLookupFlags>(0), HandleBrowseResult, this);
if (!mServiceBrowser)
{
- otbrLogWarning("failed to browse service %s: %s", mType.c_str(),
+ otbrLogWarning("Failed to browse service %s: %s", mType.c_str(),
avahi_strerror(avahi_client_errno(mPublisherAvahi->mClient)));
}
}
void PublisherAvahi::ServiceSubscription::Release(void)
{
+ for (AvahiServiceResolver *resolver : mServiceResolvers)
+ {
+ avahi_service_resolver_free(resolver);
+ }
+
+ mServiceResolvers.clear();
+
if (mServiceBrowser != nullptr)
{
avahi_service_browser_free(mServiceBrowser);
mServiceBrowser = nullptr;
}
- if (mServiceResolver != nullptr)
- {
- avahi_service_resolver_free(mServiceResolver);
- mServiceResolver = nullptr;
- }
}
void PublisherAvahi::ServiceSubscription::HandleBrowseResult(AvahiServiceBrowser * aServiceBrowser,
@@ -1028,39 +1025,52 @@ void PublisherAvahi::ServiceSubscription::HandleBrowseResult(AvahiServiceBrowser
{
OTBR_UNUSED_VARIABLE(aServiceBrowser);
OTBR_UNUSED_VARIABLE(aProtocol);
+ OTBR_UNUSED_VARIABLE(aDomain);
assert(mServiceBrowser == aServiceBrowser);
- otbrLogInfo("browse service reply: %s.%s.%s inf %u, flags=%u", aName, aType, aDomain, aInterfaceIndex, aFlags);
+ otbrLogInfo("Browse service reply: %s.%s proto %d inf %u event %d flags %d", aName, aType, aProtocol,
+ aInterfaceIndex, static_cast<int>(aEvent), static_cast<int>(aFlags));
- if (aEvent == AVAHI_BROWSER_FAILURE)
- {
- mPublisherAvahi->OnServiceResolveFailed(*this, avahi_client_errno(mPublisherAvahi->mClient));
- }
- else
- {
- Resolve(aInterfaceIndex, aProtocol, aName, aType, aDomain);
- }
- if (mServiceBrowser != nullptr)
+ switch (aEvent)
{
- avahi_service_browser_free(mServiceBrowser);
- mServiceBrowser = nullptr;
+ case AVAHI_BROWSER_NEW:
+ Resolve(aInterfaceIndex, aProtocol, aName, aType);
+ break;
+ case AVAHI_BROWSER_REMOVE:
+ mPublisherAvahi->OnServiceRemoved(static_cast<uint32_t>(aInterfaceIndex), aType, aName);
+ break;
+ case AVAHI_BROWSER_CACHE_EXHAUSTED:
+ case AVAHI_BROWSER_ALL_FOR_NOW:
+ // do nothing
+ break;
+ case AVAHI_BROWSER_FAILURE:
+ mPublisherAvahi->OnServiceResolveFailed(aType, aName, avahi_client_errno(mPublisherAvahi->mClient));
+ break;
}
}
-void PublisherAvahi::ServiceSubscription::Resolve(uint32_t aInterfaceIndex,
- AvahiProtocol aProtocol,
- const char * aInstanceName,
- const char * aType,
- const char * aDomain)
+void PublisherAvahi::ServiceSubscription::Resolve(uint32_t aInterfaceIndex,
+ AvahiProtocol aProtocol,
+ const std::string &aInstanceName,
+ const std::string &aType)
{
- otbrLogInfo("resolve service %s %s %s inf %d", aInstanceName, aType, aDomain, aInterfaceIndex);
- mServiceResolver =
- avahi_service_resolver_new(mPublisherAvahi->mClient, aInterfaceIndex, aProtocol, aInstanceName, aType, aDomain,
- AVAHI_PROTO_INET6, static_cast<AvahiLookupFlags>(0), HandleResolveResult, this);
- if (!mServiceResolver)
+ AvahiServiceResolver *resolver;
+
+ mPublisherAvahi->mServiceInstanceResolutionBeginTime[std::make_pair(aInstanceName, aType)] = Clock::now();
+
+ otbrLogInfo("Resolve service %s.%s inf %" PRIu32, aInstanceName.c_str(), aType.c_str(), aInterfaceIndex);
+
+ resolver = avahi_service_resolver_new(
+ mPublisherAvahi->mClient, aInterfaceIndex, aProtocol, aInstanceName.c_str(), aType.c_str(),
+ /* domain */ nullptr, AVAHI_PROTO_INET6, static_cast<AvahiLookupFlags>(0), HandleResolveResult, this);
+ if (resolver != nullptr)
+ {
+ AddServiceResolver(resolver);
+ }
+ else
{
- otbrLogErr("failed to resolve serivce %s: %s", mType.c_str(),
+ otbrLogErr("Failed to resolve serivce %s: %s", mType.c_str(),
avahi_strerror(avahi_client_errno(mPublisherAvahi->mClient)));
}
}
@@ -1103,57 +1113,81 @@ void PublisherAvahi::ServiceSubscription::HandleResolveResult(AvahiServiceResolv
OT_UNUSED_VARIABLE(aType);
OT_UNUSED_VARIABLE(aDomain);
- char buf[AVAHI_ADDRESS_STR_MAX];
- Ip6Address address;
- size_t totalTxtSize = 0;
+ char addrBuf[AVAHI_ADDRESS_STR_MAX] = "";
+ Ip6Address address;
+ size_t totalTxtSize = 0;
+ DiscoveredInstanceInfo instanceInfo;
+ bool resolved = false;
+ int avahiError = AVAHI_OK;
+
+ otbrLog(aEvent == AVAHI_RESOLVER_FOUND ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
+ "Resolve service reply: protocol %d %s.%s.%s = host %s port %" PRIu16 " flags %d event %d", aProtocol,
+ aName, aType, aDomain, aHostName, aPort, static_cast<int>(aFlags), static_cast<int>(aEvent));
- assert(mServiceResolver == aServiceResolver);
- VerifyOrExit(
- aEvent == AVAHI_RESOLVER_FOUND,
- otbrLogErr("failed to resolve service: %s", avahi_strerror(avahi_client_errno(mPublisherAvahi->mClient))));
- VerifyOrExit(aHostName != nullptr, otbrLogErr("host name is null"));
+ VerifyOrExit(aEvent == AVAHI_RESOLVER_FOUND, avahiError = avahi_client_errno(mPublisherAvahi->mClient));
+ avahi_address_snprint(addrBuf, sizeof(addrBuf), aAddress);
+ otbrLogInfo("Resolve service reply: address %s", addrBuf);
- mInstanceInfo.mName = aName;
- mInstanceInfo.mHostName = std::string(aHostName) + ".";
- mInstanceInfo.mPort = aPort;
- avahi_address_snprint(buf, sizeof(buf), aAddress);
- VerifyOrExit(otbrError::OTBR_ERROR_NONE == Ip6Address::FromString(buf, address),
- otbrLogErr("failed to parse the IP address: %s", buf));
+ RemoveServiceResolver(aServiceResolver);
+ VerifyOrExit(aHostName != nullptr, avahiError = AVAHI_ERR_INVALID_HOST_NAME);
- otbrLogDebug("resolve service reply: flags=%u, host=%s", aFlags, aHostName);
+ instanceInfo.mNetifIndex = static_cast<uint32_t>(aInterfaceIndex);
+ instanceInfo.mName = aName;
+ instanceInfo.mHostName = std::string(aHostName) + ".";
+ instanceInfo.mPort = aPort;
+ VerifyOrExit(otbrError::OTBR_ERROR_NONE == Ip6Address::FromString(addrBuf, address),
+ otbrLogErr("Failed to parse the IP address: %s", addrBuf), avahiError = AVAHI_ERR_INVALID_ADDRESS);
+
+ otbrLogInfo("Resolve service reply: flags=%u, host=%s", aFlags, aHostName);
VerifyOrExit(!address.IsLinkLocal() && !address.IsMulticast() && !address.IsLoopback() && !address.IsUnspecified(),
- otbrLogDebug("ignoring address %s", address.ToString().c_str()));
+ otbrLogInfo("Ignoring address %s", address.ToString().c_str()),
+ avahiError = AVAHI_ERR_INVALID_ADDRESS);
- mInstanceInfo.mAddresses.push_back(address);
+ instanceInfo.mAddresses.push_back(address);
// TODO priority
// TODO weight
// TODO use a more proper TTL
- mInstanceInfo.mTtl = kDefaultTtl;
+ instanceInfo.mTtl = kDefaultTtl;
for (auto p = aTxt; p; p = avahi_string_list_get_next(p))
{
totalTxtSize += avahi_string_list_get_size(p) + 1;
}
- mInstanceInfo.mTxtData.resize(totalTxtSize);
- avahi_string_list_serialize(aTxt, mInstanceInfo.mTxtData.data(), totalTxtSize);
+ instanceInfo.mTxtData.resize(totalTxtSize);
+ avahi_string_list_serialize(aTxt, instanceInfo.mTxtData.data(), totalTxtSize);
- otbrLogDebug("resolve service reply: address=%s, ttl=%u", address.ToString().c_str(), mInstanceInfo.mTtl);
+ otbrLogInfo("Resolve service reply: address=%s, ttl=%" PRIu32, address.ToString().c_str(), instanceInfo.mTtl);
- mPublisherAvahi->OnServiceResolved(*this);
+ resolved = true;
exit:
- if (avahi_client_errno(mPublisherAvahi->mClient) != AVAHI_OK)
+ if (resolved)
{
- mPublisherAvahi->OnServiceResolveFailed(*this, avahi_client_errno(mPublisherAvahi->mClient));
+ // NOTE: This `ServiceSubscrption` object may be freed in `OnServiceResolved`.
+ mPublisherAvahi->OnServiceResolved(mType, instanceInfo);
}
- if (mServiceBrowser != nullptr)
+ else if (avahiError != AVAHI_OK)
{
- avahi_service_resolver_free(mServiceResolver);
- mServiceResolver = nullptr;
+ mPublisherAvahi->OnServiceResolveFailed(aType, aName, avahiError);
}
}
+void PublisherAvahi::ServiceSubscription::AddServiceResolver(AvahiServiceResolver *aServiceResolver)
+{
+ assert(aServiceResolver != nullptr);
+ mServiceResolvers.insert(aServiceResolver);
+}
+
+void PublisherAvahi::ServiceSubscription::RemoveServiceResolver(AvahiServiceResolver *aServiceResolver)
+{
+ assert(aServiceResolver != nullptr);
+ assert(mServiceResolvers.find(aServiceResolver) != mServiceResolvers.end());
+
+ avahi_service_resolver_free(aServiceResolver);
+ mServiceResolvers.erase(aServiceResolver);
+}
+
void PublisherAvahi::HostSubscription::Release(void)
{
if (mRecordBrowser != nullptr)
@@ -1165,15 +1199,17 @@ void PublisherAvahi::HostSubscription::Release(void)
void PublisherAvahi::HostSubscription::Resolve(void)
{
- std::string fullHostName = mHostName + ".local.";
+ std::string fullHostName = MakeFullHostName(mHostName);
+
+ mPublisherAvahi->mHostResolutionBeginTime[mHostName] = Clock::now();
- otbrLogDebug("resolve host %s inf %d", fullHostName.c_str(), AVAHI_IF_UNSPEC);
- mRecordBrowser = avahi_record_browser_new(mPublisherAvahi->mClient, AVAHI_IF_UNSPEC, mPublisherAvahi->mProtocol,
+ otbrLogInfo("Resolve host %s inf %d", fullHostName.c_str(), static_cast<int>(AVAHI_IF_UNSPEC));
+ mRecordBrowser = avahi_record_browser_new(mPublisherAvahi->mClient, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
fullHostName.c_str(), AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA,
static_cast<AvahiLookupFlags>(0), HandleResolveResult, this);
if (!mRecordBrowser)
{
- otbrLogErr("failed to resolve host %s: %s", fullHostName.c_str(),
+ otbrLogErr("Failed to resolve host %s: %s", fullHostName.c_str(),
avahi_strerror(avahi_client_errno(mPublisherAvahi->mClient)));
}
}
@@ -1213,27 +1249,41 @@ void PublisherAvahi::HostSubscription::HandleResolveResult(AvahiRecordBrowser *
OTBR_UNUSED_VARIABLE(aType);
OTBR_UNUSED_VARIABLE(aFlags);
- Ip6Address address = *static_cast<const uint8_t(*)[16]>(aRdata);
- assert(mRecordBrowser == aRecordBrowser);
- VerifyOrExit(!address.IsLinkLocal() && !address.IsMulticast() && !address.IsLoopback() && !address.IsUnspecified());
- VerifyOrExit(aSize == 16, otbrLogErr("unexpected address data length: %u", aSize));
- otbrLogInfo("resolved host address: %s", address.ToString().c_str());
+ Ip6Address address;
+ bool resolved = false;
+ int avahiError = AVAHI_OK;
+
+ otbrLog(aEvent != AVAHI_BROWSER_FAILURE ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
+ "Resolve host reply: %s inf %d protocol %d class %" PRIu16 " type %" PRIu16 " size %zu flags %d event %d",
+ aName, aInterfaceIndex, aProtocol, aClazz, aType, aSize, static_cast<int>(aFlags),
+ static_cast<int>(aEvent));
+
+ VerifyOrExit(aEvent == AVAHI_BROWSER_NEW);
+ VerifyOrExit(aSize == OTBR_IP6_ADDRESS_SIZE || aSize == OTBR_IP4_ADDRESS_SIZE,
+ otbrLogErr("Unexpected address data length: %zu", aSize), avahiError = AVAHI_ERR_INVALID_ADDRESS);
+ VerifyOrExit(aSize == OTBR_IP6_ADDRESS_SIZE, otbrLogInfo("IPv4 address ignored"),
+ avahiError = AVAHI_ERR_INVALID_ADDRESS);
+ address = Ip6Address(*static_cast<const uint8_t(*)[OTBR_IP6_ADDRESS_SIZE]>(aRdata));
+
+ VerifyOrExit(!address.IsLinkLocal() && !address.IsMulticast() && !address.IsLoopback() && !address.IsUnspecified(),
+ avahiError = AVAHI_ERR_INVALID_ADDRESS);
+ otbrLogInfo("Resolved host address: %s", address.ToString().c_str());
mHostInfo.mHostName = std::string(aName) + ".";
mHostInfo.mAddresses.push_back(std::move(address));
// TODO: Use a more proper TTL
mHostInfo.mTtl = kDefaultTtl;
- mPublisherAvahi->OnHostResolved(*this);
+ resolved = true;
exit:
- if (avahi_client_errno(mPublisherAvahi->mClient) != AVAHI_OK)
+ if (resolved)
{
- mPublisherAvahi->OnHostResolveFailed(*this, avahi_client_errno(mPublisherAvahi->mClient));
+ // NOTE: This `HostSubscrption` object may be freed in `OnHostResolved`.
+ mPublisherAvahi->OnHostResolved(mHostName, mHostInfo);
}
- if (mRecordBrowser != nullptr)
+ else if (avahiError != AVAHI_OK)
{
- avahi_record_browser_free(mRecordBrowser);
- mRecordBrowser = nullptr;
+ mPublisherAvahi->OnHostResolveFailed(mHostName, avahiError);
}
}
diff --git a/src/mdns/mdns_avahi.hpp b/src/mdns/mdns_avahi.hpp
index 1eea53d5..efd7e940 100644
--- a/src/mdns/mdns_avahi.hpp
+++ b/src/mdns/mdns_avahi.hpp
@@ -28,12 +28,14 @@
/**
* @file
- * This file includes definition for mDNS service based on avahi.
+ * This file includes definition for mDNS publisher based on avahi.
*/
#ifndef OTBR_AGENT_MDNS_AVAHI_HPP_
#define OTBR_AGENT_MDNS_AVAHI_HPP_
+#include <memory>
+#include <set>
#include <vector>
#include <avahi-client/client.h>
@@ -43,6 +45,7 @@
#include <avahi-common/watch.h>
#include "mdns.hpp"
+#include "common/code_utils.hpp"
#include "common/mainloop.hpp"
#include "common/time.hpp"
@@ -50,327 +53,110 @@
* @addtogroup border-router-mdns
*
* @brief
- * This module includes definition for avahi-based mDNS service.
+ * This module includes definition for avahi-based mDNS publisher.
*
* @{
*/
-/**
- * This structure implements AvahiWatch.
- *
- */
-struct AvahiWatch
-{
- int mFd; ///< The file descriptor to watch.
- AvahiWatchEvent mEvents; ///< The interested events.
- int mHappened; ///< The events happened.
- AvahiWatchCallback mCallback; ///< The function to be called when interested events happened on mFd.
- void * mContext; ///< A pointer to application-specific context.
- void * mPoller; ///< The poller created this watch.
-
- /**
- * The constructor to initialize an Avahi watch.
- *
- * @param[in] aFd The file descriptor to watch.
- * @param[in] aEvents The events to watch.
- * @param[in] aCallback The function to be called when events happend on this file descriptor.
- * @param[in] aContext A pointer to application-specific context.
- * @param[in] aPoller The Poller this watcher belongs to.
- *
- */
- AvahiWatch(int aFd, AvahiWatchEvent aEvents, AvahiWatchCallback aCallback, void *aContext, void *aPoller)
- : mFd(aFd)
- , mEvents(aEvents)
- , mCallback(aCallback)
- , mContext(aContext)
- , mPoller(aPoller)
- {
- }
-};
-
-/**
- * This structure implements the AvahiTimeout.
- *
- */
-struct AvahiTimeout
-{
- otbr::Timepoint mTimeout; ///< Absolute time when this timer timeout.
- AvahiTimeoutCallback mCallback; ///< The function to be called when timeout.
- void * mContext; ///< The pointer to application-specific context.
- void * mPoller; ///< The poller created this timer.
-
- /**
- * The constructor to initialize an AvahiTimeout.
- *
- * @param[in] aTimeout A pointer to the time after which the callback should be called.
- * @param[in] aCallback The function to be called after timeout.
- * @param[in] aContext A pointer to application-specific context.
- * @param[in] aPoller The Poller this timeout belongs to.
- *
- */
- AvahiTimeout(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext, void *aPoller);
-};
-
namespace otbr {
namespace Mdns {
-/**
- * This class implements the AvahiPoll.
- *
- */
-class Poller : public MainloopProcessor
-{
-public:
- /**
- * The constructor to initialize a Poller.
- *
- */
- Poller(void);
-
- /**
- * This method updates the mainloop context.
- *
- * @param[inout] aMainloop A reference to the mainloop to be updated.
- *
- */
- void Update(MainloopContext &aMainloop) override;
-
- /**
- * This method processes mainloop events.
- *
- * @param[in] aMainloop A reference to the mainloop context.
- *
- */
- void Process(const MainloopContext &aMainloop) override;
-
- /**
- * This method returns the AvahiPoll.
- *
- * @returns A pointer to the AvahiPoll.
- *
- */
- const AvahiPoll *GetAvahiPoll(void) const { return &mAvahiPoller; }
-
-private:
- typedef std::vector<AvahiWatch *> Watches;
- typedef std::vector<AvahiTimeout *> Timers;
-
- static AvahiWatch * WatchNew(const struct AvahiPoll *aPoller,
- int aFd,
- AvahiWatchEvent aEvent,
- AvahiWatchCallback aCallback,
- void * aContext);
- AvahiWatch * WatchNew(int aFd, AvahiWatchEvent aEvent, AvahiWatchCallback aCallback, void *aContext);
- static void WatchUpdate(AvahiWatch *aWatch, AvahiWatchEvent aEvent);
- static AvahiWatchEvent WatchGetEvents(AvahiWatch *aWatch);
- static void WatchFree(AvahiWatch *aWatch);
- void WatchFree(AvahiWatch &aWatch);
- static AvahiTimeout * TimeoutNew(const AvahiPoll * aPoller,
- const struct timeval *aTimeout,
- AvahiTimeoutCallback aCallback,
- void * aContext);
- AvahiTimeout * TimeoutNew(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext);
- static void TimeoutUpdate(AvahiTimeout *aTimer, const struct timeval *aTimeout);
- static void TimeoutFree(AvahiTimeout *aTimer);
- void TimeoutFree(AvahiTimeout &aTimer);
-
- Watches mWatches;
- Timers mTimers;
- AvahiPoll mAvahiPoller;
-};
+class AvahiPoller;
/**
- * This class implements mDNS service with avahi.
+ * This class implements mDNS publisher with avahi.
*
*/
class PublisherAvahi : public Publisher
{
public:
- /**
- * The constructor to initialize a Publisher.
- *
- * @param[in] aProtocol The protocol used for publishing. IPv4, IPv6 or both.
- * @param[in] aDomain The domain of the host. nullptr to use default.
- * @param[in] aHandler The function to be called when state changes.
- * @param[in] aContext A pointer to application-specific context.
- *
- */
- PublisherAvahi(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext);
-
+ PublisherAvahi(StateCallback aStateCallback);
~PublisherAvahi(void) override;
- /**
- * This method publishes or updates a service.
- *
- * @param[in] aHostName The name of the host which this service resides on. If NULL is provided,
- * this service resides on local host and it is the implementation to provide
- * specific host name. Otherwise, the caller MUST publish the host with method
- * PublishHost.
- * @param[in] aPort The port number of this service.
- * @param[in] aName The name of this service.
- * @param[in] aType The type of this service.
- * @param[in] aSubTypeList A list of service subtypes.
- * @param[in] aTxtList A list of TXT name/value pairs.
- *
- * @retval OTBR_ERROR_NONE Successfully published or updated the service.
- * @retval OTBR_ERROR_ERRNO Failed to publish or update the service.
- *
- */
- otbrError PublishService(const char * aHostName,
- uint16_t aPort,
- const char * aName,
- const char * aType,
- const SubTypeList &aSubTypeList,
- const TxtList & aTxtList) override;
-
- /**
- * This method un-publishes a service.
- *
- * @param[in] aName The name of this service.
- * @param[in] aType The type of this service.
- *
- * @retval OTBR_ERROR_NONE Successfully un-published the service.
- * @retval OTBR_ERROR_ERRNO Failed to un-publish the service.
- *
- */
- otbrError UnpublishService(const char *aName, const char *aType) override;
-
- /**
- * This method publishes or updates a host.
- *
- * Publishing a host is advertising an AAAA RR for the host name. This method should be called
- * before a service with non-null host name is published.
- *
- * @param[in] aName The name of the host.
- * @param[in] aAddress The address of the host.
- * @param[in] aAddressLength The length of @p aAddress.
- *
- * @retval OTBR_ERROR_NONE Successfully published or updated the host.
- * @retval OTBR_ERROR_ERRNO Failed to publish or update the host.
- *
- */
- otbrError PublishHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength) override;
-
- /**
- * This method un-publishes a host.
- *
- * @param[in] aName A host name.
- *
- * @retval OTBR_ERROR_NONE Successfully un-published the host.
- * @retval OTBR_ERROR_ERRNO Failed to un-publish the host.
- *
- * @note All services reside on this host should be un-published by UnpublishService.
- *
- */
- otbrError UnpublishHost(const char *aName) override;
-
- /**
- * This method subscribes a given service or service instance. If @p aInstanceName is not empty, this method
- * subscribes the service instance. Otherwise, this method subscribes the service.
- *
- * mDNS implementations should use the `DiscoveredServiceInstanceCallback` function to notify discovered service
- * instances.
- *
- * @note Discovery Proxy implementation guarantees no duplicate subscriptions for the same service or service
- * instance.
- *
- * @param[in] aType The service type.
- * @param[in] aInstanceName The service instance to subscribe, or empty to subscribe the service.
- *
- */
- void SubscribeService(const std::string &aType, const std::string &aInstanceName) override;
-
- /**
- * This method unsubscribes a given service or service instance. If @p aInstanceName is not empty, this method
- * unsubscribes the service instance. Otherwise, this method unsubscribes the service.
- *
- * @note Discovery Proxy implementation guarantees no redundant unsubscription for a service or service instance.
- *
- * @param[in] aType The service type.
- * @param[in] aInstanceName The service instance to unsubscribe, or empty to unsubscribe the service.
- *
- */
- void UnsubscribeService(const std::string &aType, const std::string &aInstanceName) override;
-
- /**
- * This method subscribes a given host.
- *
- * mDNS implementations should use the `DiscoveredHostCallback` function to notify discovered hosts.
- *
- * @note Discovery Proxy implementation guarantees no duplicate subscriptions for the same host.
- *
- * @param[in] aHostName The host name (without domain).
- *
- */
- void SubscribeHost(const std::string &aHostName) override;
-
- /**
- * This method unsubscribes a given host.
- *
- * @note Discovery Proxy implementation guarantees no redundant unsubscription for a host.
- *
- * @param[in] aHostName The host name (without domain).
- *
- */
- void UnsubscribeHost(const std::string &aHostName) override;
-
- /**
- * This method starts the mDNS service.
- *
- * @retval OTBR_ERROR_NONE Successfully started mDNS service;
- * @retval OTBR_ERROR_MDNS Failed to start mDNS service.
- *
- */
+ void UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback) override;
+ void UnpublishHost(const std::string &aName, ResultCallback &&aCallback) override;
+ void SubscribeService(const std::string &aType, const std::string &aInstanceName) override;
+ void UnsubscribeService(const std::string &aType, const std::string &aInstanceName) override;
+ void SubscribeHost(const std::string &aHostName) override;
+ void UnsubscribeHost(const std::string &aHostName) override;
otbrError Start(void) override;
-
- /**
- * This method checks if publisher has been started.
- *
- * @retval true Already started.
- * @retval false Not started.
- *
- */
- bool IsStarted(void) const override;
-
- /**
- * This method stops the mDNS service.
- *
- */
- void Stop(void) override;
+ bool IsStarted(void) const override;
+ void Stop(void) override;
+
+protected:
+ void PublishServiceImpl(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList,
+ ResultCallback && aCallback) override;
+ void PublishHostImpl(const std::string & aName,
+ const std::vector<uint8_t> &aAddress,
+ ResultCallback && aCallback) override;
+ void OnServiceResolveFailedImpl(const std::string &aType,
+ const std::string &aInstanceName,
+ int32_t aErrorCode) override;
+ void OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode) override;
+ otbrError DnsErrorToOtbrError(int32_t aErrorCode) override;
private:
- enum
+ static constexpr size_t kMaxSizeOfTxtRecord = 1024;
+ static constexpr uint32_t kDefaultTtl = 10; // In seconds.
+
+ class AvahiServiceRegistration : public ServiceRegistration
{
- kMaxSizeOfTxtRecord = 1024,
- kMaxSizeOfServiceName = AVAHI_LABEL_MAX,
- kMaxSizeOfHost = AVAHI_LABEL_MAX,
- kMaxSizeOfDomain = AVAHI_LABEL_MAX,
- kMaxSizeOfServiceType = AVAHI_LABEL_MAX,
- kDefaultTtl = 10,
+ public:
+ AvahiServiceRegistration(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList,
+ ResultCallback && aCallback,
+ AvahiEntryGroup * aEntryGroup,
+ PublisherAvahi * aPublisher)
+ : ServiceRegistration(aHostName,
+ aName,
+ aType,
+ aSubTypeList,
+ aPort,
+ aTxtList,
+ std::move(aCallback),
+ aPublisher)
+ , mEntryGroup(aEntryGroup)
+ {
+ }
+
+ ~AvahiServiceRegistration(void) override;
+ const AvahiEntryGroup *GetEntryGroup(void) const { return mEntryGroup; }
+
+ private:
+ AvahiEntryGroup *mEntryGroup;
};
- struct Service
+ class AvahiHostRegistration : public HostRegistration
{
- std::string mName;
- std::string mType;
- SubTypeList mSubTypeList;
- std::string mHostName;
- uint16_t mPort = 0;
- AvahiEntryGroup *mGroup = nullptr;
- TxtList mTxtList;
- };
+ public:
+ AvahiHostRegistration(const std::string & aName,
+ const std::vector<uint8_t> &aAddress,
+ ResultCallback && aCallback,
+ AvahiEntryGroup * aEntryGroup,
+ PublisherAvahi * aPublisher)
+ : HostRegistration(aName, aAddress, std::move(aCallback), aPublisher)
+ , mEntryGroup(aEntryGroup)
+ {
+ }
- typedef std::vector<Service> Services;
+ ~AvahiHostRegistration(void) override;
+ const AvahiEntryGroup *GetEntryGroup(void) const { return mEntryGroup; }
- struct Host
- {
- std::string mHostName;
- AvahiAddress mAddress = {};
- AvahiEntryGroup *mGroup = nullptr;
+ private:
+ AvahiEntryGroup *mEntryGroup;
};
- struct Subscription
+ struct Subscription : private ::NonCopyable
{
PublisherAvahi *mPublisherAvahi;
@@ -387,18 +173,19 @@ private:
, mType(std::move(aType))
, mInstanceName(std::move(aInstanceName))
, mServiceBrowser(nullptr)
- , mServiceResolver(nullptr)
{
}
+ ~ServiceSubscription() { Release(); }
+
void Release(void);
void Browse(void);
- void Resolve(uint32_t aInterfaceIndex,
- AvahiProtocol aProtocol,
- const char * aInstanceName,
- const char * aType,
- const char * aDomain);
- void GetAddrInfo(uint32_t aInterfaceIndex);
+ void Resolve(uint32_t aInterfaceIndex,
+ AvahiProtocol aProtocol,
+ const std::string &aInstanceName,
+ const std::string &aType);
+ void AddServiceResolver(AvahiServiceResolver *aServiceResolver);
+ void RemoveServiceResolver(AvahiServiceResolver *aServiceResolver);
static void HandleBrowseResult(AvahiServiceBrowser * aServiceBrowser,
AvahiIfIndex aInterfaceIndex,
@@ -446,22 +233,23 @@ private:
AvahiStringList * aTxt,
AvahiLookupResultFlags aFlags);
- std::string mType;
- std::string mInstanceName;
- DiscoveredInstanceInfo mInstanceInfo;
- AvahiServiceBrowser * mServiceBrowser;
- AvahiServiceResolver * mServiceResolver;
+ std::string mType;
+ std::string mInstanceName;
+ AvahiServiceBrowser * mServiceBrowser;
+ std::set<AvahiServiceResolver *> mServiceResolvers;
};
struct HostSubscription : public Subscription
{
- explicit HostSubscription(PublisherAvahi &aMDnsSd, std::string aHostName)
- : Subscription(aMDnsSd)
+ explicit HostSubscription(PublisherAvahi &aAvahiPublisher, std::string aHostName)
+ : Subscription(aAvahiPublisher)
, mHostName(std::move(aHostName))
, mRecordBrowser(nullptr)
{
}
+ ~HostSubscription() { Release(); }
+
void Release(void);
void Resolve(void);
static void HandleResolveResult(AvahiRecordBrowser * aRecordBrowser,
@@ -492,56 +280,31 @@ private:
AvahiRecordBrowser *mRecordBrowser;
};
- typedef std::vector<Host> Hosts;
- typedef std::vector<ServiceSubscription> ServiceSubscriptionList;
- typedef std::vector<HostSubscription> HostSubscriptionList;
+ typedef std::vector<std::unique_ptr<ServiceSubscription>> ServiceSubscriptionList;
+ typedef std::vector<std::unique_ptr<HostSubscription>> HostSubscriptionList;
static void HandleClientState(AvahiClient *aClient, AvahiClientState aState, void *aContext);
void HandleClientState(AvahiClient *aClient, AvahiClientState aState);
- Hosts::iterator FindHost(const char *aHostName);
- otbrError CreateHost(AvahiClient &aClient, const char *aHostName, Hosts::iterator &aOutHostIt);
-
- Services::iterator FindService(const char *aName, const char *aType);
- Services::iterator FindService(AvahiEntryGroup *aGroup);
- otbrError CreateService(AvahiClient & aClient,
- const char * aName,
- const char * aType,
- Services::iterator &aOutServiceIt);
- static bool IsServiceOutdated(const Service & aService,
- const char * aNewHostName,
- uint16_t aNewPort,
- const SubTypeList &aNewSubTypeList);
-
- otbrError CreateGroup(AvahiClient &aClient, AvahiEntryGroup *&aOutGroup);
- static otbrError ResetGroup(AvahiEntryGroup *aGroup);
- static otbrError FreeGroup(AvahiEntryGroup *aGroup);
- void FreeAllGroups(void);
- static void HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState, void *aContext);
- void HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState);
- void CallHostOrServiceCallback(AvahiEntryGroup *aGroup, otbrError aError) const;
+ AvahiEntryGroup *CreateGroup(AvahiClient *aClient);
+ static void ReleaseGroup(AvahiEntryGroup *aGroup);
+
+ static void HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState, void *aContext);
+ void HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState);
+ void CallHostOrServiceCallback(AvahiEntryGroup *aGroup, otbrError aError);
static otbrError TxtListToAvahiStringList(const TxtList & aTxtList,
AvahiStringList * aBuffer,
size_t aBufferSize,
AvahiStringList *&aHead);
- std::string MakeFullName(const char *aName);
-
- void OnServiceResolved(ServiceSubscription &aService);
- static void OnServiceResolveFailed(const ServiceSubscription &aService, int aErrorCode);
- void OnHostResolved(HostSubscription &aHost);
- void OnHostResolveFailed(const HostSubscription &aHost, int aErrorCode);
-
- AvahiClient *mClient;
- Hosts mHosts;
- Services mServices;
- Poller mPoller;
- int mProtocol;
- const char * mDomain;
- State mState;
- StateHandler mStateHandler;
- void * mContext;
+ ServiceRegistration *FindServiceRegistration(const AvahiEntryGroup *aEntryGroup);
+ HostRegistration * FindHostRegistration(const AvahiEntryGroup *aEntryGroup);
+
+ AvahiClient * mClient;
+ std::unique_ptr<AvahiPoller> mPoller;
+ State mState;
+ StateCallback mStateCallback;
ServiceSubscriptionList mSubscribedServices;
HostSubscriptionList mSubscribedHosts;
diff --git a/src/mdns/mdns_mdnssd.cpp b/src/mdns/mdns_mdnssd.cpp
index cb88bc51..e091323d 100644
--- a/src/mdns/mdns_mdnssd.cpp
+++ b/src/mdns/mdns_mdnssd.cpp
@@ -28,7 +28,7 @@
/**
* @file
- * This file implements mDNS service based on mDNSResponder.
+ * This file implements mDNS publisher based on mDNSResponder.
*/
#define OTBR_LOG_TAG "MDNS"
@@ -40,6 +40,7 @@
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
+#include <inttypes.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
@@ -49,12 +50,13 @@
#include "common/dns_utils.hpp"
#include "common/logging.hpp"
#include "common/time.hpp"
-#include "utils/strcpy_utils.hpp"
namespace otbr {
namespace Mdns {
+static const char kDomain[] = "local.";
+
static otbrError DNSErrorToOtbrError(DNSServiceErrorType aError)
{
otbrError error;
@@ -78,7 +80,6 @@ static otbrError DNSErrorToOtbrError(DNSServiceErrorType aError)
error = OTBR_ERROR_INVALID_ARGS;
break;
- case kDNSServiceErr_AlreadyRegistered:
case kDNSServiceErr_NameConflict:
error = OTBR_ERROR_DUPLICATED;
break;
@@ -208,14 +209,11 @@ static const char *DNSErrorToString(DNSServiceErrorType aError)
}
}
-PublisherMDnsSd::PublisherMDnsSd(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext)
+PublisherMDnsSd::PublisherMDnsSd(StateCallback aCallback)
: mHostsRef(nullptr)
- , mDomain(aDomain)
, mState(State::kIdle)
- , mStateHandler(aHandler)
- , mContext(aContext)
+ , mStateCallback(std::move(aCallback))
{
- OTBR_UNUSED_VARIABLE(aProtocol);
}
PublisherMDnsSd::~PublisherMDnsSd(void)
@@ -226,7 +224,7 @@ PublisherMDnsSd::~PublisherMDnsSd(void)
otbrError PublisherMDnsSd::Start(void)
{
mState = State::kReady;
- mStateHandler(mContext, State::kReady);
+ mStateCallback(State::kReady);
return OTBR_ERROR_NONE;
}
@@ -237,23 +235,26 @@ bool PublisherMDnsSd::IsStarted(void) const
void PublisherMDnsSd::Stop(void)
{
+ ServiceRegistrationMap serviceRegistrations;
+ HostRegistrationMap hostRegistrations;
+
VerifyOrExit(mState == State::kReady);
- for (Service &service : mServices)
- {
- otbrLogInfo("Remove service %s.%s", service.mName, service.mType);
- DNSServiceRefDeallocate(service.mService);
- }
- mServices.clear();
+ std::swap(mServiceRegistrations, serviceRegistrations);
+ std::swap(mHostRegistrations, hostRegistrations);
- otbrLogInfo("Remove all hosts");
if (mHostsRef != nullptr)
{
DNSServiceRefDeallocate(mHostsRef);
+ otbrLogDebug("Deallocated DNSServiceRef for hosts: %p", mHostsRef);
mHostsRef = nullptr;
}
- mHosts.clear();
+ mSubscribedServices.clear();
+
+ mSubscribedHosts.clear();
+
+ mState = State::kIdle;
exit:
return;
@@ -261,17 +262,19 @@ exit:
void PublisherMDnsSd::Update(MainloopContext &aMainloop)
{
- for (Service &service : mServices)
+ for (auto &kv : mServiceRegistrations)
{
- assert(service.mService != nullptr);
+ auto &serviceReg = static_cast<DnssdServiceRegistration &>(*kv.second);
- int fd = DNSServiceRefSockFD(service.mService);
-
- assert(fd != -1);
+ assert(serviceReg.GetServiceRef() != nullptr);
- FD_SET(fd, &aMainloop.mReadFdSet);
+ int fd = DNSServiceRefSockFD(serviceReg.GetServiceRef());
- aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd);
+ if (fd != -1)
+ {
+ FD_SET(fd, &aMainloop.mReadFdSet);
+ aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd);
+ }
}
if (mHostsRef != nullptr)
@@ -285,28 +288,14 @@ void PublisherMDnsSd::Update(MainloopContext &aMainloop)
aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd);
}
- for (Subscription &subscription : mSubscribedServices)
+ for (const auto &service : mSubscribedServices)
{
- if (subscription.mServiceRef != nullptr)
- {
- int fd = DNSServiceRefSockFD(subscription.mServiceRef);
- assert(fd != -1);
-
- FD_SET(fd, &aMainloop.mReadFdSet);
- aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd);
- }
+ service->UpdateAll(aMainloop);
}
- for (Subscription &subscription : mSubscribedHosts)
+ for (const auto &host : mSubscribedHosts)
{
- if (subscription.mServiceRef != nullptr)
- {
- int fd = DNSServiceRefSockFD(subscription.mServiceRef);
- assert(fd != -1);
-
- FD_SET(fd, &aMainloop.mReadFdSet);
- aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd);
- }
+ host->Update(aMainloop);
}
}
@@ -314,13 +303,14 @@ void PublisherMDnsSd::Process(const MainloopContext &aMainloop)
{
std::vector<DNSServiceRef> readyServices;
- for (Service &service : mServices)
+ for (auto &kv : mServiceRegistrations)
{
- int fd = DNSServiceRefSockFD(service.mService);
+ auto &serviceReg = static_cast<DnssdServiceRegistration &>(*kv.second);
+ int fd = DNSServiceRefSockFD(serviceReg.GetServiceRef());
if (FD_ISSET(fd, &aMainloop.mReadFdSet))
{
- readyServices.push_back(service.mService);
+ readyServices.push_back(serviceReg.GetServiceRef());
}
}
@@ -334,32 +324,14 @@ void PublisherMDnsSd::Process(const MainloopContext &aMainloop)
}
}
- for (Subscription &subscription : mSubscribedServices)
+ for (const auto &service : mSubscribedServices)
{
- if (subscription.mServiceRef != nullptr)
- {
- int fd = DNSServiceRefSockFD(subscription.mServiceRef);
- assert(fd != -1);
-
- if (FD_ISSET(fd, &aMainloop.mReadFdSet))
- {
- readyServices.push_back(subscription.mServiceRef);
- }
- }
+ service->ProcessAll(aMainloop, readyServices);
}
- for (Subscription &service : mSubscribedHosts)
+ for (const auto &host : mSubscribedHosts)
{
- if (service.mServiceRef != nullptr)
- {
- int fd = DNSServiceRefSockFD(service.mServiceRef);
- assert(fd != -1);
-
- if (FD_ISSET(fd, &aMainloop.mReadFdSet))
- {
- readyServices.push_back(service.mServiceRef);
- }
- }
+ host->Process(aMainloop, readyServices);
}
for (DNSServiceRef serviceRef : readyServices)
@@ -368,513 +340,416 @@ void PublisherMDnsSd::Process(const MainloopContext &aMainloop)
if (error != kDNSServiceErr_NoError)
{
- otbrLogWarning("DNSServiceProcessResult failed: %s", DNSErrorToString(error));
+ otbrLogLevel logLevel = (error == kDNSServiceErr_BadReference) ? OTBR_LOG_INFO : OTBR_LOG_WARNING;
+ otbrLog(logLevel, OTBR_LOG_TAG, "DNSServiceProcessResult failed: %s (serviceRef = %p)",
+ DNSErrorToString(error), serviceRef);
+ }
+ if (error == kDNSServiceErr_ServiceNotRunning)
+ {
+ otbrLogWarning("Need to reconnect to mdnsd");
+ Stop();
+ Start();
+ ExitNow();
}
}
+exit:
+ return;
}
-void PublisherMDnsSd::HandleServiceRegisterResult(DNSServiceRef aService,
- const DNSServiceFlags aFlags,
- DNSServiceErrorType aError,
- const char * aName,
- const char * aType,
- const char * aDomain,
- void * aContext)
+PublisherMDnsSd::DnssdServiceRegistration::~DnssdServiceRegistration(void)
{
- static_cast<PublisherMDnsSd *>(aContext)->HandleServiceRegisterResult(aService, aFlags, aError, aName, aType,
- aDomain);
+ if (mServiceRef != nullptr)
+ {
+ DNSServiceRefDeallocate(mServiceRef);
+ }
}
-void PublisherMDnsSd::HandleServiceRegisterResult(DNSServiceRef aServiceRef,
- const DNSServiceFlags aFlags,
- DNSServiceErrorType aError,
- const char * aName,
- const char * aType,
- const char * aDomain)
+PublisherMDnsSd::DnssdHostRegistration::~DnssdHostRegistration(void)
{
- OTBR_UNUSED_VARIABLE(aDomain);
-
- otbrError error = DNSErrorToOtbrError(aError);
- std::string originalInstanceName;
- ServiceIterator service = FindPublishedService(aServiceRef);
-
- VerifyOrExit(service != mServices.end());
+ VerifyOrExit(mServiceRef != nullptr && mRecordRef != nullptr);
- // mDNSResponder could auto-rename the service instance name when name conflict
- // is detected. In this case, `aName` may not match `service->mName` and we
- // should use the original `service->mName` to find associated SRP service.
- originalInstanceName = service->mName;
-
- otbrLogInfo("Received reply for service %s.%s", originalInstanceName.c_str(), aType);
-
- if (originalInstanceName != aName)
+ if (IsCompleted())
{
- otbrLogInfo("Service %s.%s renamed to %s.%s", originalInstanceName.c_str(), aType, aName, aType);
- }
-
- if (aError == kDNSServiceErr_NoError && (aFlags & kDNSServiceFlagsAdd))
- {
- otbrLogInfo("Successfully registered service %s.%s", originalInstanceName.c_str(), aType);
- }
- else
- {
- otbrLogErr("Failed to register service %s.%s: %s", originalInstanceName.c_str(), aType,
- DNSErrorToString(aError));
- DiscardService(originalInstanceName.c_str(), aType, aServiceRef);
+ // The Bonjour mDNSResponder somehow doesn't send goodbye message for the AAAA record when it is
+ // removed by `DNSServiceRemoveRecord`. Per RFC 6762, a goodbye message of a record sets its TTL
+ // to zero but the receiver should record the TTL of 1 and flushes the cache 1 second later. Here
+ // we remove the AAAA record after updating its TTL to 1 second. This has the same effect as
+ // sending a goodbye message.
+ // TODO: resolve the goodbye issue with Bonjour mDNSResponder.
+ int dnsError = DNSServiceUpdateRecord(mServiceRef, mRecordRef, kDNSServiceFlagsUnique, mAddress.size(),
+ mAddress.data(), /* ttl */ 1);
+ otbrLogWarning("Failed to send goodbye message for host %s: %s", MakeFullHostName(mName).c_str(),
+ DNSErrorToString(dnsError));
}
- if (mServiceHandler != nullptr)
- {
- // TODO: pass the renewed service instance name back to SRP server handler.
- mServiceHandler(originalInstanceName.c_str(), aType, error, mServiceHandlerContext);
- }
+ DNSServiceRemoveRecord(mServiceRef, mRecordRef, /* flags */ 0);
+ // TODO: ?
+ // DNSRecordRefDeallocate(mRecordRef);
exit:
return;
}
-void PublisherMDnsSd::DiscardService(const char *aName, const char *aType, DNSServiceRef aServiceRef)
+Publisher::ServiceRegistration *PublisherMDnsSd::FindServiceRegistration(const DNSServiceRef &aServiceRef)
{
- OTBR_UNUSED_VARIABLE(aServiceRef);
-
- ServiceIterator service = FindPublishedService(aName, aType);
+ ServiceRegistration *result = nullptr;
- if (service != mServices.end())
+ for (auto &kv : mServiceRegistrations)
{
- assert(aServiceRef == nullptr || aServiceRef == service->mService);
+ // We are sure that the service registrations must be instances of `DnssdServiceRegistration`.
+ auto &serviceReg = static_cast<DnssdServiceRegistration &>(*kv.second);
- otbrLogInfo("Remove service ref %p", service->mService);
-
- DNSServiceRefDeallocate(service->mService);
- mServices.erase(service);
+ if (serviceReg.GetServiceRef() == aServiceRef)
+ {
+ result = kv.second.get();
+ break;
+ }
}
+
+ return result;
}
-void PublisherMDnsSd::RecordService(const char * aName,
- const char * aType,
- const char * aRegType,
- uint16_t aPort,
- DNSServiceRef aServiceRef)
+Publisher::HostRegistration *PublisherMDnsSd::FindHostRegistration(const DNSServiceRef &aServiceRef,
+ const DNSRecordRef & aRecordRef)
{
- ServiceIterator service = FindPublishedService(aName, aType);
+ HostRegistration *result = nullptr;
- if (service == mServices.end())
+ for (auto &kv : mHostRegistrations)
{
- Service newService;
+ // We are sure that the host registrations must be instances of `DnssdHostRegistration`.
+ auto &hostReg = static_cast<DnssdHostRegistration &>(*kv.second);
- otbrLogInfo("Add service: %s.%s (ref: %p)", aName, aType, aServiceRef);
-
- strcpy(newService.mName, aName);
- strcpy(newService.mType, aType);
- newService.mRegType = aRegType;
- newService.mService = aServiceRef;
- newService.mPort = aPort;
- mServices.push_back(newService);
- }
- else
- {
- assert(service->mRegType == aRegType);
- assert(service->mService == aServiceRef);
+ if (hostReg.GetServiceRef() == aServiceRef && hostReg.GetRecordRef() == aRecordRef)
+ {
+ result = kv.second.get();
+ break;
+ }
}
+
+ return result;
}
-bool PublisherMDnsSd::IsServiceOutdated(const Service &service, const std::string &aNewRegType, int aNewPort)
+void PublisherMDnsSd::HandleServiceRegisterResult(DNSServiceRef aService,
+ const DNSServiceFlags aFlags,
+ DNSServiceErrorType aError,
+ const char * aName,
+ const char * aType,
+ const char * aDomain,
+ void * aContext)
{
- return service.mRegType != aNewRegType || service.mPort != aNewPort;
+ static_cast<PublisherMDnsSd *>(aContext)->HandleServiceRegisterResult(aService, aFlags, aError, aName, aType,
+ aDomain);
}
-otbrError PublisherMDnsSd::PublishService(const char * aHostName,
- uint16_t aPort,
- const char * aName,
- const char * aType,
- const SubTypeList &aSubTypeList,
- const TxtList & aTxtList)
+void PublisherMDnsSd::HandleServiceRegisterResult(DNSServiceRef aServiceRef,
+ const DNSServiceFlags aFlags,
+ DNSServiceErrorType aError,
+ const char * aName,
+ const char * aType,
+ const char * aDomain)
{
- otbrError ret = OTBR_ERROR_NONE;
- int error = 0;
- uint8_t txt[kMaxSizeOfTxtRecord];
- uint16_t txtLength = sizeof(txt);
- std::string regType = MakeRegType(aType, aSubTypeList);
- ServiceIterator service = FindPublishedService(aName, aType);
- DNSServiceRef serviceRef = nullptr;
- char fullHostName[kMaxSizeOfDomain];
-
- if (aHostName != nullptr)
- {
- HostIterator host = FindPublishedHost(aHostName);
-
- // Make sure that the host has been published.
- VerifyOrExit(host != mHosts.end(), ret = OTBR_ERROR_INVALID_ARGS);
- SuccessOrExit(error = MakeFullName(fullHostName, sizeof(fullHostName), aHostName));
- }
-
- SuccessOrExit(ret = EncodeTxtData(aTxtList, txt, txtLength));
-
- if (service != mServices.end() && !IsServiceOutdated(*service, regType, aPort))
- {
- otbrLogInfo("Update service %s.%s", aName, aType);
+ OTBR_UNUSED_VARIABLE(aDomain);
- // Setting TTL to 0 to use default value.
- SuccessOrExit(error = DNSServiceUpdateRecord(service->mService, nullptr, 0, txtLength, txt, /* ttl */ 0));
+ otbrError error = DNSErrorToOtbrError(aError);
+ std::string originalInstanceName;
+ ServiceRegistration *serviceReg = FindServiceRegistration(aServiceRef);
- if (mServiceHandler != nullptr)
- {
- mServiceHandler(aName, aType, DNSErrorToOtbrError(error), mServiceHandlerContext);
- }
+ otbrLogInfo("Received reply for service %s.%s, serviceRef = %p", aName, aType, aServiceRef);
- ExitNow();
- }
+ VerifyOrExit(serviceReg != nullptr);
- if (service != mServices.end())
+ if (aError == kDNSServiceErr_NoError && (aFlags & kDNSServiceFlagsAdd))
{
- // Service is outdated and needs to be recreated.
- DiscardService(aName, aType, serviceRef);
+ otbrLogInfo("Successfully registered service %s.%s", aName, aType);
+ serviceReg->Complete(OTBR_ERROR_NONE);
}
-
- SuccessOrExit(error = DNSServiceRegister(&serviceRef, /* flags */ 0, kDNSServiceInterfaceIndexAny, aName,
- regType.c_str(), mDomain, (aHostName != nullptr) ? fullHostName : nullptr,
- htons(aPort), txtLength, txt, HandleServiceRegisterResult, this));
- RecordService(aName, aType, regType.c_str(), aPort, serviceRef);
-
-exit:
- if (error != kDNSServiceErr_NoError)
+ else
{
- ret = OTBR_ERROR_MDNS;
- otbrLogErr("Failed to publish service for mdnssd error: %s!", DNSErrorToString(error));
+ otbrLogErr("Failed to register service %s.%s: %s", aName, aType, DNSErrorToString(aError));
+ RemoveServiceRegistration(serviceReg->mName, serviceReg->mType, error);
}
- return ret;
-}
-otbrError PublisherMDnsSd::UnpublishService(const char *aName, const char *aType)
-{
- DiscardService(aName, aType);
- return OTBR_ERROR_NONE;
+exit:
+ return;
}
-otbrError PublisherMDnsSd::DiscardHost(const char *aName, bool aSendGoodbye)
+void PublisherMDnsSd::PublishServiceImpl(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList,
+ ResultCallback && aCallback)
{
- otbrError ret = OTBR_ERROR_NONE;
- int error = 0;
- HostIterator host = FindPublishedHost(aName);
-
- VerifyOrExit(mHostsRef != nullptr && host != mHosts.end());
-
- otbrLogInfo("Remove host: %s (record ref: %p)", host->mName, host->mRecord);
-
- if (aSendGoodbye)
+ otbrError ret = OTBR_ERROR_NONE;
+ int error = 0;
+ std::vector<uint8_t> txt;
+ SubTypeList sortedSubTypeList = SortSubTypeList(aSubTypeList);
+ TxtList sortedTxtList = SortTxtList(aTxtList);
+ std::string regType = MakeRegType(aType, sortedSubTypeList);
+ DNSServiceRef serviceRef = nullptr;
+ std::string fullHostName;
+
+ VerifyOrExit(mState == State::kReady, ret = OTBR_ERROR_INVALID_STATE);
+
+ if (!aHostName.empty())
{
- // The Bonjour mDNSResponder somehow doesn't send goodbye message for the AAAA record when it is
- // removed by `DNSServiceRemoveRecord`. Per RFC 6762, a goodbye message of a record sets its TTL
- // to zero but the receiver should record the TTL of 1 and flushes the cache 1 second later. Here
- // we remove the AAAA record after updating its TTL to 1 second. This has the same effect as
- // sending a goodbye message.
- // TODO: resolve the goodbye issue with Bonjour mDNSResponder.
- error = DNSServiceUpdateRecord(mHostsRef, host->mRecord, kDNSServiceFlagsUnique, host->mAddress.size(),
- &host->mAddress.front(), /* ttl */ 1);
- // Do not SuccessOrExit so that we always erase the host entry.
-
- DNSServiceRemoveRecord(mHostsRef, host->mRecord, /* flags */ 0);
+ fullHostName = MakeFullHostName(aHostName);
}
- mHosts.erase(host);
+
+ aCallback = HandleDuplicateServiceRegistration(aHostName, aName, aType, sortedSubTypeList, aPort, sortedTxtList,
+ std::move(aCallback));
+ VerifyOrExit(!aCallback.IsNull());
+
+ SuccessOrExit(ret = EncodeTxtData(aTxtList, txt));
+ otbrLogInfo("Registering new service %s.%s.local, serviceRef = %p", aName.c_str(), regType.c_str(), serviceRef);
+ SuccessOrExit(error = DNSServiceRegister(&serviceRef, kDNSServiceFlagsNoAutoRename, kDNSServiceInterfaceIndexAny,
+ aName.c_str(), regType.c_str(), /* domain */ nullptr,
+ !aHostName.empty() ? fullHostName.c_str() : nullptr, htons(aPort),
+ txt.size(), txt.data(), HandleServiceRegisterResult, this));
+ AddServiceRegistration(std::unique_ptr<DnssdServiceRegistration>(new DnssdServiceRegistration(
+ aHostName, aName, aType, sortedSubTypeList, aPort, sortedTxtList, std::move(aCallback), serviceRef, this)));
exit:
- if (error != kDNSServiceErr_NoError)
+ if (error != kDNSServiceErr_NoError || ret != OTBR_ERROR_NONE)
{
- ret = OTBR_ERROR_MDNS;
- otbrLogErr("Failed to remove host %s for mdnssd error: %s!", aName, DNSErrorToString(error));
+ if (error != kDNSServiceErr_NoError)
+ {
+ ret = DNSErrorToOtbrError(error);
+ otbrLogErr("Failed to publish service %s.%s for mdnssd error: %s!", aName.c_str(), aType.c_str(),
+ DNSErrorToString(error));
+ }
+
+ if (serviceRef != nullptr)
+ {
+ DNSServiceRefDeallocate(serviceRef);
+ }
+ std::move(aCallback)(ret);
}
- return ret;
}
-void PublisherMDnsSd::RecordHost(const char * aName,
- const uint8_t *aAddress,
- uint8_t aAddressLength,
- DNSRecordRef aRecordRef)
+void PublisherMDnsSd::UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback)
{
- HostIterator host = FindPublishedHost(aName);
+ otbrError error = OTBR_ERROR_NONE;
- if (host == mHosts.end())
- {
- Host newHost;
-
- otbrLogInfo("Add new host %s", aName);
-
- strcpy(newHost.mName, aName);
- std::copy(aAddress, aAddress + aAddressLength, newHost.mAddress.begin());
- newHost.mRecord = aRecordRef;
- mHosts.push_back(newHost);
- }
- else
- {
- otbrLogInfo("Update existing host %s", host->mName);
+ VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
+ RemoveServiceRegistration(aName, aType, OTBR_ERROR_ABORTED);
- // The address of the host may be updated.
- std::copy(aAddress, aAddress + aAddressLength, host->mAddress.begin());
- assert(host->mRecord == aRecordRef);
- }
+exit:
+ std::move(aCallback)(error);
}
-otbrError PublisherMDnsSd::PublishHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength)
+void PublisherMDnsSd::PublishHostImpl(const std::string & aName,
+ const std::vector<uint8_t> &aAddress,
+ ResultCallback && aCallback)
{
otbrError ret = OTBR_ERROR_NONE;
int error = 0;
- char fullName[kMaxSizeOfDomain];
- HostIterator host = FindPublishedHost(aName);
+ std::string fullName;
+ DNSRecordRef recordRef = nullptr;
+
+ VerifyOrExit(mState == Publisher::State::kReady, ret = OTBR_ERROR_INVALID_STATE);
// Supports only IPv6 for now, may support IPv4 in the future.
- VerifyOrExit(aAddressLength == OTBR_IP6_ADDRESS_SIZE, error = OTBR_ERROR_INVALID_ARGS);
+ VerifyOrExit(aAddress.size() == OTBR_IP6_ADDRESS_SIZE, error = OTBR_ERROR_INVALID_ARGS);
- SuccessOrExit(ret = MakeFullName(fullName, sizeof(fullName), aName));
+ fullName = MakeFullHostName(aName);
if (mHostsRef == nullptr)
{
SuccessOrExit(error = DNSServiceCreateConnection(&mHostsRef));
+ otbrLogDebug("Created new DNSServiceRef for hosts: %p", mHostsRef);
}
- if (host != mHosts.end())
- {
- otbrLogInfo("Update existing host %s", aName);
- SuccessOrExit(error = DNSServiceUpdateRecord(mHostsRef, host->mRecord, kDNSServiceFlagsUnique, aAddressLength,
- aAddress, /* ttl */ 0));
+ aCallback = HandleDuplicateHostRegistration(aName, aAddress, std::move(aCallback));
+ VerifyOrExit(!aCallback.IsNull());
- RecordHost(aName, aAddress, aAddressLength, host->mRecord);
- if (mHostHandler != nullptr)
- {
- mHostHandler(aName, DNSErrorToOtbrError(error), mHostHandlerContext);
- }
- }
- else
- {
- DNSRecordRef record;
-
- otbrLogInfo("Publish new host %s", aName);
- SuccessOrExit(error = DNSServiceRegisterRecord(mHostsRef, &record, kDNSServiceFlagsUnique,
- kDNSServiceInterfaceIndexAny, fullName, kDNSServiceType_AAAA,
- kDNSServiceClass_IN, aAddressLength, aAddress, /* ttl */ 0,
- HandleRegisterHostResult, this));
- RecordHost(aName, aAddress, aAddressLength, record);
- }
+ otbrLogInfo("Registering new host %s", aName.c_str());
+ SuccessOrExit(error = DNSServiceRegisterRecord(mHostsRef, &recordRef, kDNSServiceFlagsUnique,
+ kDNSServiceInterfaceIndexAny, fullName.c_str(), kDNSServiceType_AAAA,
+ kDNSServiceClass_IN, aAddress.size(), aAddress.data(), /* ttl */ 0,
+ HandleRegisterHostResult, this));
+ AddHostRegistration(std::unique_ptr<DnssdHostRegistration>(
+ new DnssdHostRegistration(aName, aAddress, std::move(aCallback), mHostsRef, recordRef, this)));
exit:
- if (error != kDNSServiceErr_NoError)
+ if (error != kDNSServiceErr_NoError || ret != OTBR_ERROR_NONE)
{
- if (mHostsRef != nullptr)
+ if (error != kDNSServiceErr_NoError)
{
- DNSServiceRefDeallocate(mHostsRef);
- mHostsRef = nullptr;
+ ret = DNSErrorToOtbrError(error);
+ otbrLogErr("Failed to publish/update host %s for mdnssd error: %s!", aName.c_str(),
+ DNSErrorToString(error));
}
- ret = OTBR_ERROR_MDNS;
- otbrLogErr("Failed to publish/update host %s for mdnssd error: %s!", aName, DNSErrorToString(error));
+ std::move(aCallback)(ret);
}
- return ret;
}
-otbrError PublisherMDnsSd::UnpublishHost(const char *aName)
+void PublisherMDnsSd::UnpublishHost(const std::string &aName, ResultCallback &&aCallback)
{
- return DiscardHost(aName);
+ otbrError error = OTBR_ERROR_NONE;
+
+ VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
+ RemoveHostRegistration(aName, OTBR_ERROR_ABORTED);
+
+exit:
+ // We may failed to unregister the host from underlying mDNS publishers, but
+ // it usually means that the mDNS publisher is already not functioning. So it's
+ // okay to return success directly since the service is not advertised anyway.
+ std::move(aCallback)(error);
}
-void PublisherMDnsSd::HandleRegisterHostResult(DNSServiceRef aHostsConnection,
- DNSRecordRef aHostRecord,
+void PublisherMDnsSd::HandleRegisterHostResult(DNSServiceRef aServiceRef,
+ DNSRecordRef aRecordRef,
DNSServiceFlags aFlags,
- DNSServiceErrorType aErrorCode,
+ DNSServiceErrorType aError,
void * aContext)
{
- static_cast<PublisherMDnsSd *>(aContext)->HandleRegisterHostResult(aHostsConnection, aHostRecord, aFlags,
- aErrorCode);
+ static_cast<PublisherMDnsSd *>(aContext)->HandleRegisterHostResult(aServiceRef, aRecordRef, aFlags, aError);
}
-void PublisherMDnsSd::HandleRegisterHostResult(DNSServiceRef aHostsConnection,
- DNSRecordRef aHostRecord,
+void PublisherMDnsSd::HandleRegisterHostResult(DNSServiceRef aServiceRef,
+ DNSRecordRef aRecordRef,
DNSServiceFlags aFlags,
- DNSServiceErrorType aErrorCode)
+ DNSServiceErrorType aError)
{
- OTBR_UNUSED_VARIABLE(aHostsConnection);
OTBR_UNUSED_VARIABLE(aFlags);
- HostIterator host = FindPublishedHost(aHostRecord);
- std::string hostName;
+ otbrError error = DNSErrorToOtbrError(aError);
+ HostRegistration *hostReg = FindHostRegistration(aServiceRef, aRecordRef);
+
+ std::string hostName;
+
+ VerifyOrExit(hostReg != nullptr);
- VerifyOrExit(host != mHosts.end());
- hostName = host->mName;
+ hostName = MakeFullHostName(hostReg->mName);
otbrLogInfo("Received reply for host %s", hostName.c_str());
- if (aErrorCode == kDNSServiceErr_NoError)
+ if (error == OTBR_ERROR_NONE)
{
otbrLogInfo("Successfully registered host %s", hostName.c_str());
+ hostReg->Complete(OTBR_ERROR_NONE);
}
else
{
- otbrLogWarning("failed to register host %s for mdnssd error: %s", hostName.c_str(),
- DNSErrorToString(aErrorCode));
-
- DiscardHost(hostName.c_str(), /* aSendGoodbye */ false);
- }
-
- if (mHostHandler != nullptr)
- {
- mHostHandler(hostName.c_str(), DNSErrorToOtbrError(aErrorCode), mHostHandlerContext);
+ otbrLogWarning("Failed to register host %s for mdnssd error: %s", hostName.c_str(), DNSErrorToString(aError));
+ RemoveHostRegistration(hostReg->mName, error);
}
exit:
return;
}
-otbrError PublisherMDnsSd::MakeFullName(char *aFullName, size_t aFullNameLength, const char *aName)
+// See `regtype` parameter of the DNSServiceRegister() function for more information.
+std::string PublisherMDnsSd::MakeRegType(const std::string &aType, SubTypeList aSubTypeList)
{
- otbrError error = OTBR_ERROR_NONE;
- size_t nameLength = strlen(aName);
- const char *domain = (mDomain == nullptr) ? "local." : mDomain;
+ std::string regType = aType;
- VerifyOrExit(nameLength <= kMaxSizeOfHost, error = OTBR_ERROR_INVALID_ARGS);
+ std::sort(aSubTypeList.begin(), aSubTypeList.end());
- assert(aFullNameLength >= nameLength + sizeof(".") + strlen(domain));
- OTBR_UNUSED_VARIABLE(aFullNameLength);
-
- strcpy(aFullName, aName);
- strcpy(aFullName + nameLength, ".");
- strcpy(aFullName + nameLength + 1, domain);
-
-exit:
- return error;
-}
-
-std::string PublisherMDnsSd::MakeRegType(const char *aType, const SubTypeList &aSubTypeList)
-{
- // See `regtype` parameter of the DNSServiceRegister() function for more information.
- std::string fullType(aType);
-
- for (const std::string &subType : aSubTypeList)
+ for (const auto &subType : aSubTypeList)
{
- fullType += ',';
- fullType += subType;
+ regType += "," + subType;
}
- return fullType;
-}
-
-PublisherMDnsSd::ServiceIterator PublisherMDnsSd::FindPublishedService(const char *aName, const char *aType)
-{
- return std::find_if(mServices.begin(), mServices.end(), [&aName, aType](const Service &service) {
- return strcmp(aName, service.mName) == 0 && IsServiceTypeEqual(aType, service.mType);
- });
-}
-
-PublisherMDnsSd::ServiceIterator PublisherMDnsSd::FindPublishedService(const DNSServiceRef &aServiceRef)
-{
- return std::find_if(mServices.begin(), mServices.end(),
- [&aServiceRef](const Service &service) { return service.mService == aServiceRef; });
-}
-
-PublisherMDnsSd::HostIterator PublisherMDnsSd::FindPublishedHost(const DNSRecordRef &aRecordRef)
-{
- return std::find_if(mHosts.begin(), mHosts.end(),
- [&aRecordRef](const Host &host) { return host.mRecord == aRecordRef; });
-}
-
-PublisherMDnsSd::HostIterator PublisherMDnsSd::FindPublishedHost(const char *aHostName)
-{
- return std::find_if(mHosts.begin(), mHosts.end(),
- [&aHostName](const Host &host) { return strcmp(host.mName, aHostName) == 0; });
+ return regType;
}
void PublisherMDnsSd::SubscribeService(const std::string &aType, const std::string &aInstanceName)
{
- mSubscribedServices.emplace_back(*this, aType, aInstanceName);
+ VerifyOrExit(mState == Publisher::State::kReady);
+ mSubscribedServices.push_back(MakeUnique<ServiceSubscription>(*this, aType, aInstanceName));
- otbrLogInfo("subscribe service %s.%s (total %zu)", aInstanceName.c_str(), aType.c_str(),
+ otbrLogInfo("Subscribe service %s.%s (total %zu)", aInstanceName.c_str(), aType.c_str(),
mSubscribedServices.size());
if (aInstanceName.empty())
{
- mSubscribedServices.back().Browse();
+ mSubscribedServices.back()->Browse();
}
else
{
- mSubscribedServices.back().Resolve(kDNSServiceInterfaceIndexAny, aInstanceName.c_str(), aType.c_str(),
- "local.");
+ mSubscribedServices.back()->Resolve(kDNSServiceInterfaceIndexAny, aInstanceName, aType, kDomain);
}
+
+exit:
+ return;
}
void PublisherMDnsSd::UnsubscribeService(const std::string &aType, const std::string &aInstanceName)
{
- ServiceSubscriptionList::iterator it =
- std::find_if(mSubscribedServices.begin(), mSubscribedServices.end(),
- [&aType, &aInstanceName](const ServiceSubscription &aService) {
- return aService.mType == aType && aService.mInstanceName == aInstanceName;
- });
+ ServiceSubscriptionList::iterator it;
+ VerifyOrExit(mState == Publisher::State::kReady);
+ it = std::find_if(mSubscribedServices.begin(), mSubscribedServices.end(),
+ [&aType, &aInstanceName](const std::unique_ptr<ServiceSubscription> &aService) {
+ return aService->mType == aType && aService->mInstanceName == aInstanceName;
+ });
assert(it != mSubscribedServices.end());
- it->Release();
mSubscribedServices.erase(it);
- otbrLogInfo("unsubscribe service %s.%s (left %zu)", aInstanceName.c_str(), aType.c_str(),
+ otbrLogInfo("Unsubscribe service %s.%s (left %zu)", aInstanceName.c_str(), aType.c_str(),
mSubscribedServices.size());
-}
-
-void PublisherMDnsSd::OnServiceResolved(PublisherMDnsSd::ServiceSubscription &aService)
-{
- otbrLogInfo("Service %s is resolved successfully: %s host %s addresses %zu", aService.mType.c_str(),
- aService.mInstanceInfo.mName.c_str(), aService.mInstanceInfo.mHostName.c_str(),
- aService.mInstanceInfo.mAddresses.size());
- if (mDiscoveredServiceInstanceCallback != nullptr)
- {
- mDiscoveredServiceInstanceCallback(aService.mType, aService.mInstanceInfo);
- }
+exit:
+ return;
}
-void PublisherMDnsSd::OnServiceResolveFailed(const ServiceSubscription &aService, DNSServiceErrorType aErrorCode)
+void PublisherMDnsSd::OnServiceResolveFailedImpl(const std::string &aType,
+ const std::string &aInstanceName,
+ int32_t aErrorCode)
{
- otbrLogWarning("Service %s resolving failed: code=%d", aService.mType.c_str(), aErrorCode);
+ otbrLogWarning("Resolve service %s.%s failed: code=%" PRId32, aInstanceName.c_str(), aType.c_str(), aErrorCode);
}
-void PublisherMDnsSd::OnHostResolved(PublisherMDnsSd::HostSubscription &aHost)
+void PublisherMDnsSd::OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode)
{
- otbrLogInfo("Host %s is resolved successfully: host %s addresses %zu ttl %u", aHost.mHostName.c_str(),
- aHost.mHostInfo.mHostName.c_str(), aHost.mHostInfo.mAddresses.size(), aHost.mHostInfo.mTtl);
-
- if (mDiscoveredHostCallback != nullptr)
- {
- mDiscoveredHostCallback(aHost.mHostName, aHost.mHostInfo);
- }
+ otbrLogWarning("Resolve host %s failed: code=%" PRId32, aHostName.c_str(), aErrorCode);
}
-void PublisherMDnsSd::OnHostResolveFailed(const PublisherMDnsSd::HostSubscription &aHost,
- DNSServiceErrorType aErrorCode)
+otbrError PublisherMDnsSd::DnsErrorToOtbrError(int32_t aErrorCode)
{
- otbrLogWarning("Host %s resolving failed: code=%d", aHost.mHostName.c_str(), aErrorCode);
+ return otbr::Mdns::DNSErrorToOtbrError(aErrorCode);
}
void PublisherMDnsSd::SubscribeHost(const std::string &aHostName)
{
- mSubscribedHosts.emplace_back(*this, aHostName);
+ VerifyOrExit(mState == State::kReady);
+ mSubscribedHosts.push_back(MakeUnique<HostSubscription>(*this, aHostName));
- otbrLogInfo("subscribe host %s (total %zu)", aHostName.c_str(), mSubscribedHosts.size());
+ otbrLogInfo("Subscribe host %s (total %zu)", aHostName.c_str(), mSubscribedHosts.size());
- mSubscribedHosts.back().Resolve();
+ mSubscribedHosts.back()->Resolve();
+
+exit:
+ return;
}
void PublisherMDnsSd::UnsubscribeHost(const std::string &aHostName)
{
- HostSubscriptionList ::iterator it =
- std::find_if(mSubscribedHosts.begin(), mSubscribedHosts.end(),
- [&aHostName](const HostSubscription &aHost) { return aHost.mHostName == aHostName; });
+ HostSubscriptionList ::iterator it;
+
+ VerifyOrExit(mState == Publisher::State::kReady);
+ it = std::find_if(
+ mSubscribedHosts.begin(), mSubscribedHosts.end(),
+ [&aHostName](const std::unique_ptr<HostSubscription> &aHost) { return aHost->mHostName == aHostName; });
assert(it != mSubscribedHosts.end());
- it->Release();
mSubscribedHosts.erase(it);
- otbrLogInfo("unsubscribe host %s (remaining %d)", aHostName.c_str(), mSubscribedHosts.size());
+ otbrLogInfo("Unsubscribe host %s (remaining %d)", aHostName.c_str(), mSubscribedHosts.size());
+
+exit:
+ return;
}
-Publisher *Publisher::Create(int aFamily, const char *aDomain, StateHandler aHandler, void *aContext)
+Publisher *Publisher::Create(StateCallback aCallback)
{
- return new PublisherMDnsSd(aFamily, aDomain, aHandler, aContext);
+ return new PublisherMDnsSd(aCallback);
}
void Publisher::Destroy(Publisher *aPublisher)
@@ -882,12 +757,12 @@ void Publisher::Destroy(Publisher *aPublisher)
delete static_cast<PublisherMDnsSd *>(aPublisher);
}
-void PublisherMDnsSd::Subscription::Release(void)
+void PublisherMDnsSd::ServiceRef::Release(void)
{
DeallocateServiceRef();
}
-void PublisherMDnsSd::Subscription::DeallocateServiceRef(void)
+void PublisherMDnsSd::ServiceRef::DeallocateServiceRef(void)
{
if (mServiceRef != nullptr)
{
@@ -896,12 +771,43 @@ void PublisherMDnsSd::Subscription::DeallocateServiceRef(void)
}
}
+void PublisherMDnsSd::ServiceRef::Update(MainloopContext &aMainloop) const
+{
+ int fd;
+
+ VerifyOrExit(mServiceRef != nullptr);
+
+ fd = DNSServiceRefSockFD(mServiceRef);
+ assert(fd != -1);
+ FD_SET(fd, &aMainloop.mReadFdSet);
+ aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd);
+exit:
+ return;
+}
+
+void PublisherMDnsSd::ServiceRef::Process(const MainloopContext & aMainloop,
+ std::vector<DNSServiceRef> &aReadyServices) const
+{
+ int fd;
+
+ VerifyOrExit(mServiceRef != nullptr);
+
+ fd = DNSServiceRefSockFD(mServiceRef);
+ assert(fd != -1);
+ if (FD_ISSET(fd, &aMainloop.mReadFdSet))
+ {
+ aReadyServices.push_back(mServiceRef);
+ }
+exit:
+ return;
+}
+
void PublisherMDnsSd::ServiceSubscription::Browse(void)
{
assert(mServiceRef == nullptr);
otbrLogInfo("DNSServiceBrowse %s", mType.c_str());
- DNSServiceBrowse(&mServiceRef, /* flags */ kDNSServiceFlagsTimeout, kDNSServiceInterfaceIndexAny, mType.c_str(),
+ DNSServiceBrowse(&mServiceRef, /* flags */ 0, kDNSServiceInterfaceIndexAny, mType.c_str(),
/* domain */ nullptr, HandleBrowseResult, this);
}
@@ -927,63 +833,111 @@ void PublisherMDnsSd::ServiceSubscription::HandleBrowseResult(DNSServiceRef
const char * aDomain)
{
OTBR_UNUSED_VARIABLE(aServiceRef);
+ OTBR_UNUSED_VARIABLE(aDomain);
- otbrLogInfo("DNSServiceBrowse reply: %s.%s%s inf %u, flags=%u, error=%d", aInstanceName, aType, aDomain,
- aInterfaceIndex, aFlags, aErrorCode);
+ otbrLogInfo("DNSServiceBrowse reply: %s %s.%s inf %" PRIu32 ", flags=%" PRIu32 ", error=%" PRId32,
+ aFlags & kDNSServiceFlagsAdd ? "add" : "remove", aInstanceName, aType, aInterfaceIndex, aFlags,
+ aErrorCode);
VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
- VerifyOrExit(aFlags & kDNSServiceFlagsAdd);
- DeallocateServiceRef();
- Resolve(aInterfaceIndex, aInstanceName, aType, aDomain);
+ if (aFlags & kDNSServiceFlagsAdd)
+ {
+ Resolve(aInterfaceIndex, aInstanceName, aType, aDomain);
+ }
+ else
+ {
+ mMDnsSd->OnServiceRemoved(aInterfaceIndex, mType, aInstanceName);
+ }
exit:
if (aErrorCode != kDNSServiceErr_NoError)
{
- mMDnsSd->OnServiceResolveFailed(*this, aErrorCode);
+ mMDnsSd->OnServiceResolveFailed(mType, mInstanceName, aErrorCode);
+ Release();
+ }
+}
+
+void PublisherMDnsSd::ServiceSubscription::Resolve(uint32_t aInterfaceIndex,
+ const std::string &aInstanceName,
+ const std::string &aType,
+ const std::string &aDomain)
+{
+ mResolvingInstances.push_back(
+ MakeUnique<ServiceInstanceResolution>(*this, aInstanceName, aType, aDomain, aInterfaceIndex));
+ mResolvingInstances.back()->Resolve();
+}
+
+void PublisherMDnsSd::ServiceSubscription::RemoveInstanceResolution(
+ PublisherMDnsSd::ServiceInstanceResolution &aInstanceResolution)
+{
+ auto it = std::find_if(mResolvingInstances.begin(), mResolvingInstances.end(),
+ [&aInstanceResolution](const std::unique_ptr<ServiceInstanceResolution> &aElem) {
+ return &aInstanceResolution == aElem.get();
+ });
+
+ assert(it != mResolvingInstances.end());
+
+ mResolvingInstances.erase(it);
+}
+
+void PublisherMDnsSd::ServiceSubscription::UpdateAll(MainloopContext &aMainloop) const
+{
+ Update(aMainloop);
+
+ for (const auto &instance : mResolvingInstances)
+ {
+ instance->Update(aMainloop);
}
- else if (!(aFlags & (kDNSServiceFlagsAdd | kDNSServiceFlagsMoreComing)))
+}
+
+void PublisherMDnsSd::ServiceSubscription::ProcessAll(const MainloopContext & aMainloop,
+ std::vector<DNSServiceRef> &aReadyServices) const
+{
+ Process(aMainloop, aReadyServices);
+
+ for (const auto &instance : mResolvingInstances)
{
- mMDnsSd->OnServiceResolveFailed(*this, kDNSServiceErr_NoSuchName);
+ instance->Process(aMainloop, aReadyServices);
}
}
-void PublisherMDnsSd::ServiceSubscription::Resolve(uint32_t aInterfaceIndex,
- const char *aInstanceName,
- const char *aType,
- const char *aDomain)
+void PublisherMDnsSd::ServiceInstanceResolution::Resolve(void)
{
assert(mServiceRef == nullptr);
- otbrLogInfo("DNSServiceResolve %s %s %s inf %d", aInstanceName, aType, aDomain, aInterfaceIndex);
- DNSServiceResolve(&mServiceRef, /* flags */ 0, aInterfaceIndex, aInstanceName, aType, aDomain, HandleResolveResult,
- this);
+ mSubscription->mMDnsSd->mServiceInstanceResolutionBeginTime[std::make_pair(mInstanceName, mTypeEndWithDot)] =
+ Clock::now();
+
+ otbrLogInfo("DNSServiceResolve %s %s inf %u", mInstanceName.c_str(), mTypeEndWithDot.c_str(), mNetifIndex);
+ DNSServiceResolve(&mServiceRef, /* flags */ kDNSServiceFlagsTimeout, mNetifIndex, mInstanceName.c_str(),
+ mTypeEndWithDot.c_str(), mDomain.c_str(), HandleResolveResult, this);
}
-void PublisherMDnsSd::ServiceSubscription::HandleResolveResult(DNSServiceRef aServiceRef,
- DNSServiceFlags aFlags,
- uint32_t aInterfaceIndex,
- DNSServiceErrorType aErrorCode,
- const char * aFullName,
- const char * aHostTarget,
- uint16_t aPort,
- uint16_t aTxtLen,
- const unsigned char *aTxtRecord,
- void * aContext)
+void PublisherMDnsSd::ServiceInstanceResolution::HandleResolveResult(DNSServiceRef aServiceRef,
+ DNSServiceFlags aFlags,
+ uint32_t aInterfaceIndex,
+ DNSServiceErrorType aErrorCode,
+ const char * aFullName,
+ const char * aHostTarget,
+ uint16_t aPort,
+ uint16_t aTxtLen,
+ const unsigned char *aTxtRecord,
+ void * aContext)
{
- static_cast<ServiceSubscription *>(aContext)->HandleResolveResult(
+ static_cast<ServiceInstanceResolution *>(aContext)->HandleResolveResult(
aServiceRef, aFlags, aInterfaceIndex, aErrorCode, aFullName, aHostTarget, aPort, aTxtLen, aTxtRecord);
}
-void PublisherMDnsSd::ServiceSubscription::HandleResolveResult(DNSServiceRef aServiceRef,
- DNSServiceFlags aFlags,
- uint32_t aInterfaceIndex,
- DNSServiceErrorType aErrorCode,
- const char * aFullName,
- const char * aHostTarget,
- uint16_t aPort,
- uint16_t aTxtLen,
- const unsigned char *aTxtRecord)
+void PublisherMDnsSd::ServiceInstanceResolution::HandleResolveResult(DNSServiceRef aServiceRef,
+ DNSServiceFlags aFlags,
+ uint32_t aInterfaceIndex,
+ DNSServiceErrorType aErrorCode,
+ const char * aFullName,
+ const char * aHostTarget,
+ uint16_t aPort,
+ uint16_t aTxtLen,
+ const unsigned char *aTxtRecord)
{
OTBR_UNUSED_VARIABLE(aServiceRef);
@@ -997,68 +951,80 @@ void PublisherMDnsSd::ServiceSubscription::HandleResolveResult(DNSServiceRef
SuccessOrExit(error = SplitFullServiceInstanceName(aFullName, instanceName, type, domain));
- mInstanceInfo.mName = instanceName;
- mInstanceInfo.mHostName = aHostTarget;
- mInstanceInfo.mPort = ntohs(aPort);
+ mInstanceInfo.mNetifIndex = aInterfaceIndex;
+ mInstanceInfo.mName = instanceName;
+ mInstanceInfo.mHostName = aHostTarget;
+ mInstanceInfo.mPort = ntohs(aPort);
mInstanceInfo.mTxtData.assign(aTxtRecord, aTxtRecord + aTxtLen);
// priority and weight are not given in the reply
mInstanceInfo.mPriority = 0;
mInstanceInfo.mWeight = 0;
DeallocateServiceRef();
- GetAddrInfo(aInterfaceIndex);
+ error = GetAddrInfo(aInterfaceIndex);
exit:
- if (aErrorCode != kDNSServiceErr_NoError || error != OTBR_ERROR_NONE)
+ if (error != OTBR_ERROR_NONE)
{
- mMDnsSd->OnServiceResolveFailed(*this, aErrorCode);
+ otbrLogWarning("Failed to resolve service instance %s", aFullName);
}
- if (error != OTBR_ERROR_NONE)
+ if (aErrorCode != kDNSServiceErr_NoError || error != OTBR_ERROR_NONE)
{
- otbrLogWarning("failed to resolve service instance %s", aFullName);
+ mSubscription->mMDnsSd->OnServiceResolveFailed(mSubscription->mType, mInstanceName, aErrorCode);
+ FinishResolution();
}
}
-void PublisherMDnsSd::ServiceSubscription::GetAddrInfo(uint32_t aInterfaceIndex)
+otbrError PublisherMDnsSd::ServiceInstanceResolution::GetAddrInfo(uint32_t aInterfaceIndex)
{
+ DNSServiceErrorType dnsError;
+
assert(mServiceRef == nullptr);
otbrLogInfo("DNSServiceGetAddrInfo %s inf %d", mInstanceInfo.mHostName.c_str(), aInterfaceIndex);
- DNSServiceGetAddrInfo(&mServiceRef, /* flags */ 0, aInterfaceIndex,
- kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4, mInstanceInfo.mHostName.c_str(),
- HandleGetAddrInfoResult, this);
+ dnsError = DNSServiceGetAddrInfo(&mServiceRef, kDNSServiceFlagsTimeout, aInterfaceIndex,
+ kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4,
+ mInstanceInfo.mHostName.c_str(), HandleGetAddrInfoResult, this);
+
+ if (dnsError != kDNSServiceErr_NoError)
+ {
+ otbrLogWarning("DNSServiceGetAddrInfo failed: %s", DNSErrorToString(dnsError));
+ }
+
+ return dnsError == kDNSServiceErr_NoError ? OTBR_ERROR_NONE : OTBR_ERROR_MDNS;
}
-void PublisherMDnsSd::ServiceSubscription::HandleGetAddrInfoResult(DNSServiceRef aServiceRef,
- DNSServiceFlags aFlags,
- uint32_t aInterfaceIndex,
- DNSServiceErrorType aErrorCode,
- const char * aHostName,
- const struct sockaddr *aAddress,
- uint32_t aTtl,
- void * aContext)
+void PublisherMDnsSd::ServiceInstanceResolution::HandleGetAddrInfoResult(DNSServiceRef aServiceRef,
+ DNSServiceFlags aFlags,
+ uint32_t aInterfaceIndex,
+ DNSServiceErrorType aErrorCode,
+ const char * aHostName,
+ const struct sockaddr *aAddress,
+ uint32_t aTtl,
+ void * aContext)
{
- static_cast<ServiceSubscription *>(aContext)->HandleGetAddrInfoResult(aServiceRef, aFlags, aInterfaceIndex,
- aErrorCode, aHostName, aAddress, aTtl);
+ static_cast<ServiceInstanceResolution *>(aContext)->HandleGetAddrInfoResult(aServiceRef, aFlags, aInterfaceIndex,
+ aErrorCode, aHostName, aAddress, aTtl);
}
-void PublisherMDnsSd::ServiceSubscription::HandleGetAddrInfoResult(DNSServiceRef aServiceRef,
- DNSServiceFlags aFlags,
- uint32_t aInterfaceIndex,
- DNSServiceErrorType aErrorCode,
- const char * aHostName,
- const struct sockaddr *aAddress,
- uint32_t aTtl)
+void PublisherMDnsSd::ServiceInstanceResolution::HandleGetAddrInfoResult(DNSServiceRef aServiceRef,
+ DNSServiceFlags aFlags,
+ uint32_t aInterfaceIndex,
+ DNSServiceErrorType aErrorCode,
+ const char * aHostName,
+ const struct sockaddr *aAddress,
+ uint32_t aTtl)
{
OTBR_UNUSED_VARIABLE(aServiceRef);
OTBR_UNUSED_VARIABLE(aInterfaceIndex);
Ip6Address address;
- otbrLogDebug("DNSServiceGetAddrInfo reply: %d, flags=%u, host=%s, sa_family=%d", aErrorCode, aFlags, aHostName,
- aAddress->sa_family);
+ otbrLog(aErrorCode == kDNSServiceErr_NoError ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
+ "DNSServiceGetAddrInfo reply: flags=%" PRIu32 ", host=%s, sa_family=%u, error=%" PRId32, aFlags, aHostName,
+ static_cast<unsigned int>(aAddress->sa_family), aErrorCode);
VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
VerifyOrExit((aFlags & kDNSServiceFlagsAdd) && aAddress->sa_family == AF_INET6);
@@ -1070,32 +1036,38 @@ void PublisherMDnsSd::ServiceSubscription::HandleGetAddrInfoResult(DNSServiceRef
mInstanceInfo.mAddresses.push_back(address);
mInstanceInfo.mTtl = aTtl;
- otbrLogDebug("DNSServiceGetAddrInfo reply: address=%s, ttl=%u", address.ToString().c_str(), aTtl);
-
- mMDnsSd->OnServiceResolved(*this);
+ otbrLogInfo("DNSServiceGetAddrInfo reply: address=%s, ttl=%" PRIu32, address.ToString().c_str(), aTtl);
exit:
- if (aErrorCode != kDNSServiceErr_NoError)
+ if (!mInstanceInfo.mAddresses.empty() || aErrorCode != kDNSServiceErr_NoError)
{
- otbrLogWarning("DNSServiceGetAddrInfo failed: %d", aErrorCode);
-
- mMDnsSd->OnServiceResolveFailed(*this, aErrorCode);
- }
- else if (mInstanceInfo.mAddresses.empty() && (aFlags & kDNSServiceFlagsMoreComing) == 0)
- {
- otbrLogDebug("DNSServiceGetAddrInfo reply: no IPv6 address found");
- mInstanceInfo.mTtl = aTtl;
- mMDnsSd->OnServiceResolved(*this);
+ FinishResolution();
}
}
+void PublisherMDnsSd::ServiceInstanceResolution::FinishResolution(void)
+{
+ ServiceSubscription * subscription = mSubscription;
+ std::string serviceName = mSubscription->mType;
+ DiscoveredInstanceInfo instanceInfo = mInstanceInfo;
+
+ // NOTE: `RemoveInstanceResolution` will free this `ServiceInstanceResolution` object.
+ // So, We can't access `mSubscription` after `RemoveInstanceResolution`.
+ subscription->RemoveInstanceResolution(*this);
+
+ // NOTE: The `ServiceSubscription` object may be freed in `OnServiceResolved`.
+ subscription->mMDnsSd->OnServiceResolved(serviceName, instanceInfo);
+}
+
void PublisherMDnsSd::HostSubscription::Resolve(void)
{
- std::string fullHostName = mHostName + ".local.";
+ std::string fullHostName = MakeFullHostName(mHostName);
assert(mServiceRef == nullptr);
- otbrLogDebug("DNSServiceGetAddrInfo %s inf %d", fullHostName.c_str(), kDNSServiceInterfaceIndexAny);
+ mMDnsSd->mHostResolutionBeginTime[mHostName] = Clock::now();
+
+ otbrLogInfo("DNSServiceGetAddrInfo %s inf %d", fullHostName.c_str(), kDNSServiceInterfaceIndexAny);
DNSServiceGetAddrInfo(&mServiceRef, /* flags */ 0, kDNSServiceInterfaceIndexAny,
kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4, fullHostName.c_str(),
@@ -1128,8 +1100,9 @@ void PublisherMDnsSd::HostSubscription::HandleResolveResult(DNSServiceRef
Ip6Address address;
- otbrLogDebug("DNSServiceGetAddrInfo reply: %d, flags=%u, host=%s, sa_family=%d", aErrorCode, aFlags, aHostName,
- aAddress->sa_family);
+ otbrLog(aErrorCode == kDNSServiceErr_NoError ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
+ "DNSServiceGetAddrInfo reply: flags=%" PRIu32 ", host=%s, sa_family=%u, error=%" PRId32, aFlags, aHostName,
+ static_cast<unsigned int>(aAddress->sa_family), aErrorCode);
VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
VerifyOrExit((aFlags & kDNSServiceFlagsAdd) && aAddress->sa_family == AF_INET6);
@@ -1142,22 +1115,15 @@ void PublisherMDnsSd::HostSubscription::HandleResolveResult(DNSServiceRef
mHostInfo.mAddresses.push_back(address);
mHostInfo.mTtl = aTtl;
- otbrLogDebug("DNSServiceGetAddrInfo reply: address=%s, ttl=%u", address.ToString().c_str(), aTtl);
+ otbrLogInfo("DNSServiceGetAddrInfo reply: address=%s, ttl=%" PRIu32, address.ToString().c_str(), aTtl);
- mMDnsSd->OnHostResolved(*this);
+ // NOTE: This `HostSubscription` object may be freed in `OnHostResolved`.
+ mMDnsSd->OnHostResolved(mHostName, mHostInfo);
exit:
if (aErrorCode != kDNSServiceErr_NoError)
{
- otbrLogWarning("DNSServiceGetAddrInfo failed: %d", aErrorCode);
-
- mMDnsSd->OnHostResolveFailed(*this, aErrorCode);
- }
- else if (mHostInfo.mAddresses.empty() && (aFlags & kDNSServiceFlagsMoreComing) == 0)
- {
- otbrLogDebug("DNSServiceGetAddrInfo reply: no IPv6 address found");
- mHostInfo.mTtl = aTtl;
- mMDnsSd->OnHostResolved(*this);
+ mMDnsSd->OnHostResolveFailed(aHostName, aErrorCode);
}
}
diff --git a/src/mdns/mdns_mdnssd.hpp b/src/mdns/mdns_mdnssd.hpp
index 39aa2e96..3fff55b6 100644
--- a/src/mdns/mdns_mdnssd.hpp
+++ b/src/mdns/mdns_mdnssd.hpp
@@ -28,7 +28,7 @@
/**
* @file
- * This file includes definition for mDNS service.
+ * This file includes definition for mDNS publisher.
*/
#ifndef OTBR_AGENT_MDNS_MDNSSD_HPP_
@@ -36,6 +36,7 @@
#include <array>
#include <map>
+#include <memory>
#include <utility>
#include <vector>
@@ -52,249 +53,148 @@ namespace otbr {
namespace Mdns {
/**
- * This class implements mDNS service with mDNSResponder.
+ * This class implements mDNS publisher with mDNSResponder.
*
*/
class PublisherMDnsSd : public MainloopProcessor, public Publisher
{
public:
- /**
- * The constructor to initialize a Publisher.
- *
- * @param[in] aProtocol The protocol used for publishing. IPv4, IPv6 or both.
- * @param[in] aDomain The domain of the host. nullptr to use default.
- * @param[in] aHandler The function to be called when state changes.
- * @param[in] aContext A pointer to application-specific context.
- *
- */
- PublisherMDnsSd(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext);
+ explicit PublisherMDnsSd(StateCallback aCallback);
~PublisherMDnsSd(void) override;
- /**
- * This method publishes or updates a service.
- *
- * @param[in] aHostName The name of the host which this service resides on. If NULL is provided,
- * this service resides on local host and it is the implementation to provide
- * specific host name. Otherwise, the caller MUST publish the host with method
- * PublishHost.
- * @param[in] aPort The port number of this service.
- * @param[in] aName The name of this service.
- * @param[in] aType The type of this service.
- * @param[in] aSubTypeList A list of service subtypes.
- * @param[in] aTxtList A list of TXT name/value pairs.
- *
- * @retval OTBR_ERROR_NONE Successfully published or updated the service.
- * @retval OTBR_ERROR_ERRNO Failed to publish or update the service.
- *
- */
- otbrError PublishService(const char * aHostName,
- uint16_t aPort,
- const char * aName,
- const char * aType,
- const SubTypeList &aSubTypeList,
- const TxtList & aTxtList) override;
-
- /**
- * This method un-publishes a service.
- *
- * @param[in] aName The name of this service.
- * @param[in] aType The type of this service.
- *
- * @retval OTBR_ERROR_NONE Successfully un-published the service.
- * @retval OTBR_ERROR_ERRNO Failed to un-publish the service.
- *
- */
- otbrError UnpublishService(const char *aName, const char *aType) override;
-
- /**
- * This method publishes or updates a host.
- *
- * Publishing a host is advertising an AAAA RR for the host name. This method should be called
- * before a service with non-null host name is published.
- *
- * @param[in] aName The name of the host.
- * @param[in] aAddress The address of the host.
- * @param[in] aAddressLength The length of @p aAddress.
- *
- * @retval OTBR_ERROR_NONE Successfully published or updated the host.
- * @retval OTBR_ERROR_ERRNO Failed to publish or update the host.
- *
- */
- otbrError PublishHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength) override;
-
- /**
- * This method un-publishes a host.
- *
- * @param[in] aName A host name.
- *
- * @retval OTBR_ERROR_NONE Successfully un-published the host.
- * @retval OTBR_ERROR_ERRNO Failed to un-publish the host.
- *
- * @note All services reside on this host should be un-published by UnpublishService.
- *
- */
- otbrError UnpublishHost(const char *aName) override;
-
- /**
- * This method subscribes a given service or service instance. If @p aInstanceName is not empty, this method
- * subscribes the service instance. Otherwise, this method subscribes the service.
- *
- * mDNS implementations should use the `DiscoveredServiceInstanceCallback` function to notify discovered service
- * instances.
- *
- * @note Discovery Proxy implementation guarantees no duplicate subscriptions for the same service or service
- * instance.
- *
- * @param[in] aType The service type.
- * @param[in] aInstanceName The service instance to subscribe, or empty to subscribe the service.
- *
- */
- void SubscribeService(const std::string &aType, const std::string &aInstanceName) override;
-
- /**
- * This method unsubscribes a given service or service instance. If @p aInstanceName is not empty, this method
- * unsubscribes the service instance. Otherwise, this method unsubscribes the service.
- *
- * @note Discovery Proxy implementation guarantees no redundant unsubscription for a service or service instance.
- *
- * @param[in] aType The service type.
- * @param[in] aInstanceName The service instance to unsubscribe, or empty to unsubscribe the service.
- *
- */
- void UnsubscribeService(const std::string &aType, const std::string &aInstanceName) override;
-
- /**
- * This method subscribes a given host.
- *
- * mDNS implementations should use the `DiscoveredHostCallback` function to notify discovered hosts.
- *
- * @note Discovery Proxy implementation guarantees no duplicate subscriptions for the same host.
- *
- * @param[in] aHostName The host name (without domain).
- *
- */
- void SubscribeHost(const std::string &aHostName) override;
-
- /**
- * This method unsubscribes a given host.
- *
- * @note Discovery Proxy implementation guarantees no redundant unsubscription for a host.
- *
- * @param[in] aHostName The host name (without domain).
- *
- */
- void UnsubscribeHost(const std::string &aHostName) override;
-
- /**
- * This method starts the mDNS service.
- *
- * @retval OTBR_ERROR_NONE Successfully started mDNS service;
- * @retval OTBR_ERROR_MDNS Failed to start mDNS service.
- *
- */
+ // Implementation of Mdns::Publisher.
+
+ void UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback) override;
+
+ void UnpublishHost(const std::string &aName, ResultCallback &&aCallback) override;
+ void SubscribeService(const std::string &aType, const std::string &aInstanceName) override;
+ void UnsubscribeService(const std::string &aType, const std::string &aInstanceName) override;
+ void SubscribeHost(const std::string &aHostName) override;
+ void UnsubscribeHost(const std::string &aHostName) override;
otbrError Start(void) override;
+ bool IsStarted(void) const override;
+ void Stop(void) override;
- /**
- * This method checks if publisher has been started.
- *
- * @retval true Already started.
- * @retval false Not started.
- *
- */
- bool IsStarted(void) const override;
-
- /**
- * This method stops the mDNS service.
- *
- */
- void Stop(void) override;
-
- /**
- * This method updates the mainloop context.
- *
- * @param[inout] aMainloop A reference to the mainloop to be updated.
- *
- */
- void Update(MainloopContext &aMainloop) override;
+ // Implementation of MainloopProcessor.
- /**
- * This method processes mainloop events.
- *
- * @param[in] aMainloop A reference to the mainloop context.
- *
- */
+ void Update(MainloopContext &aMainloop) override;
void Process(const MainloopContext &aMainloop) override;
+protected:
+ void PublishServiceImpl(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList,
+ ResultCallback && aCallback) override;
+ void PublishHostImpl(const std::string & aName,
+ const std::vector<uint8_t> &aAddress,
+ ResultCallback && aCallback) override;
+ void OnServiceResolveFailedImpl(const std::string &aType,
+ const std::string &aInstanceName,
+ int32_t aErrorCode) override;
+ void OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode) override;
+ otbrError DnsErrorToOtbrError(int32_t aErrorCode) override;
+
private:
- enum
- {
- kMaxSizeOfTxtRecord = 256,
- kMaxSizeOfServiceName = kDNSServiceMaxServiceName,
- kMaxSizeOfHost = 128,
- kMaxSizeOfDomain = kDNSServiceMaxDomainName,
- kMaxSizeOfServiceType = 69,
- };
+ static constexpr uint32_t kDefaultTtl = 10;
- struct Service
+ class DnssdServiceRegistration : public ServiceRegistration
{
- char mName[kMaxSizeOfServiceName];
- char mType[kMaxSizeOfServiceType];
- std::string mRegType; ///< Service type with optional subtypes separated by commas
- DNSServiceRef mService;
- uint16_t mPort = 0;
+ public:
+ DnssdServiceRegistration(const std::string &aHostName,
+ const std::string &aName,
+ const std::string &aType,
+ const SubTypeList &aSubTypeList,
+ uint16_t aPort,
+ const TxtList & aTxtList,
+ ResultCallback && aCallback,
+ DNSServiceRef aServiceRef,
+ PublisherMDnsSd * aPublisher)
+ : ServiceRegistration(aHostName,
+ aName,
+ aType,
+ aSubTypeList,
+ aPort,
+ aTxtList,
+ std::move(aCallback),
+ aPublisher)
+ , mServiceRef(aServiceRef)
+ {
+ }
+
+ ~DnssdServiceRegistration(void) override;
+ const DNSServiceRef &GetServiceRef() const { return mServiceRef; }
+
+ private:
+ DNSServiceRef mServiceRef;
};
- struct Host
+ class DnssdHostRegistration : public HostRegistration
{
- char mName[kMaxSizeOfServiceName];
- std::array<uint8_t, OTBR_IP6_ADDRESS_SIZE> mAddress;
- DNSRecordRef mRecord;
+ public:
+ DnssdHostRegistration(const std::string & aName,
+ const std::vector<uint8_t> &aAddress,
+ ResultCallback && aCallback,
+ DNSServiceRef aServiceRef,
+ DNSRecordRef aRecordRef,
+ Publisher * aPublisher)
+ : HostRegistration(aName, aAddress, std::move(aCallback), aPublisher)
+ , mServiceRef(aServiceRef)
+ , mRecordRef(aRecordRef)
+ {
+ }
+
+ ~DnssdHostRegistration(void) override;
+ const DNSServiceRef &GetServiceRef() const { return mServiceRef; }
+ const DNSRecordRef & GetRecordRef() const { return mRecordRef; }
+
+ private:
+ DNSServiceRef mServiceRef;
+ DNSRecordRef mRecordRef;
};
- struct Subscription
+ struct ServiceRef : private ::NonCopyable
{
- PublisherMDnsSd *mMDnsSd;
- DNSServiceRef mServiceRef;
+ DNSServiceRef mServiceRef;
- explicit Subscription(PublisherMDnsSd &aMDnsSd)
- : mMDnsSd(&aMDnsSd)
- , mServiceRef(nullptr)
+ explicit ServiceRef(void)
+ : mServiceRef(nullptr)
{
}
+ ~ServiceRef() { Release(); }
+
+ void Update(MainloopContext &aMainloop) const;
+ void Process(const MainloopContext &aMainloop, std::vector<DNSServiceRef> &aReadyServices) const;
void Release(void);
void DeallocateServiceRef(void);
};
- struct ServiceSubscription : public Subscription
+ struct ServiceSubscription;
+
+ struct ServiceInstanceResolution : public ServiceRef
{
- explicit ServiceSubscription(PublisherMDnsSd &aMDnsSd, std::string aType, std::string aInstanceName)
- : Subscription(aMDnsSd)
- , mType(std::move(aType))
+ explicit ServiceInstanceResolution(ServiceSubscription &aSubscription,
+ std::string aInstanceName,
+ std::string aType,
+ std::string aDomain,
+ uint32_t aNetifIndex)
+ : ServiceRef()
+ , mSubscription(&aSubscription)
, mInstanceName(std::move(aInstanceName))
+ , mTypeEndWithDot(std::move(aType))
+ , mDomain(std::move(aDomain))
+ , mNetifIndex(aNetifIndex)
{
}
- void Browse(void);
- void Resolve(uint32_t aInterfaceIndex, const char *aInstanceName, const char *aType, const char *aDomain);
- void GetAddrInfo(uint32_t aInterfaceIndex);
+ void Resolve(void);
+ otbrError GetAddrInfo(uint32_t aInterfaceIndex);
+ void FinishResolution(void);
- static void HandleBrowseResult(DNSServiceRef aServiceRef,
- DNSServiceFlags aFlags,
- uint32_t aInterfaceIndex,
- DNSServiceErrorType aErrorCode,
- const char * aInstanceName,
- const char * aType,
- const char * aDomain,
- void * aContext);
- void HandleBrowseResult(DNSServiceRef aServiceRef,
- DNSServiceFlags aFlags,
- uint32_t aInterfaceIndex,
- DNSServiceErrorType aErrorCode,
- const char * aInstanceName,
- const char * aType,
- const char * aDomain);
static void HandleResolveResult(DNSServiceRef aServiceRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
@@ -330,15 +230,61 @@ private:
const struct sockaddr *aAddress,
uint32_t aTtl);
- std::string mType;
+ ServiceSubscription * mSubscription;
std::string mInstanceName;
+ std::string mTypeEndWithDot;
+ std::string mDomain;
+ uint32_t mNetifIndex;
DiscoveredInstanceInfo mInstanceInfo;
};
- struct HostSubscription : public Subscription
+ struct ServiceSubscription : public ServiceRef
+ {
+ explicit ServiceSubscription(PublisherMDnsSd &aMDnsSd, std::string aType, std::string aInstanceName)
+ : ServiceRef()
+ , mMDnsSd(&aMDnsSd)
+ , mType(std::move(aType))
+ , mInstanceName(std::move(aInstanceName))
+ {
+ }
+
+ void Browse(void);
+ void Resolve(uint32_t aNetifIndex,
+ const std::string &aInstanceName,
+ const std::string &aType,
+ const std::string &aDomain);
+ void RemoveInstanceResolution(ServiceInstanceResolution &aInstanceResolution);
+ void UpdateAll(MainloopContext &aMainloop) const;
+ void ProcessAll(const MainloopContext &aMainloop, std::vector<DNSServiceRef> &aReadyServices) const;
+
+ static void HandleBrowseResult(DNSServiceRef aServiceRef,
+ DNSServiceFlags aFlags,
+ uint32_t aInterfaceIndex,
+ DNSServiceErrorType aErrorCode,
+ const char * aInstanceName,
+ const char * aType,
+ const char * aDomain,
+ void * aContext);
+ void HandleBrowseResult(DNSServiceRef aServiceRef,
+ DNSServiceFlags aFlags,
+ uint32_t aInterfaceIndex,
+ DNSServiceErrorType aErrorCode,
+ const char * aInstanceName,
+ const char * aType,
+ const char * aDomain);
+
+ PublisherMDnsSd *mMDnsSd;
+ std::string mType;
+ std::string mInstanceName;
+
+ std::vector<std::unique_ptr<ServiceInstanceResolution>> mResolvingInstances;
+ };
+
+ struct HostSubscription : public ServiceRef
{
explicit HostSubscription(PublisherMDnsSd &aMDnsSd, std::string aHostName)
- : Subscription(aMDnsSd)
+ : ServiceRef()
+ , mMDnsSd(&aMDnsSd)
, mHostName(std::move(aHostName))
{
}
@@ -360,27 +306,13 @@ private:
const struct sockaddr *aAddress,
uint32_t aTtl);
+ PublisherMDnsSd * mMDnsSd;
std::string mHostName;
DiscoveredHostInfo mHostInfo;
};
- typedef std::vector<Service> Services;
- typedef std::vector<Host> Hosts;
- typedef std::vector<Service>::iterator ServiceIterator;
- typedef std::vector<Host>::iterator HostIterator;
- typedef std::vector<ServiceSubscription> ServiceSubscriptionList;
- typedef std::vector<HostSubscription> HostSubscriptionList;
-
- void DiscardService(const char *aName, const char *aType, DNSServiceRef aServiceRef = nullptr);
- void RecordService(const char * aName,
- const char * aType,
- const char * aRegType,
- uint16_t aPort,
- DNSServiceRef aServiceRef);
- static bool IsServiceOutdated(const Service &service, const std::string &aNewRegType, int aNewPort);
-
- otbrError DiscardHost(const char *aName, bool aSendGoodbye = true);
- void RecordHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength, DNSRecordRef aRecordRef);
+ using ServiceSubscriptionList = std::vector<std::unique_ptr<ServiceSubscription>>;
+ using HostSubscriptionList = std::vector<std::unique_ptr<HostSubscription>>;
static void HandleServiceRegisterResult(DNSServiceRef aService,
const DNSServiceFlags aFlags,
@@ -405,26 +337,14 @@ private:
DNSServiceFlags aFlags,
DNSServiceErrorType aErrorCode);
- otbrError MakeFullName(char *aFullName, size_t aFullNameLength, const char *aName);
- static std::string MakeRegType(const char *aType, const SubTypeList &aSubTypeList);
-
- ServiceIterator FindPublishedService(const char *aName, const char *aType);
- ServiceIterator FindPublishedService(const DNSServiceRef &aServiceRef);
- HostIterator FindPublishedHost(const DNSRecordRef &aRecordRef);
- HostIterator FindPublishedHost(const char *aHostName);
+ static std::string MakeRegType(const std::string &aType, SubTypeList aSubTypeList);
- void OnServiceResolved(ServiceSubscription &aService);
- static void OnServiceResolveFailed(const ServiceSubscription &aService, DNSServiceErrorType aErrorCode);
- void OnHostResolved(HostSubscription &aHost);
- void OnHostResolveFailed(const HostSubscription &aHost, DNSServiceErrorType aErrorCode);
+ ServiceRegistration *FindServiceRegistration(const DNSServiceRef &aServiceRef);
+ HostRegistration * FindHostRegistration(const DNSServiceRef &aServiceRef, const DNSRecordRef &aRecordRef);
- Services mServices;
- Hosts mHosts;
DNSServiceRef mHostsRef;
- const char * mDomain;
State mState;
- StateHandler mStateHandler;
- void * mContext;
+ StateCallback mStateCallback;
ServiceSubscriptionList mSubscribedServices;
HostSubscriptionList mSubscribedHosts;
diff --git a/src/ncp/ncp_openthread.cpp b/src/ncp/ncp_openthread.cpp
index e98e774e..8f908a87 100644
--- a/src/ncp/ncp_openthread.cpp
+++ b/src/ncp/ncp_openthread.cpp
@@ -26,7 +26,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#define OTBR_LOG_TAG "AGENT"
+#define OTBR_LOG_TAG "NCP"
#include "ncp/ncp_openthread.hpp"
@@ -59,11 +59,15 @@ namespace Ncp {
static const uint16_t kThreadVersion11 = 2; ///< Thread Version 1.1
static const uint16_t kThreadVersion12 = 3; ///< Thread Version 1.2
+static const uint16_t kThreadVersion13 = 4; ///< Thread Version 1.3
ControllerOpenThread::ControllerOpenThread(const char * aInterfaceName,
const std::vector<const char *> &aRadioUrls,
- const char * aBackboneInterfaceName)
+ const char * aBackboneInterfaceName,
+ bool aDryRun,
+ bool aEnableAutoAttach)
: mInstance(nullptr)
+ , mEnableAutoAttach(aEnableAutoAttach)
{
VerifyOrDie(aRadioUrls.size() <= OT_PLATFORM_CONFIG_MAX_RADIO_URLS, "Too many Radio URLs!");
@@ -71,6 +75,8 @@ ControllerOpenThread::ControllerOpenThread(const char * aInt
mConfig.mInterfaceName = aInterfaceName;
mConfig.mBackboneInterfaceName = aBackboneInterfaceName;
+ mConfig.mDryRun = aDryRun;
+
for (const char *url : aRadioUrls)
{
mConfig.mRadioUrls[mConfig.mRadioUrlNum++] = url;
@@ -80,15 +86,45 @@ ControllerOpenThread::ControllerOpenThread(const char * aInt
ControllerOpenThread::~ControllerOpenThread(void)
{
- otSysDeinit();
+ // Make sure OpenThread Instance was gracefully de-initialized.
+ assert(mInstance == nullptr);
}
-otbrError ControllerOpenThread::Init(void)
+otbrLogLevel ControllerOpenThread::ConvertToOtbrLogLevel(otLogLevel aLogLevel)
{
- otbrError error = OTBR_ERROR_NONE;
- otLogLevel level = OT_LOG_LEVEL_NONE;
+ otbrLogLevel otbrLogLevel;
+
+ switch (aLogLevel)
+ {
+ case OT_LOG_LEVEL_NONE:
+ otbrLogLevel = OTBR_LOG_EMERG;
+ break;
+ case OT_LOG_LEVEL_CRIT:
+ otbrLogLevel = OTBR_LOG_CRIT;
+ break;
+ case OT_LOG_LEVEL_WARN:
+ otbrLogLevel = OTBR_LOG_WARNING;
+ break;
+ case OT_LOG_LEVEL_NOTE:
+ otbrLogLevel = OTBR_LOG_NOTICE;
+ break;
+ case OT_LOG_LEVEL_INFO:
+ otbrLogLevel = OTBR_LOG_INFO;
+ break;
+ case OT_LOG_LEVEL_DEBG:
+ default:
+ otbrLogLevel = OTBR_LOG_DEBUG;
+ break;
+ }
- switch (otbrLogGetLevel())
+ return otbrLogLevel;
+}
+
+otLogLevel ControllerOpenThread::ConvertToOtLogLevel(otbrLogLevel aLevel)
+{
+ otLogLevel level;
+
+ switch (aLevel)
{
case OTBR_LOG_EMERG:
case OTBR_LOG_ALERT:
@@ -106,12 +142,19 @@ otbrError ControllerOpenThread::Init(void)
level = OT_LOG_LEVEL_INFO;
break;
case OTBR_LOG_DEBUG:
- level = OT_LOG_LEVEL_DEBG;
- break;
default:
- ExitNow(error = OTBR_ERROR_OPENTHREAD);
+ level = OT_LOG_LEVEL_DEBG;
break;
}
+
+ return level;
+}
+
+void ControllerOpenThread::Init(void)
+{
+ otbrError error = OTBR_ERROR_NONE;
+ otLogLevel level = ConvertToOtLogLevel(otbrLogGetLevel());
+
VerifyOrExit(otLoggingSetLevel(level) == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD);
mInstance = otSysInit(&mConfig);
@@ -135,7 +178,15 @@ otbrError ControllerOpenThread::Init(void)
mThreadHelper = std::unique_ptr<otbr::agent::ThreadHelper>(new otbr::agent::ThreadHelper(mInstance, this));
exit:
- return error;
+ SuccessOrDie(error, "Failed to initialize NCP!");
+}
+
+void ControllerOpenThread::Deinit(void)
+{
+ assert(mInstance != nullptr);
+
+ otSysDeinit();
+ mInstance = nullptr;
}
void ControllerOpenThread::HandleStateChanged(otChangedFlags aFlags)
@@ -185,12 +236,22 @@ void ControllerOpenThread::Process(const MainloopContext &aMainloop)
otSysMainloopProcess(mInstance, &aMainloop);
- if (getenv("OTBR_NO_AUTO_ATTACH") == nullptr && mThreadHelper->TryResumeNetwork() == OT_ERROR_NONE)
+ if (IsAutoAttachEnabled() && mThreadHelper->TryResumeNetwork() == OT_ERROR_NONE)
{
- setenv("OTBR_NO_AUTO_ATTACH", "1", 0);
+ DisableAutoAttach();
}
}
+bool ControllerOpenThread::IsAutoAttachEnabled(void)
+{
+ return mEnableAutoAttach;
+}
+
+void ControllerOpenThread::DisableAutoAttach(void)
+{
+ mEnableAutoAttach = false;
+}
+
void ControllerOpenThread::PostTimerTask(Milliseconds aDelay, TaskRunner::Task<void> aTask)
{
mTaskRunner.Post(std::move(aDelay), std::move(aTask));
@@ -218,7 +279,7 @@ void ControllerOpenThread::Reset(void)
{
handler();
}
- unsetenv("OTBR_NO_AUTO_ATTACH");
+ mEnableAutoAttach = true;
}
const char *ControllerOpenThread::GetThreadVersion(void)
@@ -233,6 +294,9 @@ const char *ControllerOpenThread::GetThreadVersion(void)
case kThreadVersion12:
version = "1.2.0";
break;
+ case kThreadVersion13:
+ version = "1.3.0";
+ break;
default:
otbrLogEmerg("Unexpected thread version %hu", otThreadGetVersion());
exit(-1);
@@ -247,32 +311,7 @@ extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const ch
{
OT_UNUSED_VARIABLE(aLogRegion);
- otbrLogLevel otbrLogLevel;
-
- switch (aLogLevel)
- {
- case OT_LOG_LEVEL_NONE:
- otbrLogLevel = OTBR_LOG_EMERG;
- break;
- case OT_LOG_LEVEL_CRIT:
- otbrLogLevel = OTBR_LOG_CRIT;
- break;
- case OT_LOG_LEVEL_WARN:
- otbrLogLevel = OTBR_LOG_WARNING;
- break;
- case OT_LOG_LEVEL_NOTE:
- otbrLogLevel = OTBR_LOG_NOTICE;
- break;
- case OT_LOG_LEVEL_INFO:
- otbrLogLevel = OTBR_LOG_INFO;
- break;
- case OT_LOG_LEVEL_DEBG:
- otbrLogLevel = OTBR_LOG_DEBUG;
- break;
- default:
- otbrLogLevel = OTBR_LOG_DEBUG;
- break;
- }
+ otbrLogLevel otbrLogLevel = ControllerOpenThread::ConvertToOtbrLogLevel(aLogLevel);
va_list ap;
va_start(ap, aFormat);
@@ -280,5 +319,11 @@ extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const ch
va_end(ap);
}
+extern "C" void otPlatLogHandleLevelChanged(otLogLevel aLogLevel)
+{
+ otbrLogSetLevel(ControllerOpenThread::ConvertToOtbrLogLevel(aLogLevel));
+ otbrLogInfo("OpenThread log level changed to %d", aLogLevel);
+}
+
} // namespace Ncp
} // namespace otbr
diff --git a/src/ncp/ncp_openthread.hpp b/src/ncp/ncp_openthread.hpp
index 5cbd15a1..b21ee7a2 100644
--- a/src/ncp/ncp_openthread.hpp
+++ b/src/ncp/ncp_openthread.hpp
@@ -37,6 +37,8 @@
#include <chrono>
#include <memory>
+#include <assert.h>
+
#include <openthread/backbone_router_ftd.h>
#include <openthread/cli.h>
#include <openthread/instance.h>
@@ -65,57 +67,60 @@ public:
* @param[in] aInterfaceName A string of the NCP interface name.
* @param[in] aRadioUrls The radio URLs (can be IEEE802.15.4 or TREL radio).
* @param[in] aBackboneInterfaceName The Backbone network interface name.
+ * @param[in] aDryRun TRUE to indicate dry-run mode. FALSE otherwise.
+ * @param[in] aEnableAutoAttach Whether or not to automatically attach to the saved network.
*
*/
ControllerOpenThread(const char * aInterfaceName,
const std::vector<const char *> &aRadioUrls,
- const char * aBackboneInterfaceName);
+ const char * aBackboneInterfaceName,
+ bool aDryRun,
+ bool aEnableAutoAttach);
/**
- * This method initalize the NCP controller.
- *
- * @retval OTBR_ERROR_NONE Successfully initialized NCP controller.
+ * This method initialize the NCP controller.
*
*/
- otbrError Init(void);
+ void Init(void);
/**
- * This method get mInstance pointer.
- *
- * @retval the pointer of mInstance.
+ * This method deinitialize the NCP controller.
*
*/
- otInstance *GetInstance(void) { return mInstance; }
+ void Deinit(void);
/**
- * This method gets the thread functionality helper.
+ * This method get mInstance pointer.
*
- * @retval the pointer to the helper object.
+ * @retval The pointer of mInstance.
*
*/
- otbr::agent::ThreadHelper *GetThreadHelper(void) { return mThreadHelper.get(); }
+ otInstance *GetInstance(void)
+ {
+ assert(mInstance != nullptr);
+ return mInstance;
+ }
/**
- * This method updates the mainloop context.
+ * This method gets the thread functionality helper.
*
- * @param[inout] aMainloop A reference to the mainloop to be updated.
+ * @retval The pointer to the helper object.
*
*/
- void Update(MainloopContext &aMainloop) override;
+ otbr::agent::ThreadHelper *GetThreadHelper(void)
+ {
+ assert(mThreadHelper != nullptr);
+ return mThreadHelper.get();
+ }
- /**
- * This method processes mainloop events.
- *
- * @param[in] aMainloop A reference to the mainloop context.
- *
- */
+ void Update(MainloopContext &aMainloop) override;
void Process(const MainloopContext &aMainloop) override;
/**
* This method posts a task to the timer
*
- * @param[in] aDelay The delay in milliseconds before executing the task.
- * @param[in] aTask The task function.
+ * @param[in] aDelay The delay in milliseconds before executing the task.
+ * @param[in] aTask The task function.
*
*/
void PostTimerTask(Milliseconds aDelay, TaskRunner::Task<void> aTask);
@@ -123,7 +128,7 @@ public:
/**
* This method registers a reset handler.
*
- * @param[in] aHandler The handler function.
+ * @param[in] aHandler The handler function.
*
*/
void RegisterResetHandler(std::function<void(void)> aHandler);
@@ -131,7 +136,7 @@ public:
/**
* This method adds a event listener for Thread state changes.
*
- * @param[in] aCallback The callback to receive Thread state changed events.
+ * @param[in] aCallback The callback to receive Thread state changed events.
*
*/
void AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback);
@@ -145,7 +150,7 @@ public:
/**
* This method returns the Thread protocol version as a string.
*
- * @returns A pointer to the Thread version string.
+ * @returns A pointer to the Thread version string.
*
*/
static const char *GetThreadVersion(void);
@@ -153,11 +158,13 @@ public:
/**
* This method returns the Thread network interface name.
*
- * @returns A pointer to the Thread network interface name string.
+ * @returns A pointer to the Thread network interface name string.
*
*/
const char *GetInterfaceName(void) const { return mConfig.mInterfaceName; }
+ static otbrLogLevel ConvertToOtbrLogLevel(otLogLevel aLogLevel);
+
~ControllerOpenThread(void) override;
private:
@@ -180,6 +187,11 @@ private:
void HandleBackboneRouterNdProxyEvent(otBackboneRouterNdProxyEvent aEvent, const otIp6Address *aAddress);
#endif
+ bool IsAutoAttachEnabled(void);
+ void DisableAutoAttach(void);
+
+ static otLogLevel ConvertToOtLogLevel(otbrLogLevel aLevel);
+
otInstance *mInstance;
otPlatformConfig mConfig;
@@ -187,6 +199,7 @@ private:
std::vector<std::function<void(void)>> mResetHandlers;
TaskRunner mTaskRunner;
std::vector<ThreadStateChangedCallback> mThreadStateChangedCallbacks;
+ bool mEnableAutoAttach = false;
};
} // namespace Ncp
diff --git a/src/openwrt/ubus/otubus.cpp b/src/openwrt/ubus/otubus.cpp
index 9c2a8966..7977a395 100644
--- a/src/openwrt/ubus/otubus.cpp
+++ b/src/openwrt/ubus/otubus.cpp
@@ -273,8 +273,6 @@ void UbusServer::HandleActiveScanResultDetail(otActiveScanResult *aResult)
jsonList = blobmsg_open_table(&mBuf, nullptr);
- blobmsg_add_u32(&mBuf, "IsJoinable", aResult->mIsJoinable);
-
blobmsg_add_string(&mBuf, "NetworkName", aResult->mNetworkName.m8);
OutputBytes(aResult->mExtendedPanId.m8, OT_EXT_PAN_ID_SIZE, xpanidstring);
@@ -910,7 +908,7 @@ int UbusServer::UbusMgmtset(struct ubus_context * aContext,
error = OT_ERROR_PARSE);
length = 0;
}
- dataset.mActiveTimestamp++;
+ dataset.mActiveTimestamp.mSeconds++;
if (otCommissionerGetState(mController->GetInstance()) == OT_COMMISSIONER_STATE_DISABLED)
{
otCommissionerStop(mController->GetInstance());
diff --git a/src/openwrt/ubus/otubus.hpp b/src/openwrt/ubus/otubus.hpp
index b00e32ac..bc265cfa 100644
--- a/src/openwrt/ubus/otubus.hpp
+++ b/src/openwrt/ubus/otubus.hpp
@@ -77,15 +77,15 @@ public:
/**
* Constructor
*
- * @param[in] aController A pointer to OpenThread Controller structure.
- * @param[in] aMutex A pointer to mutex.
+ * @param[in] aController A pointer to OpenThread Controller structure.
+ * @param[in] aMutex A pointer to mutex.
*/
static void Initialize(Ncp::ControllerOpenThread *aController, std::mutex *aMutex);
/**
* This method return the instance of the global UbusServer.
*
- * @retval the reference of the UbusServer Instance.
+ * @retval The reference of the UbusServer Instance.
*
*/
static UbusServer &GetInstance(void);
@@ -99,13 +99,13 @@ public:
/**
* This method handle ubus scan function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusScanHandler(struct ubus_context * aContext,
@@ -117,13 +117,13 @@ public:
/**
* This method handle ubus get channel function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusChannelHandler(struct ubus_context * aContext,
@@ -135,13 +135,13 @@ public:
/**
* This method handle ubus set channel function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusSetChannelHandler(struct ubus_context * aContext,
@@ -153,13 +153,13 @@ public:
/**
* This method handle ubus get networkname function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusNetworknameHandler(struct ubus_context * aContext,
@@ -171,13 +171,13 @@ public:
/**
* This method handle ubus set networkname function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusSetNetworknameHandler(struct ubus_context * aContext,
@@ -189,13 +189,13 @@ public:
/**
* This method handle ubus get state function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusStateHandler(struct ubus_context * aContext,
@@ -207,13 +207,13 @@ public:
/**
* This method handle ubus set state function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusMacfilterSetStateHandler(struct ubus_context * aContext,
@@ -225,13 +225,13 @@ public:
/**
* This method handle ubus get panid function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusPanIdHandler(struct ubus_context * aContext,
@@ -243,13 +243,13 @@ public:
/**
* This method handle ubus set panid function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusSetPanIdHandler(struct ubus_context * aContext,
@@ -261,13 +261,13 @@ public:
/**
* This method handle ubus get pskc function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusPskcHandler(struct ubus_context * aContext,
@@ -279,13 +279,13 @@ public:
/**
* This method handle ubus set pskc function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusSetPskcHandler(struct ubus_context * aContext,
@@ -297,13 +297,13 @@ public:
/**
* This method handle ubus get networkkey function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusNetworkkeyHandler(struct ubus_context * aContext,
@@ -315,13 +315,13 @@ public:
/**
* This method handle ubus set networkkey function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusSetNetworkkeyHandler(struct ubus_context * aContext,
@@ -333,13 +333,13 @@ public:
/**
* This method handle ubus get rloc16 function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusRloc16Handler(struct ubus_context * aContext,
@@ -351,13 +351,13 @@ public:
/**
* This method handle ubus get extpanid function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusExtPanIdHandler(struct ubus_context * aContext,
@@ -369,13 +369,13 @@ public:
/**
* This method handle ubus set extpanid function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusSetExtPanIdHandler(struct ubus_context * aContext,
@@ -387,13 +387,13 @@ public:
/**
* This method handle ubus get mode function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusModeHandler(struct ubus_context * aContext,
@@ -405,13 +405,13 @@ public:
/**
* This method handle ubus set mode function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusSetModeHandler(struct ubus_context * aContext,
@@ -423,13 +423,13 @@ public:
/**
* This method handle ubus get partitionid function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusPartitionIdHandler(struct ubus_context * aContext,
@@ -441,13 +441,13 @@ public:
/**
* This method handle ubus get leaderdata function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusLeaderdataHandler(struct ubus_context * aContext,
@@ -459,13 +459,13 @@ public:
/**
* This method handle ubus get networkdata function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusNetworkdataHandler(struct ubus_context * aContext,
@@ -477,13 +477,13 @@ public:
/**
* This method handle ubus get parent function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusParentHandler(struct ubus_context * aContext,
@@ -495,13 +495,13 @@ public:
/**
* This method handle ubus get neighbor function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusNeighborHandler(struct ubus_context * aContext,
@@ -513,13 +513,13 @@ public:
/**
* This method handle ubus start thread function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusThreadStartHandler(struct ubus_context * aContext,
@@ -531,13 +531,13 @@ public:
/**
* This method handle ubus stop thread function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusThreadStopHandler(struct ubus_context * aContext,
@@ -549,13 +549,13 @@ public:
/**
* This method handle ubus leave function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusLeaveHandler(struct ubus_context * aContext,
@@ -567,13 +567,13 @@ public:
/**
* This method handle ubus get macfilter address function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusMacfilterAddrHandler(struct ubus_context * aContext,
@@ -585,13 +585,13 @@ public:
/**
* This method handle ubus get macfilter state function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusMacfilterStateHandler(struct ubus_context * aContext,
@@ -603,13 +603,13 @@ public:
/**
* This method handle ubus macfilter address add function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusMacfilterAddHandler(struct ubus_context * aContext,
@@ -621,13 +621,13 @@ public:
/**
* This method handle ubus macfilter address clear function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusMacfilterClearHandler(struct ubus_context * aContext,
@@ -639,13 +639,13 @@ public:
/**
* This method handle ubus macfilter address remove function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusMacfilterRemoveHandler(struct ubus_context * aContext,
@@ -657,13 +657,13 @@ public:
/**
* This method handle ubus start commissioner function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusCommissionerStartHandler(struct ubus_context * aContext,
@@ -675,13 +675,13 @@ public:
/**
* This method handle ubus add joiner function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusJoinerAddHandler(struct ubus_context * aContext,
@@ -693,13 +693,13 @@ public:
/**
* This method handle ubus remove joiner function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusJoinerRemoveHandler(struct ubus_context * aContext,
@@ -711,13 +711,13 @@ public:
/**
* This method handle ubus get joiner information function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusJoinerNumHandler(struct ubus_context * aContext,
@@ -729,13 +729,13 @@ public:
/**
* This method handle ubus mgmtset function request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
static int UbusMgmtsetHandler(struct ubus_context * aContext,
@@ -747,10 +747,10 @@ public:
/**
* This method handle initial diagnostic get response.
*
- * @param[in] aError A error of receiving the diagnostic response.
- * @param[in] aMessage A pointer to the message.
- * @param[in] aMessageInfo A pointer to the message information.
- * @param[in] aContext A pointer to the context.
+ * @param[in] aError A error of receiving the diagnostic response.
+ * @param[in] aMessage A pointer to the message.
+ * @param[in] aMessageInfo A pointer to the message information.
+ * @param[in] aContext A pointer to the context.
*
*/
static void HandleDiagnosticGetResponse(otError aError,
@@ -761,9 +761,9 @@ public:
/**
* This method handle diagnosticget response.
*
- * @param[in] aError A error of receiving the diagnostic response.
- * @param[in] aMessage A pointer to the message.
- * @param[in] aMessageInfo A pointer to the message information.
+ * @param[in] aError A error of receiving the diagnostic response.
+ * @param[in] aMessage A pointer to the message.
+ * @param[in] aMessageInfo A pointer to the message information.
*
*/
void HandleDiagnosticGetResponse(otError aError, otMessage *aMessage, const otMessageInfo *aMessageInfo);
@@ -785,8 +785,8 @@ private:
/**
* Constructor
*
- * @param[in] aController The pointer to OpenThread Controller structure.
- * @param[in] aMutex A pointer to mutex.
+ * @param[in] aController The pointer to OpenThread Controller structure.
+ * @param[in] aMutex A pointer to mutex.
*/
UbusServer(Ncp::ControllerOpenThread *aController, std::mutex *aMutex);
@@ -799,13 +799,13 @@ private:
/**
* This method detailly start scan.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
int UbusScanHandlerDetail(struct ubus_context * aContext,
@@ -817,8 +817,8 @@ private:
/**
* This method handle scan result (callback function).
*
- * @param[in] aResult A pointer to result.
- * @param[in] aContext A pointer to context.
+ * @param[in] aResult A pointer to result.
+ * @param[in] aContext A pointer to context.
*
*/
static void HandleActiveScanResult(otActiveScanResult *aResult, void *aContext);
@@ -826,7 +826,7 @@ private:
/**
* This method detailly handler the scan result, called by HandleActiveScanResult.
*
- * @param[in] aResult A pointer to result.
+ * @param[in] aResult A pointer to result.
*
*/
void HandleActiveScanResultDetail(otActiveScanResult *aResult);
@@ -834,13 +834,13 @@ private:
/**
* This method detailly handler get neighbor information.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
int UbusNeighborHandlerDetail(struct ubus_context * aContext,
@@ -852,13 +852,13 @@ private:
/**
* This method detailly handler get parent information.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
int UbusParentHandlerDetail(struct ubus_context * aContext,
@@ -870,13 +870,13 @@ private:
/**
* This method handle mgmtset request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
int UbusMgmtset(struct ubus_context * aContext,
@@ -888,13 +888,13 @@ private:
/**
* This method handle leave request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
int UbusLeaveHandlerDetail(struct ubus_context * aContext,
@@ -906,14 +906,14 @@ private:
/**
* This method handle thread related request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
- * @param[in] aAction A pointer to the action needed.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aAction A pointer to the action needed.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
int UbusThreadHandler(struct ubus_context * aContext,
@@ -926,14 +926,14 @@ private:
/**
* This method handle get information request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
- * @param[in] aAction A pointer to the action needed.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aAction A pointer to the action needed.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
int UbusGetInformation(struct ubus_context * aContext,
@@ -946,14 +946,14 @@ private:
/**
* This method handle set information request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
- * @param[in] aAction A pointer to the action needed.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aAction A pointer to the action needed.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
int UbusSetInformation(struct ubus_context * aContext,
@@ -964,16 +964,16 @@ private:
const char * aAction);
/**
- * This method handle conmmissioner related request.
+ * This method handle commissioner related request.
*
- * @param[in] aContext A pointer to the ubus context.
- * @param[in] aObj A pointer to the ubus object.
- * @param[in] aRequest A pointer to the ubus request.
- * @param[in] aMethod A pointer to the ubus method.
- * @param[in] aMsg A pointer to the ubus message.
- * @param[in] aAction A pointer to the action needed.
+ * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aObj A pointer to the ubus object.
+ * @param[in] aRequest A pointer to the ubus request.
+ * @param[in] aMethod A pointer to the ubus method.
+ * @param[in] aMsg A pointer to the ubus message.
+ * @param[in] aAction A pointer to the action needed.
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
int UbusCommissioner(struct ubus_context * aContext,
@@ -986,8 +986,8 @@ private:
/**
* This method handle conmmissione state change (callback function).
*
- * @param[in] aState The state of commissioner.
- * @param[in] aContext A pointer to the ubus context.
+ * @param[in] aState The state of commissioner.
+ * @param[in] aContext A pointer to the ubus context.
*
*/
static void HandleStateChanged(otCommissionerState aState, void *aContext);
@@ -995,7 +995,7 @@ private:
/**
* This method handle conmmissione state change.
*
- * @param[in] aState The state of commissioner.
+ * @param[in] aState The state of commissioner.
*
*/
void HandleStateChanged(otCommissionerState aState);
@@ -1003,10 +1003,10 @@ private:
/**
* This method handle joiner event (callback function).
*
- * @param[in] aEvent The joiner event type.
- * @param[in] aJoinerInfo A pointer to the Joiner Info.
- * @param[in] aJoinerId A pointer to the Joiner ID (if not known, it will be NULL).
- * @param[in] aContext A pointer to application-specific context.
+ * @param[in] aEvent The joiner event type.
+ * @param[in] aJoinerInfo A pointer to the Joiner Info.
+ * @param[in] aJoinerId A pointer to the Joiner ID (if not known, it will be NULL).
+ * @param[in] aContext A pointer to application-specific context.
*
*/
static void HandleJoinerEvent(otCommissionerJoinerEvent aEvent,
@@ -1017,9 +1017,9 @@ private:
/**
* This method handle joiner event.
*
- * @param[in] aEvent The joiner event type.
- * @param[in] aJoinerInfo A pointer to the Joiner Info.
- * @param[in] aJoinerId A pointer to the Joiner ID (if not known, it will be NULL).
+ * @param[in] aEvent The joiner event type.
+ * @param[in] aJoinerInfo A pointer to the Joiner Info.
+ * @param[in] aJoinerId A pointer to the Joiner ID (if not known, it will be NULL).
*
*/
void HandleJoinerEvent(otCommissionerJoinerEvent aEvent,
@@ -1029,8 +1029,8 @@ private:
/**
* This method convert thread network state to string.
*
- * @param[in] aInstance A pointer to the instance.
- * @param[out] aState A pointer to the string address.
+ * @param[in] aInstance A pointer to the instance.
+ * @param[out] aState A pointer to the string address.
*
*/
void GetState(otInstance *aInstance, char *aState);
@@ -1044,7 +1044,7 @@ private:
/**
* This method set ubus reconnect time.
*
- * @param[in] aTimeout A pointer to the timeout.
+ * @param[in] aTimeout A pointer to the timeout.
*
*/
static void UbusReconnTimer(struct uloop_timeout *aTimeout);
@@ -1052,7 +1052,7 @@ private:
/**
* This method detailly handle ubus reconnect time.
*
- * @param[in] aTimeout A pointer to the timeout.
+ * @param[in] aTimeout A pointer to the timeout.
*
*/
void UbusReconnTimerDetail(struct uloop_timeout *aTimeout);
@@ -1060,7 +1060,7 @@ private:
/**
* This method handle ubus connection lost.
*
- * @param[in] aContext A pointer to the context.
+ * @param[in] aContext A pointer to the context.
*
*/
static void UbusConnectionLost(struct ubus_context *aContext);
@@ -1068,9 +1068,9 @@ private:
/**
* This method connect and display ubus.
*
- * @param[in] aPath A pointer to the ubus server path(default is nullptr).
+ * @param[in] aPath A pointer to the ubus server path(default is nullptr).
*
- * @retval 0 Successfully handler the request.
+ * @retval 0 Successfully handler the request.
*
*/
int DisplayUbusInit(const char *aPath);
@@ -1084,8 +1084,8 @@ private:
/**
* This method parses an ASCII string as a long.
*
- * @param[in] aString A pointer to the ASCII string.
- * @param[out] aLong A reference to where the parsed long is placed.
+ * @param[in] aString A pointer to the ASCII string.
+ * @param[out] aLong A reference to where the parsed long is placed.
*
* @retval OT_ERROR_NONE Successfully parsed the ASCII string.
* @retval OT_ERROR_PARSE Could not parse the ASCII string.
@@ -1096,9 +1096,9 @@ private:
/**
* This method converts a hex string to binary.
*
- * @param[in] aHex A pointer to the hex string.
- * @param[out] aBin A pointer to where the binary representation is placed.
- * @param[in] aBinLength Maximum length of the binary representation.
+ * @param[in] aHex A pointer to the hex string.
+ * @param[out] aBin A pointer to where the binary representation is placed.
+ * @param[in] aBinLength Maximum length of the binary representation.
*
* @returns The number of bytes in the binary representation.
*/
@@ -1107,9 +1107,9 @@ private:
/**
* This method output bytes into char*.
*
- * @param[in] aBytes A pointer to the bytes need to be convert.
- * @param[in] aLength The length of the bytes.
- * @param[out] aOutput A pointer to the char* string.
+ * @param[in] aBytes A pointer to the bytes need to be convert.
+ * @param[in] aLength The length of the bytes.
+ * @param[out] aOutput A pointer to the char* string.
*
*/
void OutputBytes(const uint8_t *aBytes, uint8_t aLength, char *aOutput);
@@ -1117,9 +1117,9 @@ private:
/**
* This method append result in message passed to ubus.
*
- * @param[in] aError The error type of the message.
- * @param[in] aContext A pointer to the context.
- * @param[in] aRequest A pointer to the request.
+ * @param[in] aError The error type of the message.
+ * @param[in] aContext A pointer to the context.
+ * @param[in] aRequest A pointer to the request.
*
*/
void AppendResult(otError aError, struct ubus_context *aContext, struct ubus_request_data *aRequest);
@@ -1131,7 +1131,7 @@ public:
/**
* The constructor to initialize the UBus agent.
*
- * @param[in] aNcp A reference to the NCP controller.
+ * @param[in] aNcp A reference to the NCP controller.
*
*/
UBusAgent(otbr::Ncp::ControllerOpenThread &aNcp)
@@ -1146,20 +1146,7 @@ public:
*/
void Init(void);
- /**
- * This method updates the mainloop context.
- *
- * @param[inout] aMainloop A reference to the mainloop to be updated.
- *
- */
void Update(MainloopContext &aMainloop) override;
-
- /**
- * This method processes mainloop events.
- *
- * @param[in] aMainloop A reference to the mainloop context.
- *
- */
void Process(const MainloopContext &aMainloop) override;
private:
diff --git a/src/openwrt/view/admin_thread/thread_scan.htm b/src/openwrt/view/admin_thread/thread_scan.htm
index 80cd1093..6f99ef26 100644
--- a/src/openwrt/view/admin_thread/thread_scan.htm
+++ b/src/openwrt/view/admin_thread/thread_scan.htm
@@ -74,12 +74,9 @@
<div class="table">
<div class="tr table-titles">
<div class="th col-1 center"><%:RSSI%></div>
- <div class="th col-3 center"><%:Network Name%></div>
<div class="th col-1 center"><%:Channel%></div>
- <div class="th col-4 center"><%:Extended PAN Id%></div>
<div class="th col-2 center"><%:PAN Id%></div>
<div class="th col-1 left"><%:Lqi%></div>
- <div class="th col-1 center"><%:IsJoinable%></div>
<div class="th cbi-section-actions">&#160;</div>
</div>
@@ -92,29 +89,19 @@
<small><%=percent_thread_signal(net)%>%</small>
</abbr>
</div>
- <div class="td col-3 center" data-title="<%:NetworkName%>">
- <strong><%=net.NetworkName%></strong>
- </div>
<div class="td col-1 center" data-title="<%:Channel%>">
<%=net.Channel%>
</div>
- <div class="td col-4 center" data-title="<%:ExtendedPanId%>">
- <%=net.ExtendedPanId%>
- </div>
<div class="td col-2 center" data-title="<%:PanId%>">
<%=net.PanId%>
</div>
<div class="td col-1 left" data-title="<%:Lqi%>">
<%=net.Lqi%>
</div>
- <div class="td col-1 center" data-title="<%:IsJoinable%>">
- <%=net.IsJoinable%>
- </div>
<div class="td cbi-section-actions">
<!--div><%:test%></div-->
<form action="<%=url('admin/network/thread_join')%>" method="post">
<input type="hidden" name="token" value="<%=token%>" />
- <input type="hidden" name="NetworkName" value="<%=net.NetworkName%>" .>
<input type="hidden" name="PanId" value="<%=net.PanId%>" .>
<input type="hidden" name="Channel" value="<%=net.Channel%>" .>
<input class="cbi-button cbi-button-action important" type="submit" value="<%:Join Network%>" />
diff --git a/src/rest/connection.hpp b/src/rest/connection.hpp
index 454202ab..93407c30 100644
--- a/src/rest/connection.hpp
+++ b/src/rest/connection.hpp
@@ -56,10 +56,12 @@ public:
/**
* The constructor is to initialize a socket connection instance.
*
- * @param[in] aStartTime The reference start time of a conneciton which is set when created for the first time
- * and maybe reset when transfer to wait callback or wait write state.
- * @param[in] aResource A pointer to the resource handler.
- * @param[in] aFd The file descriptor for the conneciton.
+ * @param[in] aStartTime The reference start time of a connection which
+ * is set when created for the first time and maybe
+ * reset when transfer to wait callback or wait write
+ * state.
+ * @param[in] aResource A pointer to the resource handler.
+ * @param[in] aFd The file descriptor for the connection.
*
*/
Connection(steady_clock::time_point aStartTime, Resource *aResource, int aFd);
@@ -77,27 +79,14 @@ public:
*/
void Init(void);
- /**
- * This method updates the mainloop context.
- *
- * @param[inout] aMainloop A reference to the mainloop to be updated.
- *
- */
void Update(MainloopContext &aMainloop) override;
-
- /**
- * This method processes mainloop events.
- *
- * @param[in] aMainloop A reference to the mainloop context.
- *
- */
void Process(const MainloopContext &aMainloop) override;
/**
* This method indicates whether this connection no longer need to be processed.
*
- * @retval true This connection could be released in next loop.
- * @retval false This connection still needs to be processed in next loop.
+ * @retval TRUE This connection could be released in next loop.
+ * @retval FALSE This connection still needs to be processed in next loop.
*
*/
bool IsComplete(void) const;
diff --git a/src/rest/json.hpp b/src/rest/json.hpp
index fbae5b1e..2674510e 100644
--- a/src/rest/json.hpp
+++ b/src/rest/json.hpp
@@ -53,9 +53,9 @@ namespace Json {
/**
* This method formats an integer to a Json number and serialize it to a string.
*
- * @param[in] aNumber an integer need to be format.
+ * @param[in] aNumber An integer need to be format.
*
- * @returns a string serlialized by a Json number.
+ * @returns A string of serialized Json number.
*
*/
std::string Number2JsonString(const uint32_t &aNumber);
@@ -63,9 +63,9 @@ std::string Number2JsonString(const uint32_t &aNumber);
/**
* This method formats a Bytes array to a Json string and serialize it to a string.
*
- * @param[in] aBytes A Bytes array representing a hex number.
+ * @param[in] aBytes A Bytes array representing a hex number.
*
- * @returns A string serlialized by a Json string.
+ * @returns A string of serialized Json string.
*
*/
std::string Bytes2HexJsonString(const uint8_t *aBytes, uint8_t aLength);
@@ -73,9 +73,9 @@ std::string Bytes2HexJsonString(const uint8_t *aBytes, uint8_t aLength);
/**
* This method formats a C string to a Json string and serialize it to a string.
*
- * @param[in] aCString A char pointer pointing to a C string.
+ * @param[in] aCString A char pointer pointing to a C string.
*
- * @returns A string serlialized by a Json string.
+ * @returns A string of serialized Json string.
*
*/
std::string CString2JsonString(const char *aCString);
@@ -83,9 +83,9 @@ std::string CString2JsonString(const char *aCString);
/**
* This method formats a string to a Json string and serialize it to a string.
*
- * @param[in] aString A string.
+ * @param[in] aString A string.
*
- * @returns a string serlialized by a Json string.
+ * @returns A string of serialized Json string.
*
*/
std::string String2JsonString(const std::string &aString);
@@ -93,19 +93,19 @@ std::string String2JsonString(const std::string &aString);
/**
* This method formats a Node object to a Json object and serialize it to a string.
*
- * @param[in] aNode A Node object.
+ * @param[in] aNode A Node object.
*
- * @returns a string serlialized by a Json object.
+ * @returns A string of serialized Json object.
*
*/
std::string Node2JsonString(const NodeInfo &aNode);
/**
- * This method formats a vector including serveral Diagnostic object to a Json array and serialize it to a string.
+ * This method formats a vector of diagnostic objects to a Json array and serialize it to a string.
*
- * @param[in] aDiagSet A vector including serveral Diagnostic object.
+ * @param[in] aDiagSet A vector of diagnostic objects.
*
- * @returns A string serlialized by a Json array.
+ * @returns A string of serialized Json array.
*
*/
std::string Diag2JsonString(const std::vector<std::vector<otNetworkDiagTlv>> &aDiagSet);
@@ -113,9 +113,9 @@ std::string Diag2JsonString(const std::vector<std::vector<otNetworkDiagTlv>> &aD
/**
* This method formats an Ipv6Address to a Json string and serialize it to a string.
*
- * @param[in] aAddress An Ip6Address object.
+ * @param[in] aAddress An Ip6Address object.
*
- * @returns A string serlialized by a Json string.
+ * @returns A string of serialized Json string.
*
*/
std::string IpAddr2JsonString(const otIp6Address &aAddress);
@@ -123,9 +123,9 @@ std::string IpAddr2JsonString(const otIp6Address &aAddress);
/**
* This method formats a LinkModeConfig object to a Json object and serialize it to a string.
*
- * @param[in] aMode A LinkModeConfig object.
+ * @param[in] aMode A LinkModeConfig object.
*
- * @returns A string serlialized by a Json object.
+ * @returns A string of serialized Json object.
*
*/
std::string Mode2JsonString(const otLinkModeConfig &aMode);
@@ -133,9 +133,9 @@ std::string Mode2JsonString(const otLinkModeConfig &aMode);
/**
* This method formats a Connectivity object to a Json object and serialize it to a string.
*
- * @param[in] aConnectivity A Connectivity object.
+ * @param[in] aConnectivity A Connectivity object.
*
- * @returns A string serlialized by a Json object.
+ * @returns A string of serialized Json object.
*
*/
std::string Connectivity2JsonString(const otNetworkDiagConnectivity &aConnectivity);
@@ -143,9 +143,9 @@ std::string Connectivity2JsonString(const otNetworkDiagConnectivity &aConnectivi
/**
* This method formats a Route object to a Json object and serialize it to a string.
*
- * @param[in] aRoute A Route object.
+ * @param[in] aRoute A Route object.
*
- * @returns A string serlialized by a Json object.
+ * @returns A string of serialized Json object.
*
*/
std::string Route2JsonString(const otNetworkDiagRoute &aRoute);
@@ -153,9 +153,9 @@ std::string Route2JsonString(const otNetworkDiagRoute &aRoute);
/**
* This method formats a RouteData object to a Json object and serialize it to a string.
*
- * @param[in] aRouteData A RouteData object.
+ * @param[in] aRouteData A RouteData object.
*
- * @returns A string serlialized by a Json object.
+ * @returns A string of serialized Json object.
*
*/
std::string RouteData2JsonString(const otNetworkDiagRouteData &aRouteData);
@@ -163,9 +163,9 @@ std::string RouteData2JsonString(const otNetworkDiagRouteData &aRouteData);
/**
* This method formats a LeaderData object to a Json object and serialize it to a string.
*
- * @param[in] aLeaderData A LeaderData object.
+ * @param[in] aLeaderData A LeaderData object.
*
- * @returns A string serlialized by a Json object.
+ * @returns A string of serialized Json object.
*
*/
std::string LeaderData2JsonString(const otLeaderData &aLeaderData);
@@ -173,9 +173,9 @@ std::string LeaderData2JsonString(const otLeaderData &aLeaderData);
/**
* This method formats a MacCounters object to a Json object and serialize it to a string.
*
- * @param[in] aMacCounters A MacCounters object.
+ * @param[in] aMacCounters A MacCounters object.
*
- * @returns A string serlialized by a Json object.
+ * @returns A string of serialized Json object.
*
*/
std::string MacCounters2JsonString(const otNetworkDiagMacCounters &aMacCounters);
@@ -183,9 +183,9 @@ std::string MacCounters2JsonString(const otNetworkDiagMacCounters &aMacCounters)
/**
* This method formats a ChildEntry object to a Json object and serialize it to a string.
*
- * @param[in] aChildEntry A ChildEntry object.
+ * @param[in] aChildEntry A ChildEntry object.
*
- * @returns A string serlialized by a Json object.
+ * @returns A string of serialized Json object.
*
*/
std::string ChildTableEntry2JsonString(const otNetworkDiagChildEntry &aChildEntry);
@@ -193,10 +193,10 @@ std::string ChildTableEntry2JsonString(const otNetworkDiagChildEntry &aChildEntr
/**
* This method formats an error code and an error message to a Json object and serialize it to a string.
*
- * @param[in] aErrorCode An enum HttpStatusCode such as '404'.
- * @param[in] aErrorMessage Error message such as '404 Not Found'.
+ * @param[in] aErrorCode An enum HttpStatusCode such as '404'.
+ * @param[in] aErrorMessage Error message such as '404 Not Found'.
*
- * @returns A string serlialized by a Json object.
+ * @returns A string of serialized Json object.
*
*/
std::string Error2JsonString(HttpStatusCode aErrorCode, std::string aErrorMessage);
diff --git a/src/rest/parser.hpp b/src/rest/parser.hpp
index bedf16b5..a90ad759 100644
--- a/src/rest/parser.hpp
+++ b/src/rest/parser.hpp
@@ -57,7 +57,7 @@ public:
/**
* The constructor of a http request parser instance.
*
- * @param[in] aRequest A pointer to a request instance.
+ * @param[in] aRequest A pointer to a request instance.
*
*/
Parser(Request *aRequest);
@@ -71,8 +71,8 @@ public:
/**
* This method performs a parse process.
*
- * @param[in] aBuf A pointer pointing to read buffer.
- * @param[in] aLength An integer indicates how much data is to be processed by parser.
+ * @param[in] aBuf A pointer pointing to read buffer.
+ * @param[in] aLength An integer indicates how much data is to be processed by parser.
*
*/
void Process(const char *aBuf, size_t aLength);
diff --git a/src/rest/request.hpp b/src/rest/request.hpp
index a8b72333..63380f00 100644
--- a/src/rest/request.hpp
+++ b/src/rest/request.hpp
@@ -59,8 +59,8 @@ public:
/**
* This method sets the Url field of a request.
*
- * @param[in] aString A pointer points to url string.
- * @param[in] aLength Length of the url string
+ * @param[in] aString A pointer points to url string.
+ * @param[in] aLength Length of the url string
*
*/
void SetUrl(const char *aString, size_t aLength);
@@ -68,8 +68,8 @@ public:
/**
* This method sets the body field of a request.
*
- * @param[in] aString A pointer points to body string.
- * @param[in] aLength Length of the body string
+ * @param[in] aString A pointer points to body string.
+ * @param[in] aLength Length of the body string
*
*/
void SetBody(const char *aString, size_t aLength);
@@ -77,7 +77,7 @@ public:
/**
* This method sets the content-length field of a request.
*
- * @param[in] aContentLength An unsigned integer representing content-length.
+ * @param[in] aContentLength An unsigned integer representing content-length.
*
*/
void SetContentLength(size_t aContentLength);
@@ -85,7 +85,7 @@ public:
/**
* This method sets the method of the parsed request.
*
- * @param[in] aMethod An integer representing request method.
+ * @param[in] aMethod An integer representing request method.
*
*/
void SetMethod(int32_t aMethod);
diff --git a/src/rest/resource.cpp b/src/rest/resource.cpp
index 0bb73413..5c4cf7af 100644
--- a/src/rest/resource.cpp
+++ b/src/rest/resource.cpp
@@ -70,7 +70,7 @@ namespace rest {
static const char *kMulticastAddrAllRouters = "ff03::2";
// Default TlvTypes for Diagnostic inforamtion
-static const uint8_t kAllTlvTypes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15, 16, 17, 18, 19};
+static const uint8_t kAllTlvTypes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15, 16, 17, 19};
// Timeout (in Microseconds) for deleting outdated diagnostics
static const uint32_t kDiagResetTimeout = 3000000;
@@ -105,10 +105,9 @@ static std::string GetHttpStatus(HttpStatusCode aErrorCode)
}
Resource::Resource(ControllerOpenThread *aNcp)
- : mNcp(aNcp)
+ : mInstance(nullptr)
+ , mNcp(aNcp)
{
- mInstance = mNcp->GetThreadHelper()->GetInstance();
-
// Resource Handler
mResourceMap.emplace(OT_REST_RESOURCE_PATH_DIAGNOETIC, &Resource::Diagnostic);
mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE, &Resource::NodeInfo);
@@ -127,6 +126,7 @@ Resource::Resource(ControllerOpenThread *aNcp)
void Resource::Init(void)
{
+ mInstance = mNcp->GetThreadHelper()->GetInstance();
}
void Resource::Handle(Request &aRequest, Response &aResponse) const
diff --git a/src/rest/resource.hpp b/src/rest/resource.hpp
index 3b6b0fec..a1871c01 100644
--- a/src/rest/resource.hpp
+++ b/src/rest/resource.hpp
@@ -60,7 +60,7 @@ public:
/**
* The constructor initializes the resource handler instance.
*
- * @param[in] aNcp A pointer to the NCP controller.
+ * @param[in] aNcp A pointer to the NCP controller.
*
*/
Resource(ControllerOpenThread *aNcp);
@@ -76,8 +76,8 @@ public:
* This method is the main entry of resource handler, which find corresponding handler according to request url
* find the resource and set the content of response.
*
- * @param[in] aRequest A request instance referred by the Resource handler.
- * @param[inout] aResponse A response instance will be set by the Resource handler.
+ * @param[in] aRequest A request instance referred by the Resource handler.
+ * @param[in,out] aResponse A response instance will be set by the Resource handler.
*
*/
void Handle(Request &aRequest, Response &aResponse) const;
@@ -85,8 +85,8 @@ public:
/**
* This method distributes a callback handler for each connection needs a callback.
*
- * @param[in] aRequest A request instance referred by the Resource handler.
- * @param[inout] aResponse A response instance will be set by the Resource handler.
+ * @param[in] aRequest A request instance referred by the Resource handler.
+ * @param[in,out] aResponse A response instance will be set by the Resource handler.
*
*/
void HandleCallback(Request &aRequest, Response &aResponse);
@@ -95,8 +95,8 @@ public:
* This method provides a quick handler, which could directly set response code of a response and set error code and
* error message to the request body.
*
- * @param[in] aRequest A request instance referred by the Resource handler.
- * @param[inout] aErrorCode An enum class represents the status code.
+ * @param[in] aRequest A request instance referred by the Resource handler.
+ * @param[in,out] aErrorCode An enum class represents the status code.
*
*/
void ErrorHandler(Response &aResponse, HttpStatusCode aErrorCode) const;
diff --git a/src/rest/response.hpp b/src/rest/response.hpp
index 597a7321..ecfe98f4 100644
--- a/src/rest/response.hpp
+++ b/src/rest/response.hpp
@@ -66,7 +66,7 @@ public:
/**
* This method set the response body.
*
- * @param[in] aBody A string to be set as response body.
+ * @param[in] aBody A string to be set as response body.
*
*/
void SetBody(std::string &aBody);
@@ -81,7 +81,7 @@ public:
/**
* This method set the response code.
*
- * @param[in] aCode A string representing response code such as "404 not found".
+ * @param[in] aCode A string representing response code such as "404 not found".
*
*/
void SetResponsCode(std::string &aCode);
@@ -96,7 +96,7 @@ public:
/**
* This method checks whether this response need to be processed by callback handler later.
*
- * @returns A bool value indicates whether this response need to be processed by callback handler later.
+ * @returns A bool value indicates whether this response need to be processed by callback handler later.
*/
bool NeedCallback(void);
@@ -109,7 +109,7 @@ public:
/**
* This method checks whether this response is ready to be written to buffer.
*
- * @returns A bool value indicates whether this response is ready to be written to buffer..
+ * @returns A bool value indicates whether this response is ready to be written to buffer..
*/
bool IsComplete();
@@ -117,21 +117,21 @@ public:
* This method is used to set a timestamp. when a callback is needed and this field tells callback handler when to
* collect all the data and form the response.
*
- * @param[in] aStartTime A timestamp indicates when the response start to wait for callback.
+ * @param[in] aStartTime A timestamp indicates when the response start to wait for callback.
*/
void SetStartTime(steady_clock::time_point aStartTime);
/**
* This method returns a timestamp of start time.
*
- * @returns A timepoint object indicates start time.
+ * @returns A timepoint object indicates start time.
*/
steady_clock::time_point GetStartTime() const;
/**
* This method serialize a response to a string that could be sent by socket later.
*
- * @returns A string contains status line, headers and body of a response.
+ * @returns A string contains status line, headers and body of a response.
*/
std::string Serialize(void) const;
diff --git a/src/rest/rest_web_server.hpp b/src/rest/rest_web_server.hpp
index 2d1ffaef..d3e1fb97 100644
--- a/src/rest/rest_web_server.hpp
+++ b/src/rest/rest_web_server.hpp
@@ -57,7 +57,7 @@ public:
/**
* The constructor to initialize a REST server.
*
- * @param[in] aNcp A reference to the NCP controller.
+ * @param[in] aNcp A reference to the NCP controller.
*
*/
RestWebServer(ControllerOpenThread &aNcp);
@@ -74,20 +74,7 @@ public:
*/
void Init(void);
- /**
- * This method updates the mainloop context.
- *
- * @param[inout] aMainloop A reference to the mainloop to be updated.
- *
- */
void Update(MainloopContext &aMainloop) override;
-
- /**
- * This method processes mainloop events.
- *
- * @param[in] aMainloop A reference to the mainloop context.
- *
- */
void Process(const MainloopContext &aMainloop) override;
private:
diff --git a/src/sdp_proxy/advertising_proxy.cpp b/src/sdp_proxy/advertising_proxy.cpp
index b0a49adf..336eeeb8 100644
--- a/src/sdp_proxy/advertising_proxy.cpp
+++ b/src/sdp_proxy/advertising_proxy.cpp
@@ -81,6 +81,10 @@ static otError OtbrErrorToOtError(otbrError aError)
error = OT_ERROR_DUPLICATED;
break;
+ case OTBR_ERROR_INVALID_STATE:
+ error = OT_ERROR_INVALID_STATE;
+ break;
+
default:
error = OT_ERROR_FAILED;
break;
@@ -93,15 +97,14 @@ AdvertisingProxy::AdvertisingProxy(Ncp::ControllerOpenThread &aNcp, Mdns::Publis
: mNcp(aNcp)
, mPublisher(aPublisher)
{
+ mNcp.RegisterResetHandler(
+ [this]() { otSrpServerSetServiceUpdateHandler(GetInstance(), AdvertisingHandler, this); });
}
otbrError AdvertisingProxy::Start(void)
{
otSrpServerSetServiceUpdateHandler(GetInstance(), AdvertisingHandler, this);
- mPublisher.SetPublishServiceHandler(PublishServiceHandler, this);
- mPublisher.SetPublishHostHandler(PublishHostHandler, this);
-
otbrLogInfo("Started");
return OTBR_ERROR_NONE;
@@ -109,9 +112,6 @@ otbrError AdvertisingProxy::Start(void)
void AdvertisingProxy::Stop()
{
- mPublisher.SetPublishServiceHandler(nullptr, nullptr);
- mPublisher.SetPublishHostHandler(nullptr, nullptr);
-
// Outstanding updates will fail on the SRP server because of timeout.
// TODO: handle this case gracefully.
@@ -154,102 +154,29 @@ void AdvertisingProxy::AdvertisingHandler(otSrpServerServiceUpdateId aId,
}
}
-void AdvertisingProxy::PublishServiceHandler(const char *aName, const char *aType, otbrError aError, void *aContext)
-{
- std::string name(aName);
- std::string type(aType);
- AdvertisingProxy *thisPtr = static_cast<AdvertisingProxy *>(aContext);
-
- thisPtr->mTaskRunner.Post(
- [name, type, aError, thisPtr]() { thisPtr->PublishServiceHandler(name.c_str(), type.c_str(), aError); });
-}
-
-void AdvertisingProxy::PublishServiceHandler(const char *aName, const char *aType, otbrError aError)
-{
- otbrError error = OTBR_ERROR_NONE;
-
- otbrLogInfo("Handle publish service '%s.%s' result: %d", aName, aType, aError);
-
- // TODO: there may be same names between two SRP updates.
- for (auto update = mOutstandingUpdates.begin(); update != mOutstandingUpdates.end(); ++update)
- {
- for (auto nameAndType = update->mServiceNames.begin(); nameAndType != update->mServiceNames.end();
- ++nameAndType)
- {
- if (aName != nameAndType->first || !Mdns::Publisher::IsServiceTypeEqual(aType, nameAndType->second.c_str()))
- {
- continue;
- }
-
- if (aError != OTBR_ERROR_NONE || update->mCallbackCount == 1)
- {
- otSrpServerServiceUpdateId updateId = update->mId;
-
- // Erase before notifying OpenThread, because there are chances that new
- // elements may be added to `otSrpServerHandleServiceUpdateResult` and
- // the iterator will be invalidated.
- mOutstandingUpdates.erase(update);
- otSrpServerHandleServiceUpdateResult(GetInstance(), updateId, OtbrErrorToOtError(aError));
- }
- else
- {
- update->mServiceNames.erase(nameAndType);
- --update->mCallbackCount;
- }
- ExitNow();
- }
- }
-
-exit:
- if (error != OTBR_ERROR_NONE)
- {
- otbrLogWarning("Failed to handle result of service %s", aName);
- }
-}
-
-void AdvertisingProxy::PublishHostHandler(const char *aName, otbrError aError, void *aContext)
-{
- std::string name(aName);
- AdvertisingProxy *thisPtr = static_cast<AdvertisingProxy *>(aContext);
-
- thisPtr->mTaskRunner.Post([name, aError, thisPtr]() { thisPtr->PublishHostHandler(name.c_str(), aError); });
-}
-
-void AdvertisingProxy::PublishHostHandler(const char *aName, otbrError aError)
+void AdvertisingProxy::OnMdnsPublishResult(otSrpServerServiceUpdateId aUpdateId, otbrError aError)
{
- otbrError error = OTBR_ERROR_NONE;
-
- otbrLogInfo("Handle publish host '%s' result: %d", aName, aError);
-
for (auto update = mOutstandingUpdates.begin(); update != mOutstandingUpdates.end(); ++update)
{
- if (update->mHostNamePublished || aName != update->mHostName)
+ if (update->mId != aUpdateId)
{
continue;
}
if (aError != OTBR_ERROR_NONE || update->mCallbackCount == 1)
{
- otSrpServerServiceUpdateId updateId = update->mId;
-
// Erase before notifying OpenThread, because there are chances that new
// elements may be added to `otSrpServerHandleServiceUpdateResult` and
// the iterator will be invalidated.
mOutstandingUpdates.erase(update);
- otSrpServerHandleServiceUpdateResult(GetInstance(), updateId, OtbrErrorToOtError(aError));
+ otSrpServerHandleServiceUpdateResult(GetInstance(), aUpdateId, OtbrErrorToOtError(aError));
}
else
{
- update->mHostNamePublished = true;
--update->mCallbackCount;
+ otbrLogInfo("Waiting for more publishing callbacks %d", update->mCallbackCount);
}
- ExitNow();
- }
-
-exit:
- if (error != OTBR_ERROR_NONE)
- {
- otbrLogWarning("Failed to handle result of host %s", aName);
+ break;
}
}
@@ -271,18 +198,18 @@ exit:
otbrError AdvertisingProxy::PublishHostAndItsServices(const otSrpServerHost *aHost, OutstandingUpdate *aUpdate)
{
- otbrError error = OTBR_ERROR_NONE;
- const char * fullHostName;
- std::string hostName;
- std::string hostDomain;
- const otIp6Address * hostAddress;
- uint8_t hostAddressNum;
- bool hostDeleted;
- const otSrpServerService *service;
-
- fullHostName = otSrpServerHostGetFullName(aHost);
-
- otbrLogInfo("Advertise SRP service updates: host=%s", fullHostName);
+ otbrError error = OTBR_ERROR_NONE;
+ std::string hostName;
+ std::string hostDomain;
+ const otIp6Address * hostAddress;
+ uint8_t hostAddressNum;
+ bool hostDeleted;
+ const otSrpServerService * service;
+ otSrpServerServiceUpdateId updateId = 0;
+ bool hasUpdate = false;
+ std::string fullHostName = otSrpServerHostGetFullName(aHost);
+
+ otbrLogInfo("Advertise SRP service updates: host=%s", fullHostName.c_str());
SuccessOrExit(error = SplitFullHostName(fullHostName, hostName, hostDomain));
hostAddress = otSrpServerHostGetAddresses(aHost, &hostAddressNum);
@@ -290,66 +217,99 @@ otbrError AdvertisingProxy::PublishHostAndItsServices(const otSrpServerHost *aHo
if (aUpdate)
{
- aUpdate->mCallbackCount += !hostDeleted;
+ hasUpdate = true;
+ updateId = aUpdate->mId;
+ aUpdate->mCallbackCount++;
aUpdate->mHostName = hostName;
service = nullptr;
while ((service = otSrpServerHostFindNextService(aHost, service, OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY,
/* aServiceName */ nullptr, /* aInstanceName */ nullptr)))
{
- aUpdate->mCallbackCount += !hostDeleted && !otSrpServerServiceIsDeleted(service);
+ aUpdate->mCallbackCount++;
}
}
- if (!hostDeleted)
- {
- // TODO: select a preferred address or advertise all addresses from SRP client.
- otbrLogInfo("Publish SRP host: %s", fullHostName);
- SuccessOrExit(error =
- mPublisher.PublishHost(hostName.c_str(), hostAddress[0].mFields.m8, sizeof(hostAddress[0])));
- }
- else
- {
- otbrLogInfo("Unpublish SRP host: %s", fullHostName);
- SuccessOrExit(error = mPublisher.UnpublishHost(hostName.c_str()));
- }
-
service = nullptr;
while ((service = otSrpServerHostFindNextService(aHost, service, OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY,
/* aServiceName */ nullptr, /* aInstanceName */ nullptr)))
{
- const char *fullServiceName = otSrpServerServiceGetFullName(service);
+ std::string fullServiceName = otSrpServerServiceGetFullName(service);
std::string serviceName;
std::string serviceType;
std::string serviceDomain;
SuccessOrExit(error = SplitFullServiceInstanceName(fullServiceName, serviceName, serviceType, serviceDomain));
- if (aUpdate)
- {
- aUpdate->mServiceNames.emplace_back(serviceName, serviceType);
- }
-
if (!hostDeleted && !otSrpServerServiceIsDeleted(service))
{
Mdns::Publisher::TxtList txtList = MakeTxtList(service);
Mdns::Publisher::SubTypeList subTypeList = MakeSubTypeList(service);
- otbrLogInfo("Publish SRP service: %s", fullServiceName);
- SuccessOrExit(error = mPublisher.PublishService(hostName.c_str(), otSrpServerServiceGetPort(service),
- serviceName.c_str(), serviceType.c_str(), subTypeList,
- txtList));
+ otbrLogDebug("Publish SRP service '%s'", fullServiceName.c_str());
+ mPublisher.PublishService(
+ hostName, serviceName, serviceType, subTypeList, otSrpServerServiceGetPort(service), txtList,
+ [this, hasUpdate, updateId, fullServiceName](otbrError aError) {
+ otbrLogResult(aError, "Handle publish SRP service '%s'", fullServiceName.c_str());
+ if (hasUpdate)
+ {
+ OnMdnsPublishResult(updateId, aError);
+ }
+ });
}
else
{
- otbrLogInfo("Unpublish SRP service: %s", fullServiceName);
- SuccessOrExit(error = mPublisher.UnpublishService(serviceName.c_str(), serviceType.c_str()));
+ otbrLogDebug("Unpublish SRP service '%s'", fullServiceName.c_str());
+ mPublisher.UnpublishService(
+ serviceName, serviceType, [this, hasUpdate, updateId, fullServiceName](otbrError aError) {
+ // Treat `NOT_FOUND` as success when unpublishing service
+ aError = (aError == OTBR_ERROR_NOT_FOUND) ? OTBR_ERROR_NONE : aError;
+ otbrLogResult(aError, "Handle unpublish SRP service '%s'", fullServiceName.c_str());
+ if (hasUpdate)
+ {
+ OnMdnsPublishResult(updateId, aError);
+ }
+ });
}
}
+ if (!hostDeleted)
+ {
+ std::vector<uint8_t> firstHostAddress{std::begin(hostAddress[0].mFields.m8),
+ std::end(hostAddress[0].mFields.m8)};
+
+ // TODO: select a preferred address or advertise all addresses from SRP client.
+ otbrLogDebug("Publish SRP host '%s'", fullHostName.c_str());
+ mPublisher.PublishHost(
+ hostName, firstHostAddress,
+ Mdns::Publisher::ResultCallback([this, hasUpdate, updateId, fullHostName](otbrError aError) {
+ otbrLogResult(aError, "Handle publish SRP host '%s'", fullHostName.c_str());
+ if (hasUpdate)
+ {
+ OnMdnsPublishResult(updateId, aError);
+ }
+ }));
+ }
+ else
+ {
+ otbrLogDebug("Unpublish SRP host '%s'", fullHostName.c_str());
+ mPublisher.UnpublishHost(hostName, [this, hasUpdate, updateId, fullHostName](otbrError aError) {
+ // Treat `NOT_FOUND` as success when unpublishing host.
+ aError = (aError == OTBR_ERROR_NOT_FOUND) ? OTBR_ERROR_NONE : aError;
+ otbrLogResult(aError, "Handle unpublish SRP host '%s'", fullHostName.c_str());
+ if (hasUpdate)
+ {
+ OnMdnsPublishResult(updateId, aError);
+ }
+ });
+ }
+
exit:
if (error != OTBR_ERROR_NONE)
{
- otbrLogInfo("Failed to advertise SRP service updates %p", aHost);
+ if (hasUpdate)
+ {
+ otbrLogInfo("Failed to advertise SRP service updates (id = %u)", updateId);
+ }
}
return error;
}
diff --git a/src/sdp_proxy/advertising_proxy.hpp b/src/sdp_proxy/advertising_proxy.hpp
index e0947a39..7b21e6d5 100644
--- a/src/sdp_proxy/advertising_proxy.hpp
+++ b/src/sdp_proxy/advertising_proxy.hpp
@@ -41,6 +41,7 @@
#include <openthread/instance.h>
#include <openthread/srp_server.h>
+#include "common/code_utils.hpp"
#include "mdns/mdns.hpp"
#include "ncp/ncp_openthread.hpp"
@@ -50,14 +51,14 @@ namespace otbr {
* This class implements the Advertising Proxy.
*
*/
-class AdvertisingProxy
+class AdvertisingProxy : private NonCopyable
{
public:
/**
* This constructor initializes the Advertising Proxy object.
*
- * @param[in] aNcp A reference to the NCP controller.
- * @param[in] aPublisher A reference to the mDNS publisher.
+ * @param[in] aNcp A reference to the NCP controller.
+ * @param[in] aPublisher A reference to the mDNS publisher.
*
*/
explicit AdvertisingProxy(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher);
@@ -65,8 +66,8 @@ public:
/**
* This method starts the Advertising Proxy.
*
- * @retval OTBR_ERROR_NONE Successfully started the Advertising Proxy.
- * @retval ... Failed to start the Advertising Proxy.
+ * @retval OTBR_ERROR_NONE Successfully started the Advertising Proxy.
+ * @retval ... Failed to start the Advertising Proxy.
*
*/
otbrError Start(void);
@@ -86,13 +87,9 @@ public:
private:
struct OutstandingUpdate
{
- typedef std::vector<std::pair<std::string, std::string>> ServiceNameList;
-
- otSrpServerServiceUpdateId mId; // The ID of the SRP service update transaction.
- std::string mHostName; // The host name.
- ServiceNameList mServiceNames; // The list of service instance and name pairs to be updated.
- uint32_t mCallbackCount = 0; // The number of callbacks which we are waiting for.
- bool mHostNamePublished = false; // Is the host name already published?
+ otSrpServerServiceUpdateId mId; // The ID of the SRP service update transaction.
+ std::string mHostName; // The host name.
+ uint32_t mCallbackCount = 0; // The number of callbacks which we are waiting for.
};
static void AdvertisingHandler(otSrpServerServiceUpdateId aId,
@@ -103,11 +100,7 @@ private:
static Mdns::Publisher::TxtList MakeTxtList(const otSrpServerService *aSrpService);
static Mdns::Publisher::SubTypeList MakeSubTypeList(const otSrpServerService *aSrpService);
-
- static void PublishServiceHandler(const char *aName, const char *aType, otbrError aError, void *aContext);
- void PublishServiceHandler(const char *aName, const char *aType, otbrError aError);
- static void PublishHostHandler(const char *aName, otbrError aError, void *aContext);
- void PublishHostHandler(const char *aName, otbrError aError);
+ void OnMdnsPublishResult(otSrpServerServiceUpdateId aUpdateId, otbrError aError);
/**
* This method publishes a specified host and its services.
diff --git a/src/sdp_proxy/discovery_proxy.cpp b/src/sdp_proxy/discovery_proxy.cpp
index fb89833d..6aeccb28 100644
--- a/src/sdp_proxy/discovery_proxy.cpp
+++ b/src/sdp_proxy/discovery_proxy.cpp
@@ -47,39 +47,60 @@
#include "common/code_utils.hpp"
#include "common/dns_utils.hpp"
#include "common/logging.hpp"
+#include "utils/dns_utils.hpp"
+#include "utils/string_utils.hpp"
namespace otbr {
namespace Dnssd {
+static inline bool DnsLabelsEqual(const std::string &aLabel1, const std::string &aLabel2)
+{
+ return StringUtils::EqualCaseInsensitive(aLabel1, aLabel2);
+}
+
DiscoveryProxy::DiscoveryProxy(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher)
: mNcp(aNcp)
, mMdnsPublisher(aPublisher)
{
+ mNcp.RegisterResetHandler([this]() {
+ otDnssdQuerySetCallbacks(mNcp.GetInstance(), &DiscoveryProxy::OnDiscoveryProxySubscribe,
+ &DiscoveryProxy::OnDiscoveryProxyUnsubscribe, this);
+ });
}
void DiscoveryProxy::Start(void)
{
+ assert(mSubscriberId == 0);
+
otDnssdQuerySetCallbacks(mNcp.GetInstance(), &DiscoveryProxy::OnDiscoveryProxySubscribe,
&DiscoveryProxy::OnDiscoveryProxyUnsubscribe, this);
- mMdnsPublisher.SetSubscriptionCallbacks(
+ mSubscriberId = mMdnsPublisher.AddSubscriptionCallbacks(
[this](const std::string &aType, const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo) {
- OnServiceDiscovered(aType, aInstanceInfo);
+ if (!aInstanceInfo.mRemoved)
+ {
+ OnServiceDiscovered(aType, aInstanceInfo);
+ }
},
[this](const std::string &aHostName, const Mdns::Publisher::DiscoveredHostInfo &aHostInfo) {
OnHostDiscovered(aHostName, aHostInfo);
});
- otbrLogInfo("started");
+ otbrLogInfo("Started");
}
void DiscoveryProxy::Stop(void)
{
otDnssdQuerySetCallbacks(mNcp.GetInstance(), nullptr, nullptr, nullptr);
- mMdnsPublisher.SetSubscriptionCallbacks(nullptr, nullptr);
- otbrLogInfo("stopped");
+ if (mSubscriberId > 0)
+ {
+ mMdnsPublisher.RemoveSubscriptionCallbacks(mSubscriberId);
+ mSubscriberId = 0;
+ }
+
+ otbrLogInfo("Stopped");
}
void DiscoveryProxy::OnDiscoveryProxySubscribe(void *aContext, const char *aFullName)
@@ -90,10 +111,9 @@ void DiscoveryProxy::OnDiscoveryProxySubscribe(void *aContext, const char *aFull
void DiscoveryProxy::OnDiscoveryProxySubscribe(const char *aFullName)
{
std::string fullName(aFullName);
- otbrError error = OTBR_ERROR_NONE;
DnsNameInfo nameInfo = SplitFullDnsName(fullName);
- otbrLogInfo("subscribe: %s", fullName.c_str());
+ otbrLogInfo("Subscribe: %s", fullName.c_str());
if (GetServiceSubscriptionCount(nameInfo) == 1)
{
@@ -106,11 +126,6 @@ void DiscoveryProxy::OnDiscoveryProxySubscribe(const char *aFullName)
mMdnsPublisher.SubscribeHost(nameInfo.mHostName);
}
}
-
- if (error != OTBR_ERROR_NONE)
- {
- otbrLogWarning("failed to subscribe %s: %s", fullName.c_str(), otbrErrorString(error));
- }
}
void DiscoveryProxy::OnDiscoveryProxyUnsubscribe(void *aContext, const char *aFullName)
@@ -121,10 +136,9 @@ void DiscoveryProxy::OnDiscoveryProxyUnsubscribe(void *aContext, const char *aFu
void DiscoveryProxy::OnDiscoveryProxyUnsubscribe(const char *aFullName)
{
std::string fullName(aFullName);
- otbrError error = OTBR_ERROR_NONE;
DnsNameInfo nameInfo = SplitFullDnsName(fullName);
- otbrLogInfo("unsubscribe: %s", fullName.c_str());
+ otbrLogInfo("Unsubscribe: %s", fullName.c_str());
if (GetServiceSubscriptionCount(nameInfo) == 1)
{
@@ -137,26 +151,20 @@ void DiscoveryProxy::OnDiscoveryProxyUnsubscribe(const char *aFullName)
mMdnsPublisher.UnsubscribeHost(nameInfo.mHostName);
}
}
- if (error != OTBR_ERROR_NONE)
- {
- otbrLogWarning("failed to unsubscribe %s: %s", fullName.c_str(), otbrErrorString(error));
- }
}
void DiscoveryProxy::OnServiceDiscovered(const std::string & aType,
const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo)
{
otDnssdServiceInstanceInfo instanceInfo;
- const otDnssdQuery * query = nullptr;
+ const otDnssdQuery * query = nullptr;
+ std::string unescapedInstanceName = DnsUtils::UnescapeInstanceName(aInstanceInfo.mName);
- otbrLogInfo("service discovered: %s, instance %s hostname %s addresses %zu port %d priority %d "
+ otbrLogInfo("Service discovered: %s, instance %s hostname %s addresses %zu port %d priority %d "
"weight %d",
aType.c_str(), aInstanceInfo.mName.c_str(), aInstanceInfo.mHostName.c_str(),
aInstanceInfo.mAddresses.size(), aInstanceInfo.mPort, aInstanceInfo.mPriority, aInstanceInfo.mWeight);
- CheckServiceNameSanity(aType);
- CheckHostnameSanity(aInstanceInfo.mHostName);
-
instanceInfo.mAddressNum = aInstanceInfo.mAddresses.size();
if (!aInstanceInfo.mAddresses.empty())
@@ -204,14 +212,15 @@ void DiscoveryProxy::OnServiceDiscovered(const std::string &
continue;
}
- if (serviceName == aType && (instanceName.empty() || instanceName == aInstanceInfo.mName))
+ if (DnsLabelsEqual(serviceName, aType) &&
+ (instanceName.empty() || DnsLabelsEqual(instanceName, unescapedInstanceName)))
{
- std::string serviceFullName = aType + "." + domain;
- std::string hostName = TranslateDomain(aInstanceInfo.mHostName, domain);
- std::string instanceFullName = aInstanceInfo.mName + "." + serviceFullName;
+ std::string serviceFullName = aType + "." + domain;
+ std::string translatedHostName = TranslateDomain(aInstanceInfo.mHostName, domain);
+ std::string instanceFullName = unescapedInstanceName + "." + serviceFullName;
instanceInfo.mFullName = instanceFullName.c_str();
- instanceInfo.mHostName = hostName.c_str();
+ instanceInfo.mHostName = translatedHostName.c_str();
otDnssdQueryHandleDiscoveredServiceInstance(mNcp.GetInstance(), serviceFullName.c_str(), &instanceInfo);
}
@@ -225,7 +234,7 @@ void DiscoveryProxy::OnHostDiscovered(const std::string &
const otDnssdQuery *query = nullptr;
std::string resolvedHostName = aHostInfo.mHostName;
- otbrLogInfo("host discovered: %s hostname %s addresses %zu", aHostName.c_str(), aHostInfo.mHostName.c_str(),
+ otbrLogInfo("Host discovered: %s hostname %s addresses %zu", aHostName.c_str(), aHostInfo.mHostName.c_str(),
aHostInfo.mAddresses.size());
if (resolvedHostName.empty())
@@ -233,8 +242,6 @@ void DiscoveryProxy::OnHostDiscovered(const std::string &
resolvedHostName = aHostName + ".local.";
}
- CheckHostnameSanity(resolvedHostName);
-
hostInfo.mAddressNum = aHostInfo.mAddresses.size();
if (!aHostInfo.mAddresses.empty())
{
@@ -261,7 +268,7 @@ void DiscoveryProxy::OnHostDiscovered(const std::string &
splitError = SplitFullHostName(queryName, hostName, domain);
assert(splitError == OTBR_ERROR_NONE);
- if (hostName == aHostName)
+ if (DnsLabelsEqual(hostName, aHostName))
{
std::string hostFullName = TranslateDomain(resolvedHostName, domain);
@@ -277,12 +284,12 @@ std::string DiscoveryProxy::TranslateDomain(const std::string &aName, const std:
std::string domain;
VerifyOrExit(OTBR_ERROR_NONE == SplitFullHostName(aName, hostName, domain), targetName = aName);
- VerifyOrExit(domain == "local.", targetName = aName);
+ VerifyOrExit(DnsLabelsEqual(domain, "local."), targetName = aName);
targetName = hostName + "." + aTargetDomain;
exit:
- otbrLogDebug("translate domain: %s => %s", aName.c_str(), targetName.c_str());
+ otbrLogDebug("Translate domain: %s => %s", aName.c_str(), targetName.c_str());
return targetName;
}
@@ -299,35 +306,14 @@ int DiscoveryProxy::GetServiceSubscriptionCount(const DnsNameInfo &aNameInfo) co
otDnssdGetQueryTypeAndName(query, &queryName);
queryInfo = SplitFullDnsName(queryName);
- count += (aNameInfo.mInstanceName == queryInfo.mInstanceName &&
- aNameInfo.mServiceName == queryInfo.mServiceName && aNameInfo.mHostName == queryInfo.mHostName);
+ count += (DnsLabelsEqual(aNameInfo.mInstanceName, queryInfo.mInstanceName) &&
+ DnsLabelsEqual(aNameInfo.mServiceName, queryInfo.mServiceName) &&
+ DnsLabelsEqual(aNameInfo.mHostName, queryInfo.mHostName));
}
return count;
}
-void DiscoveryProxy::CheckServiceNameSanity(const std::string &aType)
-{
- size_t dotpos;
-
- OTBR_UNUSED_VARIABLE(aType);
- OTBR_UNUSED_VARIABLE(dotpos);
-
- assert(aType.length() > 0);
- assert(aType[aType.length() - 1] != '.');
- dotpos = aType.find_first_of('.');
- assert(dotpos != std::string::npos);
- assert(dotpos == aType.find_last_of('.'));
-}
-
-void DiscoveryProxy::CheckHostnameSanity(const std::string &aHostName)
-{
- OTBR_UNUSED_VARIABLE(aHostName);
-
- assert(aHostName.length() > 0);
- assert(aHostName[aHostName.length() - 1] == '.');
-}
-
uint32_t DiscoveryProxy::CapTtl(uint32_t aTtl)
{
return std::min(aTtl, static_cast<uint32_t>(kServiceTtlCapLimit));
diff --git a/src/sdp_proxy/discovery_proxy.hpp b/src/sdp_proxy/discovery_proxy.hpp
index 346dd7ea..4063aa81 100644
--- a/src/sdp_proxy/discovery_proxy.hpp
+++ b/src/sdp_proxy/discovery_proxy.hpp
@@ -55,7 +55,7 @@ namespace Dnssd {
* This class implements the DNS-SD Discovery Proxy.
*
*/
-class DiscoveryProxy
+class DiscoveryProxy : private NonCopyable
{
public:
/**
@@ -91,8 +91,6 @@ private:
void OnDiscoveryProxyUnsubscribe(const char *aSubscription);
int GetServiceSubscriptionCount(const DnsNameInfo &aNameInfo) const;
static std::string TranslateDomain(const std::string &aName, const std::string &aTargetDomain);
- static void CheckServiceNameSanity(const std::string &aType);
- static void CheckHostnameSanity(const std::string &aHostName);
void OnServiceDiscovered(const std::string & aSubscription,
const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo);
void OnHostDiscovered(const std::string &aHostName, const Mdns::Publisher::DiscoveredHostInfo &aHostInfo);
@@ -100,6 +98,7 @@ private:
Ncp::ControllerOpenThread &mNcp;
Mdns::Publisher & mMdnsPublisher;
+ uint64_t mSubscriberId = 0;
};
} // namespace Dnssd
diff --git a/src/trel_dnssd/CMakeLists.txt b/src/trel_dnssd/CMakeLists.txt
new file mode 100644
index 00000000..b0c4a93b
--- /dev/null
+++ b/src/trel_dnssd/CMakeLists.txt
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2021, The OpenThread Authors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the copyright holder nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+add_library(otbr-trel-dnssd
+ trel_dnssd.cpp
+ trel_dnssd.hpp
+)
+
+target_link_libraries(otbr-trel-dnssd PRIVATE
+ $<$<BOOL:${OTBR_MDNS}>:otbr-mdns>
+ otbr-common
+)
diff --git a/src/trel_dnssd/trel_dnssd.cpp b/src/trel_dnssd/trel_dnssd.cpp
new file mode 100644
index 00000000..daeb3e9b
--- /dev/null
+++ b/src/trel_dnssd/trel_dnssd.cpp
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2021, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes implementation of TREL DNS-SD over mDNS.
+ */
+
+#if OTBR_ENABLE_TREL
+
+#define OTBR_LOG_TAG "TrelDns"
+
+#include "trel_dnssd/trel_dnssd.hpp"
+
+#include <inttypes.h>
+#include <net/if.h>
+
+#include <openthread/instance.h>
+#include <openthread/link.h>
+#include <openthread/platform/trel.h>
+
+#include "common/code_utils.hpp"
+#include "utils/hex.hpp"
+#include "utils/string_utils.hpp"
+
+static const char kTrelServiceName[] = "_trel._udp";
+
+static otbr::TrelDnssd::TrelDnssd *sTrelDnssd = nullptr;
+
+void trelDnssdInitialize(const char *aTrelNetif)
+{
+ sTrelDnssd->Initialize(aTrelNetif);
+}
+
+void trelDnssdStartBrowse(void)
+{
+ sTrelDnssd->StartBrowse();
+}
+
+void trelDnssdStopBrowse(void)
+{
+ sTrelDnssd->StopBrowse();
+}
+
+void trelDnssdRegisterService(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
+{
+ sTrelDnssd->RegisterService(aPort, aTxtData, aTxtLength);
+}
+
+void trelDnssdRemoveService(void)
+{
+ sTrelDnssd->UnregisterService();
+}
+
+namespace otbr {
+
+namespace TrelDnssd {
+
+TrelDnssd::TrelDnssd(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher)
+ : mPublisher(aPublisher)
+ , mNcp(aNcp)
+{
+ sTrelDnssd = this;
+}
+
+void TrelDnssd::Initialize(std::string aTrelNetif)
+{
+ mTrelNetif = std::move(aTrelNetif);
+
+ if (IsInitialized())
+ {
+ otbrLogDebug("Initialized on netif \"%s\"", mTrelNetif.c_str());
+ CheckTrelNetifReady();
+ }
+ else
+ {
+ otbrLogDebug("Not initialized");
+ }
+}
+
+void TrelDnssd::StartBrowse(void)
+{
+ VerifyOrExit(IsInitialized());
+
+ otbrLogDebug("Start browsing %s services ...", kTrelServiceName);
+
+ assert(mSubscriberId == 0);
+ mSubscriberId = mPublisher.AddSubscriptionCallbacks(
+ [this](const std::string &aType, const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo) {
+ OnTrelServiceInstanceResolved(aType, aInstanceInfo);
+ },
+ /* aHostCallback */ nullptr);
+
+ if (IsReady())
+ {
+ mPublisher.SubscribeService(kTrelServiceName, /* aInstanceName */ "");
+ }
+
+exit:
+ return;
+}
+
+void TrelDnssd::StopBrowse(void)
+{
+ VerifyOrExit(IsInitialized());
+
+ otbrLogDebug("Stop browsing %s service.", kTrelServiceName);
+ assert(mSubscriberId > 0);
+
+ mPublisher.RemoveSubscriptionCallbacks(mSubscriberId);
+ mSubscriberId = 0;
+
+ if (IsReady())
+ {
+ mPublisher.UnsubscribeService(kTrelServiceName, "");
+ }
+
+exit:
+ return;
+}
+
+void TrelDnssd::RegisterService(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
+{
+ assert(aPort > 0);
+ assert(aTxtData != nullptr);
+
+ VerifyOrExit(IsInitialized());
+
+ otbrLogDebug("Register %s service: port=%u, TXT=%d bytes", kTrelServiceName, aPort, aTxtLength);
+ otbrDump(OTBR_LOG_DEBUG, OTBR_LOG_TAG, "TXT", aTxtData, aTxtLength);
+
+ if (mRegisterInfo.IsValid() && IsReady())
+ {
+ UnpublishTrelService();
+ }
+
+ mRegisterInfo.Assign(aPort, aTxtData, aTxtLength);
+
+ if (IsReady())
+ {
+ PublishTrelService();
+ }
+
+exit:
+ return;
+}
+
+void TrelDnssd::UnregisterService(void)
+{
+ VerifyOrExit(IsInitialized());
+
+ otbrLogDebug("Remove %s service", kTrelServiceName);
+ assert(mRegisterInfo.IsValid());
+
+ if (IsReady())
+ {
+ UnpublishTrelService();
+ }
+
+ mRegisterInfo.Clear();
+
+exit:
+ return;
+}
+
+void TrelDnssd::OnMdnsPublisherReady(void)
+{
+ VerifyOrExit(IsInitialized());
+
+ otbrLogDebug("mDNS Publisher is Ready");
+ mMdnsPublisherReady = true;
+ RemoveAllPeers();
+
+ if (mRegisterInfo.IsPublished())
+ {
+ mRegisterInfo.mInstanceName = "";
+ }
+
+ OnBecomeReady();
+
+exit:
+ return;
+}
+
+void TrelDnssd::OnTrelServiceInstanceResolved(const std::string & aType,
+ const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo)
+{
+ VerifyOrExit(StringUtils::EqualCaseInsensitive(aType, kTrelServiceName));
+ VerifyOrExit(aInstanceInfo.mNetifIndex == mTrelNetifIndex);
+
+ if (aInstanceInfo.mRemoved)
+ {
+ OnTrelServiceInstanceRemoved(aInstanceInfo.mName);
+ }
+ else
+ {
+ OnTrelServiceInstanceAdded(aInstanceInfo);
+ }
+
+exit:
+ return;
+}
+
+std::string TrelDnssd::GetTrelInstanceName(void)
+{
+ const otExtAddress *extaddr = otLinkGetExtendedAddress(mNcp.GetInstance());
+ std::string name;
+ char nameBuf[sizeof(otExtAddress) * 2 + 1];
+
+ Utils::Bytes2Hex(extaddr->m8, sizeof(otExtAddress), nameBuf);
+ name = StringUtils::ToLowercase(nameBuf);
+
+ assert(name.length() == sizeof(otExtAddress) * 2);
+
+ otbrLogDebug("Using instance name %s", name.c_str());
+ return name;
+}
+
+void TrelDnssd::PublishTrelService(void)
+{
+ assert(mRegisterInfo.IsValid());
+ assert(!mRegisterInfo.IsPublished());
+ assert(mTrelNetifIndex > 0);
+
+ mRegisterInfo.mInstanceName = GetTrelInstanceName();
+ mPublisher.PublishService(/* aHostName */ "", mRegisterInfo.mInstanceName, kTrelServiceName,
+ Mdns::Publisher::SubTypeList{}, mRegisterInfo.mPort, mRegisterInfo.mTxtEntries,
+ [](otbrError aError) { HandlePublishTrelServiceError(aError); });
+}
+
+void TrelDnssd::HandlePublishTrelServiceError(otbrError aError)
+{
+ if (aError != OTBR_ERROR_NONE)
+ {
+ otbrLogErr("Failed to publish TREL service: %s. TREL won't be working.", otbrErrorString(aError));
+ }
+}
+
+void TrelDnssd::UnpublishTrelService(void)
+{
+ assert(mRegisterInfo.IsValid());
+ assert(mRegisterInfo.IsPublished());
+
+ mPublisher.UnpublishService(mRegisterInfo.mInstanceName, kTrelServiceName,
+ [](otbrError aError) { HandleUnpublishTrelServiceError(aError); });
+ mRegisterInfo.mInstanceName = "";
+}
+
+void TrelDnssd::HandleUnpublishTrelServiceError(otbrError aError)
+{
+ if (aError != OTBR_ERROR_NONE)
+ {
+ otbrLogInfo("Failed to unpublish TREL service: %s", otbrErrorString(aError));
+ }
+}
+
+void TrelDnssd::OnTrelServiceInstanceAdded(const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo)
+{
+ std::string instanceName = StringUtils::ToLowercase(aInstanceInfo.mName);
+ otPlatTrelPeerInfo peerInfo;
+
+ // Remove any existing TREL service instance before adding
+ OnTrelServiceInstanceRemoved(instanceName);
+
+ otbrLogDebug("Peer discovered: %s hostname %s addresses %zu port %d priority %d "
+ "weight %d",
+ aInstanceInfo.mName.c_str(), aInstanceInfo.mHostName.c_str(), aInstanceInfo.mAddresses.size(),
+ aInstanceInfo.mPort, aInstanceInfo.mPriority, aInstanceInfo.mWeight);
+
+ for (const auto &addr : aInstanceInfo.mAddresses)
+ {
+ otbrLogDebug("Peer address: %s", addr.ToString().c_str());
+ }
+
+ if (aInstanceInfo.mAddresses.empty())
+ {
+ otbrLogWarning("Peer %s does not have any IPv6 address, ignored", aInstanceInfo.mName.c_str());
+ ExitNow();
+ }
+
+ peerInfo.mRemoved = false;
+ memcpy(&peerInfo.mSockAddr.mAddress, &aInstanceInfo.mAddresses[0], sizeof(peerInfo.mSockAddr.mAddress));
+ peerInfo.mSockAddr.mPort = aInstanceInfo.mPort;
+ peerInfo.mTxtData = aInstanceInfo.mTxtData.data();
+ peerInfo.mTxtLength = aInstanceInfo.mTxtData.size();
+
+ {
+ Peer peer(aInstanceInfo.mTxtData, peerInfo.mSockAddr);
+
+ VerifyOrExit(peer.mValid, otbrLogWarning("Peer %s is invalid", aInstanceInfo.mName.c_str()));
+
+ otPlatTrelHandleDiscoveredPeerInfo(mNcp.GetInstance(), &peerInfo);
+
+ mPeers.emplace(instanceName, peer);
+ CheckPeersNumLimit();
+ }
+
+exit:
+ return;
+}
+
+void TrelDnssd::OnTrelServiceInstanceRemoved(const std::string &aInstanceName)
+{
+ std::string instanceName = StringUtils::ToLowercase(aInstanceName);
+ auto it = mPeers.find(instanceName);
+
+ VerifyOrExit(it != mPeers.end());
+
+ otbrLogDebug("Peer removed: %s", instanceName.c_str());
+
+ // Remove the peer only when all instances are removed because one peer can have multiple instances if expired
+ // instances were not properly removed by mDNS.
+ if (CountDuplicatePeers(it->second) == 0)
+ {
+ NotifyRemovePeer(it->second);
+ }
+
+ mPeers.erase(it);
+
+exit:
+ return;
+}
+
+void TrelDnssd::CheckPeersNumLimit(void)
+{
+ const PeerMap::value_type *oldestPeer = nullptr;
+
+ VerifyOrExit(mPeers.size() >= kPeerCacheSize);
+
+ for (const auto &entry : mPeers)
+ {
+ if (oldestPeer == nullptr || entry.second.mDiscoverTime < oldestPeer->second.mDiscoverTime)
+ {
+ oldestPeer = &entry;
+ }
+ }
+
+ OnTrelServiceInstanceRemoved(oldestPeer->first);
+
+exit:
+ return;
+}
+
+void TrelDnssd::NotifyRemovePeer(const Peer &aPeer)
+{
+ otPlatTrelPeerInfo peerInfo;
+
+ peerInfo.mRemoved = true;
+ peerInfo.mTxtData = aPeer.mTxtData.data();
+ peerInfo.mTxtLength = aPeer.mTxtData.size();
+ peerInfo.mSockAddr = aPeer.mSockAddr;
+
+ otPlatTrelHandleDiscoveredPeerInfo(mNcp.GetInstance(), &peerInfo);
+}
+
+void TrelDnssd::RemoveAllPeers(void)
+{
+ for (const auto &entry : mPeers)
+ {
+ NotifyRemovePeer(entry.second);
+ }
+
+ mPeers.clear();
+}
+
+void TrelDnssd::CheckTrelNetifReady(void)
+{
+ assert(IsInitialized());
+
+ if (mTrelNetifIndex == 0)
+ {
+ mTrelNetifIndex = if_nametoindex(mTrelNetif.c_str());
+
+ if (mTrelNetifIndex != 0)
+ {
+ otbrLogDebug("Netif %s is ready: index = %" PRIu32, mTrelNetif.c_str(), mTrelNetifIndex);
+ OnBecomeReady();
+ }
+ else
+ {
+ uint16_t delay = kCheckNetifReadyIntervalMs;
+
+ otbrLogWarning("Netif %s is not ready (%s), will retry after %d seconds", mTrelNetif.c_str(),
+ strerror(errno), delay / 1000);
+ mTaskRunner.Post(Milliseconds(delay), [this]() { CheckTrelNetifReady(); });
+ }
+ }
+}
+
+bool TrelDnssd::IsReady(void) const
+{
+ assert(IsInitialized());
+
+ return mTrelNetifIndex > 0 && mMdnsPublisherReady;
+}
+
+void TrelDnssd::OnBecomeReady(void)
+{
+ if (IsReady())
+ {
+ otbrLogInfo("TREL DNS-SD Is Now Ready: Netif=%s(%" PRIu32 "), SubscriberId=%" PRIu64 ", Register=%s!",
+ mTrelNetif.c_str(), mTrelNetifIndex, mSubscriberId, mRegisterInfo.mInstanceName.c_str());
+
+ if (mSubscriberId > 0)
+ {
+ mPublisher.SubscribeService(kTrelServiceName, /* aInstanceName */ "");
+ }
+
+ if (mRegisterInfo.IsValid())
+ {
+ PublishTrelService();
+ }
+ }
+}
+
+uint16_t TrelDnssd::CountDuplicatePeers(const TrelDnssd::Peer &aPeer)
+{
+ uint16_t count = 0;
+
+ for (const auto &entry : mPeers)
+ {
+ if (&entry.second == &aPeer)
+ {
+ continue;
+ }
+
+ if (!memcmp(&entry.second.mSockAddr, &aPeer.mSockAddr, sizeof(otSockAddr)) &&
+ !memcmp(&entry.second.mExtAddr, &aPeer.mExtAddr, sizeof(otExtAddress)))
+ {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+void TrelDnssd::RegisterInfo::Assign(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
+{
+ otbrError error;
+
+ OTBR_UNUSED_VARIABLE(error);
+
+ assert(!IsPublished());
+ assert(aPort > 0);
+
+ mPort = aPort;
+ mTxtEntries.clear();
+
+ error = Mdns::Publisher::DecodeTxtData(mTxtEntries, aTxtData, aTxtLength);
+ assert(error == OTBR_ERROR_NONE);
+}
+
+void TrelDnssd::RegisterInfo::Clear(void)
+{
+ assert(!IsPublished());
+
+ mPort = 0;
+ mTxtEntries.clear();
+}
+
+const char TrelDnssd::Peer::kTxtRecordExtAddressKey[] = "xa";
+
+void TrelDnssd::Peer::ReadExtAddrFromTxtData(void)
+{
+ std::vector<Mdns::Publisher::TxtEntry> txtEntries;
+
+ memset(&mExtAddr, 0, sizeof(mExtAddr));
+
+ SuccessOrExit(Mdns::Publisher::DecodeTxtData(txtEntries, mTxtData.data(), mTxtData.size()));
+
+ for (const auto &txtEntry : txtEntries)
+ {
+ if (StringUtils::EqualCaseInsensitive(txtEntry.mName, kTxtRecordExtAddressKey))
+ {
+ VerifyOrExit(txtEntry.mValue.size() == sizeof(mExtAddr));
+
+ memcpy(mExtAddr.m8, txtEntry.mValue.data(), sizeof(mExtAddr));
+ mValid = true;
+ break;
+ }
+ }
+
+exit:
+
+ if (!mValid)
+ {
+ otbrLogInfo("Failed to dissect ExtAddr from peer TXT data");
+ }
+
+ return;
+}
+
+} // namespace TrelDnssd
+
+} // namespace otbr
+
+#endif // OTBR_ENABLE_TREL
diff --git a/src/trel_dnssd/trel_dnssd.hpp b/src/trel_dnssd/trel_dnssd.hpp
new file mode 100644
index 00000000..cf6564dc
--- /dev/null
+++ b/src/trel_dnssd/trel_dnssd.hpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2021, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes definitions for TREL DNS-SD over mDNS.
+ */
+
+#ifndef OTBR_AGENT_TREL_DNSSD_HPP_
+#define OTBR_AGENT_TREL_DNSSD_HPP_
+
+#if OTBR_ENABLE_TREL
+
+#include <assert.h>
+#include <utility>
+
+#include <openthread/instance.h>
+
+#include "common/types.hpp"
+#include "mdns/mdns.hpp"
+#include "ncp/ncp_openthread.hpp"
+
+namespace otbr {
+
+namespace TrelDnssd {
+
+/**
+ * @addtogroup border-router-trel-dnssd
+ *
+ * @brief
+ * This module includes definition for TREL DNS-SD over mDNS.
+ *
+ * @{
+ */
+
+class TrelDnssd
+{
+public:
+ /**
+ * This constructor initializes the TrelDnssd instance.
+ *
+ * @param[in] aNcp A reference to the OpenThread Controller instance.
+ * @param[in] aPublisher A reference to the mDNS Publisher.
+ *
+ */
+ explicit TrelDnssd(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher);
+
+ /**
+ * This method initializes the TrelDnssd instance.
+ *
+ * @param[in] aTrelNetif The network interface for discovering TREL peers.
+ *
+ */
+ void Initialize(std::string aTrelNetif);
+
+ /**
+ * This method starts browsing for TREL peers.
+ *
+ */
+ void StartBrowse(void);
+
+ /**
+ * This method stops browsing for TREL peers.
+ *
+ */
+ void StopBrowse(void);
+
+ /**
+ * This method registers the TREL service to DNS-SD.
+ *
+ * @param[in] aPort The UDP port of TREL service.
+ * @param[in] aTxtData The TXT data of TREL service.
+ * @param[in] aTxtLength The TXT length of TREL service.
+ *
+ */
+ void RegisterService(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength);
+
+ /**
+ * This method removes the TREL service from DNS-SD.
+ *
+ */
+ void UnregisterService(void);
+
+ /**
+ * This method notifies that mDNS Publisher is ready.
+ *
+ */
+ void OnMdnsPublisherReady(void);
+
+private:
+ static constexpr size_t kPeerCacheSize = 256;
+ static constexpr uint16_t kCheckNetifReadyIntervalMs = 5000;
+
+ struct RegisterInfo
+ {
+ uint16_t mPort = 0;
+ std::vector<Mdns::Publisher::TxtEntry> mTxtEntries;
+ std::string mInstanceName;
+
+ bool IsValid(void) const { return mPort > 0; }
+ bool IsPublished(void) const { return !mInstanceName.empty(); }
+ void Assign(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength);
+ void Clear(void);
+ };
+
+ using Clock = std::chrono::system_clock;
+
+ struct Peer
+ {
+ static const char kTxtRecordExtAddressKey[];
+
+ explicit Peer(std::vector<uint8_t> aTxtData, const otSockAddr &aSockAddr)
+ : mDiscoverTime(Clock::now())
+ , mTxtData(std::move(aTxtData))
+ , mSockAddr(aSockAddr)
+ {
+ ReadExtAddrFromTxtData();
+ }
+
+ void ReadExtAddrFromTxtData(void);
+
+ Clock::time_point mDiscoverTime;
+ std::vector<uint8_t> mTxtData;
+ otSockAddr mSockAddr;
+ otExtAddress mExtAddr;
+ bool mValid = false;
+ };
+
+ using PeerMap = std::map<std::string, Peer>;
+
+ bool IsInitialized(void) const { return !mTrelNetif.empty(); }
+ bool IsReady(void) const;
+ void OnBecomeReady(void);
+ void CheckTrelNetifReady(void);
+ std::string GetTrelInstanceName(void);
+ void PublishTrelService(void);
+ void UnpublishTrelService(void);
+ static void HandlePublishTrelServiceError(otbrError aError);
+ static void HandleUnpublishTrelServiceError(otbrError aError);
+ void OnTrelServiceInstanceResolved(const std::string & aType,
+ const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo);
+ void OnTrelServiceInstanceAdded(const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo);
+ void OnTrelServiceInstanceRemoved(const std::string &aInstanceName);
+
+ void NotifyRemovePeer(const Peer &aPeer);
+ void CheckPeersNumLimit(void);
+ void RemoveAllPeers(void);
+ uint16_t CountDuplicatePeers(const Peer &aPeer);
+
+ Mdns::Publisher & mPublisher;
+ Ncp::ControllerOpenThread &mNcp;
+ TaskRunner mTaskRunner;
+ std::string mTrelNetif;
+ uint32_t mTrelNetifIndex = 0;
+ uint64_t mSubscriberId = 0;
+ RegisterInfo mRegisterInfo;
+ PeerMap mPeers;
+ bool mMdnsPublisherReady = false;
+};
+
+/**
+ * @}
+ */
+
+} // namespace TrelDnssd
+
+} // namespace otbr
+
+#endif // OTBR_ENABLE_TREL
+
+#endif // OTBR_AGENT_TREL_DNSSD_HPP_
diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt
index 31512931..5a624844 100644
--- a/src/utils/CMakeLists.txt
+++ b/src/utils/CMakeLists.txt
@@ -28,11 +28,13 @@
add_library(otbr-utils
crc16.cpp
+ dns_utils.cpp
hex.cpp
+ infra_link_selector.cpp
pskc.cpp
socket_utils.cpp
steering_data.cpp
- strcpy_utils.cpp
+ string_utils.cpp
system_utils.cpp
thread_helper.cpp
thread_helper.hpp
diff --git a/src/utils/crc16.hpp b/src/utils/crc16.hpp
index ac4b9efc..6d2167c0 100644
--- a/src/utils/crc16.hpp
+++ b/src/utils/crc16.hpp
@@ -56,7 +56,7 @@ public:
/**
* This constructor initializes the object.
*
- * @param[in] aPolynomial The polynomial value.
+ * @param[in] aPolynomial The polynomial value.
*
*/
Crc16(Polynomial aPolynomial);
@@ -67,10 +67,10 @@ public:
*/
void Init(void) { mCrc = 0; }
- /*c*
+ /**
* This method feeds a byte value into the CRC16 computation.
*
- * @param[in] aByte The byte value.
+ * @param[in] aByte The byte value.
*
*/
void Update(uint8_t aByte);
diff --git a/src/utils/dns_utils.cpp b/src/utils/dns_utils.cpp
new file mode 100644
index 00000000..3ca7630a
--- /dev/null
+++ b/src/utils/dns_utils.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2021, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "utils/dns_utils.hpp"
+
+#include <assert.h>
+
+#include "common/code_utils.hpp"
+
+namespace otbr {
+
+namespace DnsUtils {
+
+std::string UnescapeInstanceName(const std::string &aName)
+{
+ std::string newName;
+ auto nameLen = aName.length();
+
+ newName.reserve(nameLen);
+
+ for (unsigned int i = 0; i < nameLen; i++)
+ {
+ char c = aName[i];
+
+ if (c == '\\')
+ {
+ if (i + 3 < nameLen && isdigit(aName[i + 1]) && isdigit(aName[i + 2]) && isdigit(aName[i + 3]))
+ {
+ uint8_t b = (aName[i + 1] - '0') * 100 + (aName[i + 2] - '0') * 10 + (aName[i + 3] - '0');
+
+ newName.push_back(b);
+ i += 3;
+ continue;
+ }
+
+ if (i + 1 < nameLen)
+ {
+ newName.push_back(aName[i + 1]);
+ i += 1;
+ continue;
+ }
+ }
+
+ // append all not escaped characters
+ newName.push_back(c);
+ }
+
+ return newName;
+}
+
+void CheckHostnameSanity(const std::string &aHostName)
+{
+ OTBR_UNUSED_VARIABLE(aHostName);
+
+ assert(aHostName.length() > 0);
+ assert(aHostName.back() == '.');
+}
+
+void CheckServiceNameSanity(const std::string &aServiceName)
+{
+ size_t dotpos;
+
+ OTBR_UNUSED_VARIABLE(aServiceName);
+ OTBR_UNUSED_VARIABLE(dotpos);
+
+ assert(aServiceName.length() > 0);
+ assert(aServiceName[aServiceName.length() - 1] != '.');
+ dotpos = aServiceName.find_first_of('.');
+ assert(dotpos != std::string::npos);
+ assert(dotpos == aServiceName.find_last_of('.'));
+}
+
+} // namespace DnsUtils
+
+} // namespace otbr
diff --git a/src/utils/dns_utils.hpp b/src/utils/dns_utils.hpp
new file mode 100644
index 00000000..9addf66f
--- /dev/null
+++ b/src/utils/dns_utils.hpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017-2021, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes definition for DNS utilities.
+ */
+
+#ifndef OTBR_UTILS_DNS_UTILS_HPP_
+#define OTBR_UTILS_DNS_UTILS_HPP_
+
+#include "openthread-br/config.h"
+
+#include <string>
+
+namespace otbr {
+
+namespace DnsUtils {
+
+/**
+ * This function unescapes a DNS Service Instance name according to "DNS Name Escaping".
+ *
+ * @sa "Notes on DNS Name Escaping" at
+ * https://opensource.apple.com/source/mDNSResponder/mDNSResponder-1310.140.1/mDNSShared/dns_sd.h.auto.html.
+ *
+ * @param[in] aName The DNS Service Instance name to unescape.
+ *
+ * @returns The unescaped DNS Service Instance name.
+ *
+ */
+std::string UnescapeInstanceName(const std::string &aName);
+
+/**
+ * This function checks a given host name for sanity.
+ *
+ * Check criteria:
+ * The host name must ends with dot.
+ *
+ * @param[in] aHostName The host name to check.
+ *
+ */
+void CheckHostnameSanity(const std::string &aHostName);
+
+/**
+ * This function checks a given service name for sanity.
+ *
+ * Check criteria:
+ * The service name must contain exactly one dot.
+ * The service name must not end with dot.
+ *
+ * @param[in] aServiceName The service name to check.
+ *
+ */
+void CheckServiceNameSanity(const std::string &aServiceName);
+
+} // namespace DnsUtils
+} // namespace otbr
+#endif // OTBR_UTILS_DNS_UTILS_HPP_
diff --git a/src/utils/infra_link_selector.cpp b/src/utils/infra_link_selector.cpp
new file mode 100644
index 00000000..ee68ec3d
--- /dev/null
+++ b/src/utils/infra_link_selector.cpp
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2022, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * The file implements the Infrastructure Link Selector.
+ */
+
+#if __linux__
+
+#define OTBR_LOG_TAG "ILS"
+
+#include "utils/infra_link_selector.hpp"
+
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <openthread/backbone_router_ftd.h>
+
+#include "utils/socket_utils.hpp"
+
+namespace otbr {
+namespace Utils {
+
+constexpr Milliseconds InfraLinkSelector::kInfraLinkSelectionDelay;
+
+bool InfraLinkSelector::LinkInfo::Update(LinkState aState)
+{
+ bool changed = mState != aState;
+
+ VerifyOrExit(changed);
+
+ if (mState == kUpAndRunning && aState != kUpAndRunning)
+ {
+ mWasUpAndRunning = true;
+ mLastRunningTime = Clock::now();
+ }
+
+ mState = aState;
+exit:
+ return changed;
+}
+
+InfraLinkSelector::InfraLinkSelector(std::vector<const char *> aInfraLinkNames)
+ : mInfraLinkNames(std::move(aInfraLinkNames))
+{
+ if (mInfraLinkNames.size() >= 2)
+ {
+ mNetlinkSocket = CreateNetLinkRouteSocket(RTMGRP_LINK);
+ VerifyOrDie(mNetlinkSocket != -1, "Failed to create netlink socket");
+ }
+
+ for (const char *name : mInfraLinkNames)
+ {
+ mInfraLinkInfos[name].Update(QueryInfraLinkState(name));
+ }
+}
+
+InfraLinkSelector::~InfraLinkSelector(void)
+{
+ if (mNetlinkSocket != -1)
+ {
+ close(mNetlinkSocket);
+ mNetlinkSocket = -1;
+ }
+}
+
+const char *InfraLinkSelector::Select(void)
+{
+ const char *sel;
+
+#if OTBR_ENABLE_VENDOR_INFRA_LINK_SELECT
+ sel = otbrVendorInfraLinkSelect();
+
+ if (sel == nullptr)
+ {
+ sel = SelectGeneric();
+ }
+#else
+ sel = SelectGeneric();
+#endif
+
+ return sel;
+}
+
+const char *InfraLinkSelector::SelectGeneric(void)
+{
+ const char * prevInfraLink = mCurrentInfraLink;
+ InfraLinkSelector::LinkState currentInfraLinkState = kInvalid;
+ auto now = Clock::now();
+ LinkInfo * currentInfraLinkInfo = nullptr;
+
+ VerifyOrExit(!mInfraLinkNames.empty(), mCurrentInfraLink = kDefaultInfraLinkName);
+ VerifyOrExit(mInfraLinkNames.size() > 1, mCurrentInfraLink = mInfraLinkNames.front());
+ VerifyOrExit(mRequireReselect, assert(mCurrentInfraLink != nullptr));
+
+ otbrLogInfo("Evaluating infra link among %zu netifs:", mInfraLinkNames.size());
+
+ // Prefer `mCurrentInfraLink` if it's up and running.
+ if (mCurrentInfraLink != nullptr)
+ {
+ currentInfraLinkInfo = &mInfraLinkInfos[mCurrentInfraLink];
+
+ otbrLogInfo("\tInfra link %s is in state %s", mCurrentInfraLink,
+ LinkStateToString(currentInfraLinkInfo->mState));
+
+ VerifyOrExit(currentInfraLinkInfo->mState != kUpAndRunning);
+ }
+
+ // Select an infra link with best state.
+ {
+ const char * bestInfraLink = mCurrentInfraLink;
+ InfraLinkSelector::LinkState bestState = currentInfraLinkState;
+
+ for (const char *name : mInfraLinkNames)
+ {
+ if (name != mCurrentInfraLink)
+ {
+ LinkInfo &linkInfo = mInfraLinkInfos[name];
+
+ otbrLogInfo("\tInfra link %s is in state %s", name, LinkStateToString(linkInfo.mState));
+ if (bestInfraLink == nullptr || linkInfo.mState > bestState)
+ {
+ bestInfraLink = name;
+ bestState = linkInfo.mState;
+ }
+ }
+ }
+
+ VerifyOrExit(bestInfraLink != mCurrentInfraLink);
+
+ // Prefer `mCurrentInfraLink` if no other infra link is up and running
+ VerifyOrExit(mCurrentInfraLink == nullptr || bestState == kUpAndRunning);
+
+ // Prefer `mCurrentInfraLink` if it's down for less than `kInfraLinkSelectionDelay`
+ if (mCurrentInfraLink != nullptr && currentInfraLinkInfo->mWasUpAndRunning)
+ {
+ Milliseconds timeSinceLastRunning =
+ std::chrono::duration_cast<Milliseconds>(now - currentInfraLinkInfo->mLastRunningTime);
+
+ if (timeSinceLastRunning < kInfraLinkSelectionDelay)
+ {
+ Milliseconds delay = kInfraLinkSelectionDelay - timeSinceLastRunning;
+
+ otbrLogInfo("Infra link %s was running %lldms ago, wait for %lldms to recheck.", mCurrentInfraLink,
+ timeSinceLastRunning.count(), delay.count());
+ mTaskRunner.Post(delay, [this]() { mRequireReselect = true; });
+ ExitNow();
+ }
+ }
+
+ // Current infra link changed.
+ mCurrentInfraLink = bestInfraLink;
+ }
+
+exit:
+ if (mRequireReselect)
+ {
+ mRequireReselect = false;
+
+ if (prevInfraLink != mCurrentInfraLink)
+ {
+ if (prevInfraLink == nullptr)
+ {
+ otbrLogNotice("Infra link selected: %s", mCurrentInfraLink);
+ }
+ else
+ {
+ otbrLogWarning("Infra link switched from %s to %s", prevInfraLink, mCurrentInfraLink);
+ }
+ }
+ else
+ {
+ otbrLogInfo("Infra link unchanged: %s", mCurrentInfraLink);
+ }
+ }
+
+ return mCurrentInfraLink;
+}
+
+InfraLinkSelector::LinkState InfraLinkSelector::QueryInfraLinkState(const char *aInfraLinkName)
+{
+ int sock = 0;
+ struct ifreq ifReq;
+ InfraLinkSelector::LinkState state = kInvalid;
+
+ sock = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_IP, kSocketBlock);
+ VerifyOrDie(sock != -1, "Failed to create AF_INET6 socket.");
+
+ memset(&ifReq, 0, sizeof(ifReq));
+ strncpy(ifReq.ifr_name, aInfraLinkName, sizeof(ifReq.ifr_name) - 1);
+
+ VerifyOrExit(ioctl(sock, SIOCGIFFLAGS, &ifReq) != -1);
+
+ state = (ifReq.ifr_flags & IFF_UP) ? ((ifReq.ifr_flags & IFF_RUNNING) ? kUpAndRunning : kUp) : kDown;
+
+exit:
+ if (sock != 0)
+ {
+ close(sock);
+ }
+
+ return state;
+}
+
+void InfraLinkSelector::Update(MainloopContext &aMainloop)
+{
+ if (mNetlinkSocket != -1)
+ {
+ FD_SET(mNetlinkSocket, &aMainloop.mReadFdSet);
+ aMainloop.mMaxFd = std::max(mNetlinkSocket, aMainloop.mMaxFd);
+ }
+}
+
+void InfraLinkSelector::Process(const MainloopContext &aMainloop)
+{
+ OTBR_UNUSED_VARIABLE(aMainloop);
+
+ if (mNetlinkSocket != -1 && FD_ISSET(mNetlinkSocket, &aMainloop.mReadFdSet))
+ {
+ ReceiveNetLinkMessage();
+ }
+}
+
+void InfraLinkSelector::ReceiveNetLinkMessage(void)
+{
+ const size_t kMaxNetLinkBufSize = 8192;
+ ssize_t len;
+ union
+ {
+ nlmsghdr mHeader;
+ uint8_t mBuffer[kMaxNetLinkBufSize];
+ } msgBuffer;
+
+ len = recv(mNetlinkSocket, msgBuffer.mBuffer, sizeof(msgBuffer.mBuffer), 0);
+ if (len < 0)
+ {
+ otbrLogWarning("Failed to receive netlink message: %s", strerror(errno));
+ ExitNow();
+ }
+
+ for (struct nlmsghdr *header = &msgBuffer.mHeader; NLMSG_OK(header, static_cast<size_t>(len));
+ header = NLMSG_NEXT(header, len))
+ {
+ struct ifinfomsg *ifinfo;
+
+ switch (header->nlmsg_type)
+ {
+ case RTM_NEWLINK:
+ case RTM_DELLINK:
+ ifinfo = reinterpret_cast<struct ifinfomsg *>(NLMSG_DATA(header));
+ HandleInfraLinkStateChange(ifinfo->ifi_index);
+ break;
+ case NLMSG_ERROR:
+ {
+ struct nlmsgerr *errMsg = reinterpret_cast<struct nlmsgerr *>(NLMSG_DATA(header));
+
+ otbrLogWarning("netlink NLMSG_ERROR response: seq=%u, error=%d", header->nlmsg_seq, errMsg->error);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+exit:
+ return;
+}
+
+void InfraLinkSelector::HandleInfraLinkStateChange(uint32_t aInfraLinkIndex)
+{
+ const char *infraLinkName = nullptr;
+
+ for (const char *name : mInfraLinkNames)
+ {
+ if (aInfraLinkIndex == if_nametoindex(name))
+ {
+ infraLinkName = name;
+ break;
+ }
+ }
+
+ VerifyOrExit(infraLinkName != nullptr);
+
+ {
+ LinkInfo &linkInfo = mInfraLinkInfos[infraLinkName];
+ LinkState prevState = linkInfo.mState;
+
+ if (linkInfo.Update(QueryInfraLinkState(infraLinkName)))
+ {
+ otbrLogInfo("Infra link name %s index %lu state changed: %s -> %s", infraLinkName, aInfraLinkIndex,
+ LinkStateToString(prevState), LinkStateToString(linkInfo.mState));
+ mRequireReselect = true;
+ }
+ }
+exit:
+ return;
+}
+
+const char *InfraLinkSelector::LinkStateToString(LinkState aState)
+{
+ const char *str = "";
+
+ switch (aState)
+ {
+ case kInvalid:
+ str = "INVALID";
+ break;
+ case kDown:
+ str = "DOWN";
+ break;
+ case kUp:
+ str = "UP";
+ break;
+ case kUpAndRunning:
+ str = "UP+RUNNING";
+ break;
+ }
+ return str;
+}
+
+} // namespace Utils
+} // namespace otbr
+
+#endif // __linux__
diff --git a/src/utils/infra_link_selector.hpp b/src/utils/infra_link_selector.hpp
new file mode 100644
index 00000000..250648e3
--- /dev/null
+++ b/src/utils/infra_link_selector.hpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2022, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file include definitions for the Infrastructure Link Selector.
+ */
+
+#ifndef INFRA_LINK_SELECTOR_HPP_
+#define INFRA_LINK_SELECTOR_HPP_
+
+#if __linux__
+
+#include <assert.h>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include <openthread/backbone_router_ftd.h>
+
+#include "common/code_utils.hpp"
+#include "common/mainloop.hpp"
+#include "common/task_runner.hpp"
+#include "common/time.hpp"
+
+#if OTBR_ENABLE_VENDOR_INFRA_LINK_SELECT
+/**
+ * This function implements platform specific rules for selecting infrastructure link.
+ *
+ * This function should return the infrastructure link that is selected by platform specific rules.
+ * If the function returns nullptr, the generic infrastructure link selections rules will be applied.
+ *
+ */
+extern "C" const char *otbrVendorInfraLinkSelect(void);
+#endif
+
+namespace otbr {
+namespace Utils {
+
+/**
+ * This class implements Infrastructure Link Selector.
+ *
+ */
+class InfraLinkSelector : public MainloopProcessor, private NonCopyable
+{
+public:
+ /**
+ * This constructor initializes the InfraLinkSelector instance.
+ *
+ * @param[in] aInfraLinkNames A list of infrastructure link candidates to select from.
+ *
+ */
+ explicit InfraLinkSelector(std::vector<const char *> aInfraLinkNames);
+
+ /**
+ * This destructor destroys the InfraLinkSelector instance.
+ *
+ */
+ ~InfraLinkSelector(void);
+
+ /**
+ * This method selects an infrastructure link among infrastructure link candidates using rules below:
+ *
+ * The infrastructure link in the most usable state is selected:
+ * Prefer `up and running` to `up`
+ * Prefer `up` to `down`
+ * Prefer `down` to `invalid`
+ * Once an interface is selected, it's preferred if either is true:
+ * The interface is still `up and running`
+ * No other interface is `up and running`
+ * The interface has been `up and running` within last 10 seconds
+ *
+ * @returns The selected infrastructure link.
+ *
+ */
+ const char *Select(void);
+
+private:
+ /**
+ * This enumeration infrastructure link states.
+ *
+ */
+ enum LinkState : uint8_t
+ {
+ kInvalid, ///< The infrastructure link is invalid.
+ kDown, ///< The infrastructure link is down.
+ kUp, ///< The infrastructure link is up, but not running.
+ kUpAndRunning, ///< The infrastructure link is up and running.
+
+ };
+
+ struct LinkInfo
+ {
+ LinkState mState = kInvalid;
+ Clock::time_point mLastRunningTime;
+ bool mWasUpAndRunning = false;
+
+ bool Update(LinkState aState);
+ };
+
+ static constexpr const char *kDefaultInfraLinkName = "";
+ static constexpr auto kInfraLinkSelectionDelay = Milliseconds(10000);
+
+ const char *SelectGeneric(void);
+
+ static const char *LinkStateToString(LinkState aState);
+ static LinkState QueryInfraLinkState(const char *aInfraLinkName);
+ void Update(MainloopContext &aMainloop) override;
+ void Process(const MainloopContext &aMainloop) override;
+ void ReceiveNetLinkMessage(void);
+ void HandleInfraLinkStateChange(uint32_t aInfraLinkIndex);
+
+ std::vector<const char *> mInfraLinkNames;
+ std::map<const char *, LinkInfo> mInfraLinkInfos;
+ int mNetlinkSocket = -1;
+ const char * mCurrentInfraLink = nullptr;
+ TaskRunner mTaskRunner;
+ bool mRequireReselect = true;
+};
+
+} // namespace Utils
+} // namespace otbr
+
+#endif // __linux__
+
+#endif // INFRA_LINK_SELECTOR_HPP_
diff --git a/src/utils/pskc.hpp b/src/utils/pskc.hpp
index ab92e7e9..3a037e6c 100644
--- a/src/utils/pskc.hpp
+++ b/src/utils/pskc.hpp
@@ -62,9 +62,9 @@ public:
/**
* This method computes the PSKc.
*
- * @param[in] aExtPanId a pointer to extended PAN ID.
- * @param[in] aNetworkName a pointer to network name.
- * @param[in] aPassphrase a pointer to passphrase.
+ * @param[in] aExtPanId A pointer to extended PAN ID.
+ * @param[in] aNetworkName A pointer to network name.
+ * @param[in] aPassphrase A pointer to passphrase.
*
* @returns The pointer to PSKc value.
*
diff --git a/src/utils/socket_utils.cpp b/src/utils/socket_utils.cpp
index 54b806c3..0bc1e606 100644
--- a/src/utils/socket_utils.cpp
+++ b/src/utils/socket_utils.cpp
@@ -28,6 +28,11 @@
#include "utils/socket_utils.hpp"
+#if __linux__
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#endif
+
#include "common/code_utils.hpp"
int SocketWithCloseExec(int aDomain, int aType, int aProtocol, SocketBlockOption aBlockOption)
@@ -55,3 +60,30 @@ exit:
return fd;
}
+
+#if __linux__
+int CreateNetLinkRouteSocket(uint32_t aNlGroups)
+{
+ int sock;
+ int rval = 0;
+ struct sockaddr_nl addr;
+
+ sock = SocketWithCloseExec(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, kSocketBlock);
+ VerifyOrExit(sock != -1);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ addr.nl_groups = aNlGroups; // e.g. RTMGRP_LINK | RTMGRP_IPV6_IFADDR;
+
+ rval = bind(sock, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr));
+
+exit:
+ if (rval != 0)
+ {
+ close(sock);
+ sock = -1;
+ }
+
+ return sock;
+}
+#endif
diff --git a/src/utils/socket_utils.hpp b/src/utils/socket_utils.hpp
index 0f591000..33986d3e 100644
--- a/src/utils/socket_utils.hpp
+++ b/src/utils/socket_utils.hpp
@@ -47,16 +47,26 @@ enum SocketBlockOption
/**
* This function creates a socket with SOCK_CLOEXEC flag set.
*
- * @param[in] aDomain The communication domain.
- * @param[in] aType The semantics of communication.
- * @param[in] aProtocol The protocol to use.
- * @param[in] aBlockOption Whether to add nonblock flags.
+ * @param[in] aDomain The communication domain.
+ * @param[in] aType The semantics of communication.
+ * @param[in] aProtocol The protocol to use.
+ * @param[in] aBlockOption Whether to add nonblock flags.
*
- * @returns The file descriptor of the created socket.
- *
- * @retval -1 Failed to create socket.
+ * @retval -1 Failed to create socket.
+ * @retval ... The file descriptor of the created socket.
*
*/
int SocketWithCloseExec(int aDomain, int aType, int aProtocol, SocketBlockOption aBlockOption);
+/**
+ * This function creates a Linux netlink NETLINK_ROUTE socket for receiving routing and link updates.
+ *
+ * @param[in] aNlGroups The netlink multicast groups to listen to.
+ *
+ * @retval -1 Failed to create the netlink socket.
+ * @retval ... The file descriptor of the created netlink socket.
+ *
+ */
+int CreateNetLinkRouteSocket(uint32_t aNlGroups);
+
#endif // OTBR_UTILS_SOCKET_UTILS_HPP_
diff --git a/src/utils/steering_data.hpp b/src/utils/steering_data.hpp
index b4e827e8..481b9a4d 100644
--- a/src/utils/steering_data.hpp
+++ b/src/utils/steering_data.hpp
@@ -57,7 +57,7 @@ public:
/**
* This method initializes the bloom filter.
*
- * @param[in] aLength Length of the bloom filter in bytes.
+ * @param[in] aLength The length of the bloom filter in bytes.
*
*/
void Init(uint8_t aLength);
@@ -77,7 +77,7 @@ public:
/**
* This method sets bit @p aBit.
*
- * @param[in] aBit The bit offset.
+ * @param[in] aBit The bit offset.
*
*/
void SetBit(uint8_t aBit) { mBloomFilter[mLength - 1 - (aBit / 8)] |= 1 << (aBit % 8); }
@@ -85,7 +85,7 @@ public:
/**
* This method computes the Bloom Filter.
*
- * @param[in] aJoinerId Extended address
+ * @param[in] aJoinerId Extended address
*
*/
void ComputeBloomFilter(const uint8_t *aJoinerId);
@@ -93,8 +93,8 @@ public:
/**
* This method computes joiner id from EUI64.
*
- * @param[in] aEui64 A pointer to EUI64.
- * @param[out] aJoinerId A pointer to receive joiner id. This pointer can be the same as @p aEui64.
+ * @param[in] aEui64 A pointer to EUI64.
+ * @param[out] aJoinerId A pointer to receive joiner id. This pointer can be the same as @p aEui64.
*
*/
static void ComputeJoinerId(const uint8_t *aEui64, uint8_t *aJoinerId);
diff --git a/src/utils/strcpy_utils.cpp b/src/utils/string_utils.cpp
index 3a13546d..bd48b99d 100644
--- a/src/utils/strcpy_utils.cpp
+++ b/src/utils/string_utils.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, The OpenThread Authors.
+ * Copyright (c) 2021, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,19 +26,29 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include "utils/strcpy_utils.hpp"
+#include "utils/string_utils.hpp"
+
+#include <algorithm>
#include "common/code_utils.hpp"
-int strcpy_safe(char *aDest, size_t aDestSize, const char *aSrc)
+namespace otbr {
+
+namespace StringUtils {
+
+bool EqualCaseInsensitive(const std::string &aString1, const std::string &aString2)
{
- int ret = 0;
- VerifyOrExit(aDest != nullptr, ret = -1);
- VerifyOrExit(aSrc != nullptr, ret = -1, aDest[0] = 0);
- VerifyOrExit(aDestSize > strnlen(aSrc, aDestSize), ret = -1, aDest[0] = 0);
+ return ToLowercase(aString1) == ToLowercase(aString2);
+}
- strncpy(aDest, aSrc, aDestSize);
+std::string ToLowercase(const std::string &aString)
+{
+ std::string ret = aString;
-exit:
+ std::transform(ret.begin(), ret.end(), ret.begin(), [](char c) { return std::tolower(c); });
return ret;
}
+
+} // namespace StringUtils
+
+} // namespace otbr
diff --git a/src/utils/strcpy_utils.hpp b/src/utils/string_utils.hpp
index 1637bb32..06255ead 100644
--- a/src/utils/strcpy_utils.hpp
+++ b/src/utils/string_utils.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019, The OpenThread Authors.
+ * Copyright (c) 2021, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,35 +28,44 @@
/**
* @file
- * This file includes definition for strcpy_safe().
+ * This file includes definition for string utilities.
*/
-#ifndef OTBR_UTILS_STRCPY_UTILS_HPP_
-#define OTBR_UTILS_STRCPY_UTILS_HPP_
+#ifndef OTBR_UTILS_STRING_UTILS_HPP_
+#define OTBR_UTILS_STRING_UTILS_HPP_
#include "openthread-br/config.h"
#include <string.h>
+#include <string>
-#ifdef __cplusplus
-extern "C" {
-#endif
+namespace otbr {
+
+namespace StringUtils {
+
+/**
+ * This function compares two strings in a case-insensitive manner.
+ *
+ * @param[in] aString1 The first string.
+ * @param[in] aString2 The second string.
+ *
+ * @returns Whether the two strings are equal in a case-insensitive manner.
+ *
+ */
+bool EqualCaseInsensitive(const std::string &aString1, const std::string &aString2);
/**
- * This method is a safe version of strcpy always ensuring last byte to be 0
- * If strlen(aSrc) >= n, the string will be truncated
+ * This function converts a given string to lowercase.
*
- * @param[out] aDest dest string
- * @param[in] aDestSize size of dest string buffer
- * @param[in] aSrc src string
+ * @param[in] aString The string to convert.
*
- * @returns 0 on success, -1 on error
+ * @returns A copy of @p aString with all letters converted to lowercase.
*
*/
-int strcpy_safe(char *aDest, size_t aDestSize, const char *aSrc);
+std::string ToLowercase(const std::string &aString);
+
+} // namespace StringUtils
-#ifdef __cplusplus
-}
-#endif
+} // namespace otbr
-#endif // OTBR_UTILS_STRCPY_UTILS_HPP_
+#endif // OTBR_UTILS_STRING_UTILS_HPP_
diff --git a/src/utils/thread_helper.cpp b/src/utils/thread_helper.cpp
index 9d5bf203..ecab9af1 100644
--- a/src/utils/thread_helper.cpp
+++ b/src/utils/thread_helper.cpp
@@ -26,7 +26,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#define OTBR_LOG_TAG "AGENT"
+#define OTBR_LOG_TAG "UTILS"
#include "utils/thread_helper.hpp"
@@ -92,8 +92,28 @@ void ThreadHelper::StateChangedCallback(otChangedFlags aFlags)
{
if (mAttachHandler != nullptr)
{
- mAttachHandler(OT_ERROR_NONE);
- mAttachHandler = nullptr;
+ if (mAttachPendingDatasetTlvs.mLength == 0)
+ {
+ AttachHandler handler = mAttachHandler;
+
+ mAttachHandler = nullptr;
+ handler(OT_ERROR_NONE, mAttachDelayMs);
+ }
+ else
+ {
+ otOperationalDataset emptyDataset = {};
+ otError error =
+ otDatasetSendMgmtPendingSet(mInstance, &emptyDataset, mAttachPendingDatasetTlvs.mTlvs,
+ mAttachPendingDatasetTlvs.mLength, MgmtSetResponseHandler, this);
+ if (error != OT_ERROR_NONE)
+ {
+ AttachHandler handler = mAttachHandler;
+
+ mAttachHandler = nullptr;
+ mAttachPendingDatasetTlvs = {};
+ handler(error, 0);
+ }
+ }
}
else if (mJoinerHandler != nullptr)
{
@@ -102,8 +122,46 @@ void ThreadHelper::StateChangedCallback(otChangedFlags aFlags)
}
}
}
+
+ if (aFlags & OT_CHANGED_ACTIVE_DATASET)
+ {
+ ActiveDatasetChangedCallback();
+ }
}
+void ThreadHelper::ActiveDatasetChangedCallback()
+{
+ otError error;
+ otOperationalDatasetTlvs datasetTlvs;
+
+ SuccessOrExit(error = otDatasetGetActiveTlvs(mInstance, &datasetTlvs));
+
+ for (const auto &handler : mActiveDatasetChangeHandlers)
+ {
+ handler(datasetTlvs);
+ }
+
+exit:
+ if (error != OT_ERROR_NONE)
+ {
+ otbrLogWarning("Error handling active dataset change: %s", otThreadErrorToString(error));
+ }
+}
+
+#if OTBR_ENABLE_DBUS_SERVER
+void ThreadHelper::OnUpdateMeshCopTxt(std::map<std::string, std::vector<uint8_t>> aUpdate)
+{
+ if (mUpdateMeshCopTxtHandler)
+ {
+ mUpdateMeshCopTxtHandler(std::move(aUpdate));
+ }
+ else
+ {
+ otbrLogErr("No UpdateMeshCopTxtHandler");
+ }
+}
+#endif
+
void ThreadHelper::AddDeviceRoleHandler(DeviceRoleHandler aHandler)
{
mDeviceRoleHandlers.emplace_back(aHandler);
@@ -131,6 +189,30 @@ exit:
}
}
+void ThreadHelper::EnergyScan(uint32_t aScanDuration, EnergyScanHandler aHandler)
+{
+ otError error = OT_ERROR_NONE;
+ uint32_t preferredChannels = otPlatRadioGetPreferredChannelMask(mInstance);
+
+ VerifyOrExit(aHandler != nullptr, error = OT_ERROR_BUSY);
+ VerifyOrExit(aScanDuration < UINT16_MAX, error = OT_ERROR_INVALID_ARGS);
+ mEnergyScanHandler = aHandler;
+ mEnergyScanResults.clear();
+
+ error = otLinkEnergyScan(mInstance, preferredChannels, static_cast<uint16_t>(aScanDuration),
+ &ThreadHelper::EnergyScanCallback, this);
+
+exit:
+ if (error != OT_ERROR_NONE)
+ {
+ if (aHandler)
+ {
+ mEnergyScanHandler(error, {});
+ }
+ mEnergyScanHandler = nullptr;
+ }
+}
+
void ThreadHelper::RandomFill(void *aBuf, size_t size)
{
std::uniform_int_distribution<> dist(0, UINT8_MAX);
@@ -164,6 +246,28 @@ void ThreadHelper::ActiveScanHandler(otActiveScanResult *aResult)
}
}
+void ThreadHelper::EnergyScanCallback(otEnergyScanResult *aResult, void *aThreadHelper)
+{
+ ThreadHelper *helper = static_cast<ThreadHelper *>(aThreadHelper);
+
+ helper->EnergyScanCallback(aResult);
+}
+
+void ThreadHelper::EnergyScanCallback(otEnergyScanResult *aResult)
+{
+ if (aResult == nullptr)
+ {
+ if (mEnergyScanHandler != nullptr)
+ {
+ mEnergyScanHandler(OT_ERROR_NONE, mEnergyScanResults);
+ }
+ }
+ else
+ {
+ mEnergyScanResults.push_back(*aResult);
+ }
+}
+
uint8_t ThreadHelper::RandomChannelFromChannelMask(uint32_t aChannelMask)
{
// 8 bit per byte
@@ -201,7 +305,7 @@ void ThreadHelper::Attach(const std::string & aNetworkName,
const std::vector<uint8_t> &aNetworkKey,
const std::vector<uint8_t> &aPSKc,
uint32_t aChannelMask,
- ResultHandler aHandler)
+ AttachHandler aHandler)
{
otError error = OT_ERROR_NONE;
@@ -278,6 +382,7 @@ void ThreadHelper::Attach(const std::string & aNetworkName,
SuccessOrExit(error = otThreadSetPskc(mInstance, &pskc));
SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
+ mAttachDelayMs = 0;
mAttachHandler = aHandler;
exit:
@@ -285,12 +390,12 @@ exit:
{
if (aHandler)
{
- aHandler(error);
+ aHandler(error, 0);
}
}
}
-void ThreadHelper::Attach(ResultHandler aHandler)
+void ThreadHelper::Attach(AttachHandler aHandler)
{
otError error = OT_ERROR_NONE;
@@ -308,7 +413,7 @@ exit:
{
if (aHandler)
{
- aHandler(error);
+ aHandler(error, 0);
}
}
}
@@ -419,7 +524,7 @@ void ThreadHelper::LogOpenThreadResult(const char *aAction, otError aError)
}
}
-void ThreadHelper::AttachAllNodesTo(const std::vector<uint8_t> &aDatasetTlvs, ResultHandler aHandler)
+void ThreadHelper::AttachAllNodesTo(const std::vector<uint8_t> &aDatasetTlvs, AttachHandler aHandler)
{
constexpr uint32_t kDelayTimerMilliseconds = 300 * 1000;
@@ -451,27 +556,6 @@ void ThreadHelper::AttachAllNodesTo(const std::vector<uint8_t> &aDatasetTlvs, Re
VerifyOrExit(dataset.mComponents.mIsSecurityPolicyPresent, error = OT_ERROR_INVALID_ARGS);
VerifyOrExit(dataset.mComponents.mIsChannelMaskPresent, error = OT_ERROR_INVALID_ARGS);
- if (role == OT_DEVICE_ROLE_DISABLED || role == OT_DEVICE_ROLE_DETACHED)
- {
- otOperationalDataset existingDataset;
-
- error = otDatasetGetActive(mInstance, &existingDataset);
- VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_NOT_FOUND);
-
- VerifyOrExit(error == OT_ERROR_NOT_FOUND, error = OT_ERROR_INVALID_STATE);
-
- SuccessOrExit(error = otDatasetSetActiveTlvs(mInstance, &datasetTlvs));
-
- if (!otIp6IsEnabled(mInstance))
- {
- SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
- }
- SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
-
- aHandler(OT_ERROR_NONE);
- ExitNow();
- }
-
VerifyOrExit(FindTlv(OT_MESHCOP_TLV_PENDINGTIMESTAMP, datasetTlvs.mTlvs, datasetTlvs.mLength) == nullptr &&
FindTlv(OT_MESHCOP_TLV_DELAYTIMER, datasetTlvs.mTlvs, datasetTlvs.mLength) == nullptr,
error = OT_ERROR_INVALID_ARGS);
@@ -497,14 +581,52 @@ void ThreadHelper::AttachAllNodesTo(const std::vector<uint8_t> &aDatasetTlvs, Re
datasetTlvs.mLength = reinterpret_cast<uint8_t *>(tlv->GetNext()) - datasetTlvs.mTlvs;
+ assert(datasetTlvs.mLength > 0);
+
+ if (role == OT_DEVICE_ROLE_DISABLED || role == OT_DEVICE_ROLE_DETACHED)
+ {
+ otOperationalDataset existingDataset;
+ bool hasActiveDataset;
+
+ error = otDatasetGetActive(mInstance, &existingDataset);
+ VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_NOT_FOUND);
+
+ hasActiveDataset = (error == OT_ERROR_NONE);
+
+ if (!hasActiveDataset)
+ {
+ SuccessOrExit(error = otDatasetSetActiveTlvs(mInstance, &datasetTlvs));
+ }
+
+ if (!otIp6IsEnabled(mInstance))
+ {
+ SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
+ }
+ SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
+
+ if (hasActiveDataset)
+ {
+ mAttachDelayMs = kDelayTimerMilliseconds;
+ mAttachPendingDatasetTlvs = datasetTlvs;
+ }
+ else
+ {
+ mAttachDelayMs = 0;
+ mAttachPendingDatasetTlvs = {};
+ }
+ mAttachHandler = aHandler;
+ ExitNow();
+ }
+
SuccessOrExit(error = otDatasetSendMgmtPendingSet(mInstance, &emptyDataset, datasetTlvs.mTlvs, datasetTlvs.mLength,
MgmtSetResponseHandler, this));
+ mAttachDelayMs = kDelayTimerMilliseconds;
mAttachHandler = aHandler;
exit:
if (error != OT_ERROR_NONE)
{
- aHandler(error);
+ aHandler(error, 0);
}
}
@@ -515,6 +637,9 @@ void ThreadHelper::MgmtSetResponseHandler(otError aResult, void *aContext)
void ThreadHelper::MgmtSetResponseHandler(otError aResult)
{
+ AttachHandler handler;
+ int64_t attachDelayMs;
+
LogOpenThreadResult("MgmtSetResponseHandler()", aResult);
assert(mAttachHandler != nullptr);
@@ -529,8 +654,19 @@ void ThreadHelper::MgmtSetResponseHandler(otError aResult)
break;
}
- mAttachHandler(aResult);
- mAttachHandler = nullptr;
+ attachDelayMs = mAttachDelayMs;
+ handler = mAttachHandler;
+ mAttachDelayMs = 0;
+ mAttachHandler = nullptr;
+ mAttachPendingDatasetTlvs = {};
+ if (aResult == OT_ERROR_NONE)
+ {
+ handler(aResult, attachDelayMs);
+ }
+ else
+ {
+ handler(aResult, 0);
+ }
}
#if OTBR_ENABLE_UNSECURE_JOIN
@@ -580,5 +716,10 @@ exit:
}
#endif
+void ThreadHelper::AddActiveDatasetChangeHandler(DatasetChangeHandler aHandler)
+{
+ mActiveDatasetChangeHandlers.push_back(std::move(aHandler));
+}
+
} // namespace agent
} // namespace otbr
diff --git a/src/utils/thread_helper.hpp b/src/utils/thread_helper.hpp
index aefa1961..159450a0 100644
--- a/src/utils/thread_helper.hpp
+++ b/src/utils/thread_helper.hpp
@@ -63,15 +63,19 @@ namespace agent {
class ThreadHelper
{
public:
- using DeviceRoleHandler = std::function<void(otDeviceRole)>;
- using ScanHandler = std::function<void(otError, const std::vector<otActiveScanResult> &)>;
- using ResultHandler = std::function<void(otError)>;
+ using DeviceRoleHandler = std::function<void(otDeviceRole)>;
+ using ScanHandler = std::function<void(otError, const std::vector<otActiveScanResult> &)>;
+ using EnergyScanHandler = std::function<void(otError, const std::vector<otEnergyScanResult> &)>;
+ using ResultHandler = std::function<void(otError)>;
+ using AttachHandler = std::function<void(otError, int64_t)>;
+ using UpdateMeshCopTxtHandler = std::function<void(std::map<std::string, std::vector<uint8_t>>)>;
+ using DatasetChangeHandler = std::function<void(const otOperationalDatasetTlvs &)>;
/**
* The constructor of a Thread helper.
*
- * @param[in] aInstance The Thread instance.
- * @param[in] aNcp The ncp controller.
+ * @param[in] aInstance The Thread instance.
+ * @param[in] aNcp The ncp controller.
*
*/
ThreadHelper(otInstance *aInstance, otbr::Ncp::ControllerOpenThread *aNcp);
@@ -79,16 +83,23 @@ public:
/**
* This method adds a callback for device role change.
*
- * @param[in] aHandler The device role handler.
+ * @param[in] aHandler The device role handler.
*
*/
void AddDeviceRoleHandler(DeviceRoleHandler aHandler);
/**
+ * This method adds a callback for active dataset change.
+ *
+ * @param[in] aHandler The active dataset change handler.
+ */
+ void AddActiveDatasetChangeHandler(DatasetChangeHandler aHandler);
+
+ /**
* This method permits unsecure join on port.
*
- * @param[in] aPort The port number.
- * @param[in] aSeconds The timeout to close the port, 0 for never close.
+ * @param[in] aPort The port number.
+ * @param[in] aSeconds The timeout to close the port, 0 for never close.
*
* @returns The error value of underlying OpenThread api calls.
*
@@ -98,23 +109,32 @@ public:
/**
* This method performs a Thread network scan.
*
- * @param[in] aHandler The scan result handler.
+ * @param[in] aHandler The scan result handler.
*
*/
void Scan(ScanHandler aHandler);
/**
+ * This method performs an IEEE 802.15.4 Energy Scan.
+ *
+ * @param[in] aScanDuration The duration for the scan, in milliseconds.
+ * @param[in] aHandler The scan result handler.
+ *
+ */
+ void EnergyScan(uint32_t aScanDuration, EnergyScanHandler aHandler);
+
+ /**
* This method attaches the device to the Thread network.
*
* @note The joiner start and the attach proccesses are exclusive
*
- * @param[in] aNetworkName The network name.
- * @param[in] aPanId The pan id, UINT16_MAX for random.
- * @param[in] aExtPanId The extended pan id, UINT64_MAX for random.
- * @param[in] aNetworkKey The network key, empty for random.
- * @param[in] aPSKc The pre-shared commissioner key, empty for random.
- * @param[in] aChannelMask A bitmask for valid channels, will random select one.
- * @param[in] aHandler The attach result handler.
+ * @param[in] aNetworkName The network name.
+ * @param[in] aPanId The pan id, UINT16_MAX for random.
+ * @param[in] aExtPanId The extended pan id, UINT64_MAX for random.
+ * @param[in] aNetworkKey The network key, empty for random.
+ * @param[in] aPSKc The pre-shared commissioner key, empty for random.
+ * @param[in] aChannelMask A bitmask for valid channels, will random select one.
+ * @param[in] aHandler The attach result handler.
*
*/
void Attach(const std::string & aNetworkName,
@@ -123,7 +143,7 @@ public:
const std::vector<uint8_t> &aNetworkKey,
const std::vector<uint8_t> &aPSKc,
uint32_t aChannelMask,
- ResultHandler aHandler);
+ AttachHandler aHandler);
/**
* This method detaches the device from the Thread network.
@@ -139,10 +159,10 @@ public:
* @note The joiner start and the attach proccesses are exclusive, and the
* network parameter will be set through the active dataset.
*
- * @param[in] aHandler The attach result handler.
+ * @param[in] aHandler The attach result handler.
*
*/
- void Attach(ResultHandler aHandler);
+ void Attach(AttachHandler aHandler);
/**
* This method makes all nodes in the current network attach to the network specified by the dataset TLVs.
@@ -151,7 +171,7 @@ public:
* @param[in] aHandler The result handler.
*
*/
- void AttachAllNodesTo(const std::vector<uint8_t> &aDatasetTlvs, ResultHandler aHandler);
+ void AttachAllNodesTo(const std::vector<uint8_t> &aDatasetTlvs, AttachHandler aHandler);
/**
* This method resets the OpenThread stack.
@@ -166,13 +186,13 @@ public:
*
* @note The joiner start and the attach proccesses are exclusive
*
- * @param[in] aPskd The pre-shared key for device.
- * @param[in] aProvisioningUrl The provision url.
- * @param[in] aVendorName The vendor name.
- * @param[in] aVendorModel The vendor model.
- * @param[in] aVendorSwVersion The vendor software version.
- * @param[in] aVendorData The vendor custom data.
- * @param[in] aHandler The join result handler.
+ * @param[in] aPskd The pre-shared key for device.
+ * @param[in] aProvisioningUrl The provision url.
+ * @param[in] aVendorName The vendor name.
+ * @param[in] aVendorModel The vendor model.
+ * @param[in] aVendorSwVersion The vendor software version.
+ * @param[in] aVendorData The vendor custom data.
+ * @param[in] aHandler The join result handler.
*
*/
void JoinerStart(const std::string &aPskd,
@@ -202,16 +222,37 @@ public:
/**
* This method handles OpenThread state changed notification.
*
- * @param[in] aFlags A bit-field indicating specific state that has changed. See `OT_CHANGED_*` definitions.
+ * @param[in] aFlags A bit-field indicating specific state that has changed. See `OT_CHANGED_*` definitions.
*
*/
void StateChangedCallback(otChangedFlags aFlags);
+#if OTBR_ENABLE_DBUS_SERVER
+ /**
+ * This method sets a callback for calls of UpdateVendorMeshCopTxtEntries D-Bus API.
+ *
+ * @param[in] aHandler The handler on MeshCoP TXT changes.
+ *
+ */
+ void SetUpdateMeshCopTxtHandler(UpdateMeshCopTxtHandler aHandler)
+ {
+ mUpdateMeshCopTxtHandler = std::move(aHandler);
+ }
+
+ /**
+ * This method handles MeshCoP TXT updates done by UpdateVendorMeshCopTxtEntries D-Bus API.
+ *
+ * @param[in] aUpdate The key-value pairs to be updated in the TXT record.
+ *
+ */
+ void OnUpdateMeshCopTxt(std::map<std::string, std::vector<uint8_t>> aUpdate);
+#endif
+
/**
* This method logs OpenThread action result.
*
- * @param[in] aAction The action OpenThread performs.
- * @param[in] aError The action result.
+ * @param[in] aAction The action OpenThread performs.
+ * @param[in] aError The action result.
*
*/
static void LogOpenThreadResult(const char *aAction, otError aError);
@@ -220,6 +261,9 @@ private:
static void ActiveScanHandler(otActiveScanResult *aResult, void *aThreadHelper);
void ActiveScanHandler(otActiveScanResult *aResult);
+ static void EnergyScanCallback(otEnergyScanResult *aResult, void *aThreadHelper);
+ void EnergyScanCallback(otEnergyScanResult *aResult);
+
static void JoinerCallback(otError aError, void *aThreadHelper);
void JoinerCallback(otError aResult);
@@ -229,21 +273,33 @@ private:
void RandomFill(void *aBuf, size_t size);
uint8_t RandomChannelFromChannelMask(uint32_t aChannelMask);
+ void ActiveDatasetChangedCallback();
+
otInstance *mInstance;
otbr::Ncp::ControllerOpenThread *mNcp;
ScanHandler mScanHandler;
std::vector<otActiveScanResult> mScanResults;
+ EnergyScanHandler mEnergyScanHandler;
+ std::vector<otEnergyScanResult> mEnergyScanResults;
- std::vector<DeviceRoleHandler> mDeviceRoleHandlers;
+ std::vector<DeviceRoleHandler> mDeviceRoleHandlers;
+ std::vector<DatasetChangeHandler> mActiveDatasetChangeHandlers;
std::map<uint16_t, size_t> mUnsecurePortRefCounter;
- ResultHandler mAttachHandler;
+ int64_t mAttachDelayMs = 0;
+ AttachHandler mAttachHandler;
ResultHandler mJoinerHandler;
+ otOperationalDatasetTlvs mAttachPendingDatasetTlvs = {};
+
std::random_device mRandomDevice;
+
+#if OTBR_ENABLE_DBUS_SERVER
+ UpdateMeshCopTxtHandler mUpdateMeshCopTxtHandler;
+#endif
};
} // namespace agent
diff --git a/src/web/web-service/frontend/index.html b/src/web/web-service/frontend/index.html
index ab2bc018..22976386 100644
--- a/src/web/web-service/frontend/index.html
+++ b/src/web/web-service/frontend/index.html
@@ -165,7 +165,7 @@
<input required md-maxlength="16" name="networkName" ng-model="thread.networkName">
<div ng-messages="threadForm.networkName.$error">
<div ng-message="required">This is required.</div>
- <div ng-message="md-maxlength">The Netowork Name must be no more than 16 characters long.</div>
+ <div ng-message="md-maxlength">The Network Name must be no more than 16 characters long.</div>
</div>
</md-input-container>
@@ -190,10 +190,11 @@
</md-input-container>
<md-input-container flex="50">
- <label>Passphrase</label>
- <input required name="passphrase" ng-model="thread.passphrase">
+ <label>Passphrase/Commissioner Credential</label>
+ <input required name="passphrase" ng-minlength="6" maxlength="255" ng-model="thread.passphrase">
<div ng-messages="threadForm.passphrase.$error">
<div ng-message="required">This is required.</div>
+ <div ng-message="minlength">The Passphrase must be a string between 6 and 255 characters.</div>
</div>
</md-input-container>
</div>
diff --git a/src/web/web-service/frontend/res/js/app.js b/src/web/web-service/frontend/res/js/app.js
index 37f551a0..87052007 100644
--- a/src/web/web-service/frontend/res/js/app.js
+++ b/src/web/web-service/frontend/res/js/app.js
@@ -93,7 +93,7 @@
networkName: 'OpenThreadDemo',
extPanId: '1111111122222222',
panId: '0x1234',
- passphrase: '123456',
+ passphrase: 'j01Nme',
networkKey: '00112233445566778899aabbccddeeff',
channel: 15,
prefix: 'fd11:22::',
@@ -130,7 +130,7 @@
$scope.menu[index].show = true;
if (index == 1) {
$scope.isLoading = true;
- $http.get('/available_network').then(function(response) {
+ $http.get('available_network').then(function(response) {
$scope.isLoading = false;
if (response.data.error == 0) {
$scope.networksInfo = response.data.result;
@@ -140,7 +140,7 @@
});
}
if (index == 3) {
- $http.get('/get_properties').then(function(response) {
+ $http.get('get_properties').then(function(response) {
console.log(response);
if (response.data.error == 0) {
var statusJson = response.data.result;
@@ -257,7 +257,7 @@
};
var httpRequest = $http({
method: 'POST',
- url: '/join_network',
+ url: 'join_network',
data: data,
});
@@ -277,7 +277,7 @@
$scope.qrcode = function() {
$scope.isLoading = false;
- $http.get('/get_qrcode').then(function(response) {
+ $http.get('get_qrcode').then(function(response) {
console.log(response);
$scope.res = response.data.result;
if (response.data.result == 'successful') {
@@ -323,7 +323,7 @@
$scope.isForming = true;
var httpRequest = $http({
method: 'POST',
- url: '/form_network',
+ url: 'form_network',
data: data,
});
@@ -371,7 +371,7 @@
};
var httpRequest = $http({
method: 'POST',
- url: '/add_prefix',
+ url: 'add_prefix',
data: data,
});
@@ -397,7 +397,7 @@
};
var httpRequest = $http({
method: 'POST',
- url: '/delete_prefix',
+ url: 'delete_prefix',
data: data,
});
@@ -416,7 +416,7 @@
};
var httpRequest = $http({
method: 'POST',
- url: '/commission',
+ url: 'commission',
data: data,
});
diff --git a/src/web/web-service/ot_client.cpp b/src/web/web-service/ot_client.cpp
index ef03e1e5..26351c90 100644
--- a/src/web/web-service/ot_client.cpp
+++ b/src/web/web-service/ot_client.cpp
@@ -39,13 +39,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "common/code_utils.hpp"
#include "common/logging.hpp"
-#include "utils/strcpy_utils.hpp"
// Temporary solution before posix platform header files are cleaned up.
#ifndef OPENTHREAD_POSIX_DAEMON_SOCKET_NAME
@@ -110,6 +110,32 @@ exit:
return ret == 0;
}
+void OpenThreadClient::DiscardRead(void)
+{
+ fd_set readFdSet;
+ timeval timeout = {0, 0};
+ ssize_t count;
+ int ret;
+
+ for (;;)
+ {
+ FD_ZERO(&readFdSet);
+ FD_SET(mSocket, &readFdSet);
+
+ ret = select(mSocket + 1, &readFdSet, nullptr, nullptr, &timeout);
+ if (ret <= 0)
+ {
+ break;
+ }
+
+ count = read(mSocket, mBuffer, sizeof(mBuffer));
+ if (count <= 0)
+ {
+ break;
+ }
+ }
+}
+
char *OpenThreadClient::Execute(const char *aFormat, ...)
{
va_list args;
@@ -118,6 +144,8 @@ char *OpenThreadClient::Execute(const char *aFormat, ...)
ssize_t count;
size_t rxLength = 0;
+ DiscardRead();
+
va_start(args, aFormat);
ret = vsnprintf(&mBuffer[1], sizeof(mBuffer) - 1, aFormat, args);
va_end(args);
@@ -227,7 +255,6 @@ int OpenThreadClient::Scan(WpanNetworkInfo *aNetworks, int aLength)
static const char kCliPrompt[] = "> ";
char * cliPrompt;
int matched;
- int joinable;
int lqi;
// remove prompt
@@ -243,23 +270,19 @@ int OpenThreadClient::Scan(WpanNetworkInfo *aNetworks, int aLength)
}
}
- matched = sscanf(result,
- "| %d | %s | %" PRIx64
- " | %hx | %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx | %hu | %hhd | %d |",
- &joinable, aNetworks[rval].mNetworkName, &aNetworks[rval].mExtPanId, &aNetworks[rval].mPanId,
- &aNetworks[rval].mHardwareAddress[0], &aNetworks[rval].mHardwareAddress[1],
- &aNetworks[rval].mHardwareAddress[2], &aNetworks[rval].mHardwareAddress[3],
- &aNetworks[rval].mHardwareAddress[4], &aNetworks[rval].mHardwareAddress[5],
- &aNetworks[rval].mHardwareAddress[6], &aNetworks[rval].mHardwareAddress[7],
- &aNetworks[rval].mChannel, &aNetworks[rval].mRssi, &lqi);
+ matched = sscanf(result, "| %hx | %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx | %hu | %hhd | %d |",
+ &aNetworks[rval].mPanId, &aNetworks[rval].mHardwareAddress[0],
+ &aNetworks[rval].mHardwareAddress[1], &aNetworks[rval].mHardwareAddress[2],
+ &aNetworks[rval].mHardwareAddress[3], &aNetworks[rval].mHardwareAddress[4],
+ &aNetworks[rval].mHardwareAddress[5], &aNetworks[rval].mHardwareAddress[6],
+ &aNetworks[rval].mHardwareAddress[7], &aNetworks[rval].mChannel, &aNetworks[rval].mRssi, &lqi);
// 15 is the number of output arguments of the last sscanf()
- if (matched != 15)
+ if (matched != 12)
{
continue;
}
- aNetworks[rval].mAllowingJoin = joinable != 0;
++rval;
}
diff --git a/src/web/web-service/ot_client.hpp b/src/web/web-service/ot_client.hpp
index 87ddaf50..c1ba5b98 100644
--- a/src/web/web-service/ot_client.hpp
+++ b/src/web/web-service/ot_client.hpp
@@ -70,7 +70,7 @@ public:
/**
* This constructor creates an OpenThread client.
*
- * @param[in] aNetifName The Thread network interface name.
+ * @param[in] aNetifName The Thread network interface name.
*
*/
OpenThreadClient(const char *aNetifName);
@@ -84,8 +84,8 @@ public:
/**
* This method connects to OpenThread daemon.
*
- * @retval true Successfully connected to the daemon.
- * @retval false Failed to connected to the daemon.
+ * @retval TRUE Successfully connected to the daemon.
+ * @retval FALSE Failed to connected to the daemon.
*
*/
bool Connect(void);
@@ -93,8 +93,8 @@ public:
/**
* This method executes OpenThread CLI.
*
- * @param[in] aFormat C style format string.
- * @param[in] ... C style format arguments.
+ * @param[in] aFormat C style format string.
+ * @param[in] ... C style format arguments.
*
* @returns A pointer to the output if succeeded, otherwise nullptr.
*
@@ -104,8 +104,8 @@ public:
/**
* This method reads from OpenThread CLI.
*
- * @param[in] aResponse The expected read response.
- * @param[in] aTimeout Timeout for the read, in ms.
+ * @param[in] aResponse The expected read response.
+ * @param[in] aTimeout Timeout for the read, in ms.
*
* @returns A pointer to the output if the expected response is found, otherwise nullptr.
*
@@ -115,8 +115,8 @@ public:
/**
* This method scans Thread network.
*
- * @param[out] aNetworks A pointer to the buffer to store network information.
- * @param[in] aLength Number of entries in @p aNetworks.
+ * @param[out] aNetworks A pointer to the buffer to store network information.
+ * @param[in] aLength Number of entries in @p aNetworks.
*
* @returns Number of entries found. 0 if none found.
*
@@ -131,6 +131,7 @@ public:
private:
void Disconnect(void);
+ void DiscardRead(void);
enum
{
diff --git a/src/web/web-service/web_server.cpp b/src/web/web-service/web_server.cpp
index f4baccd0..d1002b13 100644
--- a/src/web/web-service/web_server.cpp
+++ b/src/web/web-service/web_server.cpp
@@ -58,6 +58,7 @@
#define OT_RESPONSE_SUCCESS_STATUS "HTTP/1.1 200 OK\r\n"
#define OT_RESPONSE_HEADER_LENGTH "Content-Length: "
#define OT_RESPONSE_HEADER_CSS_TYPE "\r\nContent-Type: text/css"
+#define OT_RESPONSE_HEADER_TEXT_HTML_TYPE "\r\nContent-Type: text/html; charset=utf-8"
#define OT_RESPONSE_HEADER_TYPE "Content-Type: application/json\r\n charset=utf-8"
#define OT_RESPONSE_PLACEHOLD "\r\n\r\n"
#define OT_RESPONSE_FAILURE_STATUS "HTTP/1.1 400 Bad Request\r\n"
@@ -218,6 +219,7 @@ void WebServer::DefaultHttpResponse(void)
{
auto webRootPath = boost::filesystem::canonical(WEB_FILE_PATH);
auto path = boost::filesystem::canonical(webRootPath / request->path);
+
// Check if path is within webRootPath
if (std::distance(webRootPath.begin(), webRootPath.end()) > std::distance(path.begin(), path.end()) ||
!std::equal(webRootPath.begin(), webRootPath.end(), path.begin()))
@@ -238,10 +240,14 @@ void WebServer::DefaultHttpResponse(void)
auto ifs = std::make_shared<std::ifstream>();
ifs->open(path.string(), std::ifstream::in | std::ios::binary | std::ios::ate);
std::string extension = boost::filesystem::extension(path.string());
- std::string style = "";
+ std::string header = "";
if (extension == ".css")
{
- style = OT_RESPONSE_HEADER_CSS_TYPE;
+ header = OT_RESPONSE_HEADER_CSS_TYPE;
+ }
+ else if (extension == ".html")
+ {
+ header = OT_RESPONSE_HEADER_TEXT_HTML_TYPE;
}
if (*ifs)
@@ -250,7 +256,7 @@ void WebServer::DefaultHttpResponse(void)
ifs->seekg(0, std::ios::beg);
*response << OT_RESPONSE_SUCCESS_STATUS << cacheControl << etag << OT_RESPONSE_HEADER_LENGTH << length
- << style << OT_RESPONSE_PLACEHOLD;
+ << header << OT_RESPONSE_PLACEHOLD;
DefaultResourceSend(*mServer, response, ifs);
}
diff --git a/src/web/web-service/web_server.hpp b/src/web/web-service/web_server.hpp
index 21f74887..ec8f9c77 100644
--- a/src/web/web-service/web_server.hpp
+++ b/src/web/web-service/web_server.hpp
@@ -81,9 +81,9 @@ public:
/**
* This method starts the Web Server.
*
- * @param[in] aIfName The pointer to the Thread interface name.
- * @param[in] aListenAddr The http server listen address, can be nullptr for any address.
- * @param[in] aPort The port of http server.
+ * @param[in] aIfName The pointer to the Thread interface name.
+ * @param[in] aListenAddr The http server listen address, can be nullptr for any address.
+ * @param[in] aPort The port of http server.
*
*/
void StartWebServer(const char *aIfName, const char *aListenAddr, uint16_t aPort);
diff --git a/src/web/web-service/wpan_service.cpp b/src/web/web-service/wpan_service.cpp
index 44981956..d588bb67 100644
--- a/src/web/web-service/wpan_service.cpp
+++ b/src/web/web-service/wpan_service.cpp
@@ -480,13 +480,9 @@ std::string WpanService::HandleAvailableNetworkRequest()
for (int i = 0; i < mNetworksCount; i++)
{
- char extPanId[OT_EXTENDED_PANID_LENGTH * 2 + 1], panId[OT_PANID_LENGTH * 2 + 3],
- hardwareAddress[OT_HARDWARE_ADDRESS_LENGTH * 2 + 1];
- otbr::Utils::Long2Hex(bswap_64(mNetworks[i].mExtPanId), extPanId);
+ char panId[OT_PANID_LENGTH * 2 + 3], hardwareAddress[OT_HARDWARE_ADDRESS_LENGTH * 2 + 1];
otbr::Utils::Bytes2Hex(mNetworks[i].mHardwareAddress, OT_HARDWARE_ADDRESS_LENGTH, hardwareAddress);
sprintf(panId, "0x%X", mNetworks[i].mPanId);
- networkInfo[i]["nn"] = mNetworks[i].mNetworkName;
- networkInfo[i]["xp"] = extPanId;
networkInfo[i]["pi"] = panId;
networkInfo[i]["ch"] = mNetworks[i].mChannel;
networkInfo[i]["ha"] = hardwareAddress;
diff --git a/src/web/web-service/wpan_service.hpp b/src/web/web-service/wpan_service.hpp
index 569fc2d2..11af3096 100644
--- a/src/web/web-service/wpan_service.hpp
+++ b/src/web/web-service/wpan_service.hpp
@@ -148,7 +148,7 @@ public:
/**
* This method sets the Thread interface name.
*
- * @param[in] aIfName The pointer to the Thread interface name.
+ * @param[in] aIfName The pointer to the Thread interface name.
*
*/
void SetInterfaceName(const char *aIfName)
@@ -160,12 +160,12 @@ public:
/**
* This method gets status of wpan service.
*
- * @param[inout] aNetworkName The pointer to the network name.
- * @param[inout] aIfName The pointer to the extended PAN ID.
+ * @param[in,out] aNetworkName The pointer to the network name.
+ * @param[in,out] aIfName The pointer to the extended PAN ID.
*
- * @retval kWpanStatus_OK Successfully started the Thread service.
- * @retval kWpanStatus_Offline Not started the Thread service.
- * @retval kWpanStatus_Down The Thread service was down.
+ * @retval kWpanStatus_OK Successfully started the Thread service.
+ * @retval kWpanStatus_Offline Not started the Thread service.
+ * @retval kWpanStatus_Down The Thread service was down.
*
*/
int GetWpanServiceStatus(std::string &aNetworkName, std::string &aExtPanId) const;
@@ -173,8 +173,8 @@ public:
/**
* This method starts commissioner and wait for a device to join
*
- * @param[in] aPskd Joiner pskd
- * @param[in] aNetworkPassword Network password
+ * @param[in] aPskd Joiner pskd
+ * @param[in] aNetworkPassword Network password
*
* @returns The string to the http response of getting available networks.
*
diff --git a/tests/dbus/CMakeLists.txt b/tests/dbus/CMakeLists.txt
index 17882697..ae8e6417 100644
--- a/tests/dbus/CMakeLists.txt
+++ b/tests/dbus/CMakeLists.txt
@@ -53,4 +53,4 @@ add_test(
set_tests_properties(dbus-client PROPERTIES
ENVIRONMENT CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}
)
-set_tests_properties(dbus-client PROPERTIES TIMEOUT 420)
+set_tests_properties(dbus-client PROPERTIES TIMEOUT 1000)
diff --git a/tests/dbus/test-client b/tests/dbus/test-client
index a56893fe..da92b1db 100755
--- a/tests/dbus/test-client
+++ b/tests/dbus/test-client
@@ -41,6 +41,7 @@ on_exit()
sudo killall expect || true
sudo killall ot-cli-ftd || true
sudo killall ot-cli-mtd || true
+ sudo killall dbus-monitor || true
sudo rm "/etc/dbus-1/system.d/${OTBR_DBUS_SERVER_CONF}" || true
grep -iE 'ot-cli|otbr' </var/log/syslog
@@ -48,15 +49,110 @@ on_exit()
return "${status}"
}
+scan_meshcop_service()
+{
+ if command -v dns-sd; then
+ timeout 5 dns-sd -Z _meshcop._udp local. || true
+ else
+ avahi-browse -aprt || true
+ fi
+}
+
+update_meshcop_txt_and_check()
+{
+ sudo gdbus call --system --dest io.openthread.BorderRouter.wpan0 --method=io.openthread.BorderRouter.UpdateVendorMeshCopTxtEntries --object-path /io/openthread/BorderRouter/wpan0 "[('nn',[97])]" || true
+ sleep 5
+ service="$(scan_meshcop_service)"
+ grep --binary-files=text "nn=OpenThread" <<<"${service}"
+
+ sudo gdbus call --system --dest io.openthread.BorderRouter.wpan0 --method=io.openthread.BorderRouter.UpdateVendorMeshCopTxtEntries --object-path /io/openthread/BorderRouter/wpan0 "[('vn',[118,101,110,100,111,114])]"
+ sleep 5
+ service="$(scan_meshcop_service)"
+ grep --binary-files=text "vn=vendor" <<<"${service}"
+
+ sudo gdbus call --system --dest io.openthread.BorderRouter.wpan0 --method=io.openthread.BorderRouter.UpdateVendorMeshCopTxtEntries --object-path /io/openthread/BorderRouter/wpan0 "[]"
+ sleep 5
+ service="$(scan_meshcop_service)"
+ grep --binary-files=text "vn=OpenThread" <<<"${service}"
+
+ sudo gdbus call --system --dest io.openthread.BorderRouter.wpan0 --method=io.openthread.BorderRouter.UpdateVendorMeshCopTxtEntries --object-path /io/openthread/BorderRouter/wpan0 "[('A',[97,98,99]),('B',[49,50])]"
+ sleep 5
+ service="$(scan_meshcop_service)"
+ grep --binary-files=text "A=abc" <<<"${service}"
+ grep --binary-files=text "B=12" <<<"${service}"
+
+ sudo gdbus call --system --dest io.openthread.BorderRouter.wpan0 --method=io.openthread.BorderRouter.Reset --object-path /io/openthread/BorderRouter/wpan0
+ sleep 5
+ service="$(scan_meshcop_service)"
+ grep --binary-files=text "A=abc" <<<"${service}"
+ grep --binary-files=text "B=12" <<<"${service}"
+
+ sudo gdbus call --system --dest io.openthread.BorderRouter.wpan0 --method=io.openthread.BorderRouter.UpdateVendorMeshCopTxtEntries --object-path /io/openthread/BorderRouter/wpan0 "[('A',[97,99]),('B',[49,50])]"
+ sleep 5
+ service="$(scan_meshcop_service)"
+ grep --binary-files=text "A=ac" <<<"${service}"
+ grep --binary-files=text "B=12" <<<"${service}"
+}
+
main()
{
sudo rm -rf tmp
sudo install -m 644 "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent.conf /etc/dbus-1/system.d/"${OTBR_DBUS_SERVER_CONF}"
sudo service dbus reload
+ trap on_exit EXIT
sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent -d7 -I wpan0 --radio-version "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" | grep "OPENTHREAD"
+
+ local temp_dir
+ temp_dir=$(mktemp -d)
+
+ # Because we do want to run the command as root but redirect as the normal user.
+ # shellcheck disable=SC2024
+ sudo dbus-monitor --system path=/io/openthread/BorderRouter/wpan0,member=Ready >"${temp_dir}/dbus.out" &
+
+ sleep 1
+
sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent -d7 -I wpan0 "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" &
- trap on_exit EXIT
+ if ! (tail -f "${temp_dir}/dbus.out" &) | timeout 10s grep -q Ready; then
+ cat "${temp_dir}/dbus.out"
+ exit 1
+ fi
sleep 5
+
+ local ot_version
+ local rcp_version
+ local thread_version
+ ot_version=$(sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl version | grep -oE '^OPENTHREAD.*$' | tr -d '\r\n')
+ rcp_version=$(sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl rcp version | grep -oE '^OPENTHREAD.*$' | tr -d '\r\n')
+ thread_version=$(sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl thread version | grep -oE '^[0-9]+' | tr -d '\r\n')
+
+ local property_names="array:string:"
+ property_names+="OtHostVersion,"
+ property_names+="OtRcpVersion,"
+ property_names+="ThreadVersion,"
+ property_names+="Uptime,"
+ property_names+="RadioCoexMetrics,"
+ property_names+="RadioSpinelMetrics,"
+ property_names+="RcpInterfaceMetrics"
+ local result_pattern="\s+variant\s+string\s+\"${ot_version}\""
+ result_pattern+="\s+variant\s+string\s+\"${rcp_version}\""
+ result_pattern+="\s+variant\s+uint16\s+${thread_version}"
+ result_pattern+="\s+variant\s+uint64\s+\d+" # Uptime
+ result_pattern+="\s+variant\s+struct\s+{(\s+uint32\s+\d+){18}\s+boolean\s+(true|false)\s+}" # RadioCoexMetrics
+ result_pattern+="\s+variant\s+struct\s+{(\s+uint32\s+\d+){4}\s+}" # RadioSpinelMetrics
+ result_pattern+="\s+variant\s+struct\s+{\s+byte\s+\d+(\s+uint64\s+\d+){7}\s+}" # RcpInterfaceMetrics
+ sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --print-reply \
+ /io/openthread/BorderRouter/wpan0 \
+ io.openthread.BorderRouter.GetProperties \
+ "${property_names}" \
+ | grep -oPz "${result_pattern}"
+
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl ifconfig up
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl thread start
+
+ sleep 12
+
+ update_meshcop_txt_and_check
+
sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl factoryreset
sleep 1
sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \
@@ -67,6 +163,11 @@ main()
io.openthread.BorderRouter.JoinerStart \
string:ABCDEF string:mock string:mock \
string:mock string:mock string:mock 2>&1 || true) | grep NotFound
+
+ # Verify Eui64 property. 0x18b4300000000001 = 1780100529276321793
+ sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --print-reply /io/openthread/BorderRouter/wpan0 org.freedesktop.DBus.Properties.Get string:io.openthread.BorderRouter string:Eui64 \
+ | grep '1780100529276321793'
+
# The ot-cli-ftd node is used to test Thread attach.
expect <<EOF &
spawn ot-cli-ftd 3
@@ -80,7 +181,7 @@ send "ifconfig up\r\n"
expect "Done"
send "thread start\r\n"
expect "Done"
-sleep 5
+sleep 12
send "state\r\n"
expect "leader"
expect "Done"
@@ -111,7 +212,7 @@ expect "Done"
set timeout -1
expect eof
EOF
- sleep 5
+ sleep 12
sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \
--type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \
io.openthread.BorderRouter.JoinerStart \
@@ -149,11 +250,55 @@ EOF
dataset+="0x4f,0x70,0x65,0x6e,0x54,0x68,0x72,0x65,0x61,0x64,0x2d,0x30,0x36,0x62,0x37,0x01,"
dataset+="0x02,0x06,0xb7,0x04,0x10,0xf9,0xc9,0x1b,0x11,0x45,0x02,0x54,0x67,0xbf,0x11,0xed,"
dataset+="0xf9,0x01,0x1a,0x58,0x12,0x0c,0x04,0x02,0xa0,0xff,0xf8"
+
+ sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \
+ --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \
+ io.openthread.BorderRouter.AttachAllNodesTo \
+ "array:byte:${dataset}" \
+ | grep "int64 300000"
+
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl dataset pending | grep "Active Timestamp: 2"
+
+ sleep 310
+
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl dataset active | grep "Active Timestamp: 2"
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl networkkey | grep be3bd244ae6d997020a882a24a8040e2
+
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl factoryreset
+ sleep 1
+
+ sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \
+ --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \
+ io.openthread.BorderRouter.AttachAllNodesTo \
+ "array:byte:${dataset}" \
+ | grep "int64 0"
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl state | grep "leader"
+
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl factoryreset
+ sleep 1
+
+ sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \
+ --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \
+ io.openthread.BorderRouter.Attach \
+ array:byte: \
+ uint16:0xffff \
+ string:OpenThread \
+ uint64:0xffffffffffffffff \
+ array:byte: \
+ uint32:0xffffffff
+
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl state | grep "leader"
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl thread stop
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl state | grep "disabled"
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl dataset active | grep "Done"
+
sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \
--type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \
io.openthread.BorderRouter.AttachAllNodesTo \
- "array:byte:${dataset}"
+ "array:byte:${dataset}" \
+ | grep "int64 300000"
+ sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl state | grep "leader"
sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl dataset pending | grep "Active Timestamp: 2"
sleep 310
diff --git a/tests/dbus/test_dbus_client.cpp b/tests/dbus/test_dbus_client.cpp
index b31e17aa..8a625b1b 100644
--- a/tests/dbus/test_dbus_client.cpp
+++ b/tests/dbus/test_dbus_client.cpp
@@ -43,11 +43,18 @@
using otbr::DBus::ActiveScanResult;
using otbr::DBus::ClientError;
using otbr::DBus::DeviceRole;
+using otbr::DBus::EnergyScanResult;
using otbr::DBus::ExternalRoute;
using otbr::DBus::Ip6Prefix;
using otbr::DBus::LinkModeConfig;
using otbr::DBus::OnMeshPrefix;
+using otbr::DBus::SrpServerInfo;
using otbr::DBus::ThreadApiDBus;
+using otbr::DBus::TxtEntry;
+
+#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
+using otbr::DBus::DnssdCounters;
+#endif
#define TEST_ASSERT(x) \
do \
@@ -76,7 +83,7 @@ static bool operator==(const otbr::DBus::Ip6Prefix &aLhs, const otbr::DBus::Ip6P
static void CheckExternalRoute(ThreadApiDBus *aApi, const Ip6Prefix &aPrefix)
{
- ExternalRoute route;
+ ExternalRoute route = {};
std::vector<ExternalRoute> externalRouteTable;
route.mPrefix = aPrefix;
@@ -84,13 +91,97 @@ static void CheckExternalRoute(ThreadApiDBus *aApi, const Ip6Prefix &aPrefix)
route.mPreference = 0;
TEST_ASSERT(aApi->AddExternalRoute(route) == OTBR_ERROR_NONE);
+ sleep(10);
TEST_ASSERT(aApi->GetExternalRoutes(externalRouteTable) == OTBR_ERROR_NONE);
TEST_ASSERT(externalRouteTable.size() == 1);
TEST_ASSERT(externalRouteTable[0].mPrefix == aPrefix);
TEST_ASSERT(externalRouteTable[0].mPreference == 0);
TEST_ASSERT(externalRouteTable[0].mStable);
TEST_ASSERT(externalRouteTable[0].mNextHopIsThisDevice);
+
TEST_ASSERT(aApi->RemoveExternalRoute(aPrefix) == OTBR_ERROR_NONE);
+ sleep(10);
+ TEST_ASSERT(aApi->GetExternalRoutes(externalRouteTable) == OTBR_ERROR_NONE);
+ TEST_ASSERT(externalRouteTable.empty());
+}
+
+static void CheckOnMeshPrefix(ThreadApiDBus *aApi)
+{
+ OnMeshPrefix prefix = {};
+ std::vector<OnMeshPrefix> onMeshPrefixes;
+
+ prefix.mPrefix.mPrefix = {0xfd, 0xee, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
+ prefix.mPrefix.mLength = 64;
+
+ prefix.mPreference = 0;
+ prefix.mStable = true;
+
+ TEST_ASSERT(aApi->AddOnMeshPrefix(prefix) == OTBR_ERROR_NONE);
+ sleep(10);
+ TEST_ASSERT(aApi->GetOnMeshPrefixes(onMeshPrefixes) == OTBR_ERROR_NONE);
+ TEST_ASSERT(onMeshPrefixes.size() == 1);
+ TEST_ASSERT(onMeshPrefixes[0].mPrefix == prefix.mPrefix);
+ TEST_ASSERT(onMeshPrefixes[0].mPreference == 0);
+ TEST_ASSERT(onMeshPrefixes[0].mStable);
+
+ TEST_ASSERT(aApi->RemoveOnMeshPrefix(prefix.mPrefix) == OTBR_ERROR_NONE);
+ sleep(10);
+ TEST_ASSERT(aApi->GetOnMeshPrefixes(onMeshPrefixes) == OTBR_ERROR_NONE);
+ TEST_ASSERT(onMeshPrefixes.empty());
+}
+
+void CheckSrpServerInfo(ThreadApiDBus *aApi)
+{
+ SrpServerInfo srpServerInfo;
+
+ TEST_ASSERT(aApi->GetSrpServerInfo(srpServerInfo) == OTBR_ERROR_NONE);
+ TEST_ASSERT(srpServerInfo.mState == otbr::DBus::OTBR_SRP_SERVER_STATE_RUNNING);
+ TEST_ASSERT(srpServerInfo.mPort != 0);
+ TEST_ASSERT(srpServerInfo.mHosts.mFreshCount == 0);
+ TEST_ASSERT(srpServerInfo.mHosts.mDeletedCount == 0);
+ TEST_ASSERT(srpServerInfo.mHosts.mLeaseTimeTotal == 0);
+ TEST_ASSERT(srpServerInfo.mHosts.mKeyLeaseTimeTotal == 0);
+ TEST_ASSERT(srpServerInfo.mHosts.mRemainingLeaseTimeTotal == 0);
+ TEST_ASSERT(srpServerInfo.mHosts.mRemainingKeyLeaseTimeTotal == 0);
+ TEST_ASSERT(srpServerInfo.mServices.mFreshCount == 0);
+ TEST_ASSERT(srpServerInfo.mServices.mDeletedCount == 0);
+ TEST_ASSERT(srpServerInfo.mServices.mLeaseTimeTotal == 0);
+ TEST_ASSERT(srpServerInfo.mServices.mKeyLeaseTimeTotal == 0);
+ TEST_ASSERT(srpServerInfo.mServices.mRemainingLeaseTimeTotal == 0);
+ TEST_ASSERT(srpServerInfo.mServices.mRemainingKeyLeaseTimeTotal == 0);
+ TEST_ASSERT(srpServerInfo.mResponseCounters.mSuccess == 0);
+ TEST_ASSERT(srpServerInfo.mResponseCounters.mServerFailure == 0);
+ TEST_ASSERT(srpServerInfo.mResponseCounters.mFormatError == 0);
+ TEST_ASSERT(srpServerInfo.mResponseCounters.mNameExists == 0);
+ TEST_ASSERT(srpServerInfo.mResponseCounters.mRefused == 0);
+ TEST_ASSERT(srpServerInfo.mResponseCounters.mOther == 0);
+}
+
+void CheckDnssdCounters(ThreadApiDBus *aApi)
+{
+ OTBR_UNUSED_VARIABLE(aApi);
+#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
+ otbr::DBus::DnssdCounters dnssdCounters;
+
+ TEST_ASSERT(aApi->GetDnssdCounters(dnssdCounters) == OTBR_ERROR_NONE);
+ TEST_ASSERT(dnssdCounters.mSuccessResponse == 0);
+ TEST_ASSERT(dnssdCounters.mServerFailureResponse == 0);
+ TEST_ASSERT(dnssdCounters.mFormatErrorResponse == 0);
+ TEST_ASSERT(dnssdCounters.mNameErrorResponse == 0);
+ TEST_ASSERT(dnssdCounters.mNotImplementedResponse == 0);
+ TEST_ASSERT(dnssdCounters.mOtherResponse == 0);
+ TEST_ASSERT(dnssdCounters.mResolvedBySrp == 0);
+#endif
+}
+
+void CheckMdnsInfo(ThreadApiDBus *aApi)
+{
+ otbr::MdnsTelemetryInfo mdnsInfo;
+
+ TEST_ASSERT(aApi->GetMdnsTelemetryInfo(mdnsInfo) == OTBR_ERROR_NONE);
+
+ TEST_ASSERT(mdnsInfo.mServiceRegistrations.mSuccess > 0);
+ TEST_ASSERT(mdnsInfo.mServiceRegistrationEmaLatency > 0);
}
int main()
@@ -100,6 +191,8 @@ int main()
std::unique_ptr<ThreadApiDBus> api;
uint64_t extpanid = 0xdead00beaf00cafe;
std::string region;
+ uint32_t scanDuration = 1000; // 1s for each channel
+ bool stepDone = false;
dbus_error_init(&error);
connection = UniqueDBusConnection(dbus_bus_get(DBUS_BUS_SYSTEM, &error));
@@ -117,7 +210,25 @@ int main()
TEST_ASSERT(api->GetRadioRegion(region) == ClientError::ERROR_NONE);
TEST_ASSERT(region == "US");
- api->Scan([&api, extpanid](const std::vector<ActiveScanResult> &aResult) {
+ api->EnergyScan(scanDuration, [&stepDone](const std::vector<EnergyScanResult> &aResult) {
+ TEST_ASSERT(!aResult.empty());
+ printf("Energy Scan:\n");
+ for (auto &result : aResult)
+ {
+ printf("channel %d rssi %d\n", result.mChannel, result.mMaxRssi);
+ }
+
+ stepDone = true;
+ });
+
+ while (!stepDone)
+ {
+ dbus_connection_read_write_dispatch(connection.get(), 0);
+ }
+
+ stepDone = false;
+
+ api->Scan([&api, extpanid, &stepDone](const std::vector<ActiveScanResult> &aResult) {
LinkModeConfig cfg = {true, false, true};
std::vector<uint8_t> networkKey = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
@@ -125,7 +236,7 @@ int main()
for (auto &&result : aResult)
{
- printf("%s channel %d rssi %d\n", result.mNetworkName.c_str(), result.mChannel, result.mRssi);
+ printf("channel %d rssi %d\n", result.mChannel, result.mRssi);
}
api->SetLinkMode(cfg);
@@ -136,9 +247,9 @@ int main()
api->SetLinkMode(cfg);
api->Attach("Test", 0x3456, extpanid, networkKey, {}, 1 << channel,
- [&api, channel, extpanid](ClientError aError) {
+ [&api, channel, extpanid, &stepDone](ClientError aError) {
printf("Attach result %d\n", static_cast<int>(aError));
- sleep(10);
+ sleep(20);
uint64_t extpanidCheck;
std::vector<uint8_t> activeDataset;
@@ -174,6 +285,9 @@ int main()
TEST_ASSERT(api->GetInstantRssi(rssi) == OTBR_ERROR_NONE);
TEST_ASSERT(api->GetRadioTxPower(txPower) == OTBR_ERROR_NONE);
TEST_ASSERT(api->GetActiveDatasetTlvs(activeDataset) == OTBR_ERROR_NONE);
+ CheckSrpServerInfo(api.get());
+ CheckMdnsInfo(api.get());
+ CheckDnssdCounters(api.get());
api->FactoryReset(nullptr);
TEST_ASSERT(api->GetNetworkName(name) == OTBR_ERROR_NONE);
TEST_ASSERT(rloc16 != 0xffff);
@@ -187,22 +301,18 @@ int main()
exit(-1);
}
TEST_ASSERT(api->SetActiveDatasetTlvs(activeDataset) == OTBR_ERROR_NONE);
- api->Attach([&api, channel, extpanid](ClientError aErr) {
+ api->Attach([&api, channel, extpanid, &stepDone](ClientError aErr) {
uint8_t routerId;
otbr::DBus::LeaderData leaderData;
uint8_t leaderWeight;
uint16_t channelResult;
uint64_t extpanidCheck;
Ip6Prefix prefix;
- OnMeshPrefix onMeshPrefix = {};
+ std::vector<TxtEntry> updatedTxtEntries{TxtEntry{"B", {97, 98, 99}}};
prefix.mPrefix = {0xfd, 0xcd, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
prefix.mLength = 64;
- onMeshPrefix.mPrefix = prefix;
- onMeshPrefix.mPreference = 0;
- onMeshPrefix.mStable = true;
-
TEST_ASSERT(aErr == ClientError::ERROR_NONE);
TEST_ASSERT(api->GetChannel(channelResult) == OTBR_ERROR_NONE);
TEST_ASSERT(channelResult == channel);
@@ -214,29 +324,31 @@ int main()
TEST_ASSERT(api->GetRouterId(routerId) == OTBR_ERROR_NONE);
TEST_ASSERT(routerId == leaderData.mLeaderRouterId);
+ TEST_ASSERT(api->UpdateVendorMeshCopTxtEntries(updatedTxtEntries) == OTBR_ERROR_NONE);
+
CheckExternalRoute(api.get(), prefix);
- TEST_ASSERT(api->AddOnMeshPrefix(onMeshPrefix) == OTBR_ERROR_NONE);
- TEST_ASSERT(api->RemoveOnMeshPrefix(onMeshPrefix.mPrefix) == OTBR_ERROR_NONE);
+ CheckOnMeshPrefix(api.get());
api->FactoryReset(nullptr);
TEST_ASSERT(api->JoinerStart("ABCDEF", "", "", "", "", "", nullptr) ==
ClientError::OT_ERROR_NOT_FOUND);
- TEST_ASSERT(api->JoinerStart("ABCDEF", "", "", "", "", "", [&api](ClientError aJoinError) {
- DeviceRole deviceRole;
+ TEST_ASSERT(api->JoinerStart(
+ "ABCDEF", "", "", "", "", "", [&api, &stepDone](ClientError aJoinError) {
+ DeviceRole deviceRole;
- TEST_ASSERT(aJoinError == ClientError::OT_ERROR_NOT_FOUND);
+ TEST_ASSERT(aJoinError == ClientError::OT_ERROR_NOT_FOUND);
- api->FactoryReset(nullptr);
- api->GetDeviceRole(deviceRole);
- TEST_ASSERT(deviceRole == otbr::DBus::OTBR_DEVICE_ROLE_DISABLED);
+ api->FactoryReset(nullptr);
+ api->GetDeviceRole(deviceRole);
+ TEST_ASSERT(deviceRole == otbr::DBus::OTBR_DEVICE_ROLE_DISABLED);
- exit(0);
- }) == ClientError::ERROR_NONE);
+ stepDone = true;
+ }) == ClientError::ERROR_NONE);
});
});
});
- while (true)
+ while (!stepDone)
{
dbus_connection_read_write_dispatch(connection.get(), 0);
}
diff --git a/tests/mdns/main.cpp b/tests/mdns/main.cpp
index b81da384..295e0123 100644
--- a/tests/mdns/main.cpp
+++ b/tests/mdns/main.cpp
@@ -36,6 +36,8 @@
#include <netinet/in.h>
#include <signal.h>
+#include <vector>
+
#include "common/code_utils.hpp"
#include "common/logging.hpp"
#include "common/mainloop.hpp"
@@ -82,10 +84,10 @@ int RunMainloop(void)
void PublishSingleServiceWithCustomHost(void *aContext, Mdns::Publisher::State aState)
{
- uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
- uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
- uint8_t hostAddr[16] = {0};
- const char hostName[] = "custom-host";
+ uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+ uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+ std::vector<uint8_t> hostAddr(16, 0);
+ const char hostName[] = "custom-host";
hostAddr[0] = 0x20;
hostAddr[1] = 0x02;
@@ -94,26 +96,25 @@ void PublishSingleServiceWithCustomHost(void *aContext, Mdns::Publisher::State a
VerifyOrDie(aContext == &sContext, "unexpected context");
if (aState == Mdns::Publisher::State::kReady)
{
- otbrError error;
Mdns::Publisher::TxtList txtList{
- {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"dd", extAddr, sizeof(extAddr)}};
+ {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}};
- error = sContext.mPublisher->PublishHost(hostName, hostAddr, sizeof(hostAddr));
- SuccessOrDie(error, "cannot publish the host");
+ sContext.mPublisher->PublishHost(hostName, hostAddr,
+ [](otbrError aError) { SuccessOrDie(aError, "cannot publish the host"); });
- error = sContext.mPublisher->PublishService(hostName, 12345, "SingleService", "_meshcop._udp.",
- Mdns::Publisher::SubTypeList{}, txtList);
- SuccessOrDie(error, "cannot publish the service");
+ sContext.mPublisher->PublishService(
+ hostName, "SingleService", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList,
+ [](otbrError aError) { SuccessOrDie(aError, "cannot publish the service"); });
}
}
void PublishMultipleServicesWithCustomHost(void *aContext, Mdns::Publisher::State aState)
{
- uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
- uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
- uint8_t hostAddr[16] = {0};
- const char hostName1[] = "custom-host-1";
- const char hostName2[] = "custom-host-2";
+ uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+ uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+ std::vector<uint8_t> hostAddr(16, 0);
+ const char hostName1[] = "custom-host-1";
+ const char hostName2[] = "custom-host-2";
hostAddr[0] = 0x20;
hostAddr[1] = 0x02;
@@ -122,139 +123,132 @@ void PublishMultipleServicesWithCustomHost(void *aContext, Mdns::Publisher::Stat
VerifyOrDie(aContext == &sContext, "unexpected context");
if (aState == Mdns::Publisher::State::kReady)
{
- otbrError error;
Mdns::Publisher::TxtList txtList{
- {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"dd", extAddr, sizeof(extAddr)}};
+ {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}};
- error = sContext.mPublisher->PublishHost(hostName1, hostAddr, sizeof(hostAddr));
- SuccessOrDie(error, "cannot publish the first host");
+ sContext.mPublisher->PublishHost(hostName1, hostAddr,
+ [](otbrError aError) { SuccessOrDie(aError, "cannot publish the host"); });
- error = sContext.mPublisher->PublishService(hostName1, 12345, "MultipleService11", "_meshcop._udp.",
- Mdns::Publisher::SubTypeList{}, txtList);
- SuccessOrDie(error, "cannot publish the first service");
+ sContext.mPublisher->PublishService(
+ hostName1, "MultipleService11", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList,
+ [](otbrError aError) { SuccessOrDie(aError, "cannot publish the first service"); });
- error = sContext.mPublisher->PublishService(hostName1, 12345, "MultipleService12", "_meshcop._udp.",
- Mdns::Publisher::SubTypeList{}, txtList);
- SuccessOrDie(error, "cannot publish the second service");
+ sContext.mPublisher->PublishService(
+ hostName1, "MultipleService12", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList,
+ [](otbrError aError) { SuccessOrDie(aError, "cannot publish the second service"); });
- error = sContext.mPublisher->PublishHost(hostName2, hostAddr, sizeof(hostAddr));
- SuccessOrDie(error, "cannot publish the second host");
+ sContext.mPublisher->PublishHost(
+ hostName2, hostAddr, [](otbrError aError) { SuccessOrDie(aError, "cannot publish the second host"); });
- error = sContext.mPublisher->PublishService(hostName2, 12345, "MultipleService21", "_meshcop._udp.",
- Mdns::Publisher::SubTypeList{}, txtList);
- SuccessOrDie(error, "cannot publish the first service");
+ sContext.mPublisher->PublishService(
+ hostName2, "MultipleService21", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList,
+ [](otbrError aError) { SuccessOrDie(aError, "cannot publish the first service"); });
- error = sContext.mPublisher->PublishService(hostName2, 12345, "MultipleService22", "_meshcop._udp.",
- Mdns::Publisher::SubTypeList{}, txtList);
- SuccessOrDie(error, "cannot publish the second service");
+ sContext.mPublisher->PublishService(
+ hostName2, "MultipleService22", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList,
+ [](otbrError aError) { SuccessOrDie(aError, "cannot publish the second service"); });
}
}
void PublishSingleService(void *aContext, Mdns::Publisher::State aState)
{
+ OT_UNUSED_VARIABLE(aContext);
+
uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
Mdns::Publisher::TxtList txtList{
- {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"dd", extAddr, sizeof(extAddr)}};
+ {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}};
assert(aContext == &sContext);
if (aState == Mdns::Publisher::State::kReady)
{
- otbrError error = sContext.mPublisher->PublishService(nullptr, 12345, "SingleService", "_meshcop._udp.",
- Mdns::Publisher::SubTypeList{}, txtList);
- assert(error == OTBR_ERROR_NONE);
+ sContext.mPublisher->PublishService(
+ "", "SingleService", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList,
+ [](otbrError aError) { SuccessOrDie(aError, "SingleService._meshcop._udp."); });
}
}
void PublishMultipleServices(void *aContext, Mdns::Publisher::State aState)
{
+ OT_UNUSED_VARIABLE(aContext);
+
uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
assert(aContext == &sContext);
if (aState == Mdns::Publisher::State::kReady)
{
- otbrError error;
Mdns::Publisher::TxtList txtList{
- {"nn", "cool1"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"dd", extAddr, sizeof(extAddr)}};
+ {"nn", "cool1"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}};
- error = sContext.mPublisher->PublishService(nullptr, 12345, "MultipleService1", "_meshcop._udp.",
- Mdns::Publisher::SubTypeList{}, txtList);
- assert(error == OTBR_ERROR_NONE);
+ sContext.mPublisher->PublishService(
+ "", "MultipleService1", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList,
+ [](otbrError aError) { SuccessOrDie(aError, "MultipleService1._meshcop._udp."); });
}
if (aState == Mdns::Publisher::State::kReady)
{
- otbrError error;
Mdns::Publisher::TxtList txtList{
- {"nn", "cool2"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"dd", extAddr, sizeof(extAddr)}};
+ {"nn", "cool2"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}};
- error = sContext.mPublisher->PublishService(nullptr, 12345, "MultipleService2", "_meshcop._udp.",
- Mdns::Publisher::SubTypeList{}, txtList);
- assert(error == OTBR_ERROR_NONE);
+ sContext.mPublisher->PublishService(
+ "", "MultipleService2", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList,
+ [](otbrError aError) { SuccessOrDie(aError, "MultipleService2._meshcop._udp."); });
}
}
-void PublishUpdateServices(void *aContext, Mdns::Publisher::State aState)
+void PublishUpdateServices(void *aContext)
{
+ OT_UNUSED_VARIABLE(aContext);
+
uint8_t xpanidOld[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
uint8_t xpanidNew[kSizeExtPanId] = {0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41};
uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
assert(aContext == &sContext);
- if (aState == Mdns::Publisher::State::kReady)
+ if (!sContext.mUpdate)
{
- otbrError error;
-
- if (!sContext.mUpdate)
- {
- Mdns::Publisher::TxtList txtList{{"nn", "cool"},
- {"xp", xpanidOld, sizeof(xpanidOld)},
- {"tv", "1.1.1"},
- {"dd", extAddr, sizeof(extAddr)}};
-
- error = sContext.mPublisher->PublishService(nullptr, 12345, "UpdateService", "_meshcop._udp.",
- Mdns::Publisher::SubTypeList{}, txtList);
- }
- else
- {
- Mdns::Publisher::TxtList txtList{{"nn", "coolcool"},
- {"xp", xpanidNew, sizeof(xpanidNew)},
- {"tv", "1.1.1"},
- {"dd", extAddr, sizeof(extAddr)}};
+ Mdns::Publisher::TxtList txtList{
+ {"nn", "cool"}, {"xp", xpanidOld, sizeof(xpanidOld)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}};
- error = sContext.mPublisher->PublishService(nullptr, 12345, "UpdateService", "_meshcop._udp.",
- Mdns::Publisher::SubTypeList{}, txtList);
- }
- assert(error == OTBR_ERROR_NONE);
+ sContext.mPublisher->PublishService(
+ "", "UpdateService", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList,
+ [](otbrError aError) { otbrLogResult(aError, "UpdateService._meshcop._udp"); });
+ }
+ else
+ {
+ Mdns::Publisher::TxtList txtList{{"nn", "coolcool"},
+ {"xp", xpanidNew, sizeof(xpanidNew)},
+ {"tv", "1.1.1"},
+ {"xa", extAddr, sizeof(extAddr)}};
+
+ sContext.mPublisher->PublishService(
+ "", "UpdateService", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList,
+ [](otbrError aError) { SuccessOrDie(aError, "UpdateService._meshcop._udp"); });
}
}
-void PublishServiceSubTypes(void *aContext, Mdns::Publisher::State aState)
+void PublishServiceSubTypes(void *aContext)
{
+ OT_UNUSED_VARIABLE(aContext);
+
assert(aContext == &sContext);
- if (aState == Mdns::Publisher::State::kReady)
- {
- otbrError error;
- Mdns::Publisher::SubTypeList subTypeList{"_subtype1", "_SUBTYPE2"};
- if (sContext.mUpdate)
- {
- subTypeList.back() = "_SUBTYPE3";
- }
+ Mdns::Publisher::SubTypeList subTypeList{"_subtype1", "_SUBTYPE2"};
- error = sContext.mPublisher->PublishService(nullptr, 12345, "ServiceWithSubTypes", "_meshcop._udp.",
- subTypeList, Mdns::Publisher::TxtList{});
- assert(error == OTBR_ERROR_NONE);
- }
+ subTypeList.back() = "_SUBTYPE3";
+
+ sContext.mPublisher->PublishService(
+ "", "ServiceWithSubTypes", "_meshcop._udp.", subTypeList, 12345, Mdns::Publisher::TxtList{},
+ [](otbrError aError) { SuccessOrDie(aError, "ServiceWithSubTypes._meshcop._udp."); });
}
otbrError TestSingleServiceWithCustomHost(void)
{
otbrError error = OTBR_ERROR_NONE;
- Mdns::Publisher *pub =
- Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishSingleServiceWithCustomHost, &sContext);
+ Mdns::Publisher *pub = Mdns::Publisher::Create(
+ [](Mdns::Publisher::State aState) { PublishSingleServiceWithCustomHost(&sContext, aState); });
sContext.mPublisher = pub;
SuccessOrExit(error = pub->Start());
RunMainloop();
@@ -268,8 +262,8 @@ otbrError TestMultipleServicesWithCustomHost(void)
{
otbrError error = OTBR_ERROR_NONE;
- Mdns::Publisher *pub =
- Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishMultipleServicesWithCustomHost, &sContext);
+ Mdns::Publisher *pub = Mdns::Publisher::Create(
+ [](Mdns::Publisher::State aState) { PublishMultipleServicesWithCustomHost(&sContext, aState); });
sContext.mPublisher = pub;
SuccessOrExit(error = pub->Start());
RunMainloop();
@@ -283,8 +277,9 @@ otbrError TestSingleService(void)
{
otbrError ret = OTBR_ERROR_NONE;
- Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishSingleService, &sContext);
- sContext.mPublisher = pub;
+ Mdns::Publisher *pub =
+ Mdns::Publisher::Create([](Mdns::Publisher::State aState) { PublishSingleService(&sContext, aState); });
+ sContext.mPublisher = pub;
SuccessOrExit(ret = pub->Start());
RunMainloop();
@@ -298,7 +293,7 @@ otbrError TestMultipleServices(void)
otbrError ret = OTBR_ERROR_NONE;
Mdns::Publisher *pub =
- Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishMultipleServices, &sContext);
+ Mdns::Publisher::Create([](Mdns::Publisher::State aState) { PublishMultipleServices(&sContext, aState); });
sContext.mPublisher = pub;
SuccessOrExit(ret = pub->Start());
RunMainloop();
@@ -312,12 +307,17 @@ otbrError TestUpdateService(void)
{
otbrError ret = OTBR_ERROR_NONE;
- Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishUpdateServices, &sContext);
+ Mdns::Publisher *pub = Mdns::Publisher::Create([](Mdns::Publisher::State aState) {
+ if (aState == Mdns::Publisher::State::kReady)
+ {
+ sContext.mUpdate = false;
+ PublishUpdateServices(&sContext);
+ sContext.mUpdate = true;
+ PublishUpdateServices(&sContext);
+ }
+ });
sContext.mPublisher = pub;
- sContext.mUpdate = false;
SuccessOrExit(ret = pub->Start());
- sContext.mUpdate = true;
- PublishUpdateServices(&sContext, Mdns::Publisher::State::kReady);
RunMainloop();
exit:
@@ -329,12 +329,14 @@ otbrError TestServiceSubTypes(void)
{
otbrError ret = OTBR_ERROR_NONE;
- Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishServiceSubTypes, &sContext);
+ Mdns::Publisher *pub = Mdns::Publisher::Create([](Mdns::Publisher::State aState) {
+ if (aState == Mdns::Publisher::State::kReady)
+ {
+ PublishServiceSubTypes(&sContext);
+ }
+ });
sContext.mPublisher = pub;
- sContext.mUpdate = false;
SuccessOrExit(ret = pub->Start());
- sContext.mUpdate = true;
- PublishServiceSubTypes(&sContext, Mdns::Publisher::State::kReady);
RunMainloop();
exit:
@@ -358,8 +360,9 @@ otbrError TestStopService(void)
{
otbrError ret = OTBR_ERROR_NONE;
- Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishSingleService, &sContext);
- sContext.mPublisher = pub;
+ Mdns::Publisher *pub =
+ Mdns::Publisher::Create([](Mdns::Publisher::State aState) { PublishSingleService(&sContext, aState); });
+ sContext.mPublisher = pub;
SuccessOrExit(ret = pub->Start());
signal(SIGUSR1, RecoverSignal);
signal(SIGUSR2, RecoverSignal);
diff --git a/tests/mdns/test-multiple b/tests/mdns/test-multiple
index f023ed24..5ddbc54c 100755
--- a/tests/mdns/test-multiple
+++ b/tests/mdns/test-multiple
@@ -40,11 +40,11 @@ main()
if [[ ${OTBR_MDNS} == 'mDNSResponder' ]]; then
# dns-sd will not exit
- dns_sd_check MultipleService1 _meshcop._udp 'nn=cool1 xp=ABCDEFGH tv=1.1.1 dd=ABCDEFGH'
- dns_sd_check MultipleService2 _meshcop._udp 'nn=cool2 xp=ABCDEFGH tv=1.1.1 dd=ABCDEFGH'
+ dns_sd_check MultipleService1 _meshcop._udp 'nn=cool1 xp=ABCDEFGH tv=1.1.1 xa=ABCDEFGH'
+ dns_sd_check MultipleService2 _meshcop._udp 'nn=cool2 xp=ABCDEFGH tv=1.1.1 xa=ABCDEFGH'
else
- avahi_check 'MultipleService1;_meshcop._udp;.\+"dd=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=ABCDEFGH.\+"nn=cool1"'
- avahi_check 'MultipleService2;_meshcop._udp;.\+"dd=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=ABCDEFGH.\+"nn=cool2"'
+ avahi_check 'MultipleService1;_meshcop._udp;.\+"xa=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=ABCDEFGH.\+"nn=cool1"'
+ avahi_check 'MultipleService2;_meshcop._udp;.\+"xa=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=ABCDEFGH.\+"nn=cool2"'
fi
}
diff --git a/tests/mdns/test-single b/tests/mdns/test-single
index 4e38ee20..82047ff6 100755
--- a/tests/mdns/test-single
+++ b/tests/mdns/test-single
@@ -39,9 +39,9 @@ main()
start_publisher s
if [[ ${OTBR_MDNS} == 'mDNSResponder' ]]; then
- dns_sd_check SingleService _meshcop._udp 'nn=cool xp=ABCDEFGH tv=1.1.1 dd=ABCDEFGH'
+ dns_sd_check SingleService _meshcop._udp 'nn=cool xp=ABCDEFGH tv=1.1.1 xa=ABCDEFGH'
else
- avahi_check 'SingleService;_meshcop._udp;.\+"dd=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=ABCDEFGH.\+"nn=cool"'
+ avahi_check 'SingleService;_meshcop._udp;.\+"xa=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=ABCDEFGH.\+"nn=cool"'
fi
}
diff --git a/tests/mdns/test-stop b/tests/mdns/test-stop
index 4c808145..57204cac 100755
--- a/tests/mdns/test-stop
+++ b/tests/mdns/test-stop
@@ -39,28 +39,28 @@ main()
start_publisher k
if [[ ${OTBR_MDNS} == 'mDNSResponder' ]]; then
- dns_sd_check SingleService _meshcop._udp 'nn=cool xp=ABCDEFGH tv=1.1.1 dd=ABCDEFGH'
+ dns_sd_check SingleService _meshcop._udp 'nn=cool xp=ABCDEFGH tv=1.1.1 xa=ABCDEFGH'
else
- avahi_check 'SingleService;_meshcop._udp;.\+"dd=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=ABCDEFGH.\+"nn=cool"'
+ avahi_check 'SingleService;_meshcop._udp;.\+"xa=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=ABCDEFGH.\+"nn=cool"'
fi
# stop service
/bin/kill -USR1 $PID
if [[ ${OTBR_MDNS} == 'mDNSResponder' ]]; then
sleep 200
- (! dns_sd_check SingleService _meshcop._udp 'nn=cool xp=ABCDEFGH tv=1.1.1 dd=ABCDEFGH') || exit 1
+ (! dns_sd_check SingleService _meshcop._udp 'nn=cool xp=ABCDEFGH tv=1.1.1 xa=ABCDEFGH') || exit 1
else
sleep 1
- (! avahi_check 'SingleService;_meshcop._udp;.\+"dd=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=ABCDEFGH.\+"nn=cool"') || exit 1
+ (! avahi_check 'SingleService;_meshcop._udp;.\+"xa=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=ABCDEFGH.\+"nn=cool"') || exit 1
fi
# start service
/bin/kill -USR2 $PID
sleep 1
if [[ ${OTBR_MDNS} == 'mDNSResponder' ]]; then
- dns_sd_check SingleService _meshcop._udp 'nn=cool xp=ABCDEFGH tv=1.1.1 dd=ABCDEFGH'
+ dns_sd_check SingleService _meshcop._udp 'nn=cool xp=ABCDEFGH tv=1.1.1 xa=ABCDEFGH'
else
- avahi_check 'SingleService;_meshcop._udp;.\+"dd=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=ABCDEFGH.\+"nn=cool"'
+ avahi_check 'SingleService;_meshcop._udp;.\+"xa=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=ABCDEFGH.\+"nn=cool"'
fi
}
diff --git a/tests/mdns/test-update b/tests/mdns/test-update
index 34407794..1f367ab8 100755
--- a/tests/mdns/test-update
+++ b/tests/mdns/test-update
@@ -39,9 +39,9 @@ main()
start_publisher u
if [[ ${OTBR_MDNS} == 'mDNSResponder' ]]; then
- dns_sd_check UpdateService _meshcop._udp 'nn=coolcool xp=HGFEDCBA tv=1.1.1 dd=ABCDEFGH'
+ dns_sd_check UpdateService _meshcop._udp 'nn=coolcool xp=HGFEDCBA tv=1.1.1 xa=ABCDEFGH'
else
- avahi_check 'UpdateService;_meshcop._udp;.\+"dd=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=HGFEDCBA.\+"nn=coolcool"'
+ avahi_check 'UpdateService;_meshcop._udp;.\+"xa=ABCDEFGH.\+"tv=1\.1\.1.\+"xp=HGFEDCBA.\+"nn=coolcool"'
fi
}
diff --git a/tests/rest/test-rest-server b/tests/rest/test-rest-server
index deaccd36..3914bd88 100755
--- a/tests/rest/test-rest-server
+++ b/tests/rest/test-rest-server
@@ -54,10 +54,12 @@ send "ifconfig up\r\n"
expect "Done"
send "thread start\r\n"
expect "Done"
+send "srp server disable\r\n"
+expect "Done"
wait
EOF
trap on_exit EXIT
- sleep 5
+ sleep 12
sudo python3 "${CMAKE_CURRENT_SOURCE_DIR}"/test_rest.py
}
diff --git a/tests/scripts/auto-attach b/tests/scripts/auto-attach
new file mode 100755
index 00000000..f6e04711
--- /dev/null
+++ b/tests/scripts/auto-attach
@@ -0,0 +1,86 @@
+#!/bin/bash
+#
+# Copyright (c) 2022, The OpenThread Authors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the copyright holder nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+set -euxo pipefail
+
+readonly SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+readonly ABS_TOP_BUILDDIR="$(cd "${top_builddir:-"${SCRIPT_DIR}"/../../}" && pwd)"
+readonly OTBR_AGENT="${ABS_TOP_BUILDDIR}/src/agent/otbr-agent"
+readonly OT_CTL="${ABS_TOP_BUILDDIR}/third_party/openthread/repo/src/posix/ot-ctl"
+readonly OT_RCP=$(command -v ot-rcp)
+
+at_exit()
+{
+ EXIT_CODE=$?
+
+ sudo killall otbr-agent || true
+
+ exit $EXIT_CODE
+}
+
+trap at_exit INT TERM EXIT
+
+sudo "${OTBR_AGENT}" -I wpan0 -v -d 6 "spinel+hdlc+forkpty://${OT_RCP}?forkpty-arg=1" --auto-attach=invalid && exit 1
+sudo "${OTBR_AGENT}" -I wpan0 -v -d 6 "spinel+hdlc+forkpty://${OT_RCP}?forkpty-arg=1" --auto-attach= && exit 1
+sudo "${OTBR_AGENT}" -I wpan0 -v -d 6 "spinel+hdlc+forkpty://${OT_RCP}?forkpty-arg=1" --auto-attach=99999999999999999999999999999999999 && exit 1
+
+sudo cp "${ABS_TOP_BUILDDIR}/src/agent/otbr-agent.conf" /etc/dbus-1/system.d/
+sudo chmod +r /etc/dbus-1/system.d/otbr-agent.conf
+sudo systemctl reload dbus
+
+sudo "${OTBR_AGENT}" -I wpan0 -v -d 6 "spinel+hdlc+forkpty://${OT_RCP}?forkpty-arg=1" &
+sleep 10
+sudo "${OT_CTL}" factoryreset
+sleep 1
+sudo "${OT_CTL}" dataset init new
+sudo "${OT_CTL}" dataset commit active
+sudo "${OT_CTL}" ifconfig up
+sudo "${OT_CTL}" thread start
+sleep 10
+sudo "${OT_CTL}" state | grep "leader"
+
+sudo killall otbr-agent
+sleep 10
+sudo "${OTBR_AGENT}" -I wpan0 -v -d 6 "spinel+hdlc+forkpty://${OT_RCP}?forkpty-arg=1" --auto-attach=0 &
+sleep 10
+sudo "${OT_CTL}" state | grep "disabled"
+
+sudo killall otbr-agent
+sleep 10
+sudo "${OTBR_AGENT}" -I wpan0 -v -d 6 "spinel+hdlc+forkpty://${OT_RCP}?forkpty-arg=1" --auto-attach=1 &
+sleep 10
+sudo "${OT_CTL}" state | grep "leader"
+
+sudo killall otbr-agent
+sleep 10
+sudo "${OTBR_AGENT}" -I wpan0 -v -d 6 "spinel+hdlc+forkpty://${OT_RCP}?forkpty-arg=1" --auto-attach &
+sleep 10
+sudo "${OT_CTL}" state | grep "leader"
+sudo "${OT_CTL}" reset
+sleep 1
+sudo "${OT_CTL}" state | grep "disabled"
diff --git a/tests/scripts/bootstrap.sh b/tests/scripts/bootstrap.sh
index 227ab246..6293dccb 100755
--- a/tests/scripts/bootstrap.sh
+++ b/tests/scripts/bootstrap.sh
@@ -133,10 +133,13 @@ case "$(uname)" in
fi
if [ "${OTBR_MDNS-}" == 'mDNSResponder' ]; then
- SOURCE_NAME=mDNSResponder-878.30.4
+ SOURCE_NAME=mDNSResponder-1310.80.1
wget https://opensource.apple.com/tarballs/mDNSResponder/$SOURCE_NAME.tar.gz \
&& tar xvf $SOURCE_NAME.tar.gz \
- && cd $SOURCE_NAME/mDNSPosix \
+ && cd $SOURCE_NAME/Clients \
+ && sed -i '/#include <ctype.h>/a #include <stdarg.h>' dns-sd.c \
+ && sed -i '/#include <ctype.h>/a #include <sys/param.h>' dns-sd.c \
+ && cd ../mDNSPosix \
&& make os=linux && sudo make install os=linux
fi
diff --git a/tests/scripts/check-android-build b/tests/scripts/check-android-build
index 229904f4..b6582f77 100755
--- a/tests/scripts/check-android-build
+++ b/tests/scripts/check-android-build
@@ -158,7 +158,7 @@ EOF
#######################################
prepare_libmdnssd()
{
- readonly MDNSRESPONDER_SOURCE=mDNSResponder-878.30.4
+ readonly MDNSRESPONDER_SOURCE=mDNSResponder-1310.80.1
[[ ${OTBR_MDNS} == mDNSResponder ]] || return 0
@@ -198,8 +198,8 @@ OPENTHREAD_ENABLE_ANDROID_MK := 1
ANDROID_NDK := 1
OPENTHREAD_PROJECT_CFLAGS := \
-DOPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE=1 \
- -DOPENTHREAD_CONFIG_FILE=\<openthread-config-android.h\> \
- -DOPENTHREAD_PROJECT_CORE_CONFIG_FILE=\"openthread-core-posix-config.h\"
+ -DOPENTHREAD_PROJECT_CORE_CONFIG_FILE=\"openthread-core-posix-config.h\" \
+ -std=c99
EOF
}
diff --git a/tests/scripts/check-docker b/tests/scripts/check-docker
index fcf20398..395aea41 100755
--- a/tests/scripts/check-docker
+++ b/tests/scripts/check-docker
@@ -45,6 +45,7 @@ on_exit()
main()
{
+ sudo modprobe ip6table_filter
docker build -t otbr \
--build-arg OTBR_OPTIONS=-DOT_POSIX_CONFIG_RCP_BUS="${OT_POSIX_CONFIG_RCP_BUS}" \
--build-arg BACKBONE_ROUTER=0 \
diff --git a/tests/scripts/check-scripts b/tests/scripts/check-scripts
index 33ad1583..88a18c3b 100755
--- a/tests/scripts/check-scripts
+++ b/tests/scripts/check-scripts
@@ -39,6 +39,31 @@ check_otbr_agent()
org.freedesktop.DBus.ListNames | grep -q '"io.openthread.BorderRouter.wpan0"'
}
+check_upstart()
+{
+ echo 'Verify Upstart notification'
+ UPSTART_JOB=otbr-agent sudo -E otbr-agent -d7 -v "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=2" &
+ sleep 2
+ UPSTART_JOB_PID=$!
+
+ if [[ "$(ps --no-headers -o s "${UPSTART_JOB_PID}")" != T ]]; then
+ echo 'otbr-agent is not in Stopped state'
+ false
+ fi
+
+ echo 'Continue otbr-agent'
+ sudo pkill -SIGCONT -P "${UPSTART_JOB_PID}"
+ sudo kill -SIGCONT "${UPSTART_JOB_PID}"
+ sleep 2
+
+ if [[ "$(ps --no-headers -o s "${UPSTART_JOB_PID}")" == T ]]; then
+ echo 'otbr-agent did not continue'
+ false
+ fi
+ sudo pkill -P "${UPSTART_JOB_PID}"
+ wait
+}
+
main()
{
RELEASE=1 ./script/bootstrap
@@ -48,6 +73,13 @@ main()
INFRA_IF_NAME=eth0 BACKBONE_ROUTER=0 NAT64=1 ./script/setup
SOCAT_OUTPUT=/tmp/ot-socat
+ if ! command -v ot-rcp; then
+ third_party/openthread/repo/script/cmake-build simulation -DOT_COVERAGE=OFF
+ PATH=$PATH:build/simulation/examples/apps/ncp
+ fi
+
+ check_upstart
+
socat -d -d pty,raw,echo=0 pty,raw,echo=0 >/dev/null 2>$SOCAT_OUTPUT &
while true; do
if [[ "$(head -n2 $SOCAT_OUTPUT | wc -l)" == 2 ]]; then
@@ -61,13 +93,9 @@ main()
echo "RCP_PTY: ${RCP_PTY}"
echo "HOST_PTY: ${HOST_PTY}"
- if ! command -v ot-rcp; then
- make -f third_party/openthread/repo/examples/Makefile-simulation DISABLE_DOC=1 TargetTuple=otbr
- PATH=$PATH:output/otbr/bin
- fi
-
# shellcheck disable=SC2094
ot-rcp 1 >"${RCP_PTY}" <"${RCP_PTY}" &
+
INFRA_IF_NAME=eth0 RADIO_URL="spinel+hdlc+uart://${HOST_PTY}" ./script/console &
SERVICES_PID=$!
sudo service tayga start
diff --git a/tests/scripts/infra-link-selector b/tests/scripts/infra-link-selector
new file mode 100755
index 00000000..aa3c8a0c
--- /dev/null
+++ b/tests/scripts/infra-link-selector
@@ -0,0 +1,145 @@
+#!/bin/bash
+#
+# Copyright (c) 2022, The OpenThread Authors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the copyright holder nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+set -euxo pipefail
+
+readonly SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+readonly ABS_TOP_BUILDDIR="$(cd "${top_builddir:-"${SCRIPT_DIR}"/../../}" && pwd)"
+readonly OTBR_AGENT="${ABS_TOP_BUILDDIR}/src/agent/otbr-agent"
+readonly OT_RCP=$(command -v ot-rcp)
+
+at_exit()
+{
+ EXIT_CODE=$?
+
+ sudo killall otbr-agent || true
+
+ sudo ip link del ilstest0 || true
+ sudo ip link del ilstest1 || true
+ sudo ip link del ilstest2 || true
+
+ exit $EXIT_CODE
+}
+
+trap at_exit INT TERM EXIT
+
+sudo cp "${ABS_TOP_BUILDDIR}/src/agent/otbr-agent.conf" /etc/dbus-1/system.d/
+sudo chmod +r /etc/dbus-1/system.d/otbr-agent.conf
+sudo systemctl reload dbus
+
+sudo modprobe dummy
+
+prepare_infra_link()
+{
+ local netif="$1"
+ local mac="$2"
+
+ sudo ip link add "${netif}" type dummy
+ sudo ifconfig "${netif}" hw ether "${mac}"
+ sudo ifconfig "${netif}" up
+}
+
+sudo ip link del ilstest0 || true
+sudo ip link del ilstest1 || true
+sudo ip link del ilstest2 || true
+
+prepare_infra_link "ilstest0" "C8:D7:4A:4E:47:00"
+prepare_infra_link "ilstest1" "C8:D7:4A:4E:47:01"
+prepare_infra_link "ilstest2" "C8:D7:4A:4E:47:02"
+
+sleep 10
+ifconfig
+ip link list
+
+sudo "${OTBR_AGENT}" -I wpan0 -v -d7 -B ilstest0 -B ilstest1 -B ilstest2 "spinel+hdlc+forkpty://${OT_RCP}?forkpty-arg=1" 2>&1 | tee output &
+
+function check_infra_link()
+{
+ grep "\-ILS\-\-\-\-\-: Infra link \(selected\|unchanged\|switched\)" output | tail -1
+}
+
+function verify_otbr_agent_exited()
+{
+ if pgrep otbr-agent; then
+ return 1
+ fi
+}
+
+sleep 3
+# Verify ILS selects ilstest0
+check_infra_link | grep "selected: ilstest0"
+
+sudo ifconfig ilstest1 down
+sudo ifconfig ilstest2 down
+
+sleep 3
+# Verify ILS keeps using ilstest0
+check_infra_link | grep "unchanged: ilstest0"
+
+sudo ifconfig ilstest2 up
+
+sleep 3
+# Verify ILS keeps using ilstest0 because ilstest0 is still RUNNING
+check_infra_link | grep "unchanged: ilstest0"
+
+sudo ifconfig ilstest0 down
+sleep 3
+# Verify ILS keeps using ilstest0 because ilstest0 was RUNNING recently
+check_infra_link | grep "unchanged: ilstest0"
+
+sudo ifconfig ilstest0 up
+sleep 11
+
+# Verify ILS keeps using ilstest0 because ilstest0 is RUNNING again
+check_infra_link | grep "unchanged: ilstest0"
+
+sudo ifconfig ilstest0 down
+sleep 11
+# Verify ILS switches to ilstest2 after ilstest0 is DOWN for more than 10s
+check_infra_link | grep "switched from ilstest0 to ilstest2"
+verify_otbr_agent_exited
+
+# Now, only ilstest2 is RUNNING
+
+sudo "${OTBR_AGENT}" -I wpan0 -v -d7 -B ilstest0 -B ilstest1 -B ilstest2 "spinel+hdlc+forkpty://${OT_RCP}?forkpty-arg=1" 2>&1 | tee output &
+
+sleep 3
+# Verify ILS selects ilstest2 after reboot
+check_infra_link | grep "selected: ilstest2"
+
+sudo ifconfig ilstest2 down
+sleep 3
+# Verify ILS keeps using ilstest2 because ilstest2 was RUNNING recently
+check_infra_link | grep "unchanged: ilstest2"
+
+sleep 8
+sudo ifconfig ilstest1 up
+sleep 3
+# Verify ILS switches to ilstest1 because ilstest2 was not RUNNING for more than 10s
+check_infra_link | grep "switched from ilstest2 to ilstest1"
+verify_otbr_agent_exited
diff --git a/tests/scripts/meshcop b/tests/scripts/meshcop
index 2aca0280..53c56daa 100755
--- a/tests/scripts/meshcop
+++ b/tests/scripts/meshcop
@@ -104,7 +104,7 @@ readonly OT_NETWORK_NAME=MyTestNetwork
readonly TUN_NAME=wpan0
# The default meshcop service instance name
-readonly OT_SERVICE_INSTANCE='OpenThread_BorderRouter'
+readonly OT_SERVICE_INSTANCE='OpenThread\(\\032\| \)BorderRouter\(\\032\| \)#[0-9A-F][0-9A-F][0-9A-F][0-9A-F]'
echo "ORIGIN_PWD: ${ORIGIN_PWD}"
echo "TEST_BASE: ${TEST_BASE}"
@@ -445,17 +445,17 @@ test_meshcop_service()
sudo "${OT_CTL}" ifconfig up
sudo "${OT_CTL}" extaddr ${extaddr}
sudo "${OT_CTL}" thread start
- sleep 5
+ sleep 20
sudo "${OT_CTL}" state | grep "leader"
service="$(scan_meshcop_service)"
grep "${OT_SERVICE_INSTANCE}._meshcop\._udp" <<<"${service}"
grep "rv=1" <<<"${service}"
- grep "tv=1\.2\.0" <<<"${service}"
+ grep "tv=1\.3\.0" <<<"${service}"
grep "nn=${network_name}" <<<"${service}"
grep "xp=${xpanid_txt}" <<<"${service}"
- grep "dd=${extaddr_txt}" <<<"${service}"
+ grep "xa=${extaddr_txt}" <<<"${service}"
# TODO: enable the checks after enabling Thread 1.2 for tests.
#grep "dn=${domain_name}" <<< "${service}"
@@ -467,15 +467,13 @@ test_meshcop_service()
grep "at=" <<<"${service}"
grep "pt=" <<<"${service}"
- # Test if the meshcop service is unpublished when pskc is zeroed.
+ # Test if the meshcop service is published when thread is not on
sudo "${OT_CTL}" dataset init active
sudo "${OT_CTL}" dataset pskc 00000000000000000000000000000000
sudo "${OT_CTL}" dataset commit active
sleep 2
service="$(scan_meshcop_service)"
- if grep -q "${OT_SERVICE_INSTANCE}._meshcop\._udp" <<<"${service}"; then
- die "unexpect meshcop service when PSKc is zeroed!"
- fi
+ grep -q "${OT_SERVICE_INSTANCE}._meshcop\._udp" <<<"${service}"
# Test if the meshcop service is published again when a non-zero
# PSKc is set back.
@@ -506,15 +504,13 @@ test_meshcop_service()
sleep 5
service="$(scan_meshcop_service)"
grep "${OT_SERVICE_INSTANCE}._meshcop\._udp" <<<"${service}"
- grep "dd=${new_extaddr_txt}" <<<"${service}"
+ grep "xa=${new_extaddr_txt}" <<<"${service}"
- # Test if the meshcop service is unpublished when Thread is stopped.
+ # Test if the meshcop service is published when Thread is stopped.
sudo "${OT_CTL}" thread stop
sleep 2
service="$(scan_meshcop_service)"
- if grep -q "${new_network_name}._meshcop\._udp" <<<"${service}"; then
- die "unexpect meshcop service when Thread is stopped!"
- fi
+ grep -q "${OT_SERVICE_INSTANCE}._meshcop\._udp" <<<"${service}"
sudo "${OT_CTL}" thread start
sleep 5
@@ -523,7 +519,7 @@ test_meshcop_service()
# Test if the the meshcop service is unpublished when otbr-agent stops.
sudo killall "${OTBR_AGENT}"
- sleep 2
+ sleep 10
service="$(scan_meshcop_service)"
if grep -q "${OT_SERVICE_INSTANCE}._meshcop\._udp" <<<"${service}"; then
die "unexpect meshcop service when otbr-agent exits!"
diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt
index 938d4dcd..784f859e 100644
--- a/tests/unit/CMakeLists.txt
+++ b/tests/unit/CMakeLists.txt
@@ -32,6 +32,7 @@ add_executable(otbr-test-unit
main.cpp
test_dns_utils.cpp
test_logging.cpp
+ test_once_callback.cpp
test_pskc.cpp
test_task_runner.cpp
)
diff --git a/tests/unit/test_dbus_message.cpp b/tests/unit/test_dbus_message.cpp
index 80254bd3..9c48ddb9 100644
--- a/tests/unit/test_dbus_message.cpp
+++ b/tests/unit/test_dbus_message.cpp
@@ -105,7 +105,7 @@ bool operator==(const otbr::DBus::ActiveScanResult &aLhs, const otbr::DBus::Acti
aLhs.mExtendedPanId == aRhs.mExtendedPanId && aLhs.mSteeringData == aRhs.mSteeringData &&
aLhs.mPanId == aRhs.mPanId && aLhs.mJoinerUdpPort == aRhs.mJoinerUdpPort && aLhs.mChannel == aRhs.mChannel &&
aLhs.mRssi == aRhs.mRssi && aLhs.mLqi == aRhs.mLqi && aLhs.mVersion == aRhs.mVersion &&
- aLhs.mIsNative == aRhs.mIsNative && aLhs.mIsJoinable == aRhs.mIsJoinable;
+ aLhs.mIsNative == aRhs.mIsNative;
}
bool operator==(const otbr::DBus::Ip6Prefix &aLhs, const otbr::DBus::Ip6Prefix &aRhs)
@@ -298,7 +298,7 @@ TEST(DBusMessage, TestOtbrLeaderData)
TEST(DBusMessage, TestOtbrActiveScanResults)
{
DBusMessage * msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
- tuple<std::vector<otbr::DBus::ActiveScanResult>> setVals({{1, "a", 2, {3}, 4, 5, 6, 7, 8, 9, true, true}});
+ tuple<std::vector<otbr::DBus::ActiveScanResult>> setVals({{1, "a", 2, {3}, 4, 5, 6, 7, 8, 9, true, false}});
tuple<std::vector<otbr::DBus::ActiveScanResult>> getVals;
CHECK(msg != nullptr);
diff --git a/tests/unit/test_logging.cpp b/tests/unit/test_logging.cpp
index dccfc50a..b10475bc 100644
--- a/tests/unit/test_logging.cpp
+++ b/tests/unit/test_logging.cpp
@@ -92,7 +92,7 @@ TEST(Logging, TestLoggingDump)
sprintf(ident, "otbr-test-%ld", clock());
otbrLogInit(ident, OTBR_LOG_DEBUG, true);
const char s[] = "one super long string with lots of text";
- otbrDump(OTBR_LOG_INFO, "foobar", s, sizeof(s));
+ otbrDump(OTBR_LOG_INFO, "Test", "foobar", s, sizeof(s));
otbrLogDeinit();
sleep(0);
diff --git a/src/agent/agent_instance.cpp b/tests/unit/test_once_callback.cpp
index b9af3e7c..b43682c6 100644
--- a/src/agent/agent_instance.cpp
+++ b/tests/unit/test_once_callback.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The OpenThread Authors.
+ * Copyright (c) 2021, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,38 +26,42 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * @file
- * This file includes implementation for Thread border router agent instance.
- */
-
-#define OTBR_LOG_TAG "AGENT"
+#include "common/callback.hpp"
-#include "agent/agent_instance.hpp"
+#include <CppUTest/TestHarness.h>
-#include <assert.h>
+TEST_GROUP(IsNull){};
-#include "common/code_utils.hpp"
-#include "common/logging.hpp"
+TEST(IsNull, NullptrIsNull)
+{
+ otbr::OnceCallback<void(void)> noop = nullptr;
-namespace otbr {
+ CHECK_TRUE(noop.IsNull());
+}
-AgentInstance::AgentInstance(Ncp::ControllerOpenThread &aNcp)
- : mNcp(aNcp)
- , mBorderAgent(aNcp)
+TEST(IsNull, NonNullptrIsNotNull)
{
+ otbr::OnceCallback<void(void)> noop = [](void) {};
+
+ CHECK_FALSE(noop.IsNull());
}
-otbrError AgentInstance::Init(void)
+TEST(IsNull, IsNullAfterInvoking)
{
- otbrError error = OTBR_ERROR_NONE;
+ otbr::OnceCallback<int(int)> square = [](int x) { return x * x; };
- SuccessOrExit(error = mNcp.Init());
+ std::move(square)(5);
+
+ CHECK_TRUE(square.IsNull());
+}
+
+TEST_GROUP(VerifyInvocation){};
+
+TEST(VerifyInvocation, CallbackResultIsExpected)
+{
+ otbr::OnceCallback<int(int)> square = [](int x) { return x * x; };
- mBorderAgent.Init();
+ int ret = std::move(square)(5);
-exit:
- otbrLogResult(error, "Initialize OpenThread Border Router Agent");
- return error;
+ CHECK_EQUAL(ret, 25);
}
-} // namespace otbr
diff --git a/tests/unit/test_task_runner.cpp b/tests/unit/test_task_runner.cpp
index a918900f..45aa6187 100644
--- a/tests/unit/test_task_runner.cpp
+++ b/tests/unit/test_task_runner.cpp
@@ -31,6 +31,7 @@
#include <atomic>
#include <mutex>
#include <thread>
+#include <unistd.h>
#include <CppUTest/TestHarness.h>
@@ -252,6 +253,61 @@ TEST(TaskRunner, TestDelayedTasksOrder)
STRCMP_EQUAL("bac", str.c_str());
}
+TEST(TaskRunner, TestCancelDelayedTasks)
+{
+ std::string str;
+ otbr::TaskRunner taskRunner;
+ otbr::TaskRunner::TaskId tid1, tid2, tid3, tid4, tid5;
+
+ tid1 = taskRunner.Post(std::chrono::milliseconds(10), [&]() { str.push_back('a'); });
+ tid2 = taskRunner.Post(std::chrono::milliseconds(20), [&]() { str.push_back('b'); });
+ tid3 = taskRunner.Post(std::chrono::milliseconds(30), [&]() { str.push_back('c'); });
+ tid4 = taskRunner.Post(std::chrono::milliseconds(40), [&]() { str.push_back('d'); });
+ tid5 = taskRunner.Post(std::chrono::milliseconds(50), [&]() { str.push_back('e'); });
+
+ CHECK(0 < tid1);
+ CHECK(tid1 < tid2);
+ CHECK(tid2 < tid3);
+ CHECK(tid3 < tid4);
+ CHECK(tid4 < tid5);
+
+ taskRunner.Cancel(tid2);
+
+ taskRunner.Post(std::chrono::milliseconds(10), [&]() { taskRunner.Cancel(tid3); });
+ std::thread t([&]() {
+ usleep(20);
+ taskRunner.Cancel(tid4);
+ });
+
+ while (str.size() < 2)
+ {
+ int rval;
+ otbr::MainloopContext mainloop;
+
+ mainloop.mMaxFd = -1;
+ mainloop.mTimeout = {2, 0};
+
+ FD_ZERO(&mainloop.mReadFdSet);
+ FD_ZERO(&mainloop.mWriteFdSet);
+ FD_ZERO(&mainloop.mErrorFdSet);
+
+ taskRunner.Update(mainloop);
+ rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet,
+ &mainloop.mTimeout);
+ CHECK_TRUE(rval >= 0 || errno == EINTR);
+
+ taskRunner.Process(mainloop);
+ }
+
+ // Make sure the delayed task was not executed.
+ STRCMP_EQUAL("ae", str.c_str());
+
+ // Make sure it's fine to cancel expired task IDs.
+ taskRunner.Cancel(tid1);
+ taskRunner.Cancel(tid2);
+ t.join();
+}
+
TEST(TaskRunner, TestAllAPIs)
{
std::atomic<int> counter{0};
diff --git a/third_party/cJSON/repo b/third_party/cJSON/repo
deleted file mode 160000
-Subproject cf97c6f066d81fdbba4ef722cfd327bbbba2365
diff --git a/third_party/http-parser/repo b/third_party/http-parser/repo
deleted file mode 160000
-Subproject 4f15b7d510dc7c6361a26a7c6d2f7c3a17f8d87
diff --git a/third_party/openthread/CMakeLists.txt b/third_party/openthread/CMakeLists.txt
index 4623fa5d..23d3002d 100644
--- a/third_party/openthread/CMakeLists.txt
+++ b/third_party/openthread/CMakeLists.txt
@@ -29,14 +29,19 @@
set(OT_BORDER_AGENT ON CACHE BOOL "enable border agent" FORCE)
set(OT_BORDER_ROUTER ON CACHE BOOL "enable border router feature" FORCE)
set(OT_BORDER_ROUTING ${OTBR_BORDER_ROUTING} CACHE BOOL "enable border routing feature" FORCE)
+set(OT_BORDER_ROUTING_NAT64 ${OTBR_BORDER_ROUTING_NAT64} CACHE BOOL "enable border routing NAT64 feature" FORCE)
set(OT_BUILD_EXECUTABLES OFF CACHE BOOL "disable building executables" FORCE)
set(OT_BUILTIN_MBEDTLS_MANAGEMENT OFF CACHE BOOL "diable mbedTLS management" FORCE)
-set(OT_COMMISSIONER ON CACHE BOOL "enable commissioner" FORCE)
+set(OT_COMMISSIONER ON CACHE BOOL "enable commissioner")
set(OT_DAEMON ON CACHE BOOL "enable daemon mode" FORCE)
+set(OT_FIREWALL ON CACHE BOOL "enable firewall feature")
set(OT_JOINER ON CACHE BOOL "enable joiner" FORCE)
set(OT_LEGACY ON CACHE STRING "enable legacy network support" FORCE)
+if (NOT OT_THREAD_VERSION EQUAL "1.1")
+ set(OT_LINK_METRICS_SUBJECT ON CACHE BOOL "enable link metrics subject" FORCE)
+endif()
set(OT_SLAAC ON CACHE BOOL "enable SLAAC" FORCE)
-set(OT_TREL ON CACHE BOOL "enable TREL")
+set(OT_TREL ${OTBR_TREL} CACHE BOOL "enable TREL" FORCE)
if (NOT OT_LOG_LEVEL)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
@@ -63,12 +68,14 @@ if (OTBR_SRP_ADVERTISING_PROXY)
endif()
if (OTBR_BACKBONE_ROUTER)
- set(OT_THREAD_VERSION 1.2 CACHE STRING "Backbone Router requires Thread 1.2 or higher" FORCE)
set(OT_BACKBONE_ROUTER ON CACHE BOOL "Enable Backbone Router feature in OpenThread" FORCE)
set(OT_SERVICE ON CACHE BOOL "Backbone Router requires Thread network service" FORCE)
endif()
-if (OT_THREAD_VERSION STREQUAL "1.2")
+if (NOT OT_THREAD_VERSION STREQUAL "1.1")
+ if (OT_REFERENCE_DEVICE)
+ set(OT_DUA ON CACHE BOOL "Enable Thread 1.2 DUA for reference devices")
+ endif()
set(OT_MLR ON CACHE BOOL "Enable Thread 1.2 MLR by default")
endif()
@@ -89,5 +96,12 @@ target_compile_definitions(ot-config INTERFACE
"-DOPENTHREAD_CONFIG_LOG_CLI=1"
"-DOPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS=3"
"-DOPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE=1"
- "-DOPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE=$<BOOL:${OTBR_DUA_ROUTING}>"
+ "-DOPENTHREAD_CONFIG_TCP_ENABLE=0"
)
+
+if (NOT OT_THREAD_VERSION STREQUAL "1.1")
+ target_compile_definitions(ot-config INTERFACE
+ "-DOPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE=1"
+ "-DOPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE=1"
+ )
+endif()
diff --git a/third_party/openthread/repo b/third_party/openthread/repo
deleted file mode 160000
-Subproject 05e59ade17ec11808fd52e14c24babf3bff6e9c
diff --git a/tools/reference_device/testharness-discovery b/tools/reference_device/testharness-discovery
index 4fdf9a6a..58a22eae 100755
--- a/tools/reference_device/testharness-discovery
+++ b/tools/reference_device/testharness-discovery
@@ -53,7 +53,7 @@ def if_nametoindex(name):
def get_ipaddr():
- for line in os.popen(f'ip addr list dev {IFNAME} | grep inet | grep global'):
+ for line in os.popen(f'ip addr list dev {IFNAME} | grep inet6 | grep \'scope link\' '):
addr = line.strip().split()[1]
return addr.split('/')[0]