[Fabric-Sync] Allow RPC ports customization in example apps (#35194)

* [Fabric-Sync] Allow RPC ports customization in example apps

* Restyled by clang-format

* Rename SetRpcClientPort to SetRpcRemoteServerPort

---------

Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/examples/fabric-admin/commands/interactive/InteractiveCommands.cpp b/examples/fabric-admin/commands/interactive/InteractiveCommands.cpp
index 22b6341..aabcb09 100644
--- a/examples/fabric-admin/commands/interactive/InteractiveCommands.cpp
+++ b/examples/fabric-admin/commands/interactive/InteractiveCommands.cpp
@@ -31,6 +31,7 @@
 
 #if defined(PW_RPC_ENABLED)
 #include <rpc/RpcClient.h>
+#include <rpc/RpcServer.h>
 #endif
 
 using namespace chip;
@@ -116,7 +117,7 @@
 #if defined(PW_RPC_ENABLED)
 void AttemptRpcClientConnect(System::Layer * systemLayer, void * appState)
 {
-    if (InitRpcClient(kFabricBridgeServerPort) == CHIP_NO_ERROR)
+    if (StartRpcClient() == CHIP_NO_ERROR)
     {
         ChipLogProgress(NotSpecified, "Connected to Fabric-Bridge");
     }
@@ -196,6 +197,9 @@
     }
 
 #if defined(PW_RPC_ENABLED)
+    SetRpcRemoteServerPort(mFabricBridgeServerPort.Value());
+    InitRpcServer(mLocalServerPort.Value());
+    ChipLogProgress(NotSpecified, "PW_RPC initialized.");
     DeviceLayer::PlatformMgr().ScheduleWork(ExecuteDeferredConnect, 0);
 #endif
 
diff --git a/examples/fabric-admin/commands/interactive/InteractiveCommands.h b/examples/fabric-admin/commands/interactive/InteractiveCommands.h
index e3d2808..648984d 100644
--- a/examples/fabric-admin/commands/interactive/InteractiveCommands.h
+++ b/examples/fabric-admin/commands/interactive/InteractiveCommands.h
@@ -24,6 +24,9 @@
 
 #include <string>
 
+constexpr uint16_t kFabricBridgeServerPort = 33002;
+constexpr uint16_t kFabricLocalServerPort  = 33001;
+
 class Commands;
 
 class InteractiveCommand : public CHIPCommand
@@ -55,7 +58,13 @@
     InteractiveStartCommand(Commands * commandsHandler, CredentialIssuerCommands * credsIssuerConfig) :
         InteractiveCommand("start", commandsHandler, "Start an interactive shell that can then run other commands.",
                            credsIssuerConfig)
-    {}
+    {
+#if defined(PW_RPC_ENABLED)
+        AddArgument("fabric-bridge-server-port", 0, UINT16_MAX, &mFabricBridgeServerPort,
+                    "The fabric-bridge RPC port number to connect to.");
+        AddArgument("local-server-port", 0, UINT16_MAX, &mLocalServerPort, "The port number for local RPC server.");
+#endif
+    }
 
     /////////// CHIPCommand Interface /////////
     CHIP_ERROR RunCommand() override;
@@ -63,6 +72,11 @@
 private:
     char * GetCommand(char * command);
     std::string GetHistoryFilePath() const;
+
+#if defined(PW_RPC_ENABLED)
+    chip::Optional<uint16_t> mFabricBridgeServerPort{ kFabricBridgeServerPort };
+    chip::Optional<uint16_t> mLocalServerPort{ kFabricLocalServerPort };
+#endif
 };
 
 void PushCommand(const std::string & command);
diff --git a/examples/fabric-admin/main.cpp b/examples/fabric-admin/main.cpp
index c7f9089..5768abf 100644
--- a/examples/fabric-admin/main.cpp
+++ b/examples/fabric-admin/main.cpp
@@ -28,19 +28,10 @@
 #include <string>
 #include <vector>
 
-#if defined(PW_RPC_ENABLED)
-#include <rpc/RpcServer.h>
-#endif
-
 using namespace chip;
 
 void ApplicationInit()
 {
-#if defined(PW_RPC_ENABLED)
-    InitRpcServer(kFabricAdminServerPort);
-    ChipLogProgress(NotSpecified, "PW_RPC initialized.");
-#endif
-
     DeviceMgr().Init();
 }
 
diff --git a/examples/fabric-admin/rpc/RpcClient.cpp b/examples/fabric-admin/rpc/RpcClient.cpp
index 29fc2b1..df7a475 100644
--- a/examples/fabric-admin/rpc/RpcClient.cpp
+++ b/examples/fabric-admin/rpc/RpcClient.cpp
@@ -117,9 +117,13 @@
 
 } // namespace
 
