From 5293911a6a32ddcd7fe388f20ef1a26fd43d34f9 Mon Sep 17 00:00:00 2001 From: rgoliver Date: Fri, 29 Jul 2022 17:20:31 -0400 Subject: [PATCH] RPC: Support reconnect for linux rpc server (#21185) Fork default Pigweed rpc server implementation and change the behaviour on disconnect from closing and returning, to awaiting a reconnect. --- examples/chef/linux/BUILD.gn | 2 +- examples/lighting-app/linux/BUILD.gn | 2 +- examples/lighting-app/linux/main.cpp | 8 -- examples/platform/linux/system_rpc_server.cc | 118 +++++++++++++++++++ 4 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 examples/platform/linux/system_rpc_server.cc diff --git a/examples/chef/linux/BUILD.gn b/examples/chef/linux/BUILD.gn index 769bcef34d5777..bef04eab320ea5 100644 --- a/examples/chef/linux/BUILD.gn +++ b/examples/chef/linux/BUILD.gn @@ -66,7 +66,7 @@ executable("${sample_name}") { sources += [ "${chip_root}/examples/platform/linux/Rpc.cpp", - "${dir_pigweed}/targets/host/system_rpc_server.cc", + "${chip_root}/examples/platform/linux/system_rpc_server.cc", ] deps += [ diff --git a/examples/lighting-app/linux/BUILD.gn b/examples/lighting-app/linux/BUILD.gn index 1cba8d80fe1c16..721f408437d7c7 100644 --- a/examples/lighting-app/linux/BUILD.gn +++ b/examples/lighting-app/linux/BUILD.gn @@ -61,7 +61,7 @@ executable("chip-lighting-app") { sources += [ "${chip_root}/examples/platform/linux/Rpc.cpp", - "${dir_pigweed}/targets/host/system_rpc_server.cc", + "${chip_root}/examples/platform/linux/system_rpc_server.cc", ] deps += [ diff --git a/examples/lighting-app/linux/main.cpp b/examples/lighting-app/linux/main.cpp index b77d4b4fe1b3f1..7813c59979c929 100644 --- a/examples/lighting-app/linux/main.cpp +++ b/examples/lighting-app/linux/main.cpp @@ -26,10 +26,6 @@ #include #include -#if defined(PW_RPC_ENABLED) -#include "Rpc.h" -#endif // PW_RPC_ENABLED - using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; @@ -79,10 +75,6 @@ void ApplicationInit() int main(int argc, char * argv[]) { -#if PW_RPC_ENABLED - chip::rpc::Init(); -#endif - if (ChipLinuxAppInit(argc, argv) != 0) { return -1; diff --git a/examples/platform/linux/system_rpc_server.cc b/examples/platform/linux/system_rpc_server.cc new file mode 100644 index 00000000000000..d9822a7110d9cc --- /dev/null +++ b/examples/platform/linux/system_rpc_server.cc @@ -0,0 +1,118 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is a fork from: third_party/pigweed/repo/targets/host/system_rpc_server.cc + * But changes the disconnect behaviour from closing and returning, to awaiting a + * reconnection. + */ + +#include +#include +#include + +#include "pw_assert/check.h" +#include "pw_hdlc/rpc_channel.h" +#include "pw_hdlc/rpc_packets.h" +#include "pw_log/log.h" +#include "pw_rpc_system_server/rpc_server.h" +#include "pw_stream/socket_stream.h" + +namespace pw::rpc::system_server { +namespace { + +constexpr size_t kMaxTransmissionUnit = 512; +uint16_t socket_port = 33000; + +stream::SocketStream socket_stream; + +hdlc::RpcChannelOutput hdlc_channel_output(socket_stream, hdlc::kDefaultRpcAddress, "HDLC channel"); +Channel channels[] = { rpc::Channel::Create<1>(&hdlc_channel_output) }; +rpc::Server server(channels); + +} // namespace + +void set_socket_port(uint16_t new_socket_port) +{ + socket_port = new_socket_port; +} + +int GetServerSocketFd() +{ + return socket_stream.connection_fd(); +} + +void Init() +{ + log_basic::SetOutput([](std::string_view log) { + std::fprintf(stderr, "%.*s\n", static_cast(log.size()), log.data()); + hdlc::WriteUIFrame(1, as_bytes(span(log)), socket_stream).IgnoreError(); // TODO(pwbug/387): Handle Status properly + }); + + PW_LOG_INFO("Starting pw_rpc server on port %d", socket_port); + PW_CHECK_OK(socket_stream.Serve(socket_port)); +} + +rpc::Server & Server() +{ + return server; +} + +Status Start() +{ + // Declare a buffer for decoding incoming HDLC frames. + std::array input_buffer; + hdlc::Decoder decoder(input_buffer); + + while (true) + { + std::array data; + auto ret_val = socket_stream.Read(data); + if (!ret_val.ok()) + { + if (ret_val.status() == Status::OutOfRange()) + { + // An out of range status indicates the remote end has disconnected. + // Start to serve the connection again, which will allow another + // remote to connect. + PW_CHECK_OK(socket_stream.Serve(socket_port)); + } + continue; + } + + for (std::byte byte : ret_val.value()) + { + auto result = decoder.Process(byte); + if (!result.ok()) + { + // Non-OK means there isn't a complete packet yet, or there was some + // other issue. Wait for more bytes that form a complete packet. + continue; + } + hdlc::Frame & frame = result.value(); + if (frame.address() != hdlc::kDefaultRpcAddress) + { + // Wrong address; ignore the packet for now. In the future, this branch + // could expand to add packet routing or metrics. + continue; + } + + server.ProcessPacket(frame.data(), hdlc_channel_output).IgnoreError(); + } + } +} + +} // namespace pw::rpc::system_server