| // Copyright 2021 The Pigweed Authors |
| // |
| // 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 |
| // |
| // https://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. |
| |
| #include "pw_rpc/internal/endpoint.h" |
| |
| #include "pw_log/log.h" |
| |
| namespace pw::rpc::internal { |
| |
| Endpoint::~Endpoint() { |
| // Since the calls remove themselves from the Endpoint in |
| // CloseAndSendResponse(), close responders until no responders remain. |
| while (!calls_.empty()) { |
| calls_.front().CloseAndSendResponse(OkStatus()).IgnoreError(); |
| } |
| } |
| |
| Result<Packet> Endpoint::ProcessPacket(std::span<const std::byte> data, |
| Packet::Destination destination, |
| Call*& ongoing_call) { |
| Result<Packet> result = Packet::FromBuffer(data); |
| |
| if (!result.ok()) { |
| PW_LOG_WARN("Failed to decode pw_rpc packet"); |
| return Status::DataLoss(); |
| } |
| |
| Packet& packet = *result; |
| |
| if (packet.channel_id() == Channel::kUnassignedChannelId || |
| packet.service_id() == 0 || packet.method_id() == 0) { |
| PW_LOG_WARN("Received malformed pw_rpc packet"); |
| return Status::DataLoss(); |
| } |
| |
| if (packet.destination() != destination) { |
| return Status::InvalidArgument(); |
| } |
| |
| // Find an existing reader/writer for this RPC, if any. |
| ongoing_call = FindCall(packet); |
| |
| return result; |
| } |
| |
| void Endpoint::RegisterCall(Call& call) { |
| Call* const existing_call = |
| FindCallById(call.channel_id(), call.service_id(), call.method_id()); |
| |
| if (existing_call != nullptr) { |
| existing_call->HandleError(Status::Cancelled()); |
| } |
| |
| RegisterUniqueCall(call); |
| } |
| |
| Channel* Endpoint::GetInternalChannel(uint32_t id) const { |
| for (Channel& c : channels_) { |
| if (c.id() == id) { |
| return &c; |
| } |
| } |
| return nullptr; |
| } |
| |
| Channel* Endpoint::AssignChannel(uint32_t id, ChannelOutput& interface) { |
| internal::Channel* channel = |
| GetInternalChannel(Channel::kUnassignedChannelId); |
| if (channel == nullptr) { |
| return nullptr; |
| } |
| |
| *channel = Channel(id, &interface); |
| return channel; |
| } |
| |
| Call* Endpoint::FindCallById(uint32_t channel_id, |
| uint32_t service_id, |
| uint32_t method_id) { |
| for (Call& call : calls_) { |
| if (channel_id == call.channel_id() && service_id == call.service_id() && |
| method_id == call.method_id()) { |
| return &call; |
| } |
| } |
| return nullptr; |
| } |
| |
| } // namespace pw::rpc::internal |