-CHIP_ERROR InitRpcClient(uint16_t rpcServerPort)
+void SetRpcRemoteServerPort(uint16_t port)
 {
-    rpc::client::SetRpcServerPort(rpcServerPort);
+    rpc::client::SetRpcServerPort(port);
+}
+
+CHIP_ERROR StartRpcClient()
+{
     return rpc::client::StartPacketProcessing();
 }
 
diff --git a/examples/fabric-admin/rpc/RpcClient.h b/examples/fabric-admin/rpc/RpcClient.h
index 6dd2b5b..41d37cf 100644
--- a/examples/fabric-admin/rpc/RpcClient.h
+++ b/examples/fabric-admin/rpc/RpcClient.h
@@ -22,17 +22,19 @@
 
 #include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h"
 
-constexpr uint16_t kFabricBridgeServerPort = 33002;
+/**
+ * @brief Sets the RPC server port to which the RPC client will connect.
+ *
+ * @param port The port number.
+ */
+void SetRpcRemoteServerPort(uint16_t port);
 
 /**
- * @brief Initializes the RPC client with the specified server port.
+ * @brief Starts packet processing for the RPC client.
  *
- * This function sets the RPC server port and starts packet processing for the RPC client.
- *
- * @param rpcServerPort The port number on which the RPC server is running.
- * @return CHIP_NO_ERROR on successful initialization, or an appropriate CHIP_ERROR on failure.
+ * @return CHIP_NO_ERROR on successful start, or an appropriate CHIP_ERROR on failure.
  */
-CHIP_ERROR InitRpcClient(uint16_t rpcServerPort);
+CHIP_ERROR StartRpcClient();
 
 /**
  * @brief Adds a synchronized device to the RPC client.
diff --git a/examples/fabric-admin/rpc/RpcServer.h b/examples/fabric-admin/rpc/RpcServer.h
index bc03bc0..d283c0d 100644
--- a/examples/fabric-admin/rpc/RpcServer.h
+++ b/examples/fabric-admin/rpc/RpcServer.h
@@ -18,6 +18,4 @@
 
 #pragma once
 
-constexpr uint16_t kFabricAdminServerPort = 33001;
-
 void InitRpcServer(uint16_t rpcServerPort);
diff --git a/examples/fabric-bridge-app/linux/RpcClient.cpp b/examples/fabric-bridge-app/linux/RpcClient.cpp
index 633b652..3ef88e8 100644
--- a/examples/fabric-bridge-app/linux/RpcClient.cpp
+++ b/examples/fabric-bridge-app/linux/RpcClient.cpp
@@ -107,9 +107,13 @@
 
 } // namespace
 
-CHIP_ERROR InitRpcClient(uint16_t rpcServerPort)
+void SetRpcRemoteServerPort(uint16_t port)
 {
-    rpc::client::SetRpcServerPort(rpcServerPort);
+    rpc::client::SetRpcServerPort(port);
+}
+
+CHIP_ERROR StartRpcClient()
+{
     return rpc::client::StartPacketProcessing();
 }
 
diff --git a/examples/fabric-bridge-app/linux/include/RpcClient.h b/examples/fabric-bridge-app/linux/include/RpcClient.h
index f183b2e..2455bc5 100644
--- a/examples/fabric-bridge-app/linux/include/RpcClient.h
+++ b/examples/fabric-bridge-app/linux/include/RpcClient.h
@@ -21,17 +21,21 @@
 #include <controller/CommissioningWindowParams.h>
 #include <platform/CHIPDeviceLayer.h>
 
-constexpr uint16_t kFabricAdminServerPort = 33001;
+/**
+ * Sets the RPC server port to which the RPC client will connect.
+ *
+ * @param port The port number.
+ */
+void SetRpcRemoteServerPort(uint16_t port);
 
 /**
- * Initializes the RPC client by setting the server port and starting packet processing.
+ * Starts packet processing for the RPC client.
  *
- * @param rpcServerPort The port number of the RPC server.
  * @return CHIP_ERROR An error code indicating the success or failure of the initialization process.
  * - CHIP_NO_ERROR: Initialization was successful.
  * - Other error codes indicating specific failure reasons.
  */
