diff --git a/.gitignore b/.gitignore index 537cf8ba6..ed9f0ed79 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,9 @@ Makefile.in /build cmake-build-* +# Test +/tmp + #tools .vscode .idea diff --git a/android/openthread_commissioner/app/build.gradle b/android/openthread_commissioner/app/build.gradle index f6f239a01..45b4ad1f8 100644 --- a/android/openthread_commissioner/app/build.gradle +++ b/android/openthread_commissioner/app/build.gradle @@ -51,7 +51,7 @@ android { defaultConfig { applicationId "io.openthread.commissioner.app" - minSdkVersion 24 + minSdkVersion 26 targetSdkVersion 34 versionCode 1 versionName "0.0.1" diff --git a/android/openthread_commissioner/examples/qrcode/README.md b/android/openthread_commissioner/examples/qrcode/README.md new file mode 100644 index 000000000..4b3115d97 --- /dev/null +++ b/android/openthread_commissioner/examples/qrcode/README.md @@ -0,0 +1,3 @@ +# QR code + +- file `v=1&&eui=0000b57fffe15d68&&cc=J01NU5.png` is the Thread joiner device QR code which encodes the joiner EUI and PSKd as a text string (the content is `v=1&&eui=0000b57fffe15d68&&cc=J01NU5`) diff --git a/android/openthread_commissioner/examples/qrcode/v=1&&eui=0000b57fffe15d68&&cc=J01NU5.png b/android/openthread_commissioner/examples/qrcode/v=1&&eui=0000b57fffe15d68&&cc=J01NU5.png new file mode 100644 index 000000000..9c0b71bf6 Binary files /dev/null and b/android/openthread_commissioner/examples/qrcode/v=1&&eui=0000b57fffe15d68&&cc=J01NU5.png differ diff --git a/android/openthread_commissioner/service/build.gradle b/android/openthread_commissioner/service/build.gradle index 6e0894c72..4f9dfeb36 100644 --- a/android/openthread_commissioner/service/build.gradle +++ b/android/openthread_commissioner/service/build.gradle @@ -34,7 +34,7 @@ android { compileSdkVersion 34 defaultConfig { - minSdkVersion 24 + minSdkVersion 26 targetSdkVersion 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -73,10 +73,13 @@ dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation 'com.google.guava:guava:31.1-jre' implementation 'androidx.appcompat:appcompat:1.2.0' + implementation "androidx.concurrent:concurrent-futures:1.1.0" implementation 'androidx.constraintlayout:constraintlayout:2.0.2' implementation 'androidx.navigation:navigation-fragment:2.3.0' implementation 'com.google.android.gms:play-services-vision:20.1.3+' + implementation 'com.google.android.gms:play-services-threadnetwork:16.0.0' implementation 'com.google.android.material:material:1.2.1' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.5' diff --git a/android/openthread_commissioner/service/src/androidTest/java/io/openthread/commissioner/service/BorderAgentDatabaseTest.java b/android/openthread_commissioner/service/src/androidTest/java/io/openthread/commissioner/service/BorderAgentDatabaseTest.java deleted file mode 100644 index f712c2e3a..000000000 --- a/android/openthread_commissioner/service/src/androidTest/java/io/openthread/commissioner/service/BorderAgentDatabaseTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Commissioner 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. - */ - -package io.openthread.commissioner.service; - -import static org.junit.Assert.*; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import java.util.concurrent.ExecutionException; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class BorderAgentDatabaseTest { - - @Test - public void simpleBorderAgentRecord() { - BorderAgentDatabase db = BorderAgentDatabase.getDatabase(); - BorderAgentRecord record = - new BorderAgentRecord( - "12345", "test-net", new byte[] {0x01}, new byte[] {0x02}, new byte[] {0x03}); - - try { - db.insertBorderAgent(record).get(); - db.deleteBorderAgent("54321").get(); - record = db.getBorderAgent("12345").get(); - - assertNotNull(record); - assertEquals(record.getDiscriminator(), "12345"); - assertEquals(record.getNetworkName(), "test-net"); - assertArrayEquals(record.getExtendedPanId(), new byte[] {0x01}); - assertArrayEquals(record.getPskc(), new byte[] {0x02}); - assertArrayEquals(record.getActiveOperationalDataset(), new byte[] {0x03}); - - db.deleteBorderAgent("12345").get(); - record = db.getBorderAgent("12345").get(); - assertNull(record); - } catch (InterruptedException | ExecutionException e) { - fail(); - } - } -} diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDao.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDao.java deleted file mode 100644 index 56c5d7673..000000000 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDao.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Commissioner 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. - */ - -package io.openthread.commissioner.service; - -import androidx.annotation.NonNull; -import androidx.lifecycle.LiveData; -import androidx.room.Dao; -import androidx.room.Insert; -import androidx.room.OnConflictStrategy; -import androidx.room.Query; -import java.util.List; - -@Dao -public interface BorderAgentDao { - - @Query("SELECT * FROM border_agent_table ORDER BY network_name ASC") - LiveData> getAll(); - - @Query("SELECT * FROM border_agent_table WHERE discriminator=:discriminator LIMIT 1") - BorderAgentRecord getBorderAgent(@NonNull String discriminator); - - @Query( - "SELECT * FROM border_agent_table WHERE network_name=:networkName AND extended_pan_id=:extendedPanId") - List getBorderAgents( - @NonNull String networkName, @NonNull byte[] extendedPanId); - - @Insert(onConflict = OnConflictStrategy.IGNORE) - void insert(BorderAgentRecord borderAgentRecord); - - @Query("DELETE FROM border_agent_table WHERE discriminator=:discriminator") - void delete(@NonNull String discriminator); - - @Query("DELETE FROM border_agent_table") - void deleteAll(); -} diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDatabase.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDatabase.java deleted file mode 100644 index c8b7d87fe..000000000 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDatabase.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Commissioner 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. - */ - -package io.openthread.commissioner.service; - -import androidx.annotation.NonNull; -import androidx.room.Database; -import androidx.room.Room; -import androidx.room.RoomDatabase; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -@Database( - entities = {BorderAgentRecord.class}, - version = 1, - exportSchema = false) -abstract class BorderAgentDatabase extends RoomDatabase { - - abstract BorderAgentDao borderAgentDao(); - - private static volatile BorderAgentDatabase INSTANCE; - private static final int NUMBER_OF_THREADS = 2; - - static final ExecutorService executor = Executors.newFixedThreadPool(NUMBER_OF_THREADS); - - public static synchronized BorderAgentDatabase getDatabase() { - if (INSTANCE == null) { - INSTANCE = - Room.databaseBuilder( - CommissionerServiceApp.getContext(), - BorderAgentDatabase.class, - "network_credential_database") - .build(); - } - return INSTANCE; - } - - public CompletableFuture getBorderAgent(@NonNull String discriminator) { - CompletableFuture future = - CompletableFuture.supplyAsync(() -> borderAgentDao().getBorderAgent(discriminator)); - return future; - } - - public CompletableFuture insertBorderAgent(@NonNull BorderAgentRecord borderAgentRecord) { - CompletableFuture future = - CompletableFuture.runAsync( - () -> { - borderAgentDao().insert(borderAgentRecord); - }, - executor); - return future; - } - - public CompletableFuture deleteBorderAgent(@NonNull String discriminator) { - CompletableFuture future = - CompletableFuture.runAsync( - () -> { - borderAgentDao().delete(discriminator); - }, - executor); - return future; - } -} diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDiscoverer.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDiscoverer.java index f63bd587f..6e4214d12 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDiscoverer.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDiscoverer.java @@ -34,6 +34,7 @@ import android.net.nsd.NsdServiceInfo; import android.net.wifi.WifiManager; import android.util.Log; +import androidx.annotation.Nullable; import androidx.annotation.RequiresPermission; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; @@ -47,7 +48,7 @@ public class BorderAgentDiscoverer implements NsdManager.DiscoveryListener { private static final String TAG = BorderAgentDiscoverer.class.getSimpleName(); private static final String SERVICE_TYPE = "_meshcop._udp"; - private static final String KEY_DISCRIMINATOR = "discriminator"; + private static final String KEY_ID = "id"; private static final String KEY_NETWORK_NAME = "nn"; private static final String KEY_EXTENDED_PAN_ID = "xp"; @@ -62,9 +63,10 @@ public class BorderAgentDiscoverer implements NsdManager.DiscoveryListener { private boolean isScanning = false; public interface BorderAgentListener { + void onBorderAgentFound(BorderAgentInfo borderAgentInfo); - void onBorderAgentLost(String discriminator); + void onBorderAgentLost(byte[] id); } @RequiresPermission(permission.INTERNET) @@ -182,10 +184,10 @@ public void onServiceFound(NsdServiceInfo nsdServiceInfo) { @Override public void onServiceLost(NsdServiceInfo nsdServiceInfo) { - String discriminator = getBorderAgentDiscriminator(nsdServiceInfo); - if (discriminator != null) { - Log.d(TAG, "a Border Agent service is gone"); - borderAgentListener.onBorderAgentLost(discriminator); + byte[] id = getBorderAgentId(nsdServiceInfo); + if (id != null) { + Log.d(TAG, "a Border Agent service is gone: " + nsdServiceInfo.getServiceName()); + borderAgentListener.onBorderAgentLost(id); } } @@ -199,40 +201,29 @@ public void onStopDiscoveryFailed(String serviceType, int errorCode) { Log.d(TAG, "stop discovering Border Agent failed: " + errorCode); } + @Nullable private BorderAgentInfo getBorderAgentInfo(NsdServiceInfo serviceInfo) { Map attrs = serviceInfo.getAttributes(); - - // Use the host address as default discriminator. - String discriminator = serviceInfo.getHost().getHostAddress(); - - if (attrs.containsKey(KEY_DISCRIMINATOR)) { - discriminator = new String(attrs.get(KEY_DISCRIMINATOR)); - } + byte[] id = getBorderAgentId(serviceInfo); if (!attrs.containsKey(KEY_NETWORK_NAME) || !attrs.containsKey(KEY_EXTENDED_PAN_ID)) { return null; } return new BorderAgentInfo( - discriminator, + id, new String(attrs.get(KEY_NETWORK_NAME)), attrs.get(KEY_EXTENDED_PAN_ID), serviceInfo.getHost(), serviceInfo.getPort()); } - private String getBorderAgentDiscriminator(NsdServiceInfo serviceInfo) { + @Nullable + private byte[] getBorderAgentId(NsdServiceInfo serviceInfo) { Map attrs = serviceInfo.getAttributes(); - - if (attrs.containsKey(KEY_DISCRIMINATOR)) { - return new String(attrs.get(KEY_DISCRIMINATOR)); - } - - if (serviceInfo.getHost() != null) { - // Use the host address as default discriminator. - return serviceInfo.getHost().getHostAddress(); + if (attrs.containsKey(KEY_ID)) { + return attrs.get(KEY_ID).clone(); } - return null; } } diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentInfo.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentInfo.java index c60bc9a7b..0a9babede 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentInfo.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentInfo.java @@ -35,27 +35,28 @@ import java.net.UnknownHostException; public class BorderAgentInfo implements Parcelable { - public String discriminator; + + public byte[] id; public String networkName; public byte[] extendedPanId; public InetAddress host; public int port; public BorderAgentInfo( - @NonNull String discriminator, + @NonNull byte[] id, @NonNull String networkName, @NonNull byte[] extendedPanId, @NonNull InetAddress host, @NonNull int port) { - this.discriminator = discriminator; + this.id = id.clone(); this.networkName = networkName; - this.extendedPanId = extendedPanId; + this.extendedPanId = extendedPanId.clone(); this.host = host; this.port = port; } protected BorderAgentInfo(Parcel in) { - discriminator = in.readString(); + id = in.createByteArray(); networkName = in.readString(); extendedPanId = in.createByteArray(); try { @@ -67,7 +68,7 @@ protected BorderAgentInfo(Parcel in) { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeString(discriminator); + dest.writeByteArray(id); dest.writeString(networkName); dest.writeByteArray(extendedPanId); dest.writeByteArray(host.getAddress()); @@ -79,10 +80,6 @@ public int describeContents() { return 0; } - public boolean equals(BorderAgentInfo other) { - return this.discriminator.equals(other.discriminator); - } - public static final Creator CREATOR = new Creator() { @Override diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentRecord.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentRecord.java deleted file mode 100644 index 107a8ea90..000000000 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentRecord.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Commissioner 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. - */ - -package io.openthread.commissioner.service; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.room.ColumnInfo; -import androidx.room.Entity; -import androidx.room.PrimaryKey; - -@Entity(tableName = "border_agent_table") -public class BorderAgentRecord { - - @PrimaryKey - @NonNull - @ColumnInfo(name = "discriminator") - private String discriminator; - - @NonNull - @ColumnInfo(name = "network_name") - private String networkName; - - @NonNull - @ColumnInfo(name = "extended_pan_id", typeAffinity = ColumnInfo.BLOB) - private byte[] extendedPanId; - - @NonNull - @ColumnInfo(name = "pskc", typeAffinity = ColumnInfo.BLOB) - private byte[] pskc; - - @Nullable - @ColumnInfo(name = "active_operational_dataset", typeAffinity = ColumnInfo.BLOB) - private byte[] activeOperationalDataset; - - public BorderAgentRecord( - @NonNull String discriminator, - @NonNull String networkName, - @NonNull byte[] extendedPanId, - @NonNull byte[] pskc, - @Nullable byte[] activeOperationalDataset) { - this.discriminator = discriminator; - this.networkName = networkName; - this.extendedPanId = extendedPanId; - this.pskc = pskc; - this.activeOperationalDataset = activeOperationalDataset; - } - - @NonNull - public String getDiscriminator() { - return discriminator; - } - - @NonNull - public String getNetworkName() { - return networkName; - } - - @NonNull - public byte[] getExtendedPanId() { - return extendedPanId; - } - - @NonNull - public byte[] getPskc() { - return pskc; - } - - @Nullable - public byte[] getActiveOperationalDataset() { - return activeOperationalDataset; - } -} diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CommissionerUtils.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CommissionerUtils.java index a51f40970..b31748886 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CommissionerUtils.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CommissionerUtils.java @@ -29,6 +29,9 @@ package io.openthread.commissioner.service; import androidx.annotation.Nullable; +import androidx.concurrent.futures.CallbackToFutureAdapter; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; import io.openthread.commissioner.ByteArray; public class CommissionerUtils { @@ -76,4 +79,27 @@ public static String getHexString(@Nullable byte[] byteArray) { public static String getHexString(ByteArray byteArray) { return getHexString(getByteArray(byteArray)); } + + /** Converts a {@link Task} to a {@link ListenableFuture}. */ + public static ListenableFuture toListenableFuture(Task task) { + return CallbackToFutureAdapter.getFuture( + completer -> { + task.addOnCompleteListener( + completedTask -> { + if (completedTask.isCanceled()) { + completer.setCancelled(); + } else if (completedTask.isSuccessful()) { + completer.set(completedTask.getResult()); + } else { + Exception e = completedTask.getException(); + if (e != null) { + completer.setException(e); + } else { + throw new IllegalStateException(); + } + } + }); + return "toListenableFuture"; + }); + } } diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/FetchCredentialDialogFragment.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/FetchCredentialDialogFragment.java index 58b6c6f90..7331e61b3 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/FetchCredentialDialogFragment.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/FetchCredentialDialogFragment.java @@ -39,6 +39,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; +import com.google.android.gms.threadnetwork.ThreadNetworkCredentials; public class FetchCredentialDialogFragment extends DialogFragment implements DialogInterface.OnClickListener { @@ -50,12 +51,14 @@ public class FetchCredentialDialogFragment extends DialogFragment BorderAgentInfo borderAgentInfo; byte[] pskc; - private ThreadNetworkCredential credential; + private ThreadNetworkCredentials credentials; public interface CredentialListener { + void onCancelClick(FetchCredentialDialogFragment fragment); - void onConfirmClick(FetchCredentialDialogFragment fragment, ThreadNetworkCredential credential); + void onConfirmClick( + FetchCredentialDialogFragment fragment, ThreadNetworkCredentials credentials); } public FetchCredentialDialogFragment( @@ -105,7 +108,7 @@ public void onStop() { @Override public void onClick(DialogInterface dialogInterface, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { - credentialListener.onConfirmClick(this, credential); + credentialListener.onConfirmClick(this, credentials); } else { stopFetching(); credentialListener.onCancelClick(this); diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/MeshcopFragment.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/MeshcopFragment.java index f36d3700c..2ba0eb6ab 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/MeshcopFragment.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/MeshcopFragment.java @@ -40,8 +40,11 @@ import android.widget.ProgressBar; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; -import java.util.concurrent.CompletableFuture; +import com.google.common.util.concurrent.FluentFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.ListenableFuture; public class MeshcopFragment extends Fragment implements ThreadCommissionerServiceImpl.IntermediateStateCallback { @@ -55,18 +58,17 @@ public class MeshcopFragment extends Fragment ImageView doneImage; ImageView errorImage; - @NonNull private FragmentCallback meshcopCallback; + @NonNull private final FragmentCallback meshcopCallback; - @NonNull private ThreadNetworkInfoHolder networkInfoHolder; + @NonNull private final ThreadNetworkInfoHolder networkInfoHolder; - @NonNull private byte[] pskc; + @NonNull private final byte[] pskc; - @NonNull private JoinerDeviceInfo joinerDeviceInfo; + @NonNull private final JoinerDeviceInfo joinerDeviceInfo; - private ThreadCommissionerServiceImpl commissionerService = - new ThreadCommissionerServiceImpl(this); - - private CompletableFuture commissionFuture; + private final ThreadCommissionerServiceImpl commissionerService = + ThreadCommissionerServiceImpl.newInstance(this); + private ListenableFuture commissionFuture; public MeshcopFragment( @NonNull FragmentCallback meshcopCallback, @@ -127,25 +129,21 @@ private void startMeshcop() { showInProgress("Petitioning..."); commissionFuture = - commissionerService - .commissionJoinerDevice(borderAgentInfo, pskc, joinerDeviceInfo) - .thenRun( - () -> { - new Handler(Looper.getMainLooper()) - .post( - () -> { - showCommissionDone(true, "Commission Succeed"); - }); - }) - .exceptionally( - ex -> { - new Handler(Looper.getMainLooper()) - .post( - () -> { - showCommissionDone(false, ex.getMessage()); - }); - return null; - }); + commissionerService.commissionJoinerDevice(borderAgentInfo, pskc, joinerDeviceInfo); + FluentFuture.from(commissionFuture) + .addCallback( + new FutureCallback() { + @Override + public void onSuccess(Void result) { + showCommissionDone(true, "Commission Succeed"); + } + + @Override + public void onFailure(Throwable t) { + showCommissionDone(false, t.getMessage()); + } + }, + ContextCompat.getMainExecutor(getActivity())); } private void stopMeshcop() { diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkAdapter.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkAdapter.java index 96a220a62..ebb259621 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkAdapter.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkAdapter.java @@ -41,6 +41,7 @@ import java.util.Vector; public class NetworkAdapter extends BaseAdapter implements BorderAgentListener { + private Vector networks; private LayoutInflater inflater; @@ -68,10 +69,10 @@ public void addBorderAgent(BorderAgentInfo borderAgent) { new Handler(Looper.getMainLooper()).post(() -> notifyDataSetChanged()); } - public void removeBorderAgent(String lostBorderAgentDisciminator) { + public void removeBorderAgent(byte[] lostBorderAgentId) { for (ThreadNetworkInfoHolder networkInfoHolder : networks) { for (BorderAgentInfo borderAgent : networkInfoHolder.getBorderAgents()) { - if (borderAgent.discriminator.equals(lostBorderAgentDisciminator)) { + if (Arrays.equals(borderAgent.id, lostBorderAgentId)) { networkInfoHolder.getBorderAgents().remove(borderAgent); if (networkInfoHolder.getBorderAgents().isEmpty()) { networks.remove(networkInfoHolder); @@ -119,7 +120,7 @@ public void onBorderAgentFound(BorderAgentInfo borderAgentInfo) { } @Override - public void onBorderAgentLost(String discriminator) { - removeBorderAgent(discriminator); + public void onBorderAgentLost(byte[] borderAgentId) { + removeBorderAgent(borderAgentId); } } diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkCredential.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkCredential.java deleted file mode 100644 index ea37c923f..000000000 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkCredential.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Commissioner 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. - */ - -package io.openthread.commissioner.service; - -public interface NetworkCredential { - byte[] getEncoded(); -} diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ScanQrCodeFragment.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ScanQrCodeFragment.java index e2020cd74..229a6003d 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ScanQrCodeFragment.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ScanQrCodeFragment.java @@ -56,9 +56,6 @@ public class ScanQrCodeFragment extends Fragment implements Detector.Processor() { + @Override + public void onSuccess(ThreadNetworkCredentials credentials) { + if (credentials != null) { + networkInfoCallback.onNetworkSelected(selectedNetwork, credentials.getPskc()); + } else { + // Ask the user to input Commissioner password. + new InputNetworkPasswordDialogFragment(SelectNetworkFragment.this) + .show( + getParentFragmentManager(), + InputNetworkPasswordDialogFragment.class.getSimpleName()); + } + } + + @Override + public void onFailure(Throwable t) { + Log.e(TAG, "Failed to retrieve Thread network credentials from GMS", t); + showAlertDialog(t.getMessage()); + } + }, + ContextCompat.getMainExecutor(getActivity())); + } + + private void showAlertDialog(String message) { + new MaterialAlertDialogBuilder(getActivity(), R.style.ThreadNetworkAlertTheme) + .setMessage(message) + .setPositiveButton( + "OK", + ((dialog, which) -> { + networkInfoCallback.onMeshcopResult(Activity.RESULT_CANCELED); + })) + .show(); } @Override @@ -230,7 +252,7 @@ public void onCancelClick(FetchCredentialDialogFragment fragment) { @Override public void onConfirmClick( - FetchCredentialDialogFragment fragment, ThreadNetworkCredential credential) { + FetchCredentialDialogFragment fragment, ThreadNetworkCredentials credentials) { // TODO: } } diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerService.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerService.java index bdfc35fdb..87add5fca 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerService.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerService.java @@ -29,32 +29,17 @@ package io.openthread.commissioner.service; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import java.util.concurrent.CompletableFuture; +import com.google.android.gms.threadnetwork.ThreadNetworkCredentials; +import com.google.common.util.concurrent.ListenableFuture; public interface ThreadCommissionerService { - // This method returns Credential of a given Thread Network. - // If the Commissioner Service doesn't possess the Network - // Credentials already, it will fetch the Credentials from - // a Border Agent (assisting device) using the Thread - // Commissioning protocol. - // - // The pskc is used to securely connect to the Border Agent device. - // If no pskc is given, the user will be asked to input it. - // The Network Credentials will be saved in the Commissioner - // Service before returning. - CompletableFuture fetchThreadNetworkCredential( - @NonNull BorderAgentInfo borderAgentInfo, @Nullable byte[] pskc); - - // This method returns Credential of a given Thread Network stored in the database on the phone. - CompletableFuture getThreadNetworkCredential( + /** Returns Credential of a given Thread Network stored in the database on the phone. */ + ListenableFuture getThreadNetworkCredentials( @NonNull BorderAgentInfo borderAgentInfo); - // This method deletes Credential of a given Thread Network stored in the database on the phone. - CompletableFuture deleteThreadNetworkCredential(@NonNull BorderAgentInfo borderAgentInfo); - - CompletableFuture commissionJoinerDevice( + /** Securely adds a new Thread joiner device into the Thread network via MeshCoP. */ + ListenableFuture commissionJoinerDevice( @NonNull BorderAgentInfo borderAgentInfo, @NonNull byte[] pskc, @NonNull JoinerDeviceInfo joinerDeviceInfo); diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceFactory.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceFactory.java deleted file mode 100644 index d42550a13..000000000 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceFactory.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Commissioner 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. - */ - -package io.openthread.commissioner.service; - -class ThreadCommissionerServiceFactory { - public static ThreadCommissionerService getCommissionerService() { - return new ThreadCommissionerServiceImpl(null); - } -} diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceImpl.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceImpl.java index da9f34bda..e2490118e 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceImpl.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceImpl.java @@ -32,6 +32,14 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.google.android.gms.threadnetwork.ThreadBorderAgent; +import com.google.android.gms.threadnetwork.ThreadNetwork; +import com.google.android.gms.threadnetwork.ThreadNetworkClient; +import com.google.android.gms.threadnetwork.ThreadNetworkCredentials; +import com.google.common.util.concurrent.FluentFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; import io.openthread.commissioner.ByteArray; import io.openthread.commissioner.ChannelMask; import io.openthread.commissioner.Commissioner; @@ -43,14 +51,15 @@ import java.math.BigInteger; import java.net.Inet6Address; import java.net.InetAddress; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; public class ThreadCommissionerServiceImpl extends CommissionerHandler implements ThreadCommissionerService { public interface IntermediateStateCallback { + void onPetitioned(); void onJoinerRequest(@NonNull byte[] joinerId); @@ -60,93 +69,64 @@ public interface IntermediateStateCallback { private static final int SECONDS_WAIT_FOR_JOINER = 60; + private final ThreadNetworkClient threadNetworkClient; + private final Executor executor; @Nullable private IntermediateStateCallback intermediateStateCallback; - @NonNull private BorderAgentDatabase borderAgentDatabase = BorderAgentDatabase.getDatabase(); - @Nullable private JoinerDeviceInfo curJoinerInfo; private ConditionVariable curJoinerCommissioned = new ConditionVariable(); - public ThreadCommissionerServiceImpl( + public static ThreadCommissionerServiceImpl newInstance( + @Nullable IntermediateStateCallback intermediateStateCallback) { + return new ThreadCommissionerServiceImpl( + ThreadNetwork.getClient(CommissionerServiceApp.getContext()), + Executors.newSingleThreadExecutor(), + intermediateStateCallback); + } + + private ThreadCommissionerServiceImpl( + ThreadNetworkClient threadNetworkClient, + Executor executor, @Nullable IntermediateStateCallback intermediateStateCallback) { + this.threadNetworkClient = threadNetworkClient; + this.executor = executor; this.intermediateStateCallback = intermediateStateCallback; } @Override - public CompletableFuture commissionJoinerDevice( + public ListenableFuture commissionJoinerDevice( @NonNull BorderAgentInfo borderAgentInfo, @NonNull byte[] pskc, @NonNull JoinerDeviceInfo joinerDeviceInfo) { - CompletableFuture future = - CompletableFuture.runAsync( - () -> { - try { - doCommissionJoinerDevice( - borderAgentInfo, pskc, joinerDeviceInfo, SECONDS_WAIT_FOR_JOINER); - } catch (ThreadCommissionerException e) { - throw new CompletionException(e); - } - }); - return future; - } - - @Override - public CompletableFuture fetchThreadNetworkCredential( - @NonNull BorderAgentInfo borderAgentInfo, @Nullable byte[] pskc) { - return getThreadNetworkCredential(borderAgentInfo) - .thenApply( - credential -> { - if (credential != null) { - return credential; - } - - try { - byte[] activeDataset = doFetchActiveDataset(borderAgentInfo, pskc); - return new ThreadNetworkCredential(activeDataset); - } catch (ThreadCommissionerException e) { - throw new CompletionException(e); - } - }); - } - - @Override - public CompletableFuture getThreadNetworkCredential( - @NonNull BorderAgentInfo borderAgentInfo) { - return getBorderAgentRecord(borderAgentInfo) - .thenApply( - borderAgentRecord -> { - if (borderAgentRecord == null - || borderAgentRecord.getActiveOperationalDataset() == null) { - return null; - } - return new ThreadNetworkCredential(borderAgentRecord.getActiveOperationalDataset()); - }); - } - - CompletableFuture getBorderAgentRecord( - @NonNull BorderAgentInfo borderAgentInfo) { - return borderAgentDatabase.getBorderAgent(borderAgentInfo.discriminator); + return Futures.submitAsync( + () -> { + try { + doCommissionJoinerDevice( + borderAgentInfo, pskc, joinerDeviceInfo, SECONDS_WAIT_FOR_JOINER); + return Futures.immediateVoidFuture(); + } catch (ThreadCommissionerException ex) { + return Futures.immediateFailedFuture(ex); + } + }, + executor); } @Override - public CompletableFuture deleteThreadNetworkCredential( + public ListenableFuture getThreadNetworkCredentials( @NonNull BorderAgentInfo borderAgentInfo) { - return borderAgentDatabase.deleteBorderAgent(borderAgentInfo.discriminator); + return FluentFuture.from( + CommissionerUtils.toListenableFuture( + threadNetworkClient.getCredentialsByBorderAgent( + ThreadBorderAgent.newBuilder(borderAgentInfo.id).build()))) + .transform(result -> result.getCredentials(), MoreExecutors.directExecutor()); } - // This method adds given Thread Network Credential into database on the phone. - private CompletableFuture addThreadNetworkCredential( - @NonNull BorderAgentInfo borderAgentInfo, - @NonNull byte[] pskc, - @Nullable ThreadNetworkCredential networkCredential) { - BorderAgentRecord borderAgentRecord = - new BorderAgentRecord( - borderAgentInfo.discriminator, - borderAgentInfo.networkName, - borderAgentInfo.extendedPanId, - pskc, - networkCredential == null ? null : networkCredential.getEncoded()); - return borderAgentDatabase.insertBorderAgent(borderAgentRecord); + /** Adds given Thread Network Credential into database on the phone. */ + private ListenableFuture addThreadNetworkCredentials( + BorderAgentInfo borderAgentInfo, ThreadNetworkCredentials credentials) { + return CommissionerUtils.toListenableFuture( + threadNetworkClient.addCredentials( + ThreadBorderAgent.newBuilder(borderAgentInfo.id).build(), credentials)); } private void doCommissionJoinerDevice( @@ -177,8 +157,13 @@ private void doCommissionJoinerDevice( nativeCommissioner.petition( existingCommissionerId, borderAgentInfo.host.getHostAddress(), borderAgentInfo.port)); - // Save PSKc for current Border Agent once we have successfully connected to it. - addThreadNetworkCredential(borderAgentInfo, pskc, null).get(); + // Retrieves active dataset and saves it to GMS Core + ByteArray rawActiveDataset = new ByteArray(); + throwIfFail(nativeCommissioner.getRawActiveDataset(rawActiveDataset, 0xFFFF)); + ThreadNetworkCredentials credentials = + ThreadNetworkCredentials.fromActiveOperationalDataset( + CommissionerUtils.getByteArray(rawActiveDataset)); + addThreadNetworkCredentials(borderAgentInfo, credentials).get(); if (intermediateStateCallback != null) { intermediateStateCallback.onPetitioned(); @@ -235,8 +220,6 @@ private byte[] doFetchActiveDataset( getBorderAgentAddress(borderAgentInfo), borderAgentInfo.port)); - addThreadNetworkCredential(borderAgentInfo, pskc, null).get(); - if (intermediateStateCallback != null) { intermediateStateCallback.onPetitioned(); } @@ -245,10 +228,6 @@ private byte[] doFetchActiveDataset( ByteArray rawActiveDataset = new ByteArray(); throwIfFail(nativeCommissioner.getRawActiveDataset(rawActiveDataset, 0xFFFF)); return CommissionerUtils.getByteArray(rawActiveDataset); - } catch (InterruptedException e) { - throw new ThreadCommissionerException(ErrorCode.kUnknown, e.getMessage()); - } catch (ExecutionException e) { - throw new ThreadCommissionerException(ErrorCode.kUnknown, e.getMessage()); } finally { nativeCommissioner.resign(); } @@ -320,7 +299,7 @@ public void onEnergyReport(String aPeerAddr, ChannelMask aChannelMask, ByteArray @Override public void onDatasetChanged() { - Log.d(TAG, "Thread Network Dataset chanaged"); + Log.d(TAG, "Thread Network Dataset changed"); } private ByteArray getCurJoinerId() { diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadNetworkCredential.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadNetworkCredential.java deleted file mode 100644 index 3d09edd31..000000000 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadNetworkCredential.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Commissioner 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. - */ - -package io.openthread.commissioner.service; - -import android.os.Parcel; -import android.os.Parcelable; -import androidx.annotation.NonNull; - -public class ThreadNetworkCredential implements NetworkCredential, Parcelable { - - @NonNull private final byte[] activeOperationalDataset; - - public ThreadNetworkCredential(@NonNull byte[] activeOperationalDataset) { - this.activeOperationalDataset = activeOperationalDataset; - } - - protected ThreadNetworkCredential(Parcel in) { - activeOperationalDataset = in.createByteArray(); - } - - public static final Creator CREATOR = - new Creator() { - @Override - public ThreadNetworkCredential createFromParcel(Parcel in) { - return new ThreadNetworkCredential(in); - } - - @Override - public ThreadNetworkCredential[] newArray(int size) { - return new ThreadNetworkCredential[size]; - } - }; - - public byte[] getActiveOperationalDataset() { - return activeOperationalDataset; - } - - @Override - public byte[] getEncoded() { - return activeOperationalDataset; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel parcel, int i) { - parcel.writeByteArray(activeOperationalDataset); - } -} diff --git a/android/openthread_commissioner/service/src/main/res/values/styles.xml b/android/openthread_commissioner/service/src/main/res/values/styles.xml index 3641696d0..9b1966677 100644 --- a/android/openthread_commissioner/service/src/main/res/values/styles.xml +++ b/android/openthread_commissioner/service/src/main/res/values/styles.xml @@ -10,4 +10,19 @@ + + + + diff --git a/include/commissioner/defines.hpp b/include/commissioner/defines.hpp index c3fe5614a..d619f8507 100644 --- a/include/commissioner/defines.hpp +++ b/include/commissioner/defines.hpp @@ -123,6 +123,11 @@ static constexpr uint16_t kDefaultAeUdpPort = 1001; */ static constexpr uint16_t kDefaultNmkpUdpPort = 1002; +/** + * The default management UDP Port used by TMF transaction in Thread devices. + */ +static constexpr uint16_t kDefaultMmPort = 61631; + /** * If using radio 915Mhz. Default radio freq of Thread is 2.4Ghz. * diff --git a/include/commissioner/error.hpp b/include/commissioner/error.hpp index 5771eed55..9b5dba768 100644 --- a/include/commissioner/error.hpp +++ b/include/commissioner/error.hpp @@ -264,14 +264,21 @@ inline bool operator!=(const ErrorCode &aErrorCode, const Error &aError) return !(aErrorCode == aError); } +std::string ErrorCodeToString(ErrorCode code); + /** * Allows pretty-print in unit tests. * * See https://google.github.io/googletest/advanced.html#teaching-googletest-how-to-print-your-values */ -inline void PrintTo(const Error &error, std::ostream *os) +inline void PrintTo(const Error &aError, std::ostream *os) +{ + *os << aError.ToString(); +} + +inline void PrintTo(ErrorCode aErrorCode, std::ostream *os) { - *os << error.ToString(); + *os << ErrorCodeToString(aErrorCode); } } // namespace commissioner diff --git a/include/commissioner/network_data.hpp b/include/commissioner/network_data.hpp index fb488b6a4..bd4962571 100644 --- a/include/commissioner/network_data.hpp +++ b/include/commissioner/network_data.hpp @@ -52,36 +52,6 @@ static constexpr uint8_t kMlrStatusNoResources = 4; static constexpr uint8_t kMlrStatusNotPrimary = 5; static constexpr uint8_t kMlrStatusFailure = 6; -/** - * Extended PAN Id wrapper - */ -struct XpanId -{ - static constexpr uint64_t kEmptyXpanId = 0; - - uint64_t mValue; - - XpanId(uint64_t val); - - XpanId(); - - std::string str() const; - - bool operator==(const XpanId &aOther) const; - - bool operator!=(const XpanId &aOther) const; - bool operator<(const XpanId &aOther) const; - - explicit operator std::string() const; - - /** - * Decodes hexadecimal string. - */ - Error FromHex(const std::string &aInput); -}; - -typedef std::vector XpanIdArray; - /** * @brief The Commissioner Dataset of the Thread Network Data. * @@ -249,26 +219,6 @@ enum SecurityPolicyFlags kSecurityPolicyMask_VR = 1 << 5 | 1 << 6 | 1 << 7, /// Protocol version }; -/** - * A PAN identifier. - */ -struct PanId -{ - static constexpr uint64_t kEmptyPanId = 0; - - uint16_t mValue; - explicit PanId(uint16_t aValue); - PanId(const PanId &aOther) = default; - PanId(); - - PanId &operator=(const PanId &aValue) = default; - PanId &operator=(uint16_t aValue); - explicit operator uint16_t() const; - explicit operator std::string() const; - - Error FromHex(const std::string &aInput); -}; - /** * @brief The Active Operational Dataset of the Thread Network Data. * @@ -283,13 +233,13 @@ struct PanId struct ActiveOperationalDataset { Timestamp mActiveTimestamp; + ByteArray mExtendedPanId; + uint16_t mPanId; + std::string mNetworkName; Channel mChannel; ChannelMask mChannelMask; - XpanId mExtendedPanId; ByteArray mMeshLocalPrefix; ByteArray mNetworkMasterKey; - std::string mNetworkName; - PanId mPanId; ByteArray mPSKc; SecurityPolicy mSecurityPolicy; diff --git a/src/app/cli/interpreter.cpp b/src/app/cli/interpreter.cpp index b81124879..e0549f81c 100644 --- a/src/app/cli/interpreter.cpp +++ b/src/app/cli/interpreter.cpp @@ -123,6 +123,8 @@ namespace ot { namespace commissioner { using ot::commissioner::persistent_storage::Network; +using ot::commissioner::utils::Hex; +using ot::commissioner::utils::ParseInteger; namespace { /** @@ -177,10 +179,9 @@ Interpreter::NetworkSelectionComparator::~NetworkSelectionComparator() Network nwk; RegistryStatus status = mInterpreter.mRegistry->GetCurrentNetwork(nwk); - if (status == RegistryStatus::kSuccess && mStartWith.mValue != nwk.mXpan.mValue) + if (status == RegistryStatus::kSuccess && mStartWith != nwk.mXpan) { - Console::Write(nwk.mXpan.mValue == XpanId::kEmptyXpanId ? WARN_NETWORK_SELECTION_DROPPED - : WARN_NETWORK_SELECTION_CHANGED, + Console::Write(nwk.mXpan == 0 ? WARN_NETWORK_SELECTION_DROPPED : WARN_NETWORK_SELECTION_CHANGED, Console::Color::kYellow); } } @@ -351,23 +352,6 @@ template static std::string ToHex(T aInteger) return "0x" + utils::Hex(utils::Encode(aInteger)); }; -template static Error ParseInteger(T &aInteger, const std::string &aStr) -{ - Error error; - uint64_t integer; - char *endPtr = nullptr; - - integer = strtoull(aStr.c_str(), &endPtr, 0); - - VerifyOrExit(endPtr != nullptr && endPtr > aStr.c_str(), - error = ERROR_INVALID_ARGS("{} is not a valid integer", aStr)); - - aInteger = integer; - -exit: - return error; -} - static inline std::string ToLower(const std::string &aStr) { return utils::ToLower(aStr); @@ -404,11 +388,11 @@ Error Interpreter::UpdateNetworkSelectionInfo(bool onStart /*=false*/) VerifyOrExit(mRegistry->GetCurrentNetwork(nwk) == Registry::Status::kSuccess, error = ERROR_REGISTRY_ERROR(RUNTIME_CUR_NETWORK_FAILED)); - if (onStart && nwk.mXpan.mValue != XpanId::kEmptyXpanId) + if (onStart && nwk.mXpan != 0) { Console::Write(fmt::format(FMT_STRING("Network selection recalled from previous session.\n" "Restored to [{}:'{}']"), - nwk.mXpan.str(), nwk.mName), + utils::Hex(nwk.mXpan), nwk.mName), Console::Color::kGreen); } exit: @@ -549,7 +533,7 @@ Interpreter::Value Interpreter::Eval(const Expression &aExpr) if (mContext.mNwkAliases.size() > 0 || mContext.mDomAliases.size() > 0) { - XpanIdArray nids; + std::vector nids; SuccessOrExit(value = ValidateMultiNetworkSyntax(retExpr, nids)); if (IsMultiJob(retExpr)) // asynchronous processing required @@ -574,19 +558,19 @@ Interpreter::Value Interpreter::Eval(const Expression &aExpr) // handle single command using selected network if (mContext.mImportFiles.size() > 0) { - XpanId xpan = XpanId(); + uint64_t xpan = 0; if (mContext.mNwkAliases.empty()) { auto result = mRegistry->GetCurrentNetworkXpan(xpan); if (result != Registry::Status::kSuccess) { - xpan = XpanId(); + xpan = 0; } } else { - XpanIdArray nwks; - StringArray unresolved; + std::vector nwks; + StringArray unresolved; VerifyOrExit(mRegistry->GetNetworkXpansByAliases(mContext.mNwkAliases, nwks, unresolved) == Registry::Status::kSuccess, value = ERROR_INVALID_ARGS("Failed to resolve network alias for import")); @@ -624,7 +608,7 @@ bool Interpreter::IsInactiveCommissionerAllowed(const Expression &aExpr) return IsFeatureSupported(mInactiveCommissionerExecution, aExpr); } -Interpreter::Value Interpreter::ValidateMultiNetworkSyntax(const Expression &aExpr, XpanIdArray &aNids) +Interpreter::Value Interpreter::ValidateMultiNetworkSyntax(const Expression &aExpr, std::vector &aNids) { Error error; bool supported; @@ -846,7 +830,7 @@ void Interpreter::PrintOrExport(const Value &aValue) void Interpreter::PrintNetworkMessage(uint64_t aNid, std::string aMessage, Console::Color aColor) { - std::string nidHex = std::string(XpanId(aNid)); + std::string nidHex = utils::Hex(aNid); PrintNetworkMessage(nidHex, aMessage, aColor); } @@ -970,7 +954,7 @@ Interpreter::Value Interpreter::ProcessStart(const Expression &aExpr) case 1: { // starting currently selected network - XpanId nid; + uint64_t nid; RegistryStatus status = mRegistry->GetCurrentNetworkXpan(nid); VerifyOrExit(status == RegistryStatus::kSuccess, value = ERROR_REGISTRY_ERROR("getting selected network failed")); @@ -1191,7 +1175,7 @@ Interpreter::Value Interpreter::ProcessBr(const Expression &aExpr) } else { - PrintNetworkMessage(nwk.mXpan.mValue, RUNTIME_LOOKUP_FAILED, COLOR_ALIAS_FAILED); + PrintNetworkMessage(nwk.mXpan, RUNTIME_LOOKUP_FAILED, COLOR_ALIAS_FAILED); } } } @@ -1547,8 +1531,8 @@ Interpreter::Value Interpreter::ProcessBr(const Expression &aExpr) ExitNow(value = ERROR_CANCELLED("Scan cancelled by user")); } - XpanIdArray xpans; - StringArray unresolved; + std::vector xpans; + StringArray unresolved; if (!mContext.mNwkAliases.empty()) { VerifyOrExit(mRegistry->GetNetworkXpansByAliases(mContext.mNwkAliases, xpans, unresolved) == @@ -1580,8 +1564,7 @@ Interpreter::Value Interpreter::ProcessBr(const Expression &aExpr) (agentOrError.mBorderAgent.mDomainName == mContext.mDomAliases[0])) || (!mContext.mNwkAliases.empty() && (agentOrError.mBorderAgent.mPresentFlags & BorderAgent::kExtendedPanIdBit) && - (std::find(xpans.begin(), xpans.end(), XpanId(agentOrError.mBorderAgent.mExtendedPanId)) != - xpans.end()))) + (std::find(xpans.begin(), xpans.end(), agentOrError.mBorderAgent.mExtendedPanId) != xpans.end()))) { baJson.push_back(ba); } @@ -1686,9 +1669,9 @@ Interpreter::Value Interpreter::ProcessNetwork(const Expression &aExpr) } else { - StringArray aliases = {aExpr[2]}; - XpanIdArray xpans; - StringArray unresolved; + StringArray aliases = {aExpr[2]}; + std::vector xpans; + StringArray unresolved; VerifyOrExit(mRegistry->GetNetworkXpansByAliases(aliases, xpans, unresolved) == RegistryStatus::kSuccess, value = ERROR_REGISTRY_ERROR("Failed to resolve extended PAN Id for network '{}'", aExpr[2])); VerifyOrExit(xpans.size() == 1, value = ERROR_IO_ERROR("Detected {} networks instead of 1 for alias '{}'", @@ -1721,8 +1704,8 @@ Interpreter::Value Interpreter::ProcessNetwork(const Expression &aExpr) nwkData += '/'; } nwkData += nwk.mName; - json[nwk.mXpan.str()] = nwkData; - value = json.dump(JSON_INDENT_DEFAULT); + json[utils::Hex(nwk.mXpan)] = nwkData; + value = json.dump(JSON_INDENT_DEFAULT); } } else @@ -2115,7 +2098,7 @@ Interpreter::Value Interpreter::ProcessOpDatasetJob(CommissionerAppPtr &aCommiss } else if (CaseInsensitiveEqual(aExpr[2], "panid")) { - PanId panid; + uint16_t panid; if (isSet) { uint32_t delay; @@ -2127,7 +2110,7 @@ Interpreter::Value Interpreter::ProcessOpDatasetJob(CommissionerAppPtr &aCommiss else { SuccessOrExit(value = aCommissioner->GetPanId(panid)); - value = std::string(panid); + value = Hex(panid); } } else if (CaseInsensitiveEqual(aExpr[2], "pskc")) @@ -2166,7 +2149,7 @@ Interpreter::Value Interpreter::ProcessOpDatasetJob(CommissionerAppPtr &aCommiss ActiveOperationalDataset dataset; StringArray nwkAliases; StringArray unresolved; - XpanIdArray xpans; + std::vector xpans; if (isSet) { @@ -2186,13 +2169,13 @@ Interpreter::Value Interpreter::ProcessOpDatasetJob(CommissionerAppPtr &aCommiss // Get network object for the opdataset object if ((dataset.mPresentFlags & ActiveOperationalDataset::kExtendedPanIdBit) != 0) { - xpans.push_back(dataset.mExtendedPanId); + xpans.push_back(utils::Decode(dataset.mExtendedPanId)); } else { if ((dataset.mPresentFlags & ActiveOperationalDataset::kPanIdBit) != 0) { - nwkAliases.push_back(fmt::format(FMT_STRING("0x{:04X}"), dataset.mPanId.mValue)); + nwkAliases.push_back(Hex(dataset.mPanId)); } else if ((dataset.mPresentFlags & ActiveOperationalDataset::kNetworkNameBit) != 0) { @@ -2214,8 +2197,9 @@ Interpreter::Value Interpreter::ProcessOpDatasetJob(CommissionerAppPtr &aCommiss } if (mRegistry->GetNetworkByXpan(xpans[0], nwk) != RegistryStatus::kSuccess) { - Console::Write(fmt::format(FMT_STRING("Failed to find network record by XPAN '{}'"), xpans[0].str()), - Console::Color::kYellow); + Console::Write( + fmt::format(FMT_STRING("Failed to find network record by XPAN '{}'"), utils::Hex(xpans[0])), + Console::Color::kYellow); break; /// @todo It is possible that network XPAN ID /// might have change since the last sync /// so maybe it is worth to look up for @@ -2227,13 +2211,14 @@ Interpreter::Value Interpreter::ProcessOpDatasetJob(CommissionerAppPtr &aCommiss #define AODS_FIELD_IF_IS_SET(field, defaultValue) \ (((dataset.mPresentFlags & ActiveOperationalDataset::k##field##Bit) == 0) ? (defaultValue) : (dataset.m##field)) - nwk.mName = AODS_FIELD_IF_IS_SET(NetworkName, ""); - nwk.mXpan = AODS_FIELD_IF_IS_SET(ExtendedPanId, XpanId{}); + nwk.mName = AODS_FIELD_IF_IS_SET(NetworkName, ""); + nwk.mXpan = + utils::Decode(AODS_FIELD_IF_IS_SET(ExtendedPanId, ByteArray(kExtendedPanIdLength, 0))); nwk.mChannel = AODS_FIELD_IF_IS_SET(Channel, (Channel{0, 0})).mNumber; - nwk.mPan = AODS_FIELD_IF_IS_SET(PanId, PanId{}); + nwk.mPan = AODS_FIELD_IF_IS_SET(PanId, 0); if ((dataset.mPresentFlags & ActiveOperationalDataset::kPanIdBit) == 0) { - nwk.mPan = PanId::kEmptyPanId; + nwk.mPan = 0; } else { diff --git a/src/app/cli/interpreter.hpp b/src/app/cli/interpreter.hpp index 5cd2f8164..c4e0d6904 100644 --- a/src/app/cli/interpreter.hpp +++ b/src/app/cli/interpreter.hpp @@ -84,7 +84,7 @@ class Interpreter struct NetworkSelectionComparator { const Interpreter &mInterpreter; - XpanId mStartWith; + uint64_t mStartWith; bool mSuccess; NetworkSelectionComparator(const Interpreter &aInterpreter); @@ -179,7 +179,7 @@ class Interpreter * resolution of the provided network aliases is checked in the * course of execution. */ - Value ValidateMultiNetworkSyntax(const Expression &aExpr, XpanIdArray &aNids); + Value ValidateMultiNetworkSyntax(const Expression &aExpr, std::vector &aNids); /** * Resolves network aliases into a set of network ids. In the * course of resolution, duplicate network ids are compacted if diff --git a/src/app/cli/interpreter_test.cpp b/src/app/cli/interpreter_test.cpp index 4ebefba7b..39602721e 100644 --- a/src/app/cli/interpreter_test.cpp +++ b/src/app/cli/interpreter_test.cpp @@ -56,6 +56,7 @@ #include "commissioner/defines.hpp" #include "commissioner/error.hpp" #include "commissioner/network_data.hpp" +#include "common/utils.hpp" #include "fmt/core.h" #include "gmock/gmock-matchers.h" #include "gmock/gmock-spec-builders.h" @@ -63,6 +64,7 @@ #include "nlohmann/json.hpp" using namespace ot::commissioner; +using namespace ot::commissioner::utils; using namespace ot::commissioner::persistent_storage; using testing::_; @@ -97,8 +99,8 @@ class InterpreterTestSuite : public testing::Test void InitContext(TestContext &ctx) { // Minimum test setup: create config file - const std::string configFile = "./config"; - auto error = WriteFile("{\"ThreadSMRoot\": \"./\"}", configFile); + const std::string configFile = "./tmp/config"; + auto error = WriteFile("{\"ThreadSMRoot\": \"./tmp\"}", configFile); ASSERT_EQ(error.GetCode(), ErrorCode::kNone); ASSERT_NE(ctx.mDefaultCommissionerObject, nullptr); @@ -108,7 +110,7 @@ class InterpreterTestSuite : public testing::Test DoAll(WithArg<0>([&](std::shared_ptr &a) { a = ctx.mDefaultCommissionerObject; }), Return(Error{}))); - auto result = ctx.mInterpreter.Init("./config", ""); + auto result = ctx.mInterpreter.Init("./tmp/config", ""); ASSERT_EQ(result.GetCode(), ErrorCode::kNone); ctx.mRegistry = ctx.mInterpreter.mRegistry.get(); @@ -116,6 +118,12 @@ class InterpreterTestSuite : public testing::Test // Add formal default PSKc ctx.mInterpreter.mJobManager->mDefaultConf.mPSKc = {'1', '0'}; } + + void SetUp() override + { + ASSERT_TRUE(system("rm -rf tmp") == 0); + ASSERT_TRUE(system("mkdir -p tmp") == 0); + } }; TEST_F(InterpreterTestSuite, TestInit) @@ -146,7 +154,7 @@ TEST_F(InterpreterTestSuite, MNSV_ValidSyntaxPass) std::string command; Interpreter::Expression expr; Interpreter::Expression ret; - XpanIdArray nids; + std::vector nids; command = "start --nwk all"; expr = ctx.mInterpreter.ParseExpression(command); @@ -200,7 +208,7 @@ TEST_F(InterpreterTestSuite, MNSV_TwoGroupNwkAliasesFail) InitContext(ctx); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk all other"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_FALSE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -219,7 +227,7 @@ TEST_F(InterpreterTestSuite, MNSV_ThisResolvesWithCurrentSet) ASSERT_EQ(ctx.mRegistry->SetCurrentNetwork(br), RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk this"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -235,7 +243,7 @@ TEST_F(InterpreterTestSuite, MNSV_ThisUnresolvesWithCurrentUnset) RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk this"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_FALSE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -259,12 +267,12 @@ TEST_F(InterpreterTestSuite, MNSV_AllOtherSameWithCurrentUnselected) // No current network selected Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk all"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{1}), nids.end()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{2}), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 1), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 2), nids.end()); ctx.mInterpreter.mContext.Cleanup(); ctx.mInterpreter.mJobManager->CleanupJobs(); ret.clear(); @@ -273,8 +281,8 @@ TEST_F(InterpreterTestSuite, MNSV_AllOtherSameWithCurrentUnselected) expr = ctx.mInterpreter.ParseExpression("start --nwk other"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{1}), nids.end()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{2}), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 1), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 2), nids.end()); ctx.mInterpreter.mContext.Cleanup(); ctx.mInterpreter.mJobManager->CleanupJobs(); ret.clear(); @@ -300,12 +308,12 @@ TEST_F(InterpreterTestSuite, MNSV_AllOtherDifferWithCurrentSelected) ASSERT_EQ(ctx.mRegistry->SetCurrentNetwork(br), RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk all"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{1}), nids.end()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{2}), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 1), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 2), nids.end()); ctx.mInterpreter.mContext.Cleanup(); ctx.mInterpreter.mJobManager->CleanupJobs(); ret.clear(); @@ -314,8 +322,8 @@ TEST_F(InterpreterTestSuite, MNSV_AllOtherDifferWithCurrentSelected) expr = ctx.mInterpreter.ParseExpression("start --nwk other"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); - EXPECT_EQ(std::find(nids.begin(), nids.end(), XpanId{1}), nids.end()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{2}), nids.end()); + EXPECT_EQ(std::find(nids.begin(), nids.end(), 1), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 2), nids.end()); ctx.mInterpreter.mContext.Cleanup(); ctx.mInterpreter.mJobManager->CleanupJobs(); ret.clear(); @@ -338,7 +346,7 @@ TEST_F(InterpreterTestSuite, MNSV_TwoDomSwitchesFail) RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --dom domain1 --dom domain2"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_FALSE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -355,7 +363,7 @@ TEST_F(InterpreterTestSuite, MNSV_UnexistingDomainResolveFails) RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --dom domain2"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_FALSE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -377,12 +385,12 @@ TEST_F(InterpreterTestSuite, MNSV_ExistingDomainResolves) RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --dom domain1"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{1}), nids.end()); - EXPECT_EQ(std::find(nids.begin(), nids.end(), XpanId{2}), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 1), nids.end()); + EXPECT_EQ(std::find(nids.begin(), nids.end(), 2), nids.end()); } TEST_F(InterpreterTestSuite, MNSV_AmbiguousNwkResolutionFails) @@ -391,9 +399,9 @@ TEST_F(InterpreterTestSuite, MNSV_AmbiguousNwkResolutionFails) InitContext(ctx); NetworkId nid; - ASSERT_EQ(ctx.mRegistry->mStorage->Add( - Network{NetworkId{EMPTY_ID}, DomainId{EMPTY_ID}, "net1", XpanId{1}, 0, 0xAB, "", 0}, nid), - PersistentStorage::Status::kSuccess); + ASSERT_EQ( + ctx.mRegistry->mStorage->Add(Network{NetworkId{EMPTY_ID}, DomainId{EMPTY_ID}, "net1", 1, 0, 0xAB, "", 0}, nid), + PersistentStorage::Status::kSuccess); ASSERT_EQ( ctx.mRegistry->Add(BorderAgent{"127.0.0.1", 20001, ByteArray{}, "1.1", BorderAgent::State{0, 0, 0, 0, 0}, "net1", 1, "", "", Timestamp{0, 0, 0}, 0, "", ByteArray{}, "domain1", 0, 0, "", @@ -402,18 +410,18 @@ TEST_F(InterpreterTestSuite, MNSV_AmbiguousNwkResolutionFails) // lookup by PAN ID must succeed Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk ab"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_EQ(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).mError.GetCode(), ErrorCode::kNone); EXPECT_EQ(nids.size(), 1); - EXPECT_EQ(nids[0], XpanId{1}); + EXPECT_EQ(nids[0], 1); ctx.mInterpreter.mContext.Cleanup(); // create ambiguity by adding another network with the same PAN ID - ASSERT_EQ(ctx.mRegistry->mStorage->Add( - Network{NetworkId{EMPTY_ID}, DomainId{EMPTY_ID}, "net2", XpanId{2}, 0, 0xAB, "", 0}, nid), - PersistentStorage::Status::kSuccess); + ASSERT_EQ( + ctx.mRegistry->mStorage->Add(Network{NetworkId{EMPTY_ID}, DomainId{EMPTY_ID}, "net2", 2, 0, 0xAB, "", 0}, nid), + PersistentStorage::Status::kSuccess); ASSERT_EQ( ctx.mRegistry->Add(BorderAgent{"127.0.0.2", 20001, ByteArray{}, "1.1", BorderAgent::State{0, 0, 0, 0, 0}, "net2", 2, "", "", Timestamp{0, 0, 0}, 0, "", ByteArray{}, "domain2", 0, 0, "", @@ -442,7 +450,7 @@ TEST_F(InterpreterTestSuite, MNSV_SameResolutionFromTwoAliasesCollapses) RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk 1 net1"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -465,7 +473,7 @@ TEST_F(InterpreterTestSuite, MNSV_GroupAndIndividualNwkAliasesMustFail) RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk 1 all"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_FALSE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -490,12 +498,12 @@ TEST_F(InterpreterTestSuite, MNSV_DomThisResolvesWithRespectToSelection) ASSERT_EQ(ctx.mRegistry->SetCurrentNetwork(br), RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --dom this"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); EXPECT_EQ(nids.size(), 1); - EXPECT_EQ(nids[0], XpanId{1}); + EXPECT_EQ(nids[0], 1); } TEST_F(InterpreterTestSuite, MNSV_NoAliasesResolvesToThisNwk) @@ -525,12 +533,12 @@ TEST_F(InterpreterTestSuite, MNSV_NoAliasesResolvesToThisNwk) BorderRouter br; br.mNetworkId = NetworkId{2}; ASSERT_EQ(ctx.mRegistry->SetCurrentNetwork(br), RegistryStatus::kSuccess); - XpanId nid; + uint64_t nid; ASSERT_EQ(ctx.mRegistry->GetCurrentNetworkXpan(nid), RegistryStatus::kSuccess); - ASSERT_EQ(nid, XpanId{3}); + ASSERT_EQ(nid, 3); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start"); CommissionerAppMockPtr pcaMock{new CommissionerAppMock()}; @@ -660,10 +668,10 @@ TEST_F(InterpreterTestSuite, IESV_SingleImportFileMustPass) }\n\ }"; - EXPECT_EQ(WriteFile(jsonStr, "./json.json").GetCode(), ErrorCode::kNone); + EXPECT_EQ(WriteFile(jsonStr, "./tmp/json.json").GetCode(), ErrorCode::kNone); EXPECT_CALL(*commissionerAppMock, SetActiveDataset(_)).WillOnce(Return(Error{})); - expr = ctx.mInterpreter.ParseExpression("opdataset set active --import ./json.json"); + expr = ctx.mInterpreter.ParseExpression("opdataset set active --import ./tmp/json.json"); auto value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); } @@ -1113,10 +1121,10 @@ TEST_F(InterpreterTestSuite, PC_Token) value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); - EXPECT_EQ(WriteFile("123aef", "./token").GetCode(), ErrorCode::kNone); + EXPECT_EQ(WriteFile("123aef", "./tmp/token").GetCode(), ErrorCode::kNone); EXPECT_CALL(*ctx.mDefaultCommissionerObject, SetToken(_)).WillOnce(Return(Error{})); EXPECT_CALL(*ctx.mDefaultCommissionerObject, GetToken()).WillOnce(ReturnRef(token)); - expr = ctx.mInterpreter.ParseExpression("token set ./token"); + expr = ctx.mInterpreter.ParseExpression("token set ./tmp/token"); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); } @@ -1127,17 +1135,17 @@ TEST_F(InterpreterTestSuite, PC_TokenWithCCM) InitContext(ctx); // prepare CCM network record - const std::string kDomainName = "domain1"; - const std::string kNetworkName = "net1"; - const std::string kSmPath = "./dom/" + kDomainName + "/"; - XpanId xpanCcm{1}; + const std::string kDomainName = "domain1"; + const std::string kNetworkName = "net1"; + const std::string kSmPath = "./tmp/dom/" + kDomainName + "/"; + uint64_t xpanCcm = 1; + BorderAgent::State baStateCcm{BorderAgent::State::ConnectionMode::kX509Connection, 0, 0, 0, 0}; - ASSERT_EQ( - ctx.mRegistry->Add(BorderAgent{"127.0.0.1", 20001, ByteArray{}, "1.1", baStateCcm, kNetworkName, xpanCcm.mValue, - "", "", Timestamp{0, 0, 0}, 0, "", ByteArray{}, kDomainName, 0, 0, "", 0, - 0x1F | BorderAgent::kDomainNameBit | BorderAgent::kExtendedPanIdBit}), - RegistryStatus::kSuccess); + ASSERT_EQ(ctx.mRegistry->Add(BorderAgent{"127.0.0.1", 20001, ByteArray{}, "1.1", baStateCcm, kNetworkName, xpanCcm, + "", "", Timestamp{0, 0, 0}, 0, "", ByteArray{}, kDomainName, 0, 0, "", 0, + 0x1F | BorderAgent::kDomainNameBit | BorderAgent::kExtendedPanIdBit}), + RegistryStatus::kSuccess); // prepare fake SM for the CCM network std::vector> smFiles = {{"ca", kSmPath + "ca.pem"}, @@ -1164,15 +1172,15 @@ TEST_F(InterpreterTestSuite, PC_TokenWithCCM) EXPECT_EQ(ctx.mInterpreter.mRegistry->SetCurrentNetwork(xpanCcm), RegistryStatus::kSuccess); expr = ctx.mInterpreter.ParseExpression("token request 127.0.0.1 2001"); value = ctx.mInterpreter.Eval(expr); - EXPECT_TRUE(value.HasNoError()); + EXPECT_TRUE(value.HasNoError()) << "value is " << value.ToString(); const ByteArray token = {'1', '2', '3', 'a', 'e', 'f'}; EXPECT_CALL(*pcaMock, SetToken(_)).WillOnce(Return(Error{})); // note: again, we do not expect GetToken() here, same reason - EXPECT_EQ(WriteFile("123aef", "./token").GetCode(), ErrorCode::kNone); - expr = ctx.mInterpreter.ParseExpression("token set ./token"); + EXPECT_EQ(WriteFile("123aef", "./tmp/token").GetCode(), ErrorCode::kNone); + expr = ctx.mInterpreter.ParseExpression("token set ./tmp/token"); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); } @@ -1183,17 +1191,18 @@ TEST_F(InterpreterTestSuite, PC_TokenWithNonCCM) InitContext(ctx); // prepare non-CCM network record - const std::string kDomainName = "DefaultDomain"; - const std::string kNetworkName = "net2"; - const std::string kSmPath = "./nwk/" + kNetworkName + "/"; - XpanId xpanNonCcm{2}; + const std::string kDomainName = "DefaultDomain"; + const std::string kNetworkName = "net2"; + const std::string kSmPath = "./tmp/nwk/" + kNetworkName + "/"; + uint64_t xpanNonCcm = 2; + BorderAgent::State baStateNonCcm{BorderAgent::State::ConnectionMode::kPSKcConnection, 0, 0, 0, 0}; - ASSERT_EQ(ctx.mRegistry->Add(BorderAgent{"127.0.0.1", 20001, ByteArray{}, "1.1", baStateNonCcm, kNetworkName, - xpanNonCcm.mValue, "", "", Timestamp{0, 0, 0}, 0, "", ByteArray{}, - kDomainName, 0, 0, "", 0, - 0x1F | BorderAgent::kDomainNameBit | BorderAgent::kExtendedPanIdBit}), - RegistryStatus::kSuccess); + ASSERT_EQ( + ctx.mRegistry->Add(BorderAgent{"127.0.0.1", 20001, ByteArray{}, "1.1", baStateNonCcm, kNetworkName, xpanNonCcm, + "", "", Timestamp{0, 0, 0}, 0, "", ByteArray{}, kDomainName, 0, 0, "", 0, + 0x1F | BorderAgent::kDomainNameBit | BorderAgent::kExtendedPanIdBit}), + RegistryStatus::kSuccess); // prepare fake SM for the non-CCM network std::vector> smFiles = { {"ca", kSmPath + "ca.pem"}, {"key", kSmPath + "priv.pem"}, {"cert", kSmPath + "cert.pem"}}; @@ -1223,8 +1232,8 @@ TEST_F(InterpreterTestSuite, PC_TokenWithNonCCM) // note: we do not expect GetToken() here as no default config // update to happen with a network selected - EXPECT_EQ(WriteFile("123aef", "./token").GetCode(), ErrorCode::kNone); - expr = ctx.mInterpreter.ParseExpression("token set ./token"); + EXPECT_EQ(WriteFile("123aef", "./tmp/token").GetCode(), ErrorCode::kNone); + expr = ctx.mInterpreter.ParseExpression("token set ./tmp/token"); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); } @@ -1255,8 +1264,8 @@ TEST_F(InterpreterTestSuite, PC_TokenWithNone) // GetToken() to be called on default commissioner instance EXPECT_CALL(*ctx.mDefaultCommissionerObject, GetToken()).WillOnce(ReturnRef(token)); - EXPECT_EQ(WriteFile("123aef", "./token").GetCode(), ErrorCode::kNone); - expr = ctx.mInterpreter.ParseExpression("token set ./token"); + EXPECT_EQ(WriteFile("123aef", "./tmp/token").GetCode(), ErrorCode::kNone); + expr = ctx.mInterpreter.ParseExpression("token set ./tmp/token"); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); } @@ -1499,8 +1508,8 @@ TEST_F(InterpreterTestSuite, PC_NetworkIdentifyWithDomain) { EXPECT_TRUE(false) << "Failed to parse value: " << e.what(); } - EXPECT_TRUE(json.contains("0000000000000001")); - EXPECT_STREQ("domain1/net1", json.at("0000000000000001").get().c_str()); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_STREQ("domain1/net1", json.at("0x0000000000000001").get().c_str()); } TEST_F(InterpreterTestSuite, PC_NetworkIdentifyWithoutDomain) @@ -1540,8 +1549,8 @@ TEST_F(InterpreterTestSuite, PC_NetworkIdentifyWithoutDomain) { EXPECT_TRUE(false) << "Failed to parse value: " << e.what(); } - EXPECT_TRUE(json.contains("0000000000000002")); - EXPECT_STREQ("net2", json.at("0000000000000002").get().c_str()); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_STREQ("net2", json.at("0x0000000000000002").get().c_str()); } TEST_F(InterpreterTestSuite, PC_NetworkIdentifyUnset) @@ -1798,16 +1807,17 @@ TEST_F(InterpreterTestSuite, PC_OpdatasetGetActive) InitContext(ctx); NetworkId nwk_id; - EXPECT_EQ(ctx.mRegistry->mStorage->Add(Network{EMPTY_ID, EMPTY_ID, "", XpanId{1}, 0, 0, "", 0}, nwk_id), + EXPECT_EQ(ctx.mRegistry->mStorage->Add(Network{EMPTY_ID, EMPTY_ID, "", 1, 0, 0, "", 0}, nwk_id), PersistentStorage::Status::kSuccess); Network nwk; EXPECT_EQ(ctx.mRegistry->mStorage->Get(nwk_id, nwk), PersistentStorage::Status::kSuccess); - EXPECT_EQ((std::string)nwk.mPan, "0x0000"); + EXPECT_EQ(utils::Hex(nwk.mPan), "0x0000"); EXPECT_CALL(*ctx.mDefaultCommissionerObject, GetActiveDataset(_, _)) .Times(2) .WillRepeatedly(DoAll(WithArg<0>([](ActiveOperationalDataset &a) { - a.mExtendedPanId = XpanId{1}, a.mPanId = 1; + a.mExtendedPanId = ByteArray{0, 0, 0, 0, 0, 0, 0, 1}; + a.mPanId = 1; a.mPresentFlags = ActiveOperationalDataset::kPanIdBit | ActiveOperationalDataset::kExtendedPanIdBit; }), @@ -1821,19 +1831,16 @@ TEST_F(InterpreterTestSuite, PC_OpdatasetGetActive) EXPECT_TRUE(value.HasNoError()); EXPECT_EQ(ctx.mRegistry->mStorage->Get(nwk_id, nwk), PersistentStorage::Status::kSuccess); - EXPECT_EQ(nwk.mPan.mValue, 0x0001); - - EXPECT_EQ(system("rm -f ./aods.json"), 0); - EXPECT_NE(PathExists("./aods.json").GetCode(), ErrorCode::kNone); + EXPECT_EQ(nwk.mPan, 0x0001); - expr = ctx.mInterpreter.ParseExpression("opdataset get active --export ./aods.json"); + expr = ctx.mInterpreter.ParseExpression("opdataset get active --export ./tmp/aods.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); ctx.mInterpreter.PrintOrExport(value); - EXPECT_EQ(PathExists("./aods.json").GetCode(), ErrorCode::kNone); + EXPECT_EQ(PathExists("./tmp/aods.json").GetCode(), ErrorCode::kNone); std::string jsonStr; - EXPECT_EQ(ReadFile(jsonStr, "./aods.json").GetCode(), ErrorCode::kNone); + EXPECT_EQ(ReadFile(jsonStr, "./tmp/aods.json").GetCode(), ErrorCode::kNone); nlohmann::json json = nlohmann::json::parse(jsonStr); EXPECT_TRUE(json.contains("PanId")); EXPECT_STREQ("0x0001", json.at("PanId").get().c_str()); @@ -2109,7 +2116,7 @@ TEST_F(InterpreterTestSuite, PC_BrScanExport) Interpreter::Expression expr; Interpreter::Value value; - std::string jsonFileName = "./br-list.json"; + std::string jsonFileName = "./tmp/br-list.json"; EXPECT_EQ(system(fmt::format("rm -rf {}", jsonFileName).c_str()), 0); EXPECT_NE(PathExists(jsonFileName).GetCode(), ErrorCode::kNone); @@ -2139,8 +2146,7 @@ TEST_F(InterpreterTestSuite, PC_BrScanExportDirAbsent) Interpreter::Expression expr; Interpreter::Value value; - std::string jsonFileName = "./tmpdir/br-list.json"; - ASSERT_EQ(system("rm -rf ./tmpdir"), 0); + std::string jsonFileName = "./tmp/br-list.json"; expr = ctx.mInterpreter.ParseExpression(std::string("br scan --timeout 1 --export ") + jsonFileName); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); @@ -2198,23 +2204,23 @@ TEST_F(InterpreterTestSuite, PC_BrAddNoMandatoryFail) Interpreter::Expression expr; Interpreter::Value value; - EXPECT_EQ(WriteFile(brJsonNoAddr, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonNoAddr, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonNoPort, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonNoPort, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonNoVersion, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonNoVersion, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonNoState, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonNoState, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); } @@ -2267,23 +2273,23 @@ n]"; Interpreter::Expression expr; Interpreter::Value value; - EXPECT_EQ(WriteFile(brJsonNwkName, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonNwkName, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonNwkNameZeroXPan, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonNwkNameZeroXPan, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonDomainName, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonDomainName, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonDomainNameZeroXPan, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonDomainNameZeroXPan, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); } @@ -2349,42 +2355,31 @@ TEST_F(InterpreterTestSuite, PC_BrAddInterObjectInconsistencyFail) Interpreter::Expression expr; Interpreter::Value value; - EXPECT_EQ(WriteFile(brJsonSameAddr, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonSameAddr, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonSameXPanDifferentNwkNames, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonSameXPanDifferentNwkNames, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonSameXPanDifferentDomains, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonSameXPanDifferentDomains, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); } TEST_F(InterpreterTestSuite, PC_BrAdd) { -#define XPAN_1234 "1234" #define XPAN_1235 "0x1235" -#define XPAN_1236 "0000000000001236" -#define XPAN_1237 "00000000000001237" // length > 16 +#define XPAN_1236 "0x0000000000001236" TestContext ctx; InitContext(ctx); std::string brJson = "[\n\ - {\n\ - \"Addr\": \"1234::5678\",\n\ - \"Port\": 2000,\n\ - \"ThreadVersion\": \"th1.2\",\n\ - \"State\": 0,\n\ - \"NetworkName\": \"net1\",\n\ - \"ExtendedPanId\": \"" XPAN_1234 "\",\n\ - \"DomainName\": \"dom1\"\n\ - },\n\ {\n\ \"Addr\": \"1234::5679\",\n\ \"Port\": 2001,\n\ @@ -2417,35 +2412,31 @@ TEST_F(InterpreterTestSuite, PC_BrAdd) Interpreter::Expression expr; Interpreter::Value value; - EXPECT_EQ(WriteFile(brJson, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJson, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); BorderRouterArray brs; EXPECT_EQ(ctx.mInterpreter.mRegistry->GetAllBorderRouters(brs), RegistryStatus::kSuccess); - EXPECT_EQ(brs.size(), 4); + EXPECT_EQ(brs.size(), 3); NetworkArray nwks; EXPECT_EQ(ctx.mInterpreter.mRegistry->GetAllNetworks(nwks), RegistryStatus::kSuccess); - EXPECT_EQ(nwks.size(), 3); + EXPECT_EQ(nwks.size(), 2); DomainArray doms; EXPECT_EQ(ctx.mInterpreter.mRegistry->GetAllDomains(doms), RegistryStatus::kSuccess); EXPECT_EQ(doms.size(), 2); - Network nwk; - XpanId xpan; - EXPECT_EQ(xpan.FromHex(XPAN_1234).GetCode(), ErrorCode::kNone); - EXPECT_EQ(ctx.mInterpreter.mRegistry->GetNetworkByXpan(0x1234, nwk), RegistryStatus::kSuccess); - EXPECT_EQ(nwk.mXpan, xpan); - EXPECT_EQ(xpan.FromHex(XPAN_1235).GetCode(), ErrorCode::kNone); + Network nwk; + uint64_t xpan; + EXPECT_EQ(utils::ParseInteger(xpan, "0x1235").GetCode(), ErrorCode::kNone); EXPECT_EQ(ctx.mInterpreter.mRegistry->GetNetworkByXpan(0x1235, nwk), RegistryStatus::kSuccess); EXPECT_EQ(nwk.mXpan, xpan); - EXPECT_EQ(xpan.FromHex(XPAN_1236).GetCode(), ErrorCode::kNone); + EXPECT_EQ(utils::ParseInteger(xpan, "0x0000000000001236").GetCode(), ErrorCode::kNone); EXPECT_EQ(ctx.mInterpreter.mRegistry->GetNetworkByXpan(0x1236, nwk), RegistryStatus::kSuccess); EXPECT_EQ(nwk.mXpan, xpan); - EXPECT_EQ(xpan.FromHex(XPAN_1237).GetCode(), ErrorCode::kBadFormat); } TEST_F(InterpreterTestSuite, PC_BrListPositive) @@ -2624,7 +2615,7 @@ TEST_F(InterpreterTestSuite, PC_BrDeleteExplicitSelectedFails) "", 0, 0x3F | BorderAgent::kDomainNameBit}), RegistryStatus::kSuccess); - EXPECT_EQ(ctx.mRegistry->SetCurrentNetwork(XpanId{2}), RegistryStatus::kSuccess); + EXPECT_EQ(ctx.mRegistry->SetCurrentNetwork(2), RegistryStatus::kSuccess); Interpreter::Expression expr; Interpreter::Value value; diff --git a/src/app/cli/job.cpp b/src/app/cli/job.cpp index 7535e3ea7..6a38524a5 100644 --- a/src/app/cli/job.cpp +++ b/src/app/cli/job.cpp @@ -54,7 +54,7 @@ void Job::Wait() mJobThread.join(); if (!mValue.HasNoError()) { - LOG_DEBUG(LOG_REGION_JOB, "{}: job '{}' failed: {}", XpanId(mXpanId).str(), GetCommandString(), + LOG_DEBUG(LOG_REGION_JOB, "{}: job '{}' failed: {}", utils::Hex(mXpanId), GetCommandString(), mValue.ToString()); } } @@ -79,12 +79,12 @@ Job::Job(Interpreter &aInterpreter, CommissionerAppPtr &aCommApp, Interpreter::Expression aExpr, Interpreter::JobEvaluator aEval, - XpanId aXpanId) + uint64_t aXpanId) : mInterpreter(aInterpreter) , mCommissioner(aCommApp) , mExpr(aExpr) , mEval(aEval) - , mXpanId(aXpanId.mValue) + , mXpanId(aXpanId) { } diff --git a/src/app/cli/job.hpp b/src/app/cli/job.hpp index b23cfb29f..4ae1a2506 100644 --- a/src/app/cli/job.hpp +++ b/src/app/cli/job.hpp @@ -52,7 +52,7 @@ class Job CommissionerAppPtr &aCommApp, Interpreter::Expression aExpr, Interpreter::JobEvaluator aEval, - XpanId aXpanId); + uint64_t aXpanId); ~Job() = default; void Run(); diff --git a/src/app/cli/job_manager.cpp b/src/app/cli/job_manager.cpp index f0beadd01..4d2d7e3f6 100644 --- a/src/app/cli/job_manager.cpp +++ b/src/app/cli/job_manager.cpp @@ -117,7 +117,7 @@ void JobManager::SetImportFile(const std::string &importFile) mImportFile = importFile; } -Error JobManager::CreateJob(CommissionerAppPtr &aCommissioner, const Interpreter::Expression &aExpr, XpanId aXpanId) +Error JobManager::CreateJob(CommissionerAppPtr &aCommissioner, const Interpreter::Expression &aExpr, uint64_t aXpanId) { Interpreter::JobEvaluator eval; auto mapItem = Interpreter::mJobEvaluatorMap.find(utils::ToLower(aExpr[0])); @@ -133,7 +133,9 @@ Error JobManager::CreateJob(CommissionerAppPtr &aCommissioner, const Interpreter return ERROR_NONE; } -Error JobManager::PrepareJobs(const Interpreter::Expression &aExpr, const XpanIdArray &aNids, bool aGroupAlias) +Error JobManager::PrepareJobs(const Interpreter::Expression &aExpr, + const std::vector &aNids, + bool aGroupAlias) { Error error; @@ -191,7 +193,9 @@ Error JobManager::PrepareJobs(const Interpreter::Expression &aExpr, const XpanId return error; } -Error JobManager::PrepareStartJobs(const Interpreter::Expression &aExpr, const XpanIdArray &aNids, bool aGroupAlias) +Error JobManager::PrepareStartJobs(const Interpreter::Expression &aExpr, + const std::vector &aNids, + bool aGroupAlias) { Error error = ERROR_NONE; @@ -248,7 +252,9 @@ Error JobManager::PrepareStartJobs(const Interpreter::Expression &aExpr, const X return error; } -Error JobManager::PrepareStopJobs(const Interpreter::Expression &aExpr, const XpanIdArray &aNids, bool aGroupAlias) +Error JobManager::PrepareStopJobs(const Interpreter::Expression &aExpr, + const std::vector &aNids, + bool aGroupAlias) { Error error = ERROR_NONE; @@ -282,7 +288,7 @@ Error JobManager::PrepareStopJobs(const Interpreter::Expression &aExpr, const Xp return error; } -Error JobManager::PrepareDtlsConfig(const XpanId aNid, Config &aConfig) +Error JobManager::PrepareDtlsConfig(uint64_t aNid, Config &aConfig) { Error error; std::string domainName; @@ -321,12 +327,12 @@ Error JobManager::PrepareDtlsConfig(const XpanId aNid, Config &aConfig) status = mInterpreter.mRegistry->GetNetworkByXpan(aNid, nwk); VerifyOrExit(status == RegistryStatus::kSuccess, - error = ERROR_NOT_FOUND("network not found by XPAN '{}'", aNid.str())); + error = ERROR_NOT_FOUND("network not found by XPAN '{}'", utils::Hex(aNid))); isCCM = nwk.mCcm > 0; status = mInterpreter.mRegistry->GetDomainNameByXpan(aNid, domainName); if (status != RegistryStatus::kSuccess) { - LOG_DEBUG(LOG_REGION_JOB_MANAGER, "{}: domain resolution failed with status={}", XpanId(aNid).str(), + LOG_DEBUG(LOG_REGION_JOB_MANAGER, "{}: domain resolution failed with status={}", utils::Hex(aNid), static_cast(status)); } @@ -355,8 +361,8 @@ Error JobManager::PrepareDtlsConfig(const XpanId aNid, Config &aConfig) /// loading. Therefore, any other connection /// mode is considered a wrong configuration of /// border router, and respectively ignored. - LOG_DEBUG(LOG_REGION_JOB_MANAGER, "loading PSKc ignored for CCM network [{}:'{}']", aNid.str(), - nwk.mName); + LOG_DEBUG(LOG_REGION_JOB_MANAGER, "loading PSKc ignored for CCM network [{}:'{}']", + utils::Hex(aNid), nwk.mName); } goto update; } @@ -369,7 +375,7 @@ Error JobManager::PrepareDtlsConfig(const XpanId aNid, Config &aConfig) } } - error = security_material::GetNetworkSM(nwk.mXpan.str(), needCert, needPSKc, dtlsConfig); + error = security_material::GetNetworkSM(utils::Hex(nwk.mXpan), needCert, needPSKc, dtlsConfig); if (ERROR_NONE != error) { LOG_STR(DEBUG, LOG_REGION_JOB_MANAGER, error.GetMessage()); @@ -427,13 +433,13 @@ Error JobManager::PrepareDtlsConfig(const XpanId aNid, Config &aConfig) #undef UPDATE_IF_SET if (dtlsConfig.IsIncomplete(needCert, needPSKc, isCCM)) { - error = ERROR_SECURITY("incomplete DTLS configuration for the network [{}:'{}']", aNid.str(), nwk.mName); + error = ERROR_SECURITY("incomplete DTLS configuration for the network [{}:'{}']", utils::Hex(aNid), nwk.mName); } exit: return error; } -Error JobManager::MakeBorderRouterChoice(const XpanId aNid, BorderRouter &br) +Error JobManager::MakeBorderRouterChoice(uint64_t aNid, BorderRouter &br) { Error error; BRArray brs; @@ -451,7 +457,7 @@ Error JobManager::MakeBorderRouterChoice(const XpanId aNid, BorderRouter &br) } status = mInterpreter.mRegistry->GetNetworkByXpan(aNid, nwk); VerifyOrExit(status == RegistryStatus::kSuccess, - error = ERROR_NOT_FOUND("network not found by XPAN '{}'", aNid.str())); + error = ERROR_NOT_FOUND("network not found by XPAN '{}'", utils::Hex(aNid))); if (nwk.mCcm > 0) // Dealing with domain network { // - try to find active and connectable Primary BBR @@ -534,7 +540,7 @@ Error JobManager::MakeBorderRouterChoice(const XpanId aNid, BorderRouter &br) return error; } -Error JobManager::AppendImport(XpanId aXpanId, Interpreter::Expression &aExpr) +Error JobManager::AppendImport(uint64_t aXpanId, Interpreter::Expression &aExpr) { Error error; std::string jsonStr; @@ -543,13 +549,13 @@ Error JobManager::AppendImport(XpanId aXpanId, Interpreter::Expression &aExpr) SuccessOrExit(error = JsonFromFile(jsonStr, mImportFile)); jsonSrc = Json::parse(jsonStr); - if (aXpanId == XpanId()) // must be single command + if (aXpanId == 0) // must be single command { json = jsonSrc; } - else if (jsonSrc.count(aXpanId.str()) > 0) + else if (jsonSrc.count(utils::Hex(aXpanId)) > 0) { - json = jsonSrc[aXpanId.str()]; + json = jsonSrc[utils::Hex(aXpanId)]; } jsonStr = json.dump(JSON_INDENT_DEFAULT); if (utils::ToLower(aExpr[0]) == "opdataset") @@ -667,14 +673,14 @@ Interpreter::Value JobManager::CollectJobsValue() { Interpreter::Value value; nlohmann::json json; - XpanId xpan; + uint64_t xpan; for (const auto &job : mJobPool) { ASSERT(job->IsStopped()); if (job->GetValue().HasNoError()) { - xpan = XpanId{job->GetXpanId()}; + xpan = job->GetXpanId(); try { std::string valueStr = job->GetValue().ToString(); @@ -688,7 +694,7 @@ Interpreter::Value JobManager::CollectJobsValue() // nothing but [done] is printed; we need to see a // distinguished result per network } - json[xpan.str()] = nlohmann::json::parse(valueStr); + json[utils::Hex(xpan)] = nlohmann::json::parse(valueStr); } catch (std::exception &e) { ErrorMsg(xpan, e.what()); @@ -696,7 +702,7 @@ Interpreter::Value JobManager::CollectJobsValue() } else // produce error messages immediately before printing value { - ErrorMsg(XpanId{job->GetXpanId()}, job->GetValue().ToString()); + ErrorMsg(job->GetXpanId(), job->GetValue().ToString()); } } value = json.dump(JSON_INDENT_DEFAULT); @@ -719,13 +725,13 @@ void JobManager::StopCommissionerPool() Error JobManager::GetSelectedCommissioner(CommissionerAppPtr &aCommissioner) { Error error = ERROR_NONE; - XpanId nid; + uint64_t nid; RegistryStatus status; status = mInterpreter.mRegistry->GetCurrentNetworkXpan(nid); VerifyOrExit(RegistryStatus::kSuccess == status, error = ERROR_REGISTRY_ERROR("getting selected network failed")); - if (nid.mValue != XpanId::kEmptyXpanId) + if (nid != 0) { auto entry = mCommissionerPool.find(nid); if (entry != mCommissionerPool.end()) @@ -761,19 +767,19 @@ bool JobManager::IsClean() return mJobPool.size() == 0 && mImportFile.size() == 0; } -void JobManager::ErrorMsg(XpanId aNid, std::string aMessage) +void JobManager::ErrorMsg(uint64_t aNid, std::string aMessage) { - mInterpreter.PrintNetworkMessage(aNid.mValue, aMessage, Console::Color::kRed); + mInterpreter.PrintNetworkMessage(aNid, aMessage, Console::Color::kRed); } -void JobManager::WarningMsg(XpanId aNid, std::string aMessage) +void JobManager::WarningMsg(uint64_t aNid, std::string aMessage) { - mInterpreter.PrintNetworkMessage(aNid.mValue, aMessage, Console::Color::kMagenta); + mInterpreter.PrintNetworkMessage(aNid, aMessage, Console::Color::kMagenta); } -void JobManager::InfoMsg(XpanId aNid, std::string aMessage) +void JobManager::InfoMsg(uint64_t aNid, std::string aMessage) { - mInterpreter.PrintNetworkMessage(aNid.mValue, aMessage, Console::Color::kDefault); + mInterpreter.PrintNetworkMessage(aNid, aMessage, Console::Color::kDefault); } } // namespace commissioner diff --git a/src/app/cli/job_manager.hpp b/src/app/cli/job_manager.hpp index dae006b0f..72143c3d0 100644 --- a/src/app/cli/job_manager.hpp +++ b/src/app/cli/job_manager.hpp @@ -45,7 +45,6 @@ namespace commissioner { using CommissionerAppPtr = std::shared_ptr; using RegistryStatus = ot::commissioner::persistent_storage::Registry::Status; -using ot::commissioner::XpanId; using ot::commissioner::persistent_storage::BorderRouter; class JobManager @@ -61,7 +60,7 @@ class JobManager * * @see JobManager::CreateJob() */ - Error PrepareJobs(const Interpreter::Expression &aExpr, const XpanIdArray &aNids, bool aGroupAlias); + Error PrepareJobs(const Interpreter::Expression &aExpr, const std::vector &aNids, bool aGroupAlias); /** * Run all prepared jobs. * @@ -118,7 +117,7 @@ class JobManager * It is expected mImportFile contains a JSON object where the * imported part is a value of a map entry under aNid key. */ - Error AppendImport(XpanId aXpanId, Interpreter::Expression &aExpr); + Error AppendImport(uint64_t aXpanId, Interpreter::Expression &aExpr); /** * Make a well-thought choice from border routers belonging to a * given network identified by aNid XPAN ID. @@ -129,12 +128,12 @@ class JobManager * If in non-CCM mode, a BR with most highly avaliable and Thread-active * interface becomes the choice. */ - Error MakeBorderRouterChoice(const XpanId aNid, BorderRouter &br); + Error MakeBorderRouterChoice(uint64_t aNid, BorderRouter &br); private: friend class JobManagerTestSuite; - using CommissionerPool = std::map; + using CommissionerPool = std::map; using JobPool = std::vector; /** * Wait for all job threads to join. @@ -143,11 +142,11 @@ class JobManager /** * A flavor of JobManager::PrepareJobs() for `start' command specifically. */ - Error PrepareStartJobs(const Interpreter::Expression &aExpr, const XpanIdArray &aNids, bool aGroupAlias); + Error PrepareStartJobs(const Interpreter::Expression &aExpr, const std::vector &aNids, bool aGroupAlias); /** * A flavor of JobManager::PrepareJobs() for `stop' command specifically. */ - Error PrepareStopJobs(const Interpreter::Expression &aExpr, const XpanIdArray &aNids, bool aGroupAlias); + Error PrepareStopJobs(const Interpreter::Expression &aExpr, const std::vector &aNids, bool aGroupAlias); /** * Updates DTLS parts of Config for the given network. * @@ -173,15 +172,15 @@ class JobManager * connection must restart to adopt the most recent connection * information. */ - Error PrepareDtlsConfig(const XpanId aNid, Config &aConfig); + Error PrepareDtlsConfig(uint64_t aNid, Config &aConfig); /** * Creates @ref Job object and places the job into @ref JobManager::mJobPool. */ - Error CreateJob(CommissionerAppPtr &aCommissioner, const Interpreter::Expression &aExpr, XpanId aXpanId); + Error CreateJob(CommissionerAppPtr &aCommissioner, const Interpreter::Expression &aExpr, uint64_t aXpanId); - void ErrorMsg(XpanId aNid, std::string aMessage); - void WarningMsg(XpanId aNid, std::string aMessage); - void InfoMsg(XpanId aNid, std::string aMessage); + void ErrorMsg(uint64_t aNid, std::string aMessage); + void WarningMsg(uint64_t aNid, std::string aMessage); + void InfoMsg(uint64_t aNid, std::string aMessage); /** * Pool of @ref Job objects prepared per command execution. The diff --git a/src/app/cli/job_manager_test.cpp b/src/app/cli/job_manager_test.cpp index acab6733e..8efacd410 100644 --- a/src/app/cli/job_manager_test.cpp +++ b/src/app/cli/job_manager_test.cpp @@ -119,6 +119,12 @@ class JobManagerTestSuite : public testing::Test EXPECT_EQ(aContext.mJobManager.Init(aContext.mConf).mCode, ErrorCode::kNone); aContext.mInterpreter.mRegistry = aContext.mRegistry; } + + void SetUp() override + { + ASSERT_TRUE(system("rm -rf tmp") == 0); + ASSERT_TRUE(system("mkdir -p tmp") == 0); + } }; TEST_F(JobManagerTestSuite, TestInit) @@ -321,23 +327,22 @@ TEST_F(JobManagerTestSuite, StartCancel) TEST_F(JobManagerTestSuite, MalformedCredentialsJobCreateFailsByXPan) { - // Remove './nwk' subtree - ASSERT_EQ(system("rm -rf ./dom ./nwk"), 0); + ASSERT_EQ(system("rm -rf ./tmp/dom ./tmp/nwk"), 0); - EXPECT_EQ(mkdir("./nwk", 0777), 0); - EXPECT_EQ(mkdir("./nwk/0000000000000001", 0777), 0); - EXPECT_EQ(mkdir("./nwk/0000000000000002", 0777), 0); - EXPECT_EQ(mkdir("./nwk/0000000000000003", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk/0000000000000001", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk/0000000000000002", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk/0000000000000003", 0777), 0); // Loose credentials for Network 1 - EXPECT_EQ(WriteFile("1", "./nwk/0000000000000001/ca.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./nwk/0000000000000001/priv.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/0000000000000001/ca.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/0000000000000001/priv.pem").mCode, ErrorCode::kNone); // Loose credentials for Network 2 - EXPECT_EQ(WriteFile("1", "./nwk/0000000000000002/cert.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./nwk/0000000000000002/priv.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/0000000000000002/cert.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/0000000000000002/priv.pem").mCode, ErrorCode::kNone); // Loose credentials for Network 3 - EXPECT_EQ(WriteFile("1", "./nwk/0000000000000003/cert.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./nwk/0000000000000003/ca.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/0000000000000003/cert.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/0000000000000003/ca.pem").mCode, ErrorCode::kNone); TestContext ctx; SetInitialExpectations(ctx); @@ -399,23 +404,22 @@ TEST_F(JobManagerTestSuite, MalformedCredentialsJobCreateFailsByXPan) TEST_F(JobManagerTestSuite, MalformedCredentialsJobCreateFailsByName) { - // Remove './nwk' subtree - ASSERT_EQ(system("rm -rf ./dom ./nwk"), 0); + ASSERT_EQ(system("rm -rf ./tmp/dom ./tmp/nwk"), 0); - EXPECT_EQ(mkdir("./nwk", 0777), 0); - EXPECT_EQ(mkdir("./nwk/pan1", 0777), 0); - EXPECT_EQ(mkdir("./nwk/pan2", 0777), 0); - EXPECT_EQ(mkdir("./nwk/pan3", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk/pan1", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk/pan2", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk/pan3", 0777), 0); // Loose credentials for Network 1 - EXPECT_EQ(WriteFile("1", "./nwk/pan1/ca.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./nwk/pan1/priv.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/pan1/ca.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/pan1/priv.pem").mCode, ErrorCode::kNone); // Loose credentials for panwork 2 - EXPECT_EQ(WriteFile("1", "./nwk/pan2/cert.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./nwk/pan2/priv.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/pan2/cert.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/pan2/priv.pem").mCode, ErrorCode::kNone); // Loose credentials for panwork 3 - EXPECT_EQ(WriteFile("1", "./nwk/pan3/cert.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./nwk/pan3/ca.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/pan3/cert.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/pan3/ca.pem").mCode, ErrorCode::kNone); TestContext ctx; SetInitialExpectations(ctx); @@ -478,22 +482,22 @@ TEST_F(JobManagerTestSuite, MalformedCredentialsJobCreateFailsByName) TEST_F(JobManagerTestSuite, MalformedCredentialsJobCreateFailsByDomain) { // Remove SM subtrees - ASSERT_EQ(system("rm -rf ./dom ./nwk"), 0); + ASSERT_EQ(system("rm -rf ./tmp/dom ./tmp/nwk"), 0); - EXPECT_EQ(mkdir("./dom", 0777), 0); - EXPECT_EQ(mkdir("./dom/domain1", 0777), 0); - EXPECT_EQ(mkdir("./dom/domain2", 0777), 0); - EXPECT_EQ(mkdir("./dom/domain3", 0777), 0); + EXPECT_EQ(mkdir("./tmp/dom", 0777), 0); + EXPECT_EQ(mkdir("./tmp/dom/domain1", 0777), 0); + EXPECT_EQ(mkdir("./tmp/dom/domain2", 0777), 0); + EXPECT_EQ(mkdir("./tmp/dom/domain3", 0777), 0); // Loose credentials for domain1 - EXPECT_EQ(WriteFile("1", "./dom/domain1/ca.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./dom/domain1/priv.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/dom/domain1/ca.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/dom/domain1/priv.pem").mCode, ErrorCode::kNone); // Loose credentials for domain2 - EXPECT_EQ(WriteFile("1", "./dom/domain2/cert.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./dom/domain2/priv.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/dom/domain2/cert.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/dom/domain2/priv.pem").mCode, ErrorCode::kNone); // Loose credentials for domain 3 - EXPECT_EQ(WriteFile("1", "./dom/domain3/cert.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./dom/domain3/ca.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/dom/domain3/cert.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/dom/domain3/ca.pem").mCode, ErrorCode::kNone); TestContext ctx; SetInitialExpectations(ctx); @@ -623,9 +627,9 @@ TEST_F(JobManagerTestSuite, BuildFinalResultString) Interpreter::Value value = ctx.mJobManager.CollectJobsValue(); nlohmann::json json = nlohmann::json::parse(value.ToString()); - EXPECT_TRUE(json.contains(XpanId{1}.str())); - EXPECT_TRUE(json.contains(XpanId{2}.str())); - EXPECT_FALSE(json.contains(XpanId{3}.str())); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_FALSE(json.contains("0x0000000000000003")); ctx.mJobManager.CleanupJobs(); // "active" command @@ -633,12 +637,12 @@ TEST_F(JobManagerTestSuite, BuildFinalResultString) ctx.mJobManager.RunJobs(); value = ctx.mJobManager.CollectJobsValue(); json = nlohmann::json::parse(value.ToString()); - EXPECT_TRUE(json.contains(XpanId{1}.str())); - EXPECT_TRUE(json.contains(XpanId{2}.str())); - EXPECT_TRUE(json.contains(XpanId{3}.str())); - EXPECT_TRUE(json[XpanId{1}.str()]); - EXPECT_TRUE(json[XpanId{2}.str()]); - EXPECT_FALSE(json[XpanId{3}.str()]); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_TRUE(json.contains("0x0000000000000003")); + EXPECT_TRUE(json["0x0000000000000001"]); + EXPECT_TRUE(json["0x0000000000000002"]); + EXPECT_FALSE(json["0x0000000000000003"]); ctx.mJobManager.CleanupJobs(); // "sessionid" command @@ -650,10 +654,10 @@ TEST_F(JobManagerTestSuite, BuildFinalResultString) ctx.mJobManager.RunJobs(); value = ctx.mJobManager.CollectJobsValue(); json = nlohmann::json::parse(value.ToString()); - EXPECT_TRUE(json.contains(XpanId{1}.str())); - EXPECT_TRUE(json.contains(XpanId{2}.str())); - EXPECT_EQ(json[XpanId{1}.str()], 0); - EXPECT_EQ(json[XpanId{2}.str()], 1); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_EQ(json["0x0000000000000001"], 0); + EXPECT_EQ(json["0x0000000000000002"], 1); ctx.mJobManager.CleanupJobs(); // "opdataset get active" command @@ -673,12 +677,12 @@ TEST_F(JobManagerTestSuite, BuildFinalResultString) ctx.mJobManager.RunJobs(); value = ctx.mJobManager.CollectJobsValue(); json = nlohmann::json::parse(value.ToString()); - EXPECT_TRUE(json.contains(XpanId{1}.str())); - EXPECT_TRUE(json.contains(XpanId{2}.str())); - EXPECT_TRUE(json[XpanId{1}.str()].contains("PanId")); - EXPECT_TRUE(json[XpanId{2}.str()].contains("PanId")); - EXPECT_STREQ("0x0001", json[XpanId{1}.str()]["PanId"].get().c_str()); - EXPECT_STREQ("0x0002", json[XpanId{2}.str()]["PanId"].get().c_str()); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_TRUE(json["0x0000000000000001"].contains("PanId")); + EXPECT_TRUE(json["0x0000000000000002"].contains("PanId")); + EXPECT_STREQ("0x0001", json["0x0000000000000001"]["PanId"].get().c_str()); + EXPECT_STREQ("0x0002", json["0x0000000000000002"]["PanId"].get().c_str()); ctx.mJobManager.CleanupJobs(); // "opdataset set securitypolicy" command @@ -692,10 +696,10 @@ TEST_F(JobManagerTestSuite, BuildFinalResultString) ctx.mJobManager.RunJobs(); value = ctx.mJobManager.CollectJobsValue(); json = nlohmann::json::parse(value.ToString()); - EXPECT_TRUE(json.contains(XpanId{1}.str())); - EXPECT_TRUE(json.contains(XpanId{2}.str())); - EXPECT_TRUE(json[XpanId{1}.str()]); - EXPECT_TRUE(json[XpanId{2}.str()]); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_TRUE(json["0x0000000000000001"]); + EXPECT_TRUE(json["0x0000000000000002"]); ctx.mJobManager.CleanupJobs(); // "stop" command @@ -705,9 +709,9 @@ TEST_F(JobManagerTestSuite, BuildFinalResultString) ctx.mJobManager.RunJobs(); value = ctx.mJobManager.CollectJobsValue(); json = nlohmann::json::parse(value.ToString()); - EXPECT_TRUE(json.contains(XpanId{1}.str())); - EXPECT_TRUE(json.contains(XpanId{2}.str())); - EXPECT_TRUE(json[XpanId{1}.str()]); - EXPECT_TRUE(json[XpanId{2}.str()]); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_TRUE(json["0x0000000000000001"]); + EXPECT_TRUE(json["0x0000000000000002"]); ctx.mJobManager.CleanupJobs(); } diff --git a/src/app/commissioner_app.cpp b/src/app/commissioner_app.cpp index 6eb7cb2be..fbd612e3c 100644 --- a/src/app/commissioner_app.cpp +++ b/src/app/commissioner_app.cpp @@ -523,7 +523,7 @@ Error CommissionerApp::GetExtendedPanId(ByteArray &aExtendedPanId) const VerifyOrExit(mActiveDataset.mPresentFlags & ActiveOperationalDataset::kExtendedPanIdBit, error = ERROR_NOT_FOUND("cannot find valid Extended PAN ID in Active Operational Dataset")); - aExtendedPanId = utils::Encode(mActiveDataset.mExtendedPanId.mValue); + aExtendedPanId = mActiveDataset.mExtendedPanId; exit: return error; @@ -536,7 +536,7 @@ Error CommissionerApp::SetExtendedPanId(const ByteArray &aExtendedPanId) VerifyOrExit(IsActive(), error = ERROR_INVALID_STATE("the commissioner is not active")); - activeDataset.mExtendedPanId = XpanId{utils::Decode(aExtendedPanId)}; + activeDataset.mExtendedPanId = aExtendedPanId; activeDataset.mPresentFlags |= ActiveOperationalDataset::kExtendedPanIdBit; SuccessOrExit(error = mCommissioner->SetActiveDataset(activeDataset)); @@ -680,7 +680,7 @@ Error CommissionerApp::SetNetworkName(const std::string &aNetworkName) return error; } -Error CommissionerApp::GetPanId(PanId &aPanId) +Error CommissionerApp::GetPanId(uint16_t &aPanId) { Error error; @@ -696,7 +696,7 @@ Error CommissionerApp::GetPanId(PanId &aPanId) return error; } -Error CommissionerApp::SetPanId(PanId aPanId, MilliSeconds aDelay) +Error CommissionerApp::SetPanId(uint16_t aPanId, MilliSeconds aDelay) { Error error; PendingOperationalDataset pendingDataset; diff --git a/src/app/commissioner_app.hpp b/src/app/commissioner_app.hpp index 288a0933c..fe08d5dfe 100644 --- a/src/app/commissioner_app.hpp +++ b/src/app/commissioner_app.hpp @@ -202,8 +202,8 @@ class CommissionerApp : public CommissionerHandler MOCKABLE Error SetNetworkMasterKey(const ByteArray &aMasterKey, MilliSeconds aDelay); MOCKABLE Error GetNetworkName(std::string &aNetworkName) const; MOCKABLE Error SetNetworkName(const std::string &aNetworkName); - MOCKABLE Error GetPanId(PanId &aPanId); - MOCKABLE Error SetPanId(PanId aPanId, MilliSeconds aDelay); + MOCKABLE Error GetPanId(uint16_t &aPanId); + MOCKABLE Error SetPanId(uint16_t aPanId, MilliSeconds aDelay); MOCKABLE Error GetPSKc(ByteArray &aPSKc) const; MOCKABLE Error SetPSKc(const ByteArray &aPSKc); diff --git a/src/app/commissioner_app_dummy.cpp b/src/app/commissioner_app_dummy.cpp index f9024be2e..248ab00ac 100644 --- a/src/app/commissioner_app_dummy.cpp +++ b/src/app/commissioner_app_dummy.cpp @@ -303,13 +303,13 @@ Error CommissionerApp::SetNetworkName(const std::string &aNetworkName) return Error{}; } -Error CommissionerApp::GetPanId(PanId &aPanId) +Error CommissionerApp::GetPanId(uint16_t &aPanId) { UNUSED(aPanId); return Error{}; } -Error CommissionerApp::SetPanId(PanId aPanId, MilliSeconds aDelay) +Error CommissionerApp::SetPanId(uint16_t aPanId, MilliSeconds aDelay) { UNUSED(aPanId); UNUSED(aDelay); diff --git a/src/app/commissioner_app_mock.hpp b/src/app/commissioner_app_mock.hpp index 5ce32476c..5b31862f6 100644 --- a/src/app/commissioner_app_mock.hpp +++ b/src/app/commissioner_app_mock.hpp @@ -104,8 +104,8 @@ class CommissionerAppMock : public ::ot::commissioner::CommissionerApp MOCK_METHOD(Error, SetNetworkMasterKey, (const ByteArray &, MilliSeconds)); MOCK_METHOD(Error, GetNetworkName, (std::string &), (const)); MOCK_METHOD(Error, SetNetworkName, (const std::string &)); - MOCK_METHOD(Error, GetPanId, (PanId &)); - MOCK_METHOD(Error, SetPanId, (PanId, MilliSeconds)); + MOCK_METHOD(Error, GetPanId, (uint16_t &)); + MOCK_METHOD(Error, SetPanId, (uint16_t, MilliSeconds)); MOCK_METHOD(Error, GetPSKc, (ByteArray &), (const)); MOCK_METHOD(Error, SetPSKc, (const ByteArray &)); MOCK_METHOD(Error, GetSecurityPolicy, (SecurityPolicy &), (const)); diff --git a/src/app/json.cpp b/src/app/json.cpp index d81323583..7f24f91d9 100644 --- a/src/app/json.cpp +++ b/src/app/json.cpp @@ -417,18 +417,6 @@ static void from_json(const Json &aJson, SecurityPolicy &aSecurityPolicy) #undef SET } -static void to_json(Json &aJson, const ot::commissioner::PanId &aPanId) -{ - aJson = std::string(aPanId); -} - -static void from_json(const Json &aJson, ot::commissioner::PanId &aPanId) -{ - std::string panIdStr; - panIdStr = aJson.get(); - SuccessOrThrow(aPanId.FromHex(panIdStr)); -} - static void to_json(Json &aJson, const ActiveOperationalDataset &aDataset) { #define SET_IF_PRESENT(name) \ @@ -438,9 +426,19 @@ static void to_json(Json &aJson, const ActiveOperationalDataset &aDataset) }; SET_IF_PRESENT(ActiveTimestamp); + SET_IF_PRESENT(NetworkName); SET_IF_PRESENT(Channel); SET_IF_PRESENT(ChannelMask); - SET_IF_PRESENT(ExtendedPanId); + + if (aDataset.mPresentFlags & ActiveOperationalDataset::kExtendedPanIdBit) + { + aJson["ExtendedPanId"] = utils::Hex(aDataset.mExtendedPanId); + } + + if (aDataset.mPresentFlags & ActiveOperationalDataset::kPanIdBit) + { + aJson["PanId"] = utils::Hex(aDataset.mPanId); + } if (aDataset.mPresentFlags & ActiveOperationalDataset::kMeshLocalPrefixBit) { @@ -448,20 +446,12 @@ static void to_json(Json &aJson, const ActiveOperationalDataset &aDataset) }; SET_IF_PRESENT(NetworkMasterKey); - SET_IF_PRESENT(NetworkName); - SET_IF_PRESENT(PanId); SET_IF_PRESENT(PSKc); SET_IF_PRESENT(SecurityPolicy); #undef SET_IF_PRESENT } -static void from_json(const Json &aJson, XpanId &aXpanId) -{ - std::string xpanStr = aJson.get(); - SuccessOrThrow(aXpanId.FromHex(xpanStr)); -} - static void from_json(const Json &aJson, ActiveOperationalDataset &aDataset) { #define SET_IF_PRESENT(name) \ @@ -472,9 +462,21 @@ static void from_json(const Json &aJson, ActiveOperationalDataset &aDataset) }; SET_IF_PRESENT(ActiveTimestamp); + SET_IF_PRESENT(NetworkName); SET_IF_PRESENT(Channel); SET_IF_PRESENT(ChannelMask); - SET_IF_PRESENT(ExtendedPanId); + + if (aJson.contains("ExtendedPanId")) + { + SuccessOrThrow(utils::Hex(aDataset.mExtendedPanId, aJson["ExtendedPanId"])); + aDataset.mPresentFlags |= ActiveOperationalDataset::kExtendedPanIdBit; + } + + if (aJson.contains("PanId")) + { + SuccessOrThrow(utils::ParseInteger(aDataset.mPanId, aJson["PanId"])); + aDataset.mPresentFlags |= ActiveOperationalDataset::kPanIdBit; + } if (aJson.contains("MeshLocalPrefix")) { @@ -485,8 +487,6 @@ static void from_json(const Json &aJson, ActiveOperationalDataset &aDataset) }; SET_IF_PRESENT(NetworkMasterKey); - SET_IF_PRESENT(NetworkName); - SET_IF_PRESENT(PanId); SET_IF_PRESENT(PSKc); SET_IF_PRESENT(SecurityPolicy); @@ -796,11 +796,6 @@ static void from_json(const nlohmann::json &aJson, BorderAgent::State &aState) void BorderAgentFromJson(BorderAgent &aAgent, const nlohmann::json &aJson) { BorderAgent agent; - auto json2xpan = [](const nlohmann::json &field) { - XpanId xpan; - Error error = xpan.FromHex(field.get()); - return error == ERROR_NONE ? xpan.mValue : XpanId::kEmptyXpanId; - }; #define SET_IF_PRESENT(field) \ do \ @@ -812,22 +807,18 @@ void BorderAgentFromJson(BorderAgent &aAgent, const nlohmann::json &aJson) } \ } while (false) -#define SET_IF_PRESENT_X(field) \ - do \ - { \ - if (aJson.contains(#field)) \ - { \ - agent.mPresentFlags |= BorderAgent::k##field##Bit; \ - agent.m##field = json2xpan(aJson.at(#field)); \ - } \ - } while (false) - SET_IF_PRESENT(Addr); SET_IF_PRESENT(Port); SET_IF_PRESENT(ThreadVersion); SET_IF_PRESENT(State); SET_IF_PRESENT(NetworkName); - SET_IF_PRESENT_X(ExtendedPanId); + + if (aJson.contains("ExtendedPanId")) + { + SuccessOrThrow(utils::ParseInteger(agent.mExtendedPanId, aJson["ExtendedPanId"])); + agent.mPresentFlags |= BorderAgent::kExtendedPanIdBit; + } + SET_IF_PRESENT(VendorName); SET_IF_PRESENT(ModelName); SET_IF_PRESENT(ActiveTimestamp); @@ -840,7 +831,6 @@ void BorderAgentFromJson(BorderAgent &aAgent, const nlohmann::json &aJson) SET_IF_PRESENT(ServiceName); #undef SET_IF_PRESENT -#undef SET_IF_PRESENT_X aAgent = agent; } @@ -863,21 +853,17 @@ void BorderAgentToJson(const BorderAgent &aAgent, nlohmann::json &aJson) } \ } while (false) -#define SET_IF_PRESENT_X(field) \ - do \ - { \ - if (aAgent.mPresentFlags & BorderAgent::k##field##Bit) \ - { \ - aJson[#field] = XpanId(aAgent.m##field).str(); \ - } \ - } while (false) - SET_IF_PRESENT(Addr); SET_IF_PRESENT(Port); SET_IF_PRESENT(ThreadVersion); SET_IF_PRESENT(State); SET_IF_PRESENT(NetworkName); - SET_IF_PRESENT_X(ExtendedPanId); + + if (aAgent.mPresentFlags & BorderAgent::kExtendedPanIdBit) + { + aJson["ExtendedPanId"] = utils::Hex(aAgent.mExtendedPanId); + } + SET_IF_PRESENT(VendorName); SET_IF_PRESENT(ModelName); SET_IF_PRESENT(ActiveTimestamp); @@ -890,7 +876,6 @@ void BorderAgentToJson(const BorderAgent &aAgent, nlohmann::json &aJson) SET_IF_PRESENT(ServiceName); #undef SET_IF_PRESENT -#undef SET_IF_PRESENT_X } } // namespace commissioner diff --git a/src/app/ps/CMakeLists.txt b/src/app/ps/CMakeLists.txt index 2db452a92..f999f9da1 100644 --- a/src/app/ps/CMakeLists.txt +++ b/src/app/ps/CMakeLists.txt @@ -74,4 +74,10 @@ if (OT_COMM_TEST) ${PROJECT_SOURCE_DIR}/third_party/googletest/repo/googletest/include $ ) + + target_link_libraries(commissioner-ps-test + PUBLIC + commissioner-common + commissioner-app + ) endif (OT_COMM_TEST) diff --git a/src/app/ps/persistent_storage_json.cpp b/src/app/ps/persistent_storage_json.cpp index 5f1539615..006a6a55b 100644 --- a/src/app/ps/persistent_storage_json.cpp +++ b/src/app/ps/persistent_storage_json.cpp @@ -285,9 +285,9 @@ PersistentStorage::Status PersistentStorageJson::Get(BorderRouterId const &aId, aRetValue.mAgent.mNetworkName = nwk.mName; aRetValue.mAgent.mPresentFlags |= BorderAgent::kNetworkNameBit; } - if (nwk.mXpan.mValue != XpanId::kEmptyXpanId) + if (nwk.mXpan != 0) { - aRetValue.mAgent.mExtendedPanId = nwk.mXpan.mValue; + aRetValue.mAgent.mExtendedPanId = nwk.mXpan; aRetValue.mAgent.mPresentFlags |= BorderAgent::kExtendedPanIdBit; } if (nwk.mDomainId.mId != EMPTY_ID) @@ -371,8 +371,7 @@ PersistentStorage::Status PersistentStorageJson::Lookup(Network const &aValue, s (aValue.mId.mId == EMPTY_ID || (el.mId.mId == aValue.mId.mId)) && (aValue.mDomainId.mId == EMPTY_ID || (el.mDomainId.mId == aValue.mDomainId.mId)) && (aValue.mName.empty() || (aValue.mName == el.mName)) && - (aValue.mXpan.mValue == XpanId::kEmptyXpanId || aValue.mXpan == el.mXpan) && - (aValue.mPan.mValue == PanId::kEmptyPanId || (aValue.mPan.mValue == el.mPan.mValue)) && + (aValue.mXpan == 0 || aValue.mXpan == el.mXpan) && (aValue.mPan == 0 || (aValue.mPan == el.mPan)) && (aValue.mMlp.empty() || CaseInsensitiveEqual(aValue.mMlp, el.mMlp)) && (aValue.mChannel == 0 || (aValue.mChannel == el.mChannel)); @@ -476,8 +475,7 @@ PersistentStorage::Status PersistentStorageJson::LookupAny(Network const &aValue (aValue.mId.mId == EMPTY_ID || (el.mId.mId == aValue.mId.mId)) || (aValue.mDomainId.mId == EMPTY_ID || (el.mDomainId.mId == aValue.mDomainId.mId)) || (aValue.mName.empty() || (aValue.mName == el.mName)) || - (aValue.mXpan.mValue == XpanId::kEmptyXpanId || aValue.mXpan == el.mXpan) || - (aValue.mPan.mValue == PanId::kEmptyPanId || (aValue.mPan.mValue == el.mPan.mValue)) || + (aValue.mXpan == 0 || aValue.mXpan == el.mXpan) || (aValue.mPan == 0 || (aValue.mPan == el.mPan)) || (aValue.mMlp.empty() || CaseInsensitiveEqual(aValue.mMlp, el.mMlp)) || (aValue.mChannel == 0 || (aValue.mChannel == el.mChannel)); diff --git a/src/app/ps/persistent_storage_json_test.cpp b/src/app/ps/persistent_storage_json_test.cpp index 34101c920..295dc3f28 100644 --- a/src/app/ps/persistent_storage_json_test.cpp +++ b/src/app/ps/persistent_storage_json_test.cpp @@ -31,46 +31,59 @@ * The file implements unit tests for JSON-based persistent storage */ +#include +#include #include #include "persistent_storage_json.hpp" #include "app/border_agent.hpp" -#include - using namespace ot::commissioner::persistent_storage; using namespace ot::commissioner; -TEST(PSJson, CreateDefaultIfNotExists) +class PersistentStorageJsonTestSuite : public testing::Test { - PersistentStorageJson psj("./test_ps.json"); +public: + PersistentStorageJsonTestSuite() = default; + virtual ~PersistentStorageJsonTestSuite() = default; + + void SetUp() override + { + ASSERT_TRUE(system("rm -rf tmp") == 0); + ASSERT_TRUE(system("mkdir -p tmp") == 0); + } +}; + +TEST(PersistentStorageJsonTestSuite, CreateDefaultIfNotExists) +{ + PersistentStorageJson psj("./tmp/test_ps.json"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, ReadEmptyFile) +TEST(PersistentStorageJsonTestSuite, ReadEmptyFile) { - std::ofstream testTmp("./test.tmp"); + std::ofstream testTmp("./tmp/test.tmp"); testTmp.close(); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, ReadNonEmptyDefault) +TEST(PersistentStorageJsonTestSuite, ReadNonEmptyDefault) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, AddRegistrar) +TEST(PersistentStorageJsonTestSuite, AddRegistrar) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -86,9 +99,9 @@ TEST(PSJson, AddRegistrar) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, AddDomain) +TEST(PersistentStorageJsonTestSuite, AddDomain) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -104,36 +117,33 @@ TEST(PSJson, AddDomain) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, AddNetwork) +TEST(PersistentStorageJsonTestSuite, AddNetwork) { // Make the test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); NetworkId newId; - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk1", XpanId{0xFFFFFFFFFFFFFFF1ll}, 11, 0xFFF1, "2000:aaa1::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk1", 0xFFFFFFFFFFFFFFF1ll, 11, 0xFFF1, "2000:aaa1::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 0); - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk2", XpanId{0xFFFFFFFFFFFFFFF2ll}, 11, 0xFFF2, "2000:aaa2::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk2", 0xFFFFFFFFFFFFFFF2ll, 11, 0xFFF2, "2000:aaa2::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 1); - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk3", XpanId{0xFFFFFFFFFFFFFFF3ll}, 11, 0xFFF3, "2000:aaa3::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk3", 0xFFFFFFFFFFFFFFF3ll, 11, 0xFFF3, "2000:aaa3::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 2); EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, AddBorderRouter) +TEST(PersistentStorageJsonTestSuite, AddBorderRouter) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -164,9 +174,9 @@ TEST(PSJson, AddBorderRouter) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, DelRegistrar) +TEST(PersistentStorageJsonTestSuite, DelRegistrar) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -178,9 +188,9 @@ TEST(PSJson, DelRegistrar) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, DelDomain) +TEST(PersistentStorageJsonTestSuite, DelDomain) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -192,16 +202,15 @@ TEST(PSJson, DelDomain) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, DelNetwork) +TEST(PersistentStorageJsonTestSuite, DelNetwork) { PersistentStorageJson psj(""); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); NetworkId newId; - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk1", XpanId{0xFFFFFFFFFFFFFFF1ll}, 11, 0xFFF1, "2000:aaa1::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk1", 0xFFFFFFFFFFFFFFF1ll, 11, 0xFFF1, "2000:aaa1::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 0); EXPECT_TRUE(psj.Del(NetworkId(0)) == PersistentStorage::Status::kSuccess); @@ -214,9 +223,9 @@ TEST(PSJson, DelNetwork) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, DelBorderRouter) +TEST(PersistentStorageJsonTestSuite, DelBorderRouter) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -228,9 +237,9 @@ TEST(PSJson, DelBorderRouter) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetRegistrarFromEmpty) +TEST(PersistentStorageJsonTestSuite, GetRegistrarFromEmpty) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -241,9 +250,9 @@ TEST(PSJson, GetRegistrarFromEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetDomainFromEmpty) +TEST(PersistentStorageJsonTestSuite, GetDomainFromEmpty) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -254,7 +263,7 @@ TEST(PSJson, GetDomainFromEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetNetworkFromEmpty) +TEST(PersistentStorageJsonTestSuite, GetNetworkFromEmpty) { PersistentStorageJson psj(""); @@ -267,9 +276,9 @@ TEST(PSJson, GetNetworkFromEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetBorderRouterFromEmpty) +TEST(PersistentStorageJsonTestSuite, GetBorderRouterFromEmpty) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -280,12 +289,12 @@ TEST(PSJson, GetBorderRouterFromEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetRegistrarNotEmpty) +TEST(PersistentStorageJsonTestSuite, GetRegistrarNotEmpty) { // Make test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -310,12 +319,12 @@ TEST(PSJson, GetRegistrarNotEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetDomainNotEmpty) +TEST(PersistentStorageJsonTestSuite, GetDomainNotEmpty) { // Make test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -338,9 +347,9 @@ TEST(PSJson, GetDomainNotEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetNetworkNotEmpty) +TEST(PersistentStorageJsonTestSuite, GetNetworkNotEmpty) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -367,12 +376,12 @@ TEST(PSJson, GetNetworkNotEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetBorderRouterNotEmpty) +TEST(PersistentStorageJsonTestSuite, GetBorderRouterNotEmpty) { // Make the test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -412,12 +421,12 @@ TEST(PSJson, GetBorderRouterNotEmpty) } // UPD -TEST(PSJson, UpdRegistrar) +TEST(PersistentStorageJsonTestSuite, UpdRegistrar) { // Make the test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -446,12 +455,12 @@ TEST(PSJson, UpdRegistrar) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, UpdDomain) +TEST(PersistentStorageJsonTestSuite, UpdDomain) { // Make the test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -478,10 +487,10 @@ TEST(PSJson, UpdDomain) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, UpdNetwork) +TEST(PersistentStorageJsonTestSuite, UpdNetwork) { - unlink("./tmp.json"); - PersistentStorageJson psj("./tmp.json"); + unlink("./tmp/tmp.json"); + PersistentStorageJson psj("./tmp/tmp.json"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -505,12 +514,12 @@ TEST(PSJson, UpdNetwork) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, UpdBorderRouter) +TEST(PersistentStorageJsonTestSuite, UpdBorderRouter) { // Make test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -558,12 +567,12 @@ TEST(PSJson, UpdBorderRouter) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, LookupRegistrar) +TEST(PersistentStorageJsonTestSuite, LookupRegistrar) { // Make test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -634,28 +643,25 @@ TEST(PSJson, LookupRegistrar) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, LookupNetwork) +TEST(PersistentStorageJsonTestSuite, LookupNetwork) { // Make test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); // Populate storage with initial data NetworkId newId; - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk1", XpanId{0xFFFFFFFFFFFFFFF1ll}, 11, 0xFFF1, "2000:aaa1::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk1", 0xFFFFFFFFFFFFFFF1ll, 11, 0xFFF1, "2000:aaa1::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 0); - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk2", XpanId{0xFFFFFFFFFFFFFFF2ll}, 11, 0xFFF2, "2000:aaa2::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk2", 0xFFFFFFFFFFFFFFF2ll, 11, 0xFFF2, "2000:aaa2::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 1); - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk3", XpanId{0xFFFFFFFFFFFFFFF3ll}, 11, 0xFFF3, "2000:aaa3::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk3", 0xFFFFFFFFFFFFFFF3ll, 11, 0xFFF3, "2000:aaa3::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 2); // The test diff --git a/src/app/ps/registry.cpp b/src/app/ps/registry.cpp index eef177afe..15956b8ba 100644 --- a/src/app/ps/registry.cpp +++ b/src/app/ps/registry.cpp @@ -175,7 +175,7 @@ Registry::Status Registry::Add(BorderAgent const &aValue) // Decided: update network aName in the network entity if ((aValue.mPresentFlags & BorderAgent::kExtendedPanIdBit) != 0) { - nwk.mXpan = XpanId{aValue.mExtendedPanId}; + nwk.mXpan = aValue.mExtendedPanId; } else { @@ -199,7 +199,7 @@ Registry::Status Registry::Add(BorderAgent const &aValue) nwk.mName = aValue.mNetworkName; } nwk.mDomainId = dom.mId; - nwk.mXpan = XpanId{aValue.mExtendedPanId}; + nwk.mXpan = aValue.mExtendedPanId; // Provisionally set network's CCM flag considering // advertised Connection Mode. @@ -293,7 +293,7 @@ Registry::Status Registry::GetBorderRouter(const BorderRouterId aRawId, BorderRo return MapStatus(mStorage->Get(aRawId, br)); } -Registry::Status Registry::GetBorderRoutersInNetwork(const XpanId aXpan, BorderRouterArray &aRet) +Registry::Status Registry::GetBorderRoutersInNetwork(uint64_t aXpan, BorderRouterArray &aRet) { Network nwk; BorderRouter pred; @@ -306,7 +306,7 @@ Registry::Status Registry::GetBorderRoutersInNetwork(const XpanId aXpan, BorderR return status; } -Registry::Status Registry::GetNetworkXpansInDomain(const std::string &aDomainName, XpanIdArray &aRet) +Registry::Status Registry::GetNetworkXpansInDomain(const std::string &aDomainName, std::vector &aRet) { NetworkArray networks; Registry::Status status = GetNetworksInDomain(aDomainName, networks); @@ -421,9 +421,9 @@ Registry::Status Registry::GetAllNetworks(NetworkArray &aRet) return status; } -Registry::Status Registry::GetNetworkXpansByAliases(const StringArray &aAliases, - XpanIdArray &aRet, - StringArray &aUnresolved) +Registry::Status Registry::GetNetworkXpansByAliases(const StringArray &aAliases, + std::vector &aRet, + StringArray &aUnresolved) { NetworkArray networks; Registry::Status status = GetNetworksByAliases(aAliases, networks, aUnresolved); @@ -484,23 +484,32 @@ Registry::Status Registry::GetNetworksByAliases(const StringArray &aAliases, } else { - Network nwk; - XpanId xpid; - PanId pid; + Network nwk; + uint64_t xpid; + uint16_t pid; status = Registry::Status::kNotFound; - if (xpid.FromHex(alias) == ERROR_NONE) + if (utils::ParseInteger(xpid, alias) == ERROR_NONE) { status = GetNetworkByXpan(xpid, nwk); } + if (status != Registry::Status::kSuccess) { status = GetNetworkByName(alias, nwk); } - if (status != Registry::Status::kSuccess && pid.FromHex(alias) == ERROR_NONE) + + if (status != Registry::Status::kSuccess) { - status = GetNetworkByPan(alias, nwk); + bool hasHexPrefix = utils::ToLower(alias.substr(0, 2)) != "0x"; + std::string aliasAsPanId = std::string(hasHexPrefix ? "0x" : "") + alias; + + if (utils::ParseInteger(pid, aliasAsPanId) == ERROR_NONE) + { + status = GetNetworkByPan(aliasAsPanId, nwk); + } } + if (status == Registry::Status::kSuccess) { networks.push_back(nwk); @@ -533,7 +542,7 @@ Registry::Status Registry::ForgetCurrentNetwork() return SetCurrentNetwork(NetworkId{}); } -Registry::Status Registry::SetCurrentNetwork(const XpanId &aXpan) +Registry::Status Registry::SetCurrentNetwork(uint64_t aXpan) { Network nwk; Registry::Status status; @@ -571,7 +580,7 @@ Registry::Status Registry::GetCurrentNetwork(Network &aRet) : MapStatus(mStorage->Get(networkId, aRet)); } -Registry::Status Registry::GetCurrentNetworkXpan(XpanId &aRet) +Registry::Status Registry::GetCurrentNetworkXpan(uint64_t &aRet) { Registry::Status status; Network nwk; @@ -592,7 +601,7 @@ Registry::Status Registry::LookupOne(const Network &aPred, Network &aRet) return status; } -Registry::Status Registry::GetNetworkByXpan(const XpanId &aXpan, Network &aRet) +Registry::Status Registry::GetNetworkByXpan(uint64_t aXpan, Network &aRet) { Network nwk{}; nwk.mXpan = aXpan; @@ -608,9 +617,10 @@ Registry::Status Registry::GetNetworkByName(const std::string &aName, Network &a Registry::Status Registry::GetNetworkByPan(const std::string &aPan, Network &aRet) { - Network nwk{}; - PanId panId; - if (panId.FromHex(aPan).GetCode() != ErrorCode::kNone) + Network nwk{}; + uint16_t panId = 0; + + if (utils::ParseInteger(panId, aPan).GetCode() != ErrorCode::kNone) { return Registry::Status::kError; } @@ -618,7 +628,7 @@ Registry::Status Registry::GetNetworkByPan(const std::string &aPan, Network &aRe return LookupOne(nwk, aRet); } -Registry::Status Registry::GetDomainNameByXpan(const XpanId &aXpan, std::string &aName) +Registry::Status Registry::GetDomainNameByXpan(uint64_t aXpan, std::string &aName) { Registry::Status status; Network nwk; @@ -753,13 +763,13 @@ Registry::Status Registry::DropDomainIfEmpty(const DomainId &aDomainId) Registry::Status Registry::DeleteBorderRoutersInDomain(const std::string &aDomainName) { - Domain dom; - DomainArray doms; - Registry::Status status; - Network current; - XpanIdArray xpans; - StringArray aAliases; - StringArray aUnresolved; + Domain dom; + DomainArray doms; + Registry::Status status; + Network current; + std::vector xpans; + StringArray aAliases; + StringArray aUnresolved; dom.mName = aDomainName; VerifyOrExit((status = MapStatus(mStorage->Lookup(dom, doms))) == Registry::Status::kSuccess); @@ -779,7 +789,7 @@ Registry::Status Registry::DeleteBorderRoutersInDomain(const std::string &aDomai for (auto &&xpan : xpans) { - aAliases.push_back(XpanId(xpan).str()); + aAliases.push_back(utils::Hex(xpan)); } VerifyOrExit((status = DeleteBorderRoutersInNetworks(aAliases, aUnresolved)) == Registry::Status::kSuccess); VerifyOrExit(aUnresolved.empty(), status = Registry::Status::kAmbiguity); diff --git a/src/app/ps/registry.hpp b/src/app/ps/registry.hpp index af89604aa..97cc57df8 100644 --- a/src/app/ps/registry.hpp +++ b/src/app/ps/registry.hpp @@ -136,7 +136,7 @@ class Registry * @param[in] aXpan network's XPAN ID * @param[out] aRetValue resultant array of @ref BorderRouter records */ - Status GetBorderRoutersInNetwork(XpanId aXpan, BorderRouterArray &aRetValue); + Status GetBorderRoutersInNetwork(uint64_t aXpan, BorderRouterArray &aRetValue); /** * Get networks of the domain @@ -154,7 +154,7 @@ class Registry * @param[out] aRetValue vector of network XPAN IDs belonging to the domain * @note Network XPAN IDs will be appended to the end of the output vector */ - Status GetNetworkXpansInDomain(const std::string &aDomainName, XpanIdArray &aRetValue); + Status GetNetworkXpansInDomain(const std::string &aDomainName, std::vector &aRetValue); /** * Get list of all domains @@ -191,12 +191,14 @@ class Registry * @param[out] aRetValue list of network XPAN IDs * @param[out] aUnresolved list of aliases failed to resolve */ - Status GetNetworkXpansByAliases(const StringArray &aAliases, XpanIdArray &aRetValue, StringArray &aUnresolved); + Status GetNetworkXpansByAliases(const StringArray &aAliases, + std::vector &aRetValue, + StringArray &aUnresolved); /** * Set current network. */ - Status SetCurrentNetwork(const XpanId &aXpan); + Status SetCurrentNetwork(uint64_t aXpan); /** * Set current network by border router specified. @@ -219,7 +221,7 @@ class Registry * * @param [out] aRetValue current network XPAN ID */ - Status GetCurrentNetworkXpan(XpanId &aRetValue); + Status GetCurrentNetworkXpan(uint64_t &aRetValue); /** * Get network with specified extended PAN id @@ -232,7 +234,7 @@ class Registry * @li @ref REG_DATA_INVALID is more than one network was found * @li @ref REG_ERROR on other errors */ - Status GetNetworkByXpan(const XpanId &aXpan, Network &aRetValue); + Status GetNetworkByXpan(uint64_t aXpan, Network &aRetValue); /** * Get network with specified name @@ -271,7 +273,7 @@ class Registry * @li @ref REG_AMBUGUITY is more than one network was found * @li @ref REG_ERROR on other errors */ - Status GetDomainNameByXpan(const XpanId &aXpan, std::string &aName); + Status GetDomainNameByXpan(uint64_t aXpan, std::string &aName); /** * Remove border router record. diff --git a/src/app/ps/registry_entries.cpp b/src/app/ps/registry_entries.cpp index 2ee214942..e9586800e 100644 --- a/src/app/ps/registry_entries.cpp +++ b/src/app/ps/registry_entries.cpp @@ -156,8 +156,8 @@ void to_json(json &aJson, const Network &aValue) aJson = json{{JSON_ID, aValue.mId}, {JSON_DOM_REF, aValue.mDomainId}, {JSON_NAME, aValue.mName}, - {JSON_PAN, std::string(aValue.mPan)}, - {JSON_XPAN, std::string(aValue.mXpan)}, + {JSON_PAN, utils::Hex(aValue.mPan)}, + {JSON_XPAN, utils::Hex(aValue.mXpan)}, {JSON_CHANNEL, aValue.mChannel}, {JSON_MLP, aValue.mMlp}, {JSON_CCM, aValue.mCcm}}; @@ -165,15 +165,16 @@ void to_json(json &aJson, const Network &aValue) void from_json(const json &aJson, Network &aValue) { + std::string hexStr; + aJson.at(JSON_ID).get_to(aValue.mId); aJson.at(JSON_DOM_REF).get_to(aValue.mDomainId); aJson.at(JSON_NAME).get_to(aValue.mName); - std::string hexStr; aJson.at(JSON_PAN).get_to(hexStr); - SuccessOrThrow(aValue.mPan.FromHex(hexStr)); + SuccessOrThrow(utils::ParseInteger(aValue.mPan, hexStr)); aJson.at(JSON_XPAN).get_to(hexStr); - SuccessOrThrow(aValue.mXpan.FromHex(hexStr)); + SuccessOrThrow(utils::ParseInteger(aValue.mXpan, hexStr)); aJson.at(JSON_CHANNEL).get_to(aValue.mChannel); aJson.at(JSON_MLP).get_to(aValue.mMlp); @@ -407,14 +408,14 @@ Domain::Domain() { } -Network::Network(NetworkId const &aId, - DomainId const &aDomainId, - std::string const &aName, - XpanId const &aXpan, - unsigned int const aChannel, - uint16_t const aPan, - std::string const &aMlp, - int const aCcm) +Network::Network(const NetworkId &aId, + const DomainId &aDomainId, + const std::string &aName, + uint64_t aXpan, + unsigned int aChannel, + uint16_t aPan, + const std::string &aMlp, + int aCcm) : mId(aId) , mDomainId(aDomainId) , mName(aName) @@ -427,7 +428,7 @@ Network::Network(NetworkId const &aId, } Network::Network() - : Network(EMPTY_ID, EMPTY_ID, "", XpanId{}, 0, 0, "", -1) + : Network(EMPTY_ID, EMPTY_ID, "", 0, 0, 0, "", -1) { } diff --git a/src/app/ps/registry_entries.hpp b/src/app/ps/registry_entries.hpp index cf69e8c4e..39dac0cf7 100644 --- a/src/app/ps/registry_entries.hpp +++ b/src/app/ps/registry_entries.hpp @@ -138,20 +138,20 @@ struct Network NetworkId mId; /**< unique mId in registry */ DomainId mDomainId; /**< reference to the domain the network belongs to */ std::string mName; /**< network name */ - XpanId mXpan; /**< Extended PAN_ID */ + uint64_t mXpan; /**< Extended PAN_ID */ unsigned int mChannel; /**< network channel */ - PanId mPan; /**< PAN_ID */ + uint16_t mPan; /**< PAN_ID */ std::string mMlp; /**< Mesh-local prefix */ int mCcm; /**< Commercial commissioning mode;<0 not set, * 0 false, >0 true */ - Network(NetworkId const &aId, - DomainId const &aDomainId, - std::string const &aName, - XpanId const &aXpan, + Network(const NetworkId &aId, + const DomainId &aDomainId, + const std::string &aName, + uint64_t aXpan, unsigned int aChannel, uint16_t aPan, - std::string const &aMlp, + const std::string &aMlp, int aCcm); Network(); }; diff --git a/src/app/ps/registry_test.cpp b/src/app/ps/registry_test.cpp index 1c0ad96e4..867b28386 100644 --- a/src/app/ps/registry_test.cpp +++ b/src/app/ps/registry_test.cpp @@ -31,22 +31,22 @@ * The file implements registry test suite. */ -#include - -#include "registry.hpp" - +#include #include -#include +#include #include "app/cli/console.hpp" +#include "app/ps/registry.hpp" +#include "common/utils.hpp" #define INFO(str) Console::Write(str) using namespace ot::commissioner::persistent_storage; +using namespace ot::commissioner::utils; using namespace ot::commissioner; -const char json_path[] = "./registry_test.json"; +const char json_path[] = "./tmp/registry_test.json"; TEST(RegJson, CreateEmptyRegistry) { @@ -91,7 +91,7 @@ TEST(RegJson, CreateBorderRouterFromBorderAgent) EXPECT_TRUE(reg.GetBorderRouter(BorderRouterId{0}, ret_val) == Registry::Status::kSuccess); EXPECT_TRUE(ret_val.mNetworkId.mId == 0); Network nwk; - EXPECT_TRUE(reg.GetNetworkByXpan(XpanId{0}, nwk) == Registry::Status::kSuccess); + EXPECT_TRUE(reg.GetNetworkByXpan(0, nwk) == Registry::Status::kSuccess); EXPECT_TRUE(nwk.mDomainId.mId == EMPTY_ID); } @@ -163,7 +163,7 @@ TEST(RegJson, CreateBorderRouterFromBorderAgent) EXPECT_TRUE((val.mAgent.mPresentFlags & (BorderAgent::kAddrBit | BorderAgent::kPortBit)) == (BorderAgent::kAddrBit | BorderAgent::kPortBit)); EXPECT_TRUE(val.mAgent.mAddr == "1.1.1.1"); - INFO(val.mAgent.mNetworkName + " : " + XpanId(val.mAgent.mExtendedPanId).str()); + INFO(val.mAgent.mNetworkName + " : " + utils::Hex(val.mAgent.mExtendedPanId)); Network nwk; EXPECT_TRUE(reg.GetNetworkByXpan(val.mAgent.mExtendedPanId, nwk) == Registry::Status::kSuccess); // Modify explicitly diff --git a/src/common/error.cpp b/src/common/error.cpp index 37c0f6acb..7467cd9ad 100644 --- a/src/common/error.cpp +++ b/src/common/error.cpp @@ -42,7 +42,7 @@ namespace ot { namespace commissioner { // Returns the std::string representation of the status code. -static std::string ErrorCodeToString(ErrorCode code) +std::string ErrorCodeToString(ErrorCode code) { switch (code) { diff --git a/src/common/logging.hpp b/src/common/logging.hpp index 4d6592677..52bc23d3d 100644 --- a/src/common/logging.hpp +++ b/src/common/logging.hpp @@ -51,6 +51,7 @@ #define LOG_REGION_JOB_MANAGER "job-manager" #define LOG_REGION_JOB "job" #define LOG_REGION_SECURITY_MATERIALS "security-materials" +#define LOG_REGION_MESHDIAG "meshdiag" #define LOG(aLevel, aRegion, aFmt, ...) \ do \ diff --git a/src/common/utils.hpp b/src/common/utils.hpp index fa900ffaf..c48286fae 100644 --- a/src/common/utils.hpp +++ b/src/common/utils.hpp @@ -42,6 +42,7 @@ #include "commissioner/defines.hpp" #include "commissioner/error.hpp" +#include "common/error_macros.hpp" #define ASSERT(aCondition) \ do \ @@ -188,6 +189,33 @@ std::string ToLower(const std::string &aStr); bool CaseInsensitiveEqual(const std::string &aLhs, const std::string &aRhs); +/** + * Returns the Hex string of an integer with zero paddings. + * + * For example, it returns "0xface" for integer 0xface. + */ +template std::string Hex(T aInteger) +{ + return std::string("0x") + Hex(Encode(aInteger)); +} + +template Error ParseInteger(T &aInteger, const std::string &aStr) +{ + Error error; + uint64_t integer; + char *endPtr = nullptr; + + integer = strtoull(aStr.c_str(), &endPtr, 0); + + VerifyOrExit(endPtr != nullptr && endPtr == aStr.c_str() + aStr.length(), + error = ERROR_INVALID_ARGS("{} is not a valid integer", aStr)); + + aInteger = integer; + +exit: + return error; +} + } // namespace utils } // namespace commissioner diff --git a/src/common/utils_test.cpp b/src/common/utils_test.cpp index 0d228e63a..b454e59db 100644 --- a/src/common/utils_test.cpp +++ b/src/common/utils_test.cpp @@ -118,6 +118,29 @@ TEST(UtilsTest, HexEncodingDecoding_DecodingHexStringWithInvalidCharactersShould EXPECT_EQ(utils::Hex(buf, "00010g"), ErrorCode::kInvalidArgs); } +TEST(UtilsTest, ParseInteger_HexStringShouldSuccess) +{ + int value; + + EXPECT_EQ(utils::ParseInteger(value, "0xface"), ErrorCode::kNone); + EXPECT_EQ(value, 0xface); +} + +TEST(UtilsTest, ParseInteger_DecimalStringShouldSuccess) +{ + int value; + + EXPECT_EQ(utils::ParseInteger(value, "65535"), ErrorCode::kNone); + EXPECT_EQ(value, 65535); +} + +TEST(UtilsTest, ParseInteger_IntegerWithTrailingNonDigitsShouldFail) +{ + int value; + + EXPECT_EQ(utils::ParseInteger(value, "0xfacegg"), ErrorCode::kInvalidArgs); +} + } // namespace commissioner } // namespace ot diff --git a/src/java/commissioner.i b/src/java/commissioner.i index 4d65d5aa2..e6725c85e 100644 --- a/src/java/commissioner.i +++ b/src/java/commissioner.i @@ -43,8 +43,8 @@ #include %} -%include %include +%include %include %include %include @@ -63,6 +63,7 @@ %apply signed char { uint8_t }; %apply const signed char & { const uint8_t & }; %template(ByteArray) std::vector; + // Override the typemap of `uint8_t`. %apply unsigned char { uint8_t }; %apply const unsigned char & { const uint8_t & }; @@ -140,7 +141,6 @@ namespace commissioner { %ignore Commissioner::GetPendingDataset(Handler aHandler, uint16_t aDatasetFlags); %ignore Commissioner::SetPendingDataset(ErrorHandler aHandler, const PendingOperationalDataset &aPendingDataset); %ignore Commissioner::SetSecurePendingDataset(ErrorHandler aHandler, - const std::string & aPbbrAddr, uint32_t aMaxRetrievalTimer, const PendingOperationalDataset &aDataset); %ignore Commissioner::CommandReenroll(ErrorHandler aHandler, const std::string &aDstAddr); @@ -164,27 +164,22 @@ namespace commissioner { uint16_t aScanDuration, const std::string &aDstAddr); %ignore Commissioner::RegisterMulticastListener(Handler aHandler, - const std::string & aPbbrAddr, const std::vector &aMulticastAddrList, uint32_t aTimeout); %ignore Commissioner::RequestToken(Handler aHandler, const std::string &aAddr, uint16_t aPort); - // Remove operators and move constructor of Error, XpanId, PanId. + // Remove operators and move constructor of Error. %ignore Error::operator=(const Error &aError); %ignore Error::Error(Error &&aError) noexcept; %ignore Error::operator=(Error &&aError) noexcept; %ignore Error::operator==(const Error &aOther) const; %ignore Error::operator!=(const Error &aOther) const; - %ignore XpanId::operator==(const XpanId &aOther) const; - %ignore XpanId::operator!=(const uint64_t aOther) const; - %ignore XpanId::operator<(const XpanId aOther) const; - %ignore XpanId::operator std::string() const; - %ignore PanId::operator=(uint16_t aValue); - %ignore PanId::operator uint16_t() const; %ignore operator==(const Error &aError, const ErrorCode &aErrorCode); %ignore operator!=(const Error &aError, const ErrorCode &aErrorCode); %ignore operator==(const ErrorCode &aErrorCode, const Error &aError); %ignore operator!=(const ErrorCode &aErrorCode, const Error &aError); + %ignore PrintTo(const Error &aError, std::ostream *os); + %ignore PrintTo(ErrorCode aErrorCode, std::ostream *os); } } diff --git a/src/library/coap.cpp b/src/library/coap.cpp index 0bafc9859..e64957f35 100644 --- a/src/library/coap.cpp +++ b/src/library/coap.cpp @@ -328,10 +328,13 @@ Error Message::Deserialize(Header &aHeader, const ByteArray &aBuf, size_t &aOffs header.mMessageId = aBuf[offset++]; header.mMessageId = (header.mMessageId << 8) | aBuf[offset++]; - VerifyOrExit(offset + header.mTokenLength <= aBuf.size(), - error = ERROR_BAD_FORMAT("premature end of CoAP message header")); - memcpy(header.mToken, &aBuf[offset], std::min(header.mTokenLength, kMaxTokenLength)); - offset += header.mTokenLength; + if (header.mTokenLength != 0) + { + VerifyOrExit(offset + header.mTokenLength <= aBuf.size(), + error = ERROR_BAD_FORMAT("premature end of CoAP message header")); + memcpy(header.mToken, &aBuf[offset], std::min(header.mTokenLength, kMaxTokenLength)); + offset += header.mTokenLength; + } aHeader = header; aOffset = offset; diff --git a/src/library/coap_test.cpp b/src/library/coap_test.cpp index b4d9ed106..7dc1b1f3e 100644 --- a/src/library/coap_test.cpp +++ b/src/library/coap_test.cpp @@ -131,6 +131,18 @@ TEST(CoapTest, CoapMessageHeader_TokenIsPresent) EXPECT_EQ(message->GetToken(), ByteArray{0xfa}); } +TEST(CoapTest, CoapMessageHeader_TokenLengthIsZero) +{ + ByteArray buffer{'`', 0, 0, 1}; + Error error; + auto message = Message::Deserialize(error, buffer); + + EXPECT_NE(message, nullptr); + EXPECT_EQ(error, ErrorCode::kNone); + + EXPECT_EQ(message->GetToken(), ByteArray{}); +} + TEST(CoapTest, CoapMessageHeader_TokenLengthIsTooLong) { ByteArray buffer{0x49, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}; diff --git a/src/library/commissioner_impl.cpp b/src/library/commissioner_impl.cpp index de96b1586..94404161d 100644 --- a/src/library/commissioner_impl.cpp +++ b/src/library/commissioner_impl.cpp @@ -70,8 +70,6 @@ namespace commissioner { static constexpr uint16_t kLeaderAloc16 = 0xFC00; static constexpr uint16_t kPrimaryBbrAloc16 = 0xFC38; -static constexpr uint16_t kDefaultMmPort = 61631; - static constexpr uint32_t kMinKeepAliveInterval = 30; static constexpr uint32_t kMaxKeepAliveInterval = 45; @@ -1488,7 +1486,7 @@ Error CommissionerImpl::DecodeActiveOperationalDataset(ActiveOperationalDataset if (auto extendedPanId = tlvSet[tlv::Type::kExtendedPanId]) { - dataset.mExtendedPanId = XpanId{utils::Decode(extendedPanId->GetValue())}; + dataset.mExtendedPanId = extendedPanId->GetValue(); dataset.mPresentFlags |= ActiveOperationalDataset::kExtendedPanIdBit; } @@ -1627,7 +1625,7 @@ Error CommissionerImpl::EncodeActiveOperationalDataset(coap::Request if (aDataset.mPresentFlags & ActiveOperationalDataset::kExtendedPanIdBit) { - SuccessOrExit(error = AppendTlv(aRequest, {tlv::Type::kExtendedPanId, aDataset.mExtendedPanId.mValue})); + SuccessOrExit(error = AppendTlv(aRequest, {tlv::Type::kExtendedPanId, aDataset.mExtendedPanId})); } if (aDataset.mPresentFlags & ActiveOperationalDataset::kMeshLocalPrefixBit) @@ -1647,7 +1645,7 @@ Error CommissionerImpl::EncodeActiveOperationalDataset(coap::Request if (aDataset.mPresentFlags & ActiveOperationalDataset::kPanIdBit) { - SuccessOrExit(error = AppendTlv(aRequest, {tlv::Type::kPanId, aDataset.mPanId.mValue})); + SuccessOrExit(error = AppendTlv(aRequest, {tlv::Type::kPanId, aDataset.mPanId})); } if (aDataset.mPresentFlags & ActiveOperationalDataset::kPSKcBit) diff --git a/src/library/joiner_session.cpp b/src/library/joiner_session.cpp index b20638770..cd34ee6b1 100644 --- a/src/library/joiner_session.cpp +++ b/src/library/joiner_session.cpp @@ -187,11 +187,12 @@ void JoinerSession::HandleJoinFin(const coap::Request &aJoinFin) if (auto provisioningUrlTlv = tlvSet[tlv::Type::kProvisioningURL]) { - auto vendorDataTlv = tlvSet[tlv::Type::kVendorData]; - VerifyOrExit(vendorDataTlv != nullptr, error = ERROR_BAD_FORMAT("no valid Vendor Data TLV found")); - provisioningUrl = provisioningUrlTlv->GetValueAsString(); - vendorData = vendorDataTlv->GetValue(); + } + + if (auto vendorDataTlv = tlvSet[tlv::Type::kVendorData]) + { + vendorData = vendorDataTlv->GetValue(); } LOG_INFO(LOG_REGION_JOINER_SESSION, diff --git a/src/library/network_data.cpp b/src/library/network_data.cpp index cbb8cc396..c062d2e44 100644 --- a/src/library/network_data.cpp +++ b/src/library/network_data.cpp @@ -123,123 +123,6 @@ std::string Ipv6PrefixToString(ByteArray aPrefix) return addr.ToString() + "/" + std::to_string(prefixLength); } -XpanId::XpanId(uint64_t val) - : mValue(val) -{ -} - -XpanId::XpanId() - : XpanId(kEmptyXpanId) -{ -} - -std::string XpanId::str() const -{ - return std::string(*this); -} - -bool XpanId::operator==(const XpanId &aOther) const -{ - return mValue == aOther.mValue; -} - -bool XpanId::operator!=(const XpanId &aOther) const -{ - return !(*this == aOther); -} - -bool XpanId::operator<(const XpanId &aOther) const -{ - return mValue < aOther.mValue; -} - -XpanId::operator std::string() const -{ - std::ostringstream value; - value << std::uppercase << std::hex << std::setw(sizeof(mValue) * 2) << std::setfill('0') << mValue; - return value.str(); -} - -/** - * Converts hex string to the corresponding integer type. - * @attention Makes no validity checks. - */ -Error XpanId::FromHex(const std::string &aInput) -{ - mValue = 0; - - std::string input = aInput; - if (utils::ToLower(input.substr(0, 2)) == "0x") - { - input = input.substr(2); - } - if (input.empty() || input.length() > 16) - return ERROR_BAD_FORMAT("{}: wrong XPAN ID string length", input.length()); - for (auto c : input) - { - if (!std::isxdigit(c)) - { - return ERROR_BAD_FORMAT("{}: not a hex string", input); - } - } - - std::istringstream is(input); - is >> std::hex >> mValue; - return ERROR_NONE; -} - -PanId::PanId(uint16_t aValue) - : mValue(aValue) -{ -} - -PanId::PanId() - : PanId(kEmptyPanId) -{ -} - -PanId &PanId::operator=(uint16_t aValue) -{ - mValue = aValue; - return *this; -} - -PanId::operator uint16_t() const -{ - return mValue; -} - -PanId::operator std::string() const -{ - std::ostringstream value; - value << "0x" << std::uppercase << std::hex << std::setw(sizeof(mValue) * 2) << std::setfill('0') << mValue; - return value.str(); -} - -Error PanId::FromHex(const std::string &aInput) -{ - mValue = 0; - - std::string input = aInput; - if (utils::ToLower(input.substr(0, 2)) == "0x") - { - input = input.substr(2); - } - if (input.empty() || input.length() > 4) - return ERROR_BAD_FORMAT("{}: wrong PAN ID string length", input.length()); - for (auto c : input) - { - if (!std::isxdigit(c)) - { - return ERROR_BAD_FORMAT("{}: not a hex string", input); - } - } - - std::istringstream is(input); - is >> std::hex >> mValue; - return ERROR_NONE; -} - ActiveOperationalDataset::ActiveOperationalDataset() : mActiveTimestamp(Timestamp::Cur()) , mPresentFlags(kActiveTimestampBit) diff --git a/src/library/tlv.cpp b/src/library/tlv.cpp index 70405817f..2226db4ea 100644 --- a/src/library/tlv.cpp +++ b/src/library/tlv.cpp @@ -220,6 +220,73 @@ bool Tlv::IsValid() const { return false; } + else if (mScope == Scope::kNetworkDiag) + { + switch (mType) + { + // Network disgnostic layer TLVs + case Type::kNetworkDiagExtMacAddress: + return length >= 8; + case Type::kNetworkDiagMacAddress: + return length >= 2; + case Type::kNetworkDiagMode: + return length == 1; + case Type::kNetworkDiagTimeout: + return length == 4; + case Type::kNetworkDiagConnectivity: + return true; + case Type::kNetworkDiagRoute64: + return length >= 4; + case Type::kNetworkDiagLeaderData: + return length == 8; + case Type::kNetworkDiagNetworkData: + return true; + case Type::kNetworkDiagIpv6Address: + return (length % 16 == 0) && (length / 16 >= 1 && length / 16 <= 15); + case Type::kNetworkDiagMacCounters: + return length >= 36; + case Type::kNetworkDiagBatteryLevel: + return length == 1; + case Type::kNetworkDiagSupplyVoltage: + return length == 2; + case Type::kNetworkDiagChildTable: + return true; // list of 0 or more child entry data + case Type::kNetworkDiagChannelPages: + return length >= 1; // 1 or more 8-bit integers + case Type::kNetworkDiagTypeList: + return length >= 1; // 1 or more 8-bit integers + case Type::kNetworkDiagMaxChildTimeout: + return length == 4; + case Type::kNetworkDiagLDevIDSubjectPubKeyInfo: + return true; + case Type::kNetworkDiagIDevIDCert: + return true; + case Type::kNetworkDiagEui64: + return length == 8; + case Type::kNetworkDiagVersion: + return length == 2; + case Type::kNetworkDiagVendorName: + return length >= 4; + case Type::kNetworkDiagVendorModel: + return length >= 4; + case Type::kNetworkDiagVendorSWVersion: + return length >= 2; + case Type::kNetworkDiagChild: + return length >= 43; + case Type::kNetworkDiagChildIpv6Address: + return (length % 16 == 0) && (length / 16 >= 1 && length / 16 <= 15); + case Type::kNetworkDiagRouterNeighbor: + return length >= 24; + case Type::kNetworkDiagAnswer: + return length == 2; + case Type::kNetworkDiagQueryID: + return length == 2; + case Type::kNetworkDiagMleCounters: + return length >= 66; + default: + return false; + } + } switch (mType) { diff --git a/src/library/tlv.hpp b/src/library/tlv.hpp index b478767ad..e2b52eaa6 100644 --- a/src/library/tlv.hpp +++ b/src/library/tlv.hpp @@ -63,6 +63,7 @@ enum class Scope : uint8_t kMeshCoP = 0, kThread, kMeshLink, + kNetworkDiag, }; enum class Type : uint8_t @@ -139,6 +140,38 @@ enum class Type : uint8_t kCommissionerPenSignature = 70, kDiscoveryRequest = 128, kDiscoveryResponse = 129, + + // TMF Network Diagnositcs TLVs + kNetworkDiagExtMacAddress = 0, + kNetworkDiagMacAddress = 1, + kNetworkDiagMode = 2, + kNetworkDiagTimeout = 3, + kNetworkDiagConnectivity = 4, + kNetworkDiagRoute64 = 5, + kNetworkDiagLeaderData = 6, + kNetworkDiagNetworkData = 7, + kNetworkDiagIpv6Address = 8, + kNetworkDiagMacCounters = 9, + kNetworkDiagBatteryLevel = 14, + kNetworkDiagSupplyVoltage = 15, + kNetworkDiagChildTable = 16, + kNetworkDiagChannelPages = 17, + kNetworkDiagTypeList = 18, + kNetworkDiagMaxChildTimeout = 19, + kNetworkDiagLDevIDSubjectPubKeyInfo = 20, + kNetworkDiagIDevIDCert = 21, + kNetworkDiagEui64 = 23, + kNetworkDiagVersion = 24, + kNetworkDiagVendorName = 25, + kNetworkDiagVendorModel = 26, + kNetworkDiagVendorSWVersion = 27, + kNetworkDiagThreadStackVersion = 28, + kNetworkDiagChild = 29, + kNetworkDiagChildIpv6Address = 30, + kNetworkDiagRouterNeighbor = 31, + kNetworkDiagAnswer = 32, + kNetworkDiagQueryID = 33, + kNetworkDiagMleCounters = 34, }; using TlvPtr = std::shared_ptr; diff --git a/src/library/udp_proxy.cpp b/src/library/udp_proxy.cpp index e6abf62a1..77a546d93 100644 --- a/src/library/udp_proxy.cpp +++ b/src/library/udp_proxy.cpp @@ -81,7 +81,8 @@ Error ProxyEndpoint::Send(const ByteArray &aRequest, MessageSubType aSubType) VerifyOrExit(mBrClient.IsConnected(), error = ERROR_INVALID_STATE("not connected to the border agent")); - utils::Encode(udpPayload, mBrClient.GetDtlsSession().GetLocalPort()); + // set the source port to default mamagement port for UDP_Tx message + utils::Encode(udpPayload, kDefaultMmPort); utils::Encode(udpPayload, GetPeerPort()); udpPayload.insert(udpPayload.end(), aRequest.begin(), aRequest.end()); @@ -151,6 +152,7 @@ void ProxyClient::HandleUdpRx(const coap::Request &aUdpRx) Error error; Address peerAddr; uint16_t peerPort; + uint16_t destPort; tlv::TlvPtr srcAddr = nullptr; tlv::TlvPtr udpEncap = nullptr; @@ -163,6 +165,12 @@ void ProxyClient::HandleUdpRx(const coap::Request &aUdpRx) peerPort = utils::Decode(udpEncap->GetValue()); + // get the dest port from the UDP_Rx message + destPort = utils::Decode(&udpEncap->GetValue()[2], sizeof(uint16_t)); + VerifyOrExit(destPort == kDefaultMmPort, + ERROR_UNIMPLEMENTED("dropping UDP_RX.ntf message to port {}: only port {} is supported", destPort, + kDefaultMmPort)); + mEndpoint.SetPeerAddr(peerAddr); mEndpoint.SetPeerPort(peerPort); diff --git a/src/library/uri.hpp b/src/library/uri.hpp index c528ba9a6..d8535eb93 100644 --- a/src/library/uri.hpp +++ b/src/library/uri.hpp @@ -75,6 +75,14 @@ static const char *const kJoinEnt = "/c/je"; static const char *const kJoinFin = "/c/jf"; static const char *const kJoinApp = "/c/ja"; +/* + * Thread diagnostic URIs + */ +static const char *const kDiagGet = "/d/dg"; +static const char *const kDiagGetQuery = "/d/dq"; +static const char *const kDiagGetAns = "/d/da"; +static const char *const kDiagRst = "/d/dr"; + /* * Thread Network Layer URIs */ diff --git a/tests/integration/test_domain_syntax.sh b/tests/integration/test_domain_syntax.sh index d41d3074b..468edd644 100755 --- a/tests/integration/test_domain_syntax.sh +++ b/tests/integration/test_domain_syntax.sh @@ -75,7 +75,7 @@ test_select_identify() { send_command_to_commissioner "network select thread1" send_command_to_commissioner "network identify" "thread1" - send_command_to_commissioner "network select 2222222222222222" + send_command_to_commissioner "network select 0x2222222222222222" send_command_to_commissioner "network identify" "thread2" send_command_to_commissioner "network select none" @@ -151,10 +151,10 @@ test_start_stop_mn_all() { commissioner_mdns_scan_import ${CUR_DIR}/etc/br_scan_initial send_command_to_commissioner "start --nwk all" - send_command_to_commissioner "active --nwk all" 'DEAD00BEEF00CAFE.*true' - send_command_to_commissioner "sessionid --nwk all" 'DEAD00BEEF00CAFE": \d*' - send_command_to_commissioner "opdataset get active --nwk all" 'DEAD00BEEF00CAFE": {' - send_command_to_commissioner "commdataset get --nwk all" 'DEAD00BEEF00CAFE": {' + send_command_to_commissioner "active --nwk all" '0xdead00beef00cafe.*true' + send_command_to_commissioner "sessionid --nwk all" '0xdead00beef00cafe": \d*' + send_command_to_commissioner "opdataset get active --nwk all" '0xdead00beef00cafe": {' + send_command_to_commissioner "commdataset get --nwk all" '0xdead00beef00cafe": {' send_command_to_commissioner "opdataset set securitypolicy 1000 ff --nwk all" send_command_to_commissioner "opdataset get pending --nwk all" send_command_to_commissioner "stop --nwk all" @@ -179,12 +179,12 @@ test_start_stop_mn_other() { mdns_hosts_map_addresses commissioner_mdns_scan_import ${CUR_DIR}/etc/br_scan_initial - send_command_to_commissioner "network select 2222222222222222" + send_command_to_commissioner "network select 0x2222222222222222" send_command_to_commissioner "start --nwk other" send_command_to_commissioner "active --nwk other" '1111111111111111": false' - send_command_to_commissioner "sessionid --nwk other" 'DEAD00BEEF00CAFE": \d*' - send_command_to_commissioner "opdataset get active --nwk other" 'DEAD00BEEF00CAFE": {' - send_command_to_commissioner "commdataset get --nwk other" 'DEAD00BEEF00CAFE": {' + send_command_to_commissioner "sessionid --nwk other" '0xdead00beef00cafe": \d*' + send_command_to_commissioner "opdataset get active --nwk other" '0xdead00beef00cafe": {' + send_command_to_commissioner "commdataset get --nwk other" '0xdead00beef00cafe": {' send_command_to_commissioner "opdataset set securitypolicy 1000 ff --nwk other" send_command_to_commissioner "opdataset get pending --nwk other" send_command_to_commissioner "stop --nwk other" @@ -212,10 +212,10 @@ test_start_stop_mn_dom() { set -x send_command_to_commissioner "start --dom TestDomainName" - send_command_to_commissioner "active --dom TestDomainName" '2222222222222222": false' - send_command_to_commissioner "sessionid --dom TestDomainName" 'DEAD00BEEF00CAFE": \d*' - send_command_to_commissioner "opdataset get active --dom TestDomainName" 'DEAD00BEEF00CAFE": {' - send_command_to_commissioner "commdataset get --dom TestDomainName" 'DEAD00BEEF00CAFE": {' + send_command_to_commissioner "active --dom TestDomainName" '0x2222222222222222": false' + send_command_to_commissioner "sessionid --dom TestDomainName" '0xdead00beef00cafe": \d*' + send_command_to_commissioner "opdataset get active --dom TestDomainName" '0xdead00beef00cafe": {' + send_command_to_commissioner "commdataset get --dom TestDomainName" '0xdead00beef00cafe": {' send_command_to_commissioner "opdataset set securitypolicy 1000 ff --dom TestDomainName" send_command_to_commissioner "opdataset get pending --dom TestDomainName" send_command_to_commissioner "stop --dom TestDomainName"