From 12092756fafd8d644f4a1dd2b88061d08e5266e1 Mon Sep 17 00:00:00 2001 From: Marcos B <15697303+gmarcosb@users.noreply.github.com> Date: Wed, 22 Jun 2022 21:32:02 -0600 Subject: [PATCH] Allow UDP listening port selection for Android (#19596) * Allow UDP listening port selection for Android * Restyled by google-java-format * Restyled by clang-format Co-authored-by: Restyled.io --- .../java/AndroidDeviceControllerWrapper.cpp | 4 +- .../java/AndroidDeviceControllerWrapper.h | 3 +- src/controller/java/BUILD.gn | 1 + .../java/CHIPDeviceController-JNI.cpp | 52 ++++++-- .../ChipDeviceController.java | 32 +---- .../devicecontroller/ControllerParams.java | 118 ++++++++++++++++++ 6 files changed, 172 insertions(+), 38 deletions(-) create mode 100644 src/controller/java/src/chip/devicecontroller/ControllerParams.java diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp index 25299318448045..2c585c70fb0c6d 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.cpp +++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp @@ -74,7 +74,7 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew( chip::Inet::EndPointManager * tcpEndPointManager, chip::Inet::EndPointManager * udpEndPointManager, AndroidOperationalCredentialsIssuerPtr opCredsIssuerPtr, jobject keypairDelegate, jbyteArray rootCertificate, jbyteArray intermediateCertificate, jbyteArray nodeOperationalCertificate, - jbyteArray ipkEpochKey, CHIP_ERROR * errInfoOnFailure) + jbyteArray ipkEpochKey, uint16_t listenPort, CHIP_ERROR * errInfoOnFailure) { if (errInfoOnFailure == nullptr) { @@ -140,7 +140,7 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew( #if CONFIG_NETWORK_LAYER_BLE initParams.bleLayer = DeviceLayer::ConnectivityMgr().GetBleLayer(); #endif - initParams.listenPort = CHIP_PORT + 1; + initParams.listenPort = listenPort; setupParams.pairingDelegate = wrapper.get(); setupParams.operationalCredentialsDelegate = opCredsIssuer; initParams.fabricIndependentStorage = wrapper.get(); diff --git a/src/controller/java/AndroidDeviceControllerWrapper.h b/src/controller/java/AndroidDeviceControllerWrapper.h index 14651e5dfbd891..7437701cbcf8aa 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.h +++ b/src/controller/java/AndroidDeviceControllerWrapper.h @@ -111,6 +111,7 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel * @param[in] intermediateCertificate an X.509 DER-encoded intermediate certificate for this node * @param[in] nodeOperationalCertificate an X.509 DER-encoded operational certificate for this node * @param[in] ipkEpochKey the IPK epoch key to use for this node + * @param[in] listenPort the UDP port to listen on * @param[out] errInfoOnFailure a pointer to a CHIP_ERROR that will be populated if this method returns nullptr */ static AndroidDeviceControllerWrapper * AllocateNew(JavaVM * vm, jobject deviceControllerObj, chip::NodeId nodeId, @@ -120,7 +121,7 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel AndroidOperationalCredentialsIssuerPtr opCredsIssuer, jobject keypairDelegate, jbyteArray rootCertificate, jbyteArray intermediateCertificate, jbyteArray nodeOperationalCertificate, - jbyteArray ipkEpochKey, CHIP_ERROR * errInfoOnFailure); + jbyteArray ipkEpochKey, uint16_t listenPort, CHIP_ERROR * errInfoOnFailure); private: using ChipDeviceControllerPtr = std::unique_ptr; diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index bb704ce4cc5905..b808a6b36f561f 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -87,6 +87,7 @@ android_library("java") { "src/chip/devicecontroller/ChipCommandType.java", "src/chip/devicecontroller/ChipDeviceController.java", "src/chip/devicecontroller/ChipDeviceControllerException.java", + "src/chip/devicecontroller/ControllerParams.java", "src/chip/devicecontroller/DiscoveredDevice.java", "src/chip/devicecontroller/GetConnectedDeviceCallbackJni.java", "src/chip/devicecontroller/KeypairDelegate.java", diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index 50ac6a8c4a35d7..5bf7a2c5cc5391 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -87,6 +87,8 @@ pthread_t sIOThread = PTHREAD_NULL; jclass sChipDeviceControllerExceptionCls = NULL; +const char * PARAMS_CLASS = "()Lchip/devicecontroller/ControllerParams;"; + } // namespace // NOTE: Remote device ID is in sync with the echo server device id @@ -153,9 +155,7 @@ void JNI_OnUnload(JavaVM * jvm, void * reserved) chip::Platform::MemoryShutdown(); } -JNI_METHOD(jlong, newDeviceController) -(JNIEnv * env, jobject self, jobject keypairDelegate, jbyteArray rootCertificate, jbyteArray intermediateCertificate, - jbyteArray operationalCertificate, jbyteArray ipk) +JNI_METHOD(jlong, newDeviceController)(JNIEnv * env, jobject self, jobject controllerParams) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; @@ -163,14 +163,48 @@ JNI_METHOD(jlong, newDeviceController) long result = 0; ChipLogProgress(Controller, "newDeviceController() called"); - std::unique_ptr opCredsIssuer( - new chip::Controller::AndroidOperationalCredentialsIssuer()); - wrapper = AndroidDeviceControllerWrapper::AllocateNew( - sJVM, self, kLocalDeviceId, chip::kUndefinedCATs, &DeviceLayer::SystemLayer(), DeviceLayer::TCPEndPointManager(), - DeviceLayer::UDPEndPointManager(), std::move(opCredsIssuer), keypairDelegate, rootCertificate, intermediateCertificate, - operationalCertificate, ipk, &err); + + // Retrieve initialization params. + jmethodID getUdpListenPort; + err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getUdpListenPort", PARAMS_CLASS, &getUdpListenPort); SuccessOrExit(err); + jmethodID getKeypairDelegate; + err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getKeypairDelegate", PARAMS_CLASS, + &getKeypairDelegate); + + jmethodID getRootCertificate; + err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getRootCertificate", PARAMS_CLASS, + &getRootCertificate); + + jmethodID getIntermediateCertificate; + err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getIntermediateCertificate", PARAMS_CLASS, + &getIntermediateCertificate); + + jmethodID getOperationalCertificate; + err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getOperationalCertificate", PARAMS_CLASS, + &getOperationalCertificate); + + jmethodID getIpk; + err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getIpk", PARAMS_CLASS, &getIpk); + + { + uint16_t listenPort = env->CallIntMethod(controllerParams, getUdpListenPort); + jobject keypairDelegate = env->CallObjectMethod(controllerParams, getKeypairDelegate); + jbyteArray rootCertificate = (jbyteArray) env->CallObjectMethod(controllerParams, getRootCertificate); + jbyteArray intermediateCertificate = (jbyteArray) env->CallObjectMethod(controllerParams, getIntermediateCertificate); + jbyteArray operationalCertificate = (jbyteArray) env->CallObjectMethod(controllerParams, getOperationalCertificate); + jbyteArray ipk = (jbyteArray) env->CallObjectMethod(controllerParams, getIpk); + + std::unique_ptr opCredsIssuer( + new chip::Controller::AndroidOperationalCredentialsIssuer()); + wrapper = AndroidDeviceControllerWrapper::AllocateNew( + sJVM, self, kLocalDeviceId, chip::kUndefinedCATs, &DeviceLayer::SystemLayer(), DeviceLayer::TCPEndPointManager(), + DeviceLayer::UDPEndPointManager(), std::move(opCredsIssuer), keypairDelegate, rootCertificate, intermediateCertificate, + operationalCertificate, ipk, listenPort, &err); + SuccessOrExit(err); + } + // Create and start the IO thread. Must be called after Controller()->Init if (sIOThread == PTHREAD_NULL) { diff --git a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java index 698d95e2ffe52e..b9d916bc6636c4 100644 --- a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java +++ b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java @@ -39,25 +39,14 @@ public static void loadJni() { return; } - /** - * Returns a new {@link ChipDeviceController} with ephemerally generated operational credentials. - */ + /** Returns a new {@link ChipDeviceController} with default parameters. */ public ChipDeviceController() { - deviceControllerPtr = newDeviceController(); + this(ControllerParams.newBuilder().build()); } - /** - * Returns a new {@link ChipDeviceController} which uses the provided {@code operationalKeyConfig} - * as its operating credentials. - */ - public ChipDeviceController(OperationalKeyConfig operationalKeyConfig) { - deviceControllerPtr = - newDeviceController( - operationalKeyConfig.getKeypairDelegate(), - operationalKeyConfig.getTrustedRootCertificate(), - operationalKeyConfig.getIntermediateCertificate(), - operationalKeyConfig.getNodeOperationalCertificate(), - operationalKeyConfig.getIpkEpochKey()); + /** Returns a new {@link ChipDeviceController} with the specified parameters. */ + public ChipDeviceController(ControllerParams params) { + deviceControllerPtr = newDeviceController(params); } public void setCompletionListener(CompletionListener listener) { @@ -431,16 +420,7 @@ public native void readPath( long devicePtr, List attributePaths); - private long newDeviceController() { - return newDeviceController(null, null, null, null, null); - } - - private native long newDeviceController( - @Nullable KeypairDelegate keypairDelegate, - @Nullable byte[] rootCertificate, - @Nullable byte[] intermediateCertificate, - @Nullable byte[] operationalCertificate, - @Nullable byte[] ipk); + private native long newDeviceController(ControllerParams params); private native void pairDevice( long deviceControllerPtr, diff --git a/src/controller/java/src/chip/devicecontroller/ControllerParams.java b/src/controller/java/src/chip/devicecontroller/ControllerParams.java new file mode 100644 index 00000000000000..ee7f7d09d63faa --- /dev/null +++ b/src/controller/java/src/chip/devicecontroller/ControllerParams.java @@ -0,0 +1,118 @@ +package chip.devicecontroller; + +import androidx.annotation.Nullable; + +/** Parameters representing initialization arguments for {@link ChipDeviceController}. */ +public final class ControllerParams { + + private final int udpListenPort; + @Nullable private final KeypairDelegate keypairDelegate; + @Nullable private final byte[] rootCertificate; + @Nullable private final byte[] intermediateCertificate; + @Nullable private final byte[] operationalCertificate; + @Nullable private final byte[] ipk; + + private static final int LEGACY_GLOBAL_CHIP_PORT = 5540; + + /** @param udpListenPort the UDP listening port, or 0 to pick any available port. */ + private ControllerParams(Builder builder) { + this.udpListenPort = builder.udpListenPort; + this.keypairDelegate = builder.keypairDelegate; + this.rootCertificate = builder.rootCertificate; + this.intermediateCertificate = builder.intermediateCertificate; + this.operationalCertificate = builder.operationalCertificate; + this.ipk = builder.ipk; + } + + /** Gets the UDP listening port; 0 indicates "any available port" */ + public int getUdpListenPort() { + return udpListenPort; + } + + public KeypairDelegate getKeypairDelegate() { + return keypairDelegate; + } + + public byte[] getRootCertificate() { + return rootCertificate; + } + + public byte[] getIntermediateCertificate() { + return intermediateCertificate; + } + + public byte[] getOperationalCertificate() { + return operationalCertificate; + } + + public byte[] getIpk() { + return ipk; + } + + /** Returns parameters with ephemerally generated operational credentials */ + public static Builder newBuilder() { + return new Builder(); + } + + /** + * Returns parameters which uses the provided {@code operationalKeyConfig} as its operating + * credentials. + */ + public static Builder newBuilder(OperationalKeyConfig operationalKeyConfig) { + return newBuilder() + .setKeypairDelegate(operationalKeyConfig.getKeypairDelegate()) + .setRootCertificate(operationalKeyConfig.getTrustedRootCertificate()) + .setIntermediateCertificate(operationalKeyConfig.getIntermediateCertificate()) + .setOperationalCertificate(operationalKeyConfig.getNodeOperationalCertificate()) + .setIpk(operationalKeyConfig.getIpkEpochKey()); + } + + /** Builder for {@link ControllerParams}. */ + public static class Builder { + private int udpListenPort = LEGACY_GLOBAL_CHIP_PORT + 1; + @Nullable private KeypairDelegate keypairDelegate = null; + @Nullable private byte[] rootCertificate = null; + @Nullable private byte[] intermediateCertificate = null; + @Nullable private byte[] operationalCertificate = null; + @Nullable private byte[] ipk = null; + + private Builder() {} + + public Builder setUdpListenPort(int udpListenPort) { + if (udpListenPort < 0) { + throw new IllegalArgumentException("udpListenPort must be >= 0"); + } + this.udpListenPort = udpListenPort; + return this; + } + + public Builder setKeypairDelegate(KeypairDelegate keypairDelegate) { + this.keypairDelegate = keypairDelegate; + return this; + } + + public Builder setRootCertificate(byte[] rootCertificate) { + this.rootCertificate = rootCertificate; + return this; + } + + public Builder setIntermediateCertificate(byte[] intermediateCertificate) { + this.intermediateCertificate = intermediateCertificate; + return this; + } + + public Builder setOperationalCertificate(byte[] operationalCertificate) { + this.operationalCertificate = operationalCertificate; + return this; + } + + public Builder setIpk(byte[] ipk) { + this.ipk = ipk; + return this; + } + + public ControllerParams build() { + return new ControllerParams(this); + } + } +}