-CHIP_ERROR InitRpcClient(uint16_t rpcServerPort);
+CHIP_ERROR StartRpcClient();
 
 /**
  * Opens a commissioning window for a specified node using setup PIN (passcode).
diff --git a/examples/fabric-bridge-app/linux/include/RpcServer.h b/examples/fabric-bridge-app/linux/include/RpcServer.h
index f86858b..d283c0d 100644
--- a/examples/fabric-bridge-app/linux/include/RpcServer.h
+++ b/examples/fabric-bridge-app/linux/include/RpcServer.h
@@ -18,6 +18,4 @@
 
 #pragma once
 
-constexpr uint16_t kFabricBridgeServerPort = 33002;
-
 void InitRpcServer(uint16_t rpcServerPort);
diff --git a/examples/fabric-bridge-app/linux/main.cpp b/examples/fabric-bridge-app/linux/main.cpp
index 08c7078..d08673a 100644
--- a/examples/fabric-bridge-app/linux/main.cpp
+++ b/examples/fabric-bridge-app/linux/main.cpp
@@ -16,6 +16,10 @@
  *    limitations under the License.
  */
 
+#include <cstdlib>
+#include <sys/ioctl.h>
+#include <thread>
+
 #include <AppMain.h>
 
 #include "BridgedAdministratorCommissioning.h"
@@ -28,15 +32,13 @@
 #include <app/AttributeAccessInterfaceRegistry.h>
 #include <app/CommandHandlerInterfaceRegistry.h>
 #include <app/clusters/ecosystem-information-server/ecosystem-information-server.h>
+#include <lib/support/CHIPArgParser.hpp>
 
 #if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE
 #include "RpcClient.h"
 #include "RpcServer.h"
 #endif
 
-#include <sys/ioctl.h>
-#include <thread>
-
 // This is declared here and not in a header because zap/embr assumes all clusters
 // are defined in a static endpoint in the .zap file. From there, the codegen will
 // automatically use PluginApplicationCallbacksHeader.jinja to declare and call
@@ -59,8 +61,48 @@
 constexpr uint16_t kRetryIntervalS = 3;
 #endif
 
+uint16_t gFabricAdminServerPort = 33001;
+uint16_t gLocalServerPort       = 33002;
+
 BridgedDeviceBasicInformationImpl gBridgedDeviceBasicInformationAttributes;
 
+constexpr uint16_t kOptionFabricAdminServerPortNumber = 0xFF01;
+constexpr uint16_t kOptionLocalServerPortNumber       = 0xFF02;
+
+ArgParser::OptionDef sProgramCustomOptionDefs[] = {
+    { "fabric-admin-server-port", ArgParser::kArgumentRequired, kOptionFabricAdminServerPortNumber },
+    { "local-server-port", ArgParser::kArgumentRequired, kOptionLocalServerPortNumber },
+    {},
+};
+
+const char sProgramCustomOptionHelp[] = "  --fabric-admin-server-port <port>\n"
+                                        "       The fabric-admin RPC port number to connect to (default: 33001).\n"
+                                        "  --local-server-port <port>\n"
+                                        "       The port number for local RPC server (default: 33002).\n"
+                                        "\n";
+
+bool HandleCustomOption(const char * aProgram, ArgParser::OptionSet * aOptions, int aIdentifier, const char * aName,
+                        const char * aValue)
+{
+    switch (aIdentifier)
+    {
+    case kOptionFabricAdminServerPortNumber:
+        gFabricAdminServerPort = atoi(aValue);
+        break;
+    case kOptionLocalServerPortNumber:
+        gLocalServerPort = atoi(aValue);
+        break;
+    default:
+        ArgParser::PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName);
+        return false;
+    }
+
+    return true;
+}
+
+ArgParser::OptionSet sProgramCustomOptions = { HandleCustomOption, sProgramCustomOptionDefs, "GENERAL OPTIONS",
+                                               sProgramCustomOptionHelp };
+
 bool KeyboardHit()
 {
     int bytesWaiting;
@@ -105,7 +147,7 @@
 #if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE
 void AttemptRpcClientConnect(System::Layer * systemLayer, void * appState)
 {
-    if (InitRpcClient(kFabricAdminServerPort) == CHIP_NO_ERROR)
+    if (StartRpcClient() == CHIP_NO_ERROR)
     {
         ChipLogProgress(NotSpecified, "Connected to Fabric-Admin");
     }
@@ -258,7 +300,8 @@
     AttributeAccessInterfaceRegistry::Instance().Register(&gBridgedDeviceBasicInformationAttributes);
 
 #if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE
-    InitRpcServer(kFabricBridgeServerPort);
+    SetRpcRemoteServerPort(gFabricAdminServerPort);
+    InitRpcServer(gLocalServerPort);
     AttemptRpcClientConnect(&DeviceLayer::SystemLayer(), nullptr);
 #endif
 
@@ -285,7 +328,7 @@
 
 int main(int argc, char * argv[])
 {
-    if (ChipLinuxAppInit(argc, argv) != 0)
+    if (ChipLinuxAppInit(argc, argv, &sProgramCustomOptions) != 0)
     {
         return -1;
     }