blob: aeecd91254c1b121df7e41464eb3f43e43aabbe0 [file] [log] [blame]
Wyatt Heplerddfc0772021-09-03 16:46:25 -07001// Copyright 2021 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15#include "pw_rpc/internal/endpoint.h"
16
Wyatt Heplerc8bdc7d2021-10-20 09:29:01 -070017#include <mutex>
18
Wyatt Heplerddfc0772021-09-03 16:46:25 -070019#include "pw_log/log.h"
Wyatt Heplerc8bdc7d2021-10-20 09:29:01 -070020#include "pw_rpc/internal/lock.h"
Wyatt Heplerddfc0772021-09-03 16:46:25 -070021
22namespace pw::rpc::internal {
23
Wyatt Heplerc8bdc7d2021-10-20 09:29:01 -070024RpcLock& rpc_lock() {
25 static RpcLock lock;
26 return lock;
27}
28
Wyatt Heplerddfc0772021-09-03 16:46:25 -070029Endpoint::~Endpoint() {
30 // Since the calls remove themselves from the Endpoint in
31 // CloseAndSendResponse(), close responders until no responders remain.
32 while (!calls_.empty()) {
33 calls_.front().CloseAndSendResponse(OkStatus()).IgnoreError();
34 }
35}
36
37Result<Packet> Endpoint::ProcessPacket(std::span<const std::byte> data,
Wyatt Hepler1d000cc2021-10-20 11:05:06 -070038 Packet::Destination destination) {
Wyatt Heplerddfc0772021-09-03 16:46:25 -070039 Result<Packet> result = Packet::FromBuffer(data);
40
41 if (!result.ok()) {
42 PW_LOG_WARN("Failed to decode pw_rpc packet");
43 return Status::DataLoss();
44 }
45
46 Packet& packet = *result;
47
48 if (packet.channel_id() == Channel::kUnassignedChannelId ||
49 packet.service_id() == 0 || packet.method_id() == 0) {
50 PW_LOG_WARN("Received malformed pw_rpc packet");
51 return Status::DataLoss();
52 }
53
54 if (packet.destination() != destination) {
55 return Status::InvalidArgument();
56 }
57
Wyatt Heplerddfc0772021-09-03 16:46:25 -070058 return result;
59}
60
Wyatt Hepler960f5df2021-09-08 10:17:21 -070061void Endpoint::RegisterCall(Call& call) {
Wyatt Heplerc8bdc7d2021-10-20 09:29:01 -070062 std::lock_guard lock(rpc_lock());
63
Wyatt Hepler960f5df2021-09-08 10:17:21 -070064 Call* const existing_call =
65 FindCallById(call.channel_id(), call.service_id(), call.method_id());
66
67 if (existing_call != nullptr) {
68 existing_call->HandleError(Status::Cancelled());
Wyatt Heplerc8bdc7d2021-10-20 09:29:01 -070069 rpc_lock().lock(); // Reacquire after releasing to call the user callback
Wyatt Heplerddfc0772021-09-03 16:46:25 -070070 }
Wyatt Hepler960f5df2021-09-08 10:17:21 -070071
72 RegisterUniqueCall(call);
Wyatt Heplerddfc0772021-09-03 16:46:25 -070073}
74
75Channel* Endpoint::GetInternalChannel(uint32_t id) const {
76 for (Channel& c : channels_) {
77 if (c.id() == id) {
78 return &c;
79 }
80 }
81 return nullptr;
82}
83
84Channel* Endpoint::AssignChannel(uint32_t id, ChannelOutput& interface) {
85 internal::Channel* channel =
86 GetInternalChannel(Channel::kUnassignedChannelId);
87 if (channel == nullptr) {
88 return nullptr;
89 }
90
91 *channel = Channel(id, &interface);
92 return channel;
93}
94
Wyatt Hepler960f5df2021-09-08 10:17:21 -070095Call* Endpoint::FindCallById(uint32_t channel_id,
96 uint32_t service_id,
97 uint32_t method_id) {
98 for (Call& call : calls_) {
99 if (channel_id == call.channel_id() && service_id == call.service_id() &&
100 method_id == call.method_id()) {
101 return &call;
102 }
103 }
104 return nullptr;
105}
106
Wyatt Heplerddfc0772021-09-03 16:46:25 -0700107} // namespace pw::rpc::internal