xref: /aosp_15_r20/external/pigweed/pw_rpc/server.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2020 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker // clang-format off
16*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/log_config.h" // PW_LOG_* macros must be first.
17*61c4878aSAndroid Build Coastguard Worker 
18*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/server.h"
19*61c4878aSAndroid Build Coastguard Worker // clang-format on
20*61c4878aSAndroid Build Coastguard Worker 
21*61c4878aSAndroid Build Coastguard Worker #include <algorithm>
22*61c4878aSAndroid Build Coastguard Worker 
23*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/endpoint.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/packet.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/service_id.h"
27*61c4878aSAndroid Build Coastguard Worker 
28*61c4878aSAndroid Build Coastguard Worker namespace pw::rpc {
29*61c4878aSAndroid Build Coastguard Worker namespace {
30*61c4878aSAndroid Build Coastguard Worker 
31*61c4878aSAndroid Build Coastguard Worker using internal::Packet;
32*61c4878aSAndroid Build Coastguard Worker using internal::pwpb::PacketType;
33*61c4878aSAndroid Build Coastguard Worker 
34*61c4878aSAndroid Build Coastguard Worker }  // namespace
35*61c4878aSAndroid Build Coastguard Worker 
ProcessPacket(ConstByteSpan packet_data)36*61c4878aSAndroid Build Coastguard Worker Status Server::ProcessPacket(ConstByteSpan packet_data) {
37*61c4878aSAndroid Build Coastguard Worker   PW_TRY_ASSIGN(Packet packet,
38*61c4878aSAndroid Build Coastguard Worker                 Endpoint::ProcessPacket(packet_data, Packet::kServer));
39*61c4878aSAndroid Build Coastguard Worker   return ProcessPacket(packet);
40*61c4878aSAndroid Build Coastguard Worker }
41*61c4878aSAndroid Build Coastguard Worker 
ProcessPacket(internal::Packet packet)42*61c4878aSAndroid Build Coastguard Worker Status Server::ProcessPacket(internal::Packet packet) {
43*61c4878aSAndroid Build Coastguard Worker   internal::rpc_lock().lock();
44*61c4878aSAndroid Build Coastguard Worker 
45*61c4878aSAndroid Build Coastguard Worker   static constexpr bool kLogAllIncomingPackets = false;
46*61c4878aSAndroid Build Coastguard Worker   if constexpr (kLogAllIncomingPackets) {
47*61c4878aSAndroid Build Coastguard Worker     PW_LOG_INFO("RPC server received packet type %u for %u:%08x/%08x",
48*61c4878aSAndroid Build Coastguard Worker                 static_cast<unsigned>(packet.type()),
49*61c4878aSAndroid Build Coastguard Worker                 static_cast<unsigned>(packet.channel_id()),
50*61c4878aSAndroid Build Coastguard Worker                 static_cast<unsigned>(packet.service_id()),
51*61c4878aSAndroid Build Coastguard Worker                 static_cast<unsigned>(packet.method_id()));
52*61c4878aSAndroid Build Coastguard Worker   }
53*61c4878aSAndroid Build Coastguard Worker 
54*61c4878aSAndroid Build Coastguard Worker   internal::ChannelBase* channel = GetInternalChannel(packet.channel_id());
55*61c4878aSAndroid Build Coastguard Worker   if (channel == nullptr) {
56*61c4878aSAndroid Build Coastguard Worker     internal::rpc_lock().unlock();
57*61c4878aSAndroid Build Coastguard Worker     PW_LOG_WARN("RPC server received packet for unknown channel %u",
58*61c4878aSAndroid Build Coastguard Worker                 static_cast<unsigned>(packet.channel_id()));
59*61c4878aSAndroid Build Coastguard Worker     return Status::Unavailable();
60*61c4878aSAndroid Build Coastguard Worker   }
61*61c4878aSAndroid Build Coastguard Worker 
62*61c4878aSAndroid Build Coastguard Worker   const auto [service, method] = FindMethodLocked(packet);
63*61c4878aSAndroid Build Coastguard Worker 
64*61c4878aSAndroid Build Coastguard Worker   if (method == nullptr) {
65*61c4878aSAndroid Build Coastguard Worker     // Don't send responses to errors to avoid infinite error cycles.
66*61c4878aSAndroid Build Coastguard Worker     if (packet.type() != PacketType::CLIENT_ERROR) {
67*61c4878aSAndroid Build Coastguard Worker       channel->Send(Packet::ServerError(packet, Status::NotFound()))
68*61c4878aSAndroid Build Coastguard Worker           .IgnoreError();
69*61c4878aSAndroid Build Coastguard Worker     }
70*61c4878aSAndroid Build Coastguard Worker     internal::rpc_lock().unlock();
71*61c4878aSAndroid Build Coastguard Worker     PW_LOG_DEBUG("Received packet on channel %u for unknown RPC %08x/%08x",
72*61c4878aSAndroid Build Coastguard Worker                  static_cast<unsigned>(packet.channel_id()),
73*61c4878aSAndroid Build Coastguard Worker                  static_cast<unsigned>(packet.service_id()),
74*61c4878aSAndroid Build Coastguard Worker                  static_cast<unsigned>(packet.method_id()));
75*61c4878aSAndroid Build Coastguard Worker     return OkStatus();  // OK since the packet was handled.
76*61c4878aSAndroid Build Coastguard Worker   }
77*61c4878aSAndroid Build Coastguard Worker 
78*61c4878aSAndroid Build Coastguard Worker   // Handle request packets separately to avoid an unnecessary call lookup. The
79*61c4878aSAndroid Build Coastguard Worker   // Call constructor looks up and cancels any duplicate calls.
80*61c4878aSAndroid Build Coastguard Worker   if (packet.type() == PacketType::REQUEST) {
81*61c4878aSAndroid Build Coastguard Worker     const internal::CallContext context(
82*61c4878aSAndroid Build Coastguard Worker         *this, packet.channel_id(), *service, *method, packet.call_id());
83*61c4878aSAndroid Build Coastguard Worker     method->Invoke(context, packet);
84*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
85*61c4878aSAndroid Build Coastguard Worker   }
86*61c4878aSAndroid Build Coastguard Worker 
87*61c4878aSAndroid Build Coastguard Worker   IntrusiveList<internal::Call>::iterator call = FindCall(packet);
88*61c4878aSAndroid Build Coastguard Worker 
89*61c4878aSAndroid Build Coastguard Worker   switch (packet.type()) {
90*61c4878aSAndroid Build Coastguard Worker     case PacketType::CLIENT_STREAM:
91*61c4878aSAndroid Build Coastguard Worker       HandleClientStreamPacket(packet, *channel, call);
92*61c4878aSAndroid Build Coastguard Worker       break;
93*61c4878aSAndroid Build Coastguard Worker     case PacketType::CLIENT_ERROR:
94*61c4878aSAndroid Build Coastguard Worker       if (call != calls_end()) {
95*61c4878aSAndroid Build Coastguard Worker         PW_LOG_DEBUG("Server call %u for %u:%08x/%08x terminated with error %s",
96*61c4878aSAndroid Build Coastguard Worker                      static_cast<unsigned>(packet.call_id()),
97*61c4878aSAndroid Build Coastguard Worker                      static_cast<unsigned>(packet.channel_id()),
98*61c4878aSAndroid Build Coastguard Worker                      static_cast<unsigned>(packet.service_id()),
99*61c4878aSAndroid Build Coastguard Worker                      static_cast<unsigned>(packet.method_id()),
100*61c4878aSAndroid Build Coastguard Worker                      packet.status().str());
101*61c4878aSAndroid Build Coastguard Worker         call->HandleError(packet.status());
102*61c4878aSAndroid Build Coastguard Worker       } else {
103*61c4878aSAndroid Build Coastguard Worker         internal::rpc_lock().unlock();
104*61c4878aSAndroid Build Coastguard Worker       }
105*61c4878aSAndroid Build Coastguard Worker       break;
106*61c4878aSAndroid Build Coastguard Worker     case PacketType::CLIENT_REQUEST_COMPLETION:
107*61c4878aSAndroid Build Coastguard Worker       HandleCompletionRequest(packet, *channel, call);
108*61c4878aSAndroid Build Coastguard Worker       break;
109*61c4878aSAndroid Build Coastguard Worker     case PacketType::REQUEST:  // Handled above
110*61c4878aSAndroid Build Coastguard Worker     case PacketType::RESPONSE:
111*61c4878aSAndroid Build Coastguard Worker     case PacketType::SERVER_ERROR:
112*61c4878aSAndroid Build Coastguard Worker     case PacketType::SERVER_STREAM:
113*61c4878aSAndroid Build Coastguard Worker     default:
114*61c4878aSAndroid Build Coastguard Worker       internal::rpc_lock().unlock();
115*61c4878aSAndroid Build Coastguard Worker       PW_LOG_WARN("pw_rpc server unable to handle packet of type %u",
116*61c4878aSAndroid Build Coastguard Worker                   unsigned(packet.type()));
117*61c4878aSAndroid Build Coastguard Worker   }
118*61c4878aSAndroid Build Coastguard Worker 
119*61c4878aSAndroid Build Coastguard Worker   return OkStatus();  // OK since the packet was handled
120*61c4878aSAndroid Build Coastguard Worker }
121*61c4878aSAndroid Build Coastguard Worker 
FindMethod(uint32_t service_id,uint32_t method_id)122*61c4878aSAndroid Build Coastguard Worker std::tuple<Service*, const internal::Method*> Server::FindMethod(
123*61c4878aSAndroid Build Coastguard Worker     uint32_t service_id, uint32_t method_id) {
124*61c4878aSAndroid Build Coastguard Worker   internal::RpcLockGuard lock;
125*61c4878aSAndroid Build Coastguard Worker   return FindMethodLocked(service_id, method_id);
126*61c4878aSAndroid Build Coastguard Worker }
127*61c4878aSAndroid Build Coastguard Worker 
FindMethodLocked(uint32_t service_id,uint32_t method_id)128*61c4878aSAndroid Build Coastguard Worker std::tuple<Service*, const internal::Method*> Server::FindMethodLocked(
129*61c4878aSAndroid Build Coastguard Worker     uint32_t service_id, uint32_t method_id) {
130*61c4878aSAndroid Build Coastguard Worker   auto service = std::find_if(services_.begin(), services_.end(), [&](auto& s) {
131*61c4878aSAndroid Build Coastguard Worker     return internal::UnwrapServiceId(s.service_id()) == service_id;
132*61c4878aSAndroid Build Coastguard Worker   });
133*61c4878aSAndroid Build Coastguard Worker 
134*61c4878aSAndroid Build Coastguard Worker   if (service == services_.end()) {
135*61c4878aSAndroid Build Coastguard Worker     return {};
136*61c4878aSAndroid Build Coastguard Worker   }
137*61c4878aSAndroid Build Coastguard Worker 
138*61c4878aSAndroid Build Coastguard Worker   return {&(*service), service->FindMethod(method_id)};
139*61c4878aSAndroid Build Coastguard Worker }
140*61c4878aSAndroid Build Coastguard Worker 
HandleCompletionRequest(const internal::Packet & packet,internal::ChannelBase & channel,IntrusiveList<internal::Call>::iterator call) const141*61c4878aSAndroid Build Coastguard Worker void Server::HandleCompletionRequest(
142*61c4878aSAndroid Build Coastguard Worker     const internal::Packet& packet,
143*61c4878aSAndroid Build Coastguard Worker     internal::ChannelBase& channel,
144*61c4878aSAndroid Build Coastguard Worker     IntrusiveList<internal::Call>::iterator call) const {
145*61c4878aSAndroid Build Coastguard Worker   if (call == calls_end()) {
146*61c4878aSAndroid Build Coastguard Worker     channel.Send(Packet::ServerError(packet, Status::FailedPrecondition()))
147*61c4878aSAndroid Build Coastguard Worker         .IgnoreError();  // Errors are logged in Channel::Send.
148*61c4878aSAndroid Build Coastguard Worker     internal::rpc_lock().unlock();
149*61c4878aSAndroid Build Coastguard Worker     PW_LOG_DEBUG(
150*61c4878aSAndroid Build Coastguard Worker         "Received a request completion packet for %u:%08x/%08x, which is not a"
151*61c4878aSAndroid Build Coastguard Worker         "pending call",
152*61c4878aSAndroid Build Coastguard Worker         static_cast<unsigned>(packet.channel_id()),
153*61c4878aSAndroid Build Coastguard Worker         static_cast<unsigned>(packet.service_id()),
154*61c4878aSAndroid Build Coastguard Worker         static_cast<unsigned>(packet.method_id()));
155*61c4878aSAndroid Build Coastguard Worker     return;
156*61c4878aSAndroid Build Coastguard Worker   }
157*61c4878aSAndroid Build Coastguard Worker 
158*61c4878aSAndroid Build Coastguard Worker   if (call->client_requested_completion()) {
159*61c4878aSAndroid Build Coastguard Worker     internal::rpc_lock().unlock();
160*61c4878aSAndroid Build Coastguard Worker     PW_LOG_DEBUG("Received multiple completion requests for %u:%08x/%08x",
161*61c4878aSAndroid Build Coastguard Worker                  static_cast<unsigned>(packet.channel_id()),
162*61c4878aSAndroid Build Coastguard Worker                  static_cast<unsigned>(packet.service_id()),
163*61c4878aSAndroid Build Coastguard Worker                  static_cast<unsigned>(packet.method_id()));
164*61c4878aSAndroid Build Coastguard Worker     return;
165*61c4878aSAndroid Build Coastguard Worker   }
166*61c4878aSAndroid Build Coastguard Worker 
167*61c4878aSAndroid Build Coastguard Worker   static_cast<internal::ServerCall&>(*call).HandleClientRequestedCompletion();
168*61c4878aSAndroid Build Coastguard Worker }
169*61c4878aSAndroid Build Coastguard Worker 
HandleClientStreamPacket(const internal::Packet & packet,internal::ChannelBase & channel,IntrusiveList<internal::Call>::iterator call) const170*61c4878aSAndroid Build Coastguard Worker void Server::HandleClientStreamPacket(
171*61c4878aSAndroid Build Coastguard Worker     const internal::Packet& packet,
172*61c4878aSAndroid Build Coastguard Worker     internal::ChannelBase& channel,
173*61c4878aSAndroid Build Coastguard Worker     IntrusiveList<internal::Call>::iterator call) const {
174*61c4878aSAndroid Build Coastguard Worker   if (call == calls_end()) {
175*61c4878aSAndroid Build Coastguard Worker     channel.Send(Packet::ServerError(packet, Status::FailedPrecondition()))
176*61c4878aSAndroid Build Coastguard Worker         .IgnoreError();  // Errors are logged in Channel::Send.
177*61c4878aSAndroid Build Coastguard Worker     internal::rpc_lock().unlock();
178*61c4878aSAndroid Build Coastguard Worker     PW_LOG_DEBUG(
179*61c4878aSAndroid Build Coastguard Worker         "Received client stream packet for %u:%08x/%08x, which is not pending",
180*61c4878aSAndroid Build Coastguard Worker         static_cast<unsigned>(packet.channel_id()),
181*61c4878aSAndroid Build Coastguard Worker         static_cast<unsigned>(packet.service_id()),
182*61c4878aSAndroid Build Coastguard Worker         static_cast<unsigned>(packet.method_id()));
183*61c4878aSAndroid Build Coastguard Worker     return;
184*61c4878aSAndroid Build Coastguard Worker   }
185*61c4878aSAndroid Build Coastguard Worker 
186*61c4878aSAndroid Build Coastguard Worker   if (!call->has_client_stream()) {
187*61c4878aSAndroid Build Coastguard Worker     channel.Send(Packet::ServerError(packet, Status::InvalidArgument()))
188*61c4878aSAndroid Build Coastguard Worker         .IgnoreError();  // Errors are logged in Channel::Send.
189*61c4878aSAndroid Build Coastguard Worker     internal::rpc_lock().unlock();
190*61c4878aSAndroid Build Coastguard Worker     PW_LOG_DEBUG(
191*61c4878aSAndroid Build Coastguard Worker         "Received client stream packet for %u:%08x/%08x, which doesn't have a "
192*61c4878aSAndroid Build Coastguard Worker         "client stream",
193*61c4878aSAndroid Build Coastguard Worker         static_cast<unsigned>(packet.channel_id()),
194*61c4878aSAndroid Build Coastguard Worker         static_cast<unsigned>(packet.service_id()),
195*61c4878aSAndroid Build Coastguard Worker         static_cast<unsigned>(packet.method_id()));
196*61c4878aSAndroid Build Coastguard Worker     return;
197*61c4878aSAndroid Build Coastguard Worker   }
198*61c4878aSAndroid Build Coastguard Worker 
199*61c4878aSAndroid Build Coastguard Worker   if (call->client_requested_completion()) {
200*61c4878aSAndroid Build Coastguard Worker     channel.Send(Packet::ServerError(packet, Status::FailedPrecondition()))
201*61c4878aSAndroid Build Coastguard Worker         .IgnoreError();  // Errors are logged in Channel::Send.
202*61c4878aSAndroid Build Coastguard Worker     internal::rpc_lock().unlock();
203*61c4878aSAndroid Build Coastguard Worker     PW_LOG_DEBUG(
204*61c4878aSAndroid Build Coastguard Worker         "Received client stream packet for %u:%08x/%08x, but its client stream "
205*61c4878aSAndroid Build Coastguard Worker         "is closed",
206*61c4878aSAndroid Build Coastguard Worker         static_cast<unsigned>(packet.channel_id()),
207*61c4878aSAndroid Build Coastguard Worker         static_cast<unsigned>(packet.service_id()),
208*61c4878aSAndroid Build Coastguard Worker         static_cast<unsigned>(packet.method_id()));
209*61c4878aSAndroid Build Coastguard Worker     return;
210*61c4878aSAndroid Build Coastguard Worker   }
211*61c4878aSAndroid Build Coastguard Worker 
212*61c4878aSAndroid Build Coastguard Worker   call->HandlePayload(packet.payload());
213*61c4878aSAndroid Build Coastguard Worker }
214*61c4878aSAndroid Build Coastguard Worker 
215*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::rpc